@@ -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,
@@ -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) */
@@ -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
@@ -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) {
@@ -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 */
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@perex.cz> --- 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(-)