diff options
author | Jaroslav Kysela <perex@perex.cz> | 2004-03-26 16:08:01 +0000 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2004-03-26 16:08:01 +0000 |
commit | a190b87d940a7a467d80ce43236c85cd471b74a1 (patch) | |
tree | be981f909083483d53c7d2439ca02fd31c911b59 | |
parent | 25f864b059fe00b6ab5a938e588cc4cb126a2e53 (diff) | |
download | alsa-lib-a190b87d940a7a467d80ce43236c85cd471b74a1.tar.gz |
Initial implementation of PCM simple API extension.
-rw-r--r-- | include/pcm.h | 16 | ||||
-rw-r--r-- | src/Versions | 8 | ||||
-rw-r--r-- | src/pcm/Makefile.am | 2 | ||||
-rw-r--r-- | src/pcm/pcm_simple.c | 268 |
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; +} |