From 301a62f90ad3f8198835ae17ce922a2e4fd70a43 Mon Sep 17 00:00:00 2001 From: Abramo Bagnara Date: Thu, 19 Apr 2001 21:18:23 +0000 Subject: [PATCH] Improved automatic start/stop --- include/local.h | 45 ++++++++++++ include/pcm.h | 18 +++-- src/pcm/pcm.c | 160 ++++++++++++++++++++++++++++++++++--------- src/pcm/pcm_hw.c | 6 +- src/pcm/pcm_local.h | 4 +- src/pcm/pcm_null.c | 54 +++++++-------- src/pcm/pcm_params.c | 4 +- src/pcm/pcm_share.c | 29 ++++---- 8 files changed, 229 insertions(+), 91 deletions(-) diff --git a/include/local.h b/include/local.h index 6959f13d..903c36a4 100644 --- a/include/local.h +++ b/include/local.h @@ -53,4 +53,49 @@ typedef enum _snd_set_mode { size_t page_align(size_t size); size_t page_size(void); +#define HAVE_GNU_LD +#define HAVE_ELF +#define HAVE_ASM_PREVIOUS_DIRECTIVE + +/* Stolen from libc-symbols.h in GNU glibc */ + +/* When a reference to SYMBOL is encountered, the linker will emit a + warning message MSG. */ +#ifdef HAVE_GNU_LD +# ifdef HAVE_ELF + +/* We want the .gnu.warning.SYMBOL section to be unallocated. */ +# ifdef HAVE_ASM_PREVIOUS_DIRECTIVE +# define __make_section_unallocated(section_string) \ + asm (".section " section_string "\n\t.previous"); +# elif defined HAVE_ASM_POPSECTION_DIRECTIVE +# define __make_section_unallocated(section_string) \ + asm (".pushsection " section_string "\n\t.popsection"); +# else +# define __make_section_unallocated(section_string) +# endif + +/* Tacking on "\n\t#" to the section name makes gcc put it's bogus + section attributes on what looks like a comment to the assembler. */ +# ifdef HAVE_SECTION_QUOTES +# define link_warning(symbol, msg) \ + __make_section_unallocated (".gnu.warning." #symbol) \ + static const char __evoke_link_warning_##symbol[] \ + __attribute__ ((section (".gnu.warning." #symbol "\"\n\t#\""))) = msg; +# else +# define link_warning(symbol, msg) \ + __make_section_unallocated (".gnu.warning." #symbol) \ + static const char __evoke_link_warning_##symbol[] \ + __attribute__ ((section (".gnu.warning." #symbol "\n\t#"))) = msg; +# endif +# else +# define link_warning(symbol, msg) \ + asm (".stabs \"" msg "\",30,0,0,0\n\t" \ + ".stabs \"" __SYMBOL_PREFIX #symbol "\",1,0,0,0\n"); +# endif +#else +/* We will never be heard; they will all die horribly. */ +# define link_warning(symbol, msg) +#endif + #endif diff --git a/include/pcm.h b/include/pcm.h index a8e0dcb5..52cd738f 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -172,19 +172,19 @@ typedef enum _snd_pcm_state { /** PCM start mode */ typedef enum _snd_pcm_start { /** Automatic start on data read/write */ - SND_PCM_START_DATA = SNDRV_PCM_START_DATA, + SND_PCM_START_DATA, /** Explicit start */ - SND_PCM_START_EXPLICIT = SNDRV_PCM_START_EXPLICIT, - SND_PCM_START_LAST = SNDRV_PCM_START_LAST, + SND_PCM_START_EXPLICIT, + SND_PCM_START_LAST, } snd_pcm_start_t; /** PCM xrun mode */ typedef enum _snd_pcm_xrun { /** Xrun detection disabled */ - SND_PCM_XRUN_NONE = SNDRV_PCM_XRUN_NONE, + SND_PCM_XRUN_NONE, /** Stop on xrun detection */ - SND_PCM_XRUN_STOP = SNDRV_PCM_XRUN_STOP, - SND_PCM_XRUN_LAST = SNDRV_PCM_XRUN_LAST, + SND_PCM_XRUN_STOP, + SND_PCM_XRUN_LAST, } snd_pcm_xrun_t; /** PCM timestamp mode */ @@ -695,6 +695,12 @@ snd_pcm_uframes_t snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *par int snd_pcm_sw_params_set_xfer_align(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); snd_pcm_uframes_t snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *params); +int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +snd_pcm_uframes_t snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *params); + +int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +snd_pcm_uframes_t snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params); + int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); snd_pcm_uframes_t snd_pcm_sw_params_get_silence_threshold(const snd_pcm_sw_params_t *params); diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index d032603b..f0590d14 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -225,13 +225,13 @@ int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) err = pcm->ops->sw_params(pcm->op_arg, params); if (err < 0) return err; - pcm->start_mode = snd_pcm_sw_params_get_start_mode(params); - pcm->xrun_mode = snd_pcm_sw_params_get_xrun_mode(params); pcm->tstamp_mode = snd_pcm_sw_params_get_tstamp_mode(params); pcm->period_step = params->period_step; pcm->sleep_min = params->sleep_min; pcm->avail_min = params->avail_min; pcm->xfer_align = params->xfer_align; + pcm->start_threshold = params->start_threshold; + pcm->stop_threshold = params->stop_threshold; pcm->silence_threshold = params->silence_threshold; pcm->silence_size = params->silence_size; pcm->boundary = params->boundary; @@ -713,7 +713,7 @@ const char *snd_pcm_subformat_description(snd_pcm_subformat_t subformat) } /** - * \brief get name of PCM start mode setting + * \brief (DEPRECATED) get name of PCM start mode setting * \param mode PCM start mode * \return ascii name of PCM start mode setting */ @@ -723,8 +723,10 @@ const char *snd_pcm_start_mode_name(snd_pcm_start_t mode) return snd_pcm_start_mode_names[snd_enum_to_int(mode)]; } +link_warning(snd_pcm_start_mode_name, "Warning: start_mode is deprecated, consider to use start_threshold"); + /** - * \brief get name of PCM xrun mode setting + * \brief (DEPRECATED) get name of PCM xrun mode setting * \param mode PCM xrun mode * \return ascii name of PCM xrun mode setting */ @@ -734,6 +736,8 @@ const char *snd_pcm_xrun_mode_name(snd_pcm_xrun_t mode) return snd_pcm_xrun_mode_names[snd_enum_to_int(mode)]; } +link_warning(snd_pcm_xrun_mode_name, "Warning: xrun_mode is deprecated, consider to use stop_threshold"); + /** * \brief get name of PCM tstamp mode setting * \param mode PCM tstamp mode @@ -793,16 +797,16 @@ int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, snd_output_t *out) assert(pcm); assert(out); assert(pcm->setup); - snd_output_printf(out, "start_mode : %s\n", snd_pcm_start_mode_name(pcm->start_mode)); - snd_output_printf(out, "xrun_mode : %s\n", snd_pcm_xrun_mode_name(pcm->xrun_mode)); snd_output_printf(out, "tstamp_mode : %s\n", snd_pcm_tstamp_mode_name(pcm->tstamp_mode)); - snd_output_printf(out, "period_step : %ld\n", (long)pcm->period_step); - snd_output_printf(out, "sleep_min : %ld\n", (long)pcm->sleep_min); - snd_output_printf(out, "avail_min : %ld\n", (long)pcm->avail_min); - snd_output_printf(out, "xfer_align : %ld\n", (long)pcm->xfer_align); - snd_output_printf(out, "silence_threshold: %ld\n", (long)pcm->silence_threshold); - snd_output_printf(out, "silence_size : %ld\n", (long)pcm->silence_size); - snd_output_printf(out, "boundary : %ld\n", (long)pcm->boundary); + snd_output_printf(out, "period_step : %d\n", pcm->period_step); + snd_output_printf(out, "sleep_min : %d\n", pcm->sleep_min); + snd_output_printf(out, "avail_min : %ld\n", pcm->avail_min); + snd_output_printf(out, "xfer_align : %ld\n", pcm->xfer_align); + snd_output_printf(out, "start_threshold : %ld\n", pcm->start_threshold); + snd_output_printf(out, "stop_threshold : %ld\n", pcm->stop_threshold); + snd_output_printf(out, "silence_threshold: %ld\n", pcm->silence_threshold); + snd_output_printf(out, "silence_size : %ld\n", pcm->silence_size); + snd_output_printf(out, "boundary : %ld\n", pcm->boundary); return 0; } @@ -3287,13 +3291,13 @@ int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) { assert(pcm && params); assert(pcm->setup); - params->start_mode = snd_enum_to_int(pcm->start_mode); - params->xrun_mode = snd_enum_to_int(pcm->xrun_mode); params->tstamp_mode = snd_enum_to_int(pcm->tstamp_mode); params->period_step = pcm->period_step; params->sleep_min = pcm->sleep_min; params->avail_min = pcm->avail_min; params->xfer_align = pcm->xfer_align; + params->start_threshold = pcm->start_threshold; + params->stop_threshold = pcm->stop_threshold; params->silence_threshold = pcm->silence_threshold; params->silence_size = pcm->silence_size; params->boundary = pcm->boundary; @@ -3365,34 +3369,48 @@ void snd_pcm_sw_params_copy(snd_pcm_sw_params_t *dst, const snd_pcm_sw_params_t } /** - * \brief Set start mode inside a software configuration container + * \brief (DEPRECATED) Set start mode inside a software configuration container * \param pcm PCM handle * \param params Software configuration container * \param val Start mode * \return 0 otherwise a negative error code */ -int snd_pcm_sw_params_set_start_mode(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_start_t val) +int snd_pcm_sw_params_set_start_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_start_t val) { assert(pcm && params); - assert(val <= SND_PCM_START_LAST); - params->start_mode = snd_enum_to_int(val); + switch (val) { + case SND_PCM_START_DATA: + params->start_threshold = 1; + break; + case SND_PCM_START_EXPLICIT: + params->start_threshold = pcm->boundary; + break; + default: + assert(0); + break; + } return 0; } +link_warning(snd_pcm_sw_params_set_start_mode, "Warning: start_mode is deprecated, consider to use start_threshold"); + /** - * \brief Get start mode from a software configuration container + * \brief (DEPRECATED) Get start mode from a software configuration container * \param params Software configuration container * \return start mode */ snd_pcm_start_t snd_pcm_sw_params_get_start_mode(const snd_pcm_sw_params_t *params) { assert(params); - return snd_int_to_enum(params->start_mode); + /* FIXME: Ugly */ + return params->start_threshold > 1024 * 1024 ? SND_PCM_START_EXPLICIT : SND_PCM_START_DATA; } +link_warning(snd_pcm_sw_params_get_start_mode, "Warning: start_mode is deprecated, consider to use start_threshold"); + /** - * \brief Set xrun mode inside a software configuration container + * \brief (DEPRECATED) Set xrun mode inside a software configuration container * \param pcm PCM handle * \param params Software configuration container * \param val Xrun mode @@ -3401,22 +3419,35 @@ snd_pcm_start_t snd_pcm_sw_params_get_start_mode(const snd_pcm_sw_params_t *para int snd_pcm_sw_params_set_xrun_mode(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_xrun_t val) { assert(pcm && params); - assert(val <= SND_PCM_XRUN_LAST); - params->xrun_mode = snd_enum_to_int(val); + switch (val) { + case SND_PCM_XRUN_STOP: + params->stop_threshold = pcm->buffer_size; + break; + case SND_PCM_XRUN_NONE: + params->stop_threshold = pcm->boundary; + break; + default: + assert(0); + break; + } return 0; } +link_warning(snd_pcm_sw_params_set_xrun_mode, "Warning: xrun_mode is deprecated, consider to use stop_threshold"); + /** - * \brief Get xrun mode from a software configuration container + * \brief (DEPRECATED) Get xrun mode from a software configuration container * \param params Software configuration container * \return xrun mode */ snd_pcm_xrun_t snd_pcm_sw_params_get_xrun_mode(const snd_pcm_sw_params_t *params) { assert(params); - return snd_int_to_enum(params->xrun_mode); + /* FIXME: Ugly */ + return params->stop_threshold > 1024 * 1024 ? SND_PCM_XRUN_NONE : SND_PCM_XRUN_STOP; } +link_warning(snd_pcm_sw_params_get_xrun_mode, "Warning: xrun_mode is deprecated, consider to use stop_threshold"); /** * \brief Set timestamp mode inside a software configuration container @@ -3539,6 +3570,68 @@ snd_pcm_uframes_t snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *pa } +/** + * \brief Set start threshold inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Start threshold in frames + * \return 0 otherwise a negative error code + * + * PCM is automatically started when playback frames available to PCM + * are >= threshold or when requested capture frames are >= threshold + */ +int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +{ + assert(pcm && params); + params->start_threshold = val; + return 0; +} + +/** + * \brief Get start threshold from a software configuration container + * \param params Software configuration container + * \return Start threshold in frames + * + * PCM is automatically started when playback frames available to PCM + * are >= threshold or when requested capture frames are >= threshold + */ +snd_pcm_uframes_t snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *params) +{ + assert(params); + return params->start_threshold; +} + +/** + * \brief Set stop threshold inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Stop threshold in frames + * \return 0 otherwise a negative error code + * + * PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available + * frames is >= threshold + */ +int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +{ + assert(pcm && params); + params->stop_threshold = val; + return 0; +} + +/** + * \brief Get stop threshold from a software configuration container + * \param params Software configuration container + * \return Stop threshold in frames + * + * PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available + * frames is >= threshold + */ +snd_pcm_uframes_t snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params) +{ + assert(params); + return params->stop_threshold; +} + /** * \brief Set silence threshold inside a software configuration container * \param pcm PCM handle @@ -4015,7 +4108,7 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_ switch (snd_enum_to_int(state)) { case SND_PCM_STATE_PREPARED: - if (pcm->start_mode == SND_PCM_START_DATA) { + if (size >= pcm->start_threshold) { err = snd_pcm_start(pcm); if (err < 0) goto _end; @@ -4156,11 +4249,14 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area goto _end; } #endif - if (state == SND_PCM_STATE_PREPARED && - pcm->start_mode == SND_PCM_START_DATA) { - err = snd_pcm_start(pcm); - if (err < 0) - goto _end; + if (state == SND_PCM_STATE_PREPARED) { + snd_pcm_sframes_t hw_avail = pcm->buffer_size - avail; + hw_avail += frames; + if (hw_avail >= (snd_pcm_sframes_t) pcm->start_threshold) { + err = snd_pcm_start(pcm); + if (err < 0) + goto _end; + } } } _end: diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 0adf5ca6..1c1e51a9 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -151,12 +151,12 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) { snd_pcm_hw_t *hw = pcm->private_data; int fd = hw->fd; - if ((snd_pcm_start_t) params->start_mode == pcm->start_mode && - (snd_pcm_xrun_t) params->xrun_mode == pcm->xrun_mode && - (snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode && + if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode && params->period_step == pcm->period_step && params->sleep_min == pcm->sleep_min && params->xfer_align == pcm->xfer_align && + params->start_threshold == pcm->start_threshold && + params->stop_threshold == pcm->stop_threshold && params->silence_threshold == pcm->silence_threshold && params->silence_size == pcm->silence_size) { hw->mmap_control->avail_min = params->avail_min; diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 0d68bc2b..7c36f2c9 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -132,12 +132,12 @@ struct _snd_pcm { snd_pcm_uframes_t period_size; unsigned int period_time; /* period duration */ unsigned int tick_time; - snd_pcm_start_t start_mode; /* start mode */ - snd_pcm_xrun_t xrun_mode; /* xrun detection mode */ snd_pcm_tstamp_t tstamp_mode; /* timestamp mode */ unsigned int period_step; unsigned int sleep_min; snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */ + snd_pcm_uframes_t start_threshold; + snd_pcm_uframes_t stop_threshold; snd_pcm_uframes_t silence_threshold; /* Silence filling happens when noise is nearest than this */ snd_pcm_uframes_t silence_size; /* Silence filling size */ diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index bd3f6a16..387ad4cd 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -117,7 +117,9 @@ static int snd_pcm_null_start(snd_pcm_t *pcm) assert(null->state == SND_PCM_STATE_PREPARED); null->state = SND_PCM_STATE_RUNNING; if (pcm->stream == SND_PCM_STREAM_CAPTURE) - snd_pcm_mmap_appl_forward(pcm, pcm->buffer_size); + *pcm->hw_ptr = *pcm->appl_ptr + pcm->buffer_size; + else + *pcm->hw_ptr = *pcm->appl_ptr; return 0; } @@ -153,10 +155,11 @@ static snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f { snd_pcm_null_t *null = pcm->private_data; switch (snd_enum_to_int(null->state)) { - case SND_PCM_STATE_PREPARED: case SND_PCM_STATE_RUNNING: - snd_pcm_mmap_appl_backward(pcm, frames); snd_pcm_mmap_hw_backward(pcm, frames); + /* Fall through */ + case SND_PCM_STATE_PREPARED: + snd_pcm_mmap_appl_backward(pcm, frames); return frames; default: return -EBADFD; @@ -167,56 +170,45 @@ static snd_pcm_sframes_t snd_pcm_null_fwd(snd_pcm_t *pcm, snd_pcm_uframes_t size { snd_pcm_null_t *null = pcm->private_data; switch (snd_enum_to_int(null->state)) { - case SND_PCM_STATE_PREPARED: case SND_PCM_STATE_RUNNING: - snd_pcm_mmap_appl_forward(pcm, size); snd_pcm_mmap_hw_forward(pcm, size); + /* Fall through */ + case SND_PCM_STATE_PREPARED: + snd_pcm_mmap_appl_forward(pcm, size); return size; default: return -EBADFD; } } +static snd_pcm_uframes_t snd_pcm_null_xfer_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_mmap_appl_forward(pcm, size); + snd_pcm_mmap_hw_forward(pcm, size); + return size; +} + static snd_pcm_sframes_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) { - snd_pcm_null_t *null = pcm->private_data; - if (null->state == SND_PCM_STATE_PREPARED && - pcm->start_mode != SND_PCM_START_EXPLICIT) { - null->state = SND_PCM_STATE_RUNNING; - } - return snd_pcm_null_fwd(pcm, size); + return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas); } static snd_pcm_sframes_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) { - snd_pcm_null_t *null = pcm->private_data; - if (null->state == SND_PCM_STATE_PREPARED && - pcm->start_mode != SND_PCM_START_EXPLICIT) { - null->state = SND_PCM_STATE_RUNNING; - } - return snd_pcm_null_fwd(pcm, size); + return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas); } static snd_pcm_sframes_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) { - snd_pcm_null_t *null = pcm->private_data; - if (null->state == SND_PCM_STATE_PREPARED && - pcm->start_mode != SND_PCM_START_EXPLICIT) { - null->state = SND_PCM_STATE_RUNNING; - snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size); - } - return snd_pcm_null_fwd(pcm, size); + return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas); } static snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) { - snd_pcm_null_t *null = pcm->private_data; - if (null->state == SND_PCM_STATE_PREPARED && - pcm->start_mode != SND_PCM_START_EXPLICIT) { - null->state = SND_PCM_STATE_RUNNING; - snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size); - } - return snd_pcm_null_fwd(pcm, size); + return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas); } static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm, diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c index e9685111..ac7099c9 100644 --- a/src/pcm/pcm_params.c +++ b/src/pcm/pcm_params.c @@ -2022,13 +2022,13 @@ static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params { assert(pcm && params); assert(pcm->setup); - params->start_mode = snd_enum_to_int(SND_PCM_START_DATA); - params->xrun_mode = snd_enum_to_int(SND_PCM_XRUN_STOP); params->tstamp_mode = snd_enum_to_int(SND_PCM_TSTAMP_NONE); params->period_step = 1; params->sleep_min = 0; params->avail_min = pcm->period_size; params->xfer_align = pcm->period_size; + params->start_threshold = 1; + params->stop_threshold = pcm->buffer_size; params->silence_threshold = 0; params->silence_size = 0; params->boundary = pcm->buffer_size; diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 873d1810..69e78b71 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -182,7 +182,7 @@ static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *sla - draining silencing - return distance in frames to next event */ -static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun) +static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm) { snd_pcm_share_t *share = pcm->private_data; snd_pcm_share_slave_t *slave = share->slave; @@ -204,12 +204,12 @@ static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun) default: return INT_MAX; } - if (slave_xrun && pcm->xrun_mode != SND_PCM_XRUN_NONE) { + share->hw_ptr = slave->hw_ptr; + avail = snd_pcm_mmap_avail(pcm); + if (avail >= pcm->stop_threshold) { _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN); goto update_poll; } - share->hw_ptr = slave->hw_ptr; - avail = snd_pcm_mmap_avail(pcm); hw_avail = buffer_size - avail; slave_avail = snd_pcm_share_slave_avail(slave); if (avail < slave_avail) { @@ -247,18 +247,18 @@ static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun) } break; case SND_PCM_STATE_RUNNING: - if (pcm->xrun_mode != SND_PCM_XRUN_NONE) { - if (hw_avail <= 0) { - _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN); - break; - } - if ((snd_pcm_uframes_t)hw_avail < missing) - missing = hw_avail; + if (avail >= pcm->stop_threshold) { + _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN); + break; + } else { + snd_pcm_uframes_t xrun_missing = pcm->stop_threshold - avail; + if (missing > xrun_missing) + missing = xrun_missing; } ready_missing = pcm->avail_min - avail; if (ready_missing > 0) { ready = 0; - if ((snd_pcm_uframes_t)ready_missing < missing) + if (missing > (snd_pcm_uframes_t)ready_missing) missing = ready_missing; } running = 1; @@ -322,12 +322,11 @@ static snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *sla snd_pcm_uframes_t missing = INT_MAX; struct list_head *i; snd_pcm_sframes_t avail = snd_pcm_avail_update(slave->pcm); - int slave_xrun = (avail == -EPIPE); slave->hw_ptr = *slave->pcm->hw_ptr; list_for_each(i, &slave->clients) { snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); snd_pcm_t *pcm = share->pcm; - snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm, slave_xrun); + snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm); if (m < missing) missing = m; } @@ -396,7 +395,7 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm) snd_pcm_uframes_t missing; snd_pcm_sframes_t avail = snd_pcm_avail_update(spcm); slave->hw_ptr = *slave->pcm->hw_ptr; - missing = _snd_pcm_share_missing(pcm, avail == -EPIPE); + missing = _snd_pcm_share_missing(pcm); if (!slave->polling) { pthread_cond_signal(&slave->poll_cond); return; -- 2.47.1