]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Initial implementation of PCM simple API extension.
authorJaroslav Kysela <perex@perex.cz>
Fri, 26 Mar 2004 16:08:01 +0000 (16:08 +0000)
committerJaroslav Kysela <perex@perex.cz>
Fri, 26 Mar 2004 16:08:01 +0000 (16:08 +0000)
include/pcm.h
src/Versions
src/pcm/Makefile.am
src/pcm/pcm_simple.c [new file with mode: 0644]

index b6d485f26d3af506b7707a9fb5ccc22d8992981a..bbbb582fec83c931cd88477994503da58b65a32f 100644 (file)
@@ -1241,6 +1241,14 @@ typedef enum _snd_spcm_xrun_type {
        SND_SPCM_XRUN_STOP
 } snd_spcm_xrun_type_t;
 
+/** Simple PCM duplex type */
+typedef enum _snd_spcm_duplex_type {
+       /** liberal duplex - the buffer and period sizes might not match */
+       SND_SPCM_DUPLEX_LIBERAL = 0,
+       /** pedantic duplex - the buffer and period sizes MUST match */
+       SND_SPCM_DUPLEX_PEDANTIC
+} snd_spcm_duplex_type_t;
+
 int snd_spcm_init(snd_pcm_t *pcm,
                  unsigned int rate,
                  unsigned int channels,
@@ -1258,7 +1266,13 @@ int snd_spcm_init_duplex(snd_pcm_t *playback_pcm,
                         snd_pcm_subformat_t subformat,
                         snd_spcm_latency_t latency,
                         snd_pcm_access_t access,
-                        snd_spcm_xrun_type_t xrun_type);
+                        snd_spcm_xrun_type_t xrun_type,
+                        snd_spcm_duplex_type_t duplex_type);
+
+int snd_spcm_init_get_params(snd_pcm_t *pcm,
+                            unsigned int *rate,
+                            snd_pcm_uframes_t *buffer_size,
+                            snd_pcm_uframes_t *period_size);
 
 /** \} */
 
index 52eb295c55ea3eea0f0df2d352c33d96ed008098..c4a9d9e55c6392d88027b2518e85a7fb92e633a8 100644 (file)
@@ -144,3 +144,11 @@ ALSA_0.9.8 {
     snd_ctl_elem_remove;
     snd_hctl_poll_descriptors_revents;
 } ALSA_0.9.7;
+
+ALSA_1.0.4 {
+  global:
+
+    snd_spcm_init;
+    snd_spcm_init_duplex;
+    snd_spcm_init_get_params;
+} ALSA_0.9.8;
index 64c35076c62c0578b94eafcdfe93cc7949d49776..07213f21f8e4e28d28f0472caf0f814a70368d85 100644 (file)
@@ -4,7 +4,7 @@ DIST_SUBDIRS = ext scopes
 EXTRA_LTLIBRARIES = libpcm.la
 
 libpcm_la_SOURCES = atomic.c mask.c interval.c \
-                   pcm.c pcm_params.c \
+                   pcm.c pcm_params.c pcm_simple.c \
                    pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \
                    pcm_route.c pcm_mulaw.c pcm_alaw.c pcm_adpcm.c \
                    pcm_rate.c pcm_plug.c pcm_misc.c pcm_mmap.c pcm_multi.c \
