The driver may not require to touch the sample stream for the drain operation at all. Handle this situation in alsa-lib. Signed-off-by: Jaroslav Kysela <perex@xxxxxxxx> --- include/pcm.h | 1 + include/sound/uapi/asound.h | 1 + src/pcm/pcm.c | 23 +++++++++++++++++++++++ src/pcm/pcm_hw.c | 4 +++- src/pcm/pcm_local.h | 2 ++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/pcm.h b/include/pcm.h index b5a514fa..f15462d9 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -722,6 +722,7 @@ int snd_pcm_hw_params_is_half_duplex(const snd_pcm_hw_params_t *params); int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params); int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params); int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_does_perfect_drain(const snd_pcm_hw_params_t *params); int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params); /* deprecated, use audio_ts_type */ int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t *params, int type); int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params, diff --git a/include/sound/uapi/asound.h b/include/sound/uapi/asound.h index fc18c024..0b8834f2 100644 --- a/include/sound/uapi/asound.h +++ b/include/sound/uapi/asound.h @@ -281,6 +281,7 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ #define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ #define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ +#define SNDRV_PCM_INFO_PERFECT_DRAIN 0x00000040 /* silencing at the end of stream is not required */ #define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ #define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ #define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 88b13ed4..099d83ee 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -3707,6 +3707,29 @@ int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *param return !!(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP); } +/** + * \brief Check if hardware does perfect drain + * \param params Configuration space + * \retval 0 Hardware doesn't do perfect drain + * \retval 1 Hardware does perfect drain + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single configuration from the configuration space. + * + * The perfect drain means that the hardware does not use samples + * beyond the stream application pointer. + */ +int snd_pcm_hw_params_does_perfect_drain(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_PERFECT_DRAIN); +} + /** * \brief Check if hardware supports audio wallclock timestamps * \param params Configuration space diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 30ff843c..ea0c2ef2 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -99,6 +99,7 @@ typedef struct { struct snd_pcm_sync_ptr *sync_ptr; bool prepare_reset_sw_params; + bool perfect_drain; int period_event; snd_timer_t *period_timer; @@ -398,6 +399,7 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) params->info &= ~0xf0000000; if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) params->info |= SND_PCM_INFO_MONOTONIC; + hw->perfect_drain = !!(params->info & SND_PCM_INFO_PERFECT_DRAIN); return query_status_data(hw); } @@ -739,7 +741,7 @@ static int snd_pcm_hw_drain(snd_pcm_t *pcm) if (pcm->stream != SND_PCM_STREAM_PLAYBACK) goto __skip_silence; - if (hw->drain_silence == 0) + if (hw->drain_silence == 0 || hw->perfect_drain) goto __skip_silence; snd_pcm_sw_params_current_no_lock(pcm, &sw_params); if (hw->drain_silence > 0) { diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 4a859cd1..b039dda0 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -79,6 +79,8 @@ #define SND_PCM_INFO_DOUBLE SNDRV_PCM_INFO_DOUBLE /** device transfers samples in batch */ #define SND_PCM_INFO_BATCH SNDRV_PCM_INFO_BATCH +/** device does perfect drain (silencing not required) */ +#define SND_PCM_INFO_PERFECT_DRAIN SNDRV_PCM_INFO_PERFECT_DRAIN /** device accepts interleaved samples */ #define SND_PCM_INFO_INTERLEAVED SNDRV_PCM_INFO_INTERLEAVED /** device accepts non-interleaved samples */ -- 2.39.2