On Wed, 26 Oct 2016 16:30:17 +0200, Alan Young wrote:
Hi,
When the kernel reports current (playback) delay via a call to snd_pcm_status() or snd_pcm_delay() for a normal hardware PCM, then the delay value reported is the sum of space used in the ring buffer plus any delay reported from the underlying runtime driver.
snd_pcm_dshare_status() and snd_pcm_dshare_delay() discard this refinement and simply report the use of some ring buffer. Why does it do this and how could the reporting be improved?
The lack of delay calculation is just for simplicity. We're tracking the different hw_avail per each d-* PCM, the delay value has to be re-calculated for each as in the current way. But we may put the additional delay computed from the slave PCM, indeed.
In particular I am struggling to understand the relationship between a dshare instance's (view of a) ring buffer and the slave (hw) PCM's ring buffer.
Basically d*-plugins share the same ring buffer as the underlying slave PCM hw layer. The d-plugins have the buffers in shared memory in addition for keeping the 32bit data for clipping. But in general the ring buffer size and the position are same as the hw.
I understand that the *slowptr* configuration item can be set to get more accurate position updates as part of this reporting but I get the feeling that this will not on its own solve the problem. If it did then one could simply use the delay value reported by the slave PCM.
Actually slowptr option is enabled as default. It calls the hwsync of the slave hw at each status update, instead of the passive update from the hw PCM itself.
The context of these questions is using dshare to expose 4 logical stereo devices on a platform using an ARM-based SoC with a single 8-channel hardware driver. I need to get the same level of delay report accuracy as I would do without using dshare.
Well, basically the additional delay can be deduced from delay - buffer_size - avail (This is applied for playback. For capture, it's slightly different.)
A patch like below *might* work (totally untested!)
thanks,
Takashi
--- diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index c5b3178a4990..8e21a6ec5fc2 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -214,6 +214,7 @@ static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) { snd_pcm_direct_t *dshare = pcm->private_data; + snd_pcm_status_t slave_status;
switch (dshare->state) { case SNDRV_PCM_STATE_DRAINING: @@ -225,12 +226,15 @@ static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) } memset(status, 0, sizeof(*status)); snd_pcm_status(dshare->spcm, status); + slave_status = *status; status->state = snd_pcm_state(dshare->spcm); status->trigger_tstamp = dshare->trigger_tstamp; status->avail = snd_pcm_mmap_playback_avail(pcm); status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max; dshare->avail_max = 0; status->delay = snd_pcm_mmap_playback_delay(pcm); + status->delay += slave_status.delay + slave_status.avail - + dshare->spcm->buffer_size; return 0; }