In interface version 2.0.14, ALSA PCM core request feedback to applications when they operate any PCM frames in mmap operation for a type of devices with SNDRV_PCM_INFO_ACK_APPLPTR flag.
This commit adds support for this change to keep compatibility for existent applications which uses alsa-lib API.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- src/pcm/pcm_hw.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-)
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 30cd5d0f..880109ad 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -105,6 +105,7 @@ typedef struct { /* for chmap */ unsigned int chmap_caps; snd_pcm_chmap_query_t **chmap_override; + int ack_applptr; } snd_pcm_hw_t;
#define SNDRV_FILE_PCM_STREAM_PLAYBACK ALSA_DEVICE_DIRECTORY "pcmC%iD%ip" @@ -128,11 +129,12 @@ struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm) } #endif /* DOC_HIDDEN */
-static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) +static int sync_ptr1(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr, + unsigned int flags) { int err; - hw->sync_ptr->flags = flags; - err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR, (hw)->sync_ptr); + sync_ptr->flags = flags; + err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR, sync_ptr); if (err < 0) { err = -errno; SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); @@ -143,7 +145,7 @@ static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags)
static inline int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) { - return hw->sync_ptr ? sync_ptr1(hw, flags) : 0; + return hw->sync_ptr ? sync_ptr1(hw, hw->sync_ptr, flags) : 0; }
static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) @@ -295,6 +297,14 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) return err; }
+ /* + * For drivers with SNDRV_PCM_INFO_ACK_APPLPTR, this has an effect + * to tell that user land can perform MMAP operation as corresponding + * hardware expects. For the other drivers, this has no side-effect. + */ + if (hw->version >= SNDRV_PROTOCOL_VERSION(2, 0, 14)) + params->flags |= SNDRV_PCM_INFO_ACK_APPLPTR; + if (hw_refine_call(hw, params) < 0) { err = -errno; // SYSMSG("SNDRV_PCM_IOCTL_HW_REFINE failed"); @@ -322,6 +332,15 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) { snd_pcm_hw_t *hw = pcm->private_data; int err; + + /* + * For drivers with SNDRV_PCM_INFO_ACK_APPLPTR, this has an effect + * to tell that user land can perform MMAP operation as corresponding + * hardware expects. For the other drivers, this has no side-effect. + */ + if (hw->version >= SNDRV_PROTOCOL_VERSION(2, 0, 14)) + params->flags |= SNDRV_PCM_INFO_ACK_APPLPTR; + if (hw_params_call(hw, params) < 0) { err = -errno; SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err); @@ -337,6 +356,11 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); } + + if (hw->version >= SNDRV_PROTOCOL_VERSION(2, 0, 14) && + (params->info & SNDRV_PCM_INFO_ACK_APPLPTR)) + hw->ack_applptr = 1; + return 0; }
@@ -568,7 +592,8 @@ static int snd_pcm_hw_hwsync(snd_pcm_t *pcm) int fd = hw->fd, err; if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) { if (hw->sync_ptr) { - err = sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_HWSYNC); + err = sync_ptr1(hw, hw->sync_ptr, + SNDRV_PCM_SYNC_PTR_HWSYNC); if (err < 0) return err; } else { @@ -995,7 +1020,13 @@ static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm, snd_pcm_hw_t *hw = pcm->private_data;
snd_pcm_mmap_appl_forward(pcm, size); - sync_ptr(hw, 0); + if (hw->sync_ptr) { + sync_ptr1(hw, hw->sync_ptr, 0); + } else if (hw->ack_applptr) { + struct snd_pcm_sync_ptr sync_ptr = {0}; + sync_ptr.c.control = *hw->mmap_control; + sync_ptr1(hw, &sync_ptr, 0); + } #ifdef DEBUG_MMAP fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size); #endif