diff --git a/src/pcm/pcm_simple.c b/src/pcm/pcm_simple.c
new file mode 100644 (file)
index 0000000..aab509a
--- /dev/null
@@ -0,0 +1,268 @@
+/**
+ * \file pcm/pcm_simple.c
+ * \ingroup PCM_Simple
+ * \brief PCM Simple Interface
+ * \author Jaroslav Kysela <perex@suse.cz>
+ * \date 2004
+ */
+/*
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include "pcm_local.h"
+
+static int set_buffer_time(snd_spcm_latency_t latency,
+                          unsigned int *buffer_time)
+{
+       switch (latency) {
+       case SND_SPCM_LATENCY_STANDARD:
+               *buffer_time = 350000;
+               break;
+       case SND_SPCM_LATENCY_MEDIUM:
+               *buffer_time = 25000;
+               break;
+       case SND_SPCM_LATENCY_REALTIME:
+               *buffer_time = 2500;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int set_hw_params(snd_pcm_t *pcm,
+                        snd_pcm_hw_params_t *hw_params,
+                        unsigned int *rate,
+                        unsigned int channels,
+                        snd_pcm_format_t format,
+                        snd_pcm_subformat_t subformat,
+                        unsigned int *buffer_time,
+                        unsigned int *period_time,
+                        snd_pcm_access_t access)
+{
+       int err;
+
+       /*
+        * hardware parameters
+        */     
+       err = snd_pcm_hw_params_any(pcm, hw_params);
+       if (err < 0)
+               return err;
+       err = snd_pcm_hw_params_set_access(pcm, hw_params, access);
+       if (err < 0)
+               return err;
+       err = snd_pcm_hw_params_set_format(pcm, hw_params, format);
+       if (err < 0)
+               return err;
+       if (subformat != SND_PCM_SUBFORMAT_STD) {
+               err = snd_pcm_hw_params_set_subformat(pcm, hw_params, subformat);
+               if (err < 0)
+                       return err;
+       }
+       err = snd_pcm_hw_params_set_channels(pcm, hw_params, channels);
+       if (err < 0)
+               return err;
+       err = INTERNAL(snd_pcm_hw_params_set_rate_near)(pcm, hw_params, rate, 0);
+       if (err < 0)
+               return err;
+       err = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(pcm, hw_params, buffer_time, NULL);
+       if (err < 0)
+               return err;
+       if (period_time == NULL || *period_time == 0) {
+               unsigned int periods = 3;
+               err = INTERNAL(snd_pcm_hw_params_set_periods_near)(pcm, hw_params, &periods, NULL);
+               if (err < 0)
+                       return err;
+               if (periods == 1)
+                       return -EINVAL;
+               if (*period_time == 0) {
+                       err = INTERNAL(snd_pcm_hw_params_get_period_time)(hw_params, period_time, NULL);
+                       if (err < 0)
+                               return err;
+               }                       
+       } else {
+               err = snd_pcm_hw_params_set_period_time(pcm, hw_params, *period_time, 0);
+               if (err < 0)
+                       return err;
+               if (*buffer_time == *period_time)
+                       return -EINVAL;
+       }
+       err = snd_pcm_hw_params(pcm, hw_params);
+       if (err < 0)
+               return err;
+       return 0;
+}              
+
+static int set_sw_params(snd_pcm_t *pcm,
+                        snd_pcm_sw_params_t *sw_params,
+                        snd_spcm_xrun_type_t xrun_type)
+{
+       int err;
+
+       err = snd_pcm_sw_params_current(pcm, sw_params);                
+       if (err < 0)
+               return err;
+       err = snd_pcm_sw_params_set_start_threshold(pcm, sw_params, (pcm->buffer_size / pcm->period_size) * pcm->period_size);
+       if (err < 0)
+               return err;
+       err = snd_pcm_sw_params_set_avail_min(pcm, sw_params, pcm->period_size);
+       if (err < 0)
+               return err;
+       switch (xrun_type) {
+       case SND_SPCM_XRUN_STOP:
+               err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->buffer_size);
+               break;
+       case SND_SPCM_XRUN_IGNORE:
+               err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->boundary);
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (err < 0)
+               return err;
+       err = snd_pcm_sw_params_set_xfer_align(pcm, sw_params, 1);
+       if (err < 0)
+               return err;
+       err = snd_pcm_sw_params(pcm, sw_params);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+int snd_spcm_init(snd_pcm_t *pcm,
+                 unsigned int rate,
+                 unsigned int channels,
+                 snd_pcm_format_t format,
+                 snd_pcm_subformat_t subformat,
+                 snd_spcm_latency_t latency,
+                 snd_pcm_access_t access,
+                 snd_spcm_xrun_type_t xrun_type)
+{
+       int err;
+       snd_pcm_hw_params_t *hw_params;
+       snd_pcm_sw_params_t *sw_params;
+       unsigned int rrate;
+       unsigned int buffer_time;
+
+       snd_pcm_hw_params_alloca(&hw_params);
+       snd_pcm_sw_params_alloca(&sw_params);
+
+       assert(pcm);
+       assert(rate > 5000 && rate < 192000);
+       assert(channels > 1 && channels < 512);
+
+       rrate = rate;
+       err = set_buffer_time(latency, &buffer_time);
+       if (err < 0)
+               return err;
+       err = set_hw_params(pcm, hw_params,
+                           &rrate, channels, format, subformat,
+                           &buffer_time, NULL, access);
+       if (err < 0)
+               return err;
+
+       err = set_sw_params(pcm, sw_params, xrun_type);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+int snd_spcm_init_duplex(snd_pcm_t *playback_pcm,
+                        snd_pcm_t *capture_pcm,
+                        unsigned int rate,
+                        unsigned int channels,
+                        snd_pcm_format_t format,
+                        snd_pcm_subformat_t subformat,
+                        snd_spcm_latency_t latency,
+                        snd_pcm_access_t access,
+                        snd_spcm_xrun_type_t xrun_type,
+                        snd_spcm_duplex_type_t duplex_type)
+{
+       int err, i;
+       snd_pcm_hw_params_t *hw_params;
+       snd_pcm_sw_params_t *sw_params;
+       unsigned int rrate;
+       unsigned int xbuffer_time, buffer_time[2];
+       unsigned int period_time[2];
+       snd_pcm_t *pcms[2];
+
+       snd_pcm_hw_params_alloca(&hw_params);
+       snd_pcm_sw_params_alloca(&sw_params);
+
+       assert(playback_pcm);
+       assert(capture_pcm);
+       assert(rate > 5000 && rate < 192000);
+       assert(channels > 1 && channels < 512);
+
+       pcms[0] = playback_pcm;
+       pcms[1] = capture_pcm;
+
+       /*
+        * hardware parameters
+        */
+       err = set_buffer_time(latency, &xbuffer_time);  
+       if (err < 0)
+               return err;
+       
+       for (i = 0; i < 2; i++) {
+               buffer_time[i] = xbuffer_time;
+               period_time[i] = i > 0 ? period_time[0] : 0;
+               rrate = rate;
+               err = set_hw_params(pcms[i], hw_params,
+                                   &rrate, channels, format, subformat,
+                                   &buffer_time[i], &period_time[i], access);
+               if (err < 0)
+                       return err;
+       }
+       if (buffer_time[0] == buffer_time[1] &&
+           period_time[0] == period_time[1])
+               goto __sw_params;
+       if (duplex_type == SND_SPCM_DUPLEX_LIBERAL)
+               goto __sw_params;
+       /* FIXME: */
+       return -EINVAL;
+
+       /*
+        * software parameters
+        */
+      __sw_params:
+       for (i = 0; i < 2; i++) {
+               err = set_sw_params(pcms[i], sw_params, xrun_type);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+int snd_spcm_init_get_params(snd_pcm_t *pcm,
+                            unsigned int *rate,
+                            snd_pcm_uframes_t *buffer_size,
+                            snd_pcm_uframes_t *period_size)
+{
+       assert(pcm);
+       if (!pcm->setup)
+               return -EBADFD;
+       if (rate)
+               *rate = pcm->rate;
+       if (buffer_size)
+               *buffer_size = pcm->buffer_size;
+       if (period_size)
+               *period_size = pcm->period_size;
+       return 0;
+}