The recent kernel informs user-space when a driver requires the explicit notification of appl_ptr update via a new flag, SNDRV_PCM_INFO_SYNC_APPLPTR. When this flag is set, the user-space is supposed to report the appl_ptr via SNDRV_PCM_IOCTL_SYNC_PTR ioctl.
This patch implements the requested behavior in the PCM hw plugin.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/asound.h | 1 + src/pcm/pcm_hw.c | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/include/sound/asound.h b/include/sound/asound.h index fb8d7d7ef8ad..346db40e5932 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -268,6 +268,7 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ #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_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_hw.c b/src/pcm/pcm_hw.c index 30cd5d0f6503..8855868f5ea2 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -91,6 +91,7 @@ typedef struct { int fd; int card, device, subdevice; int sync_ptr_ioctl; + int sync_applptr; volatile struct snd_pcm_mmap_status * mmap_status; struct snd_pcm_mmap_control *mmap_control; struct snd_pcm_sync_ptr *sync_ptr; @@ -128,11 +129,13 @@ 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 *ptr, + unsigned int flags) { int err; - hw->sync_ptr->flags = flags; - err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR, (hw)->sync_ptr); + + ptr->flags = flags; + err = ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, ptr); if (err < 0) { err = -errno; SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); @@ -143,7 +146,15 @@ 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; +} + +/* explicit notification of appl_ptr update to kernel */ +static int sync_applptr(snd_pcm_hw_t *hw) +{ + struct snd_pcm_sync_ptr ptr; + ptr.c.control = *hw->mmap_control; + return sync_ptr1(hw, &ptr, 0); }
static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) @@ -327,6 +338,7 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err); return err; } + hw->sync_applptr = !!(params->info & SNDRV_PCM_INFO_SYNC_APPLPTR); params->info &= ~0xf0000000; if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) params->info |= SND_PCM_INFO_MONOTONIC; @@ -568,7 +580,7 @@ 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 +1007,10 @@ 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_ptr(hw, 0); + else if (hw->sync_applptr) + sync_applptr(hw); #ifdef DEBUG_MMAP fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size); #endif