summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2004-03-26 16:08:01 +0000
committerJaroslav Kysela <perex@perex.cz>2004-03-26 16:08:01 +0000
commita190b87d940a7a467d80ce43236c85cd471b74a1 (patch)
treebe981f909083483d53c7d2439ca02fd31c911b59
parent25f864b059fe00b6ab5a938e588cc4cb126a2e53 (diff)
downloadalsa-lib-a190b87d940a7a467d80ce43236c85cd471b74a1.tar.gz
Initial implementation of PCM simple API extension.
-rw-r--r--include/pcm.h16
-rw-r--r--src/Versions8
-rw-r--r--src/pcm/Makefile.am2
-rw-r--r--src/pcm/pcm_simple.c268
4 files changed, 292 insertions, 2 deletions
diff --git a/include/pcm.h b/include/pcm.h
index b6d485f2..bbbb582f 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -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);
/** \} */
diff --git a/src/Versions b/src/Versions
index 52eb295c..c4a9d9e5 100644
--- a/src/Versions
+++ b/src/Versions
@@ -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;
diff --git a/src/pcm/Makefile.am b/src/pcm/Makefile.am
index 64c35076..07213f21 100644
--- a/src/pcm/Makefile.am
+++ b/src/pcm/Makefile.am
@@ -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
index 00000000..aab509a7
--- /dev/null
+++ b/src/pcm/pcm_simple.c
@@ -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;
+}