summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2023-05-02 10:34:41 +0200
committerJaroslav Kysela <perex@perex.cz>2023-05-03 15:58:56 +0200
commit264d6c43ee382bf4d6b1cf35c3920a8793c575e2 (patch)
treec09afcb8c385a65524a3864f2bd5c1f967914c78
parent90e25887d24661a0bdc169b7b14525a97a4645c1 (diff)
downloadalsa-lib-264d6c43ee382bf4d6b1cf35c3920a8793c575e2.tar.gz
pcm: hw: introduce SNDRV_PCM_HW_PARAMS_DRAIN_SILENCE
The application may not require to touch the playback sample stream for the drain operation at all. In this case, the application is responsible to setup a silencing mechanism for the playback or another graceful stop (like using the rewind operation). Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--include/pcm.h2
-rw-r--r--include/sound/uapi/asound.h3
-rw-r--r--src/pcm/pcm.c37
-rw-r--r--src/pcm/pcm_hw.c3
-rw-r--r--src/pcm/pcm_local.h1
5 files changed, 45 insertions, 1 deletions
diff --git a/include/pcm.h b/include/pcm.h
index dd031b6c..966d6ffd 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -822,6 +822,8 @@ int snd_pcm_hw_params_set_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *par
int snd_pcm_hw_params_get_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val);
int snd_pcm_hw_params_set_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
int snd_pcm_hw_params_get_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val);
+int snd_pcm_hw_params_set_drain_silence(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
+int snd_pcm_hw_params_get_drain_silence(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val);
int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
int snd_pcm_hw_params_get_period_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
diff --git a/include/sound/uapi/asound.h b/include/sound/uapi/asound.h
index 0b8834f2..62a0364f 100644
--- a/include/sound/uapi/asound.h
+++ b/include/sound/uapi/asound.h
@@ -390,6 +390,9 @@ typedef int snd_pcm_hw_param_t;
#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */
#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */
#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */
+#define SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE (1<<3) /* suppress the silence fill
+ * for draining
+ */
struct snd_interval {
unsigned int min, max;
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index d387da3d..997a8a6a 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -4959,6 +4959,43 @@ int snd_pcm_hw_params_get_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *par
}
/**
+ * \brief Restrict a configuration space to fill the end of playback stream with silence when drain() is invoked
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val 0 = disabled, 1 = enabled (default) fill the end of the playback stream with silence when drain() is invoked
+ * \return Zero on success, otherwise a negative error code.
+ *
+ * When disabled, the application should handle the end of stream gracefully
+ * (fill the silent samples to align to the period size plus some extra
+ * samples for hardware / driver without perfect drain). Note that the rewind
+ * may be used for this purpose or the sw_params silencing mechanism.
+ */
+int snd_pcm_hw_params_set_drain_silence(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val)
+{
+ assert(pcm && params);
+ if (val)
+ params->flags &= ~SND_PCM_HW_PARAMS_NO_DRAIN_SILENCE;
+ else
+ params->flags |= SND_PCM_HW_PARAMS_NO_DRAIN_SILENCE;
+ params->rmask = ~0;
+ return snd_pcm_hw_refine(pcm, params);
+}
+
+/**
+ * \brief Extract drain with the filling of silence samples from a configuration space
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val 0 = disabled, 1 = enabled
+ * \return 0 otherwise a negative error code
+ */
+int snd_pcm_hw_params_get_drain_silence(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)
+{
+ assert(pcm && params && val);
+ *val = params->flags & SND_PCM_HW_PARAMS_NO_DRAIN_SILENCE ? 0 : 1;
+ return 0;
+}
+
+/**
* \brief Extract period time from a configuration space
* \param params Configuration space
* \param val Returned approximate period duration in us
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index 37a18b86..180a3e84 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -399,7 +399,8 @@ 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);
+ hw->perfect_drain = !!(params->info & SND_PCM_INFO_PERFECT_DRAIN) ||
+ !!(params->flags & SND_PCM_HW_PARAMS_NO_DRAIN_SILENCE);
return query_status_data(hw);
}
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index b039dda0..abea6654 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -107,6 +107,7 @@
#define SND_PCM_HW_PARAMS_NORESAMPLE SNDRV_PCM_HW_PARAMS_NORESAMPLE
#define SND_PCM_HW_PARAMS_EXPORT_BUFFER SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER
#define SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP
+#define SND_PCM_HW_PARAMS_NO_DRAIN_SILENCE SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE
#define SND_PCM_INFO_MONOTONIC 0x80000000