* snd_pcm_delay, hw buffers and driver api (v2)
@ 2009-08-13 21:35 Kai Vehmanen
2009-08-13 21:57 ` Kai Vehmanen
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Kai Vehmanen @ 2009-08-13 21:35 UTC (permalink / raw)
To: alsa-devel; +Cc: Ujfalusi Peter, ext-eero.nurkkala
Hi,
as I got at least one reply, reposting this in a new thread to catch more
people. Originally sent to alsa-devel thread:
"[PATCH 11/20] OMAP: McBSP: Add link DMA mode selection)"
http://kerneltrap.org/mailarchive/alsa-devel/2009/7/30/6272573
---
So not strictly related to the patch that started the original thread, but
this touches on, and is a good example of, one question I've been
wondering for some time now as an app developer. Could Takashi, Jaroslav,
Mark, or others comment on this as well, perhaps? Dropping linux-omap as
this is a generic ALSA question.
On Wed, 12 Aug 2009, Jarkko Nikula wrote:
[i.e. pcm_pointer == hw_ptr]
> The threshold based transfer will cause that omap_pcm_pointer will
> loose a bit its accuracy. Probably irrelevant but still better to play
> safe at least over one kernel release before making it default.
[...]
> element:
> 614
> 669
> 691
[...]
> threshold:
> 512
> 512
> 1024
> 1024
In both cases, this value (hw_ptr) shows the status of sending data to an
separate entity, and one that has its own buffer (multiple ms) before the
actual DAC/ADC.
So when application developer uses snd_pcm_delay(), the result is not
quite what the ALSA API says:
alsa-lib.git/src/pcm/pcm.c:
--cut--
* For playback the delay is defined as the time that a frame that is written
* to the PCM stream shortly after this call will take to be actually
* audible. It is as such the overall latency from the write call to the final
* DAC.
[...]
int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
--cut--
Of course, there are many other cases where the same happens, as the
latency of the HW (or where it is connected) is not known. But we also
have many cases where we _do_ know more about the latency, and we are just
missing the means to expose this info. I think this applies to this OMAP
patch as well. E.g. the HW can tell fairly accurately the current status
(i.e. which sample is played-out/captured _now_). Now that brings us to my
question -- how to expose this info in an ALSA driver.
Elsewhere in alsa-lib docs, there is more accurate description of
current implementation and behaviour of snd_pcm_delay():
alsa-lib.git/src/pcm/pcm.c:
--cut--
The function #snd_pcm_delay() returns the delay in samples.
For playback, it means count of samples in the ring buffer before
the next sample will be sent to DAC.
--cut--
So e.g. the OMAP patch that this thread started from, complies with this
definition, and element/threshold modes just differ in accuracy (although
threshold implementation should warn the application with the
SNDRV_PCM_INFO_BATCH flag).
But how would a driver expose both bits of info to apps (in a standard
fashion): 1) the hw_ptr for shuffling bits out of the ringbuffer, and 2)
the delay to next played-out/captured sample. For application developers,
(2) is the piece of info we are mostly interested in (if I write a sample
now, how long it will be until it's played out).
One obvious solution (that has been used already in other ALSA drivers) is
to virtualize the hw_ptr, but this way you lose the accurate info about
ringbuffer status. Ideally both pieces of info could be exposed. But as I
see it, drivers currently can only implement "pointer" to relay this info.
Jaroslav proposed some ideas earlier this year, but then the discussion
faded:
"Re: Driver code with mpc5200 pointer problem.", 2009-04-28
http://article.gmane.org/gmane.linux.alsa.devel/62170
Takashi made basicly the same point I've tried to make above
"Re: Driver code with mpc5200 pointer problem.", 2009-04-28
http://article.gmane.org/gmane.linux.alsa.devel/62172
Mark also commented to the same thread:
http://article.gmane.org/gmane.linux.alsa.devel/62176, 2009-04-28
Any update/ideas on this topic? Personally I think adding a new driver
callback would make most sense, as that would allow to take full benefit
from hardware that allows to query sample-accurate position of playout
(i.e. not just support exposing a fixed latency). Of course that's
potentially a big change. In alsa-lib, snd_pcm_hwsync() could call this
driver callback, and a new variant of snd_pcm_delay() could present the
information to the applications.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: snd_pcm_delay, hw buffers and driver api (v2)
2009-08-13 21:35 snd_pcm_delay, hw buffers and driver api (v2) Kai Vehmanen
@ 2009-08-13 21:57 ` Kai Vehmanen
2009-08-14 10:38 ` James Courtier-Dutton
2009-08-14 12:13 ` Clemens Ladisch
2 siblings, 0 replies; 6+ messages in thread
From: Kai Vehmanen @ 2009-08-13 21:57 UTC (permalink / raw)
To: alsa-devel
Hi,
[ continuing to restart the thread. Here's a reply to Mark's mail to the
original misplaced thread at:
http://kerneltrap.org/mailarchive/alsa-devel/2009/7/30/6272573 ]
On Thu, 13 Aug 2009, Mark Brown wrote:
> On Thu, Aug 13, 2009 at 11:46:52PM +0300, Kai Vehmanen wrote:
>> But how would a driver expose both bits of info to apps (in a standard
>> fashion): 1) the hw_ptr for shuffling bits out of the ringbuffer, and 2)
>> the delay to next played-out/captured sample. For application developers,
>> (2) is the piece of info we are mostly interested in (if I write a sample
>> now, how long it will be until it's played out).
>
> Both bits of information are very interesting to applications - some
> applications want to work on the data they're sending for as long as
> possible (things like pulse which do mixing are the obvious example of
> this).
For sure, that's true. I was meaning to say, that when using
snd_pcm_delay(), (2) is what applications are mostly interested in. But
yeah, snd_pcm_avail()/snd_pcm_avail_delay() are certainly important to
applications as well. But I initialled ignored this part, as it would seem
this part of the API is already in good shape (especially after the recent
updates like snd_pcm_avail_delay()).
>> Any update/ideas on this topic? Personally I think adding a new driver
>> callback would make most sense, as that would allow to take full benefit
>> from hardware that allows to query sample-accurate position of playout
>> (i.e. not just support exposing a fixed latency). Of course that's
>> potentially a big change. In alsa-lib, snd_pcm_hwsync() could call this
>> driver callback, and a new variant of snd_pcm_delay() could present the
>> information to the applications.
>
> If we're adding a new API it should be possible to add one which
> provides the required information without disturbing the semantics of
> the existing APIs.
For sure. Changes to e.g. snd_pcm_delay() semantics (especially with
current set of drivers) would cause no end of nasty bugs, agreed. Probably
reusing snd_pcm_hwsync() is a bad idea as well. Maybe just add a new
snd_pcm_hwdelay() or some such which calls the new driver callback (->
provides an atomic snapshot of snd_pcm_avail_delay + fill-status of ext-hw
buffers).
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: snd_pcm_delay, hw buffers and driver api (v2)
2009-08-13 21:35 snd_pcm_delay, hw buffers and driver api (v2) Kai Vehmanen
2009-08-13 21:57 ` Kai Vehmanen
@ 2009-08-14 10:38 ` James Courtier-Dutton
2009-08-14 22:02 ` Kai Vehmanen
2009-08-14 12:13 ` Clemens Ladisch
2 siblings, 1 reply; 6+ messages in thread
From: James Courtier-Dutton @ 2009-08-14 10:38 UTC (permalink / raw)
To: Kai Vehmanen; +Cc: alsa-devel, Ujfalusi Peter, ext-eero.nurkkala
2009/8/13 Kai Vehmanen <kvehmanen@eca.cx>:
> Hi,
>
>
> Any update/ideas on this topic? Personally I think adding a new driver
> callback would make most sense, as that would allow to take full benefit
> from hardware that allows to query sample-accurate position of playout
> (i.e. not just support exposing a fixed latency). Of course that's
> potentially a big change. In alsa-lib, snd_pcm_hwsync() could call this
> driver callback, and a new variant of snd_pcm_delay() could present the
> information to the applications.
snd_pcm_delay() does not just support exposing a fixed latency. The
value returned is dynamic.
In the current ALSA implementation, the value returns a real time
count of how many samples are already in the hardware buffer.
So, if one makes a call to snd_pcm_delay(), waits for a period of a
few samples, the new value returned in snd_pcm_delay() is going to be
different, but only for sound cards that support this level of
accuracy.
So, I think the snd_pcm_delay() function is already doing what you want.
It was me who originally requested the snd_pcm_delay() function to be
introduced into the API, for the purposes of audio/video sync in the
media player xine.
Kind Regards
James
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: snd_pcm_delay, hw buffers and driver api (v2)
2009-08-13 21:35 snd_pcm_delay, hw buffers and driver api (v2) Kai Vehmanen
2009-08-13 21:57 ` Kai Vehmanen
2009-08-14 10:38 ` James Courtier-Dutton
@ 2009-08-14 12:13 ` Clemens Ladisch
2009-08-14 23:27 ` Kai Vehmanen
2 siblings, 1 reply; 6+ messages in thread
From: Clemens Ladisch @ 2009-08-14 12:13 UTC (permalink / raw)
To: Kai Vehmanen; +Cc: alsa-devel, Ujfalusi Peter, ext-eero.nurkkala
Kai Vehmanen wrote:
> ...
> In both cases, this value (hw_ptr) shows the status of sending data to an
> separate entity, and one that has its own buffer (multiple ms) before the
> actual DAC/ADC.
>
> So when application developer uses snd_pcm_delay(), the result is not
> quite what the ALSA API says: ...
snd_pcm_avail() returns the free part of the buffer.
snd_pcm_delay() returns the filled part of the buffer plus
the additional delay imposed by the device.
The additional delay can be set by the driver in
pcm_substream->runtime->delay. (Currently, only
the USB audio driver bothers to set this.)
HTH
Clemens
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: snd_pcm_delay, hw buffers and driver api (v2)
2009-08-14 10:38 ` James Courtier-Dutton
@ 2009-08-14 22:02 ` Kai Vehmanen
0 siblings, 0 replies; 6+ messages in thread
From: Kai Vehmanen @ 2009-08-14 22:02 UTC (permalink / raw)
To: James Courtier-Dutton; +Cc: alsa-devel
Hi,
On Fri, 14 Aug 2009, James Courtier-Dutton wrote:
> snd_pcm_delay() does not just support exposing a fixed latency. The
> value returned is dynamic.
yes, I'm aware of that, and I was in fact quoting the documentation in my
original mail, which indeed states that (although there are two
descriptions, written with slightly different wording in alsa-lib pcm.c).
> In the current ALSA implementation, the value returns a real time
> count of how many samples are already in the hardware buffer.
> So, if one makes a call to snd_pcm_delay(), waits for a period of a
> few samples, the new value returned in snd_pcm_delay() is going to be
> different, but only for sound cards that support this level of
> accuracy.
[...]
> So, I think the snd_pcm_delay() function is already doing what you
> want. It was me who originally requested the snd_pcm_delay() function to be
> introduced into the API, for the purposes of audio/video sync in the
> media player xine.
Yes, acking that as well. It's just that we now start to have more drivers
for HW, which include separate, fairly big, buffers of their own. I.e.
something like the "URB buffering" of USB audio, but with potentially even
larger buffers. My understanding is that so far these delays have not been
exposed via ALSA and snd_pcm_delay(), although semantically these should
be taken into consideration in the result of snd_pcm_delay() (as they
directly affect e.g. a/v sync).
So if we have drivers that could expose this information, my question
is how to do it with ALSA.
I've been looking at the ALSA code, and e.g. current implementation of
snd_pcm_delay()->snd_pcm_hw_delay() in alsa-lib/src/pcm/pcm_hw.c, just
returns the diff between 'hw_ptr' and 'appl_ptr'. The
SNDRV_PCM_IOCTL_DELAY is called only for cases where the control structs
cannot be mmap'ed, and the result is the same anyways. On the kernel side,
drivers just implement the "pointer" method returning one value (->
hw_ptr). This tells the delay to last transfer from ringbuffer to/from HW,
but not necessarily the full latency up until the codec.
Now one approach is full double-buffering, or virtualizeing the 'hw_ptr',
(this seems to be done in e.g. the cs46xx driver). This is certainly one
way to do it, but it seems somewhat messy, and based on earlier discussion
(see the archive links in my original post to this thread), at least some
of you share this view. A potential problem is for instance if application
wants to do late mixing of samples and resubmit the samples
[hw_ptr+X,hw_ptr+X+Y] in the ringbuffer. With the virtualized hw_ptr
(usb-audio,cs46xx), this range might already been transfered to the HW,
and thus application edits of that range will be discarded. You can warn
applications about this by declaring SNDRV_PCM_INFO_BATCH/BLOCK_TRANSFER
flags in the driver (as is done by usb-audio+cs46xx), but for apps, an
accurate hw_ptr reflecting which parts of ringbuffer have been consumed,
would be easier to handle.
Basicly transfering the bytes from the ALSA ringbuffer to a
codec/dsp-memory, and actually playing those samples out a DAC or digital
interface, are two different things, and ideally the application could
track both of these pieces of information. Former is important for i/o
scheduling, latter for e.g. a/v sync.
So one alternative would be to extend the driver interface, so that they
could expose both pieces of info. The 'pointer' method would return
ringbuffer/hw_ptr as currently, and a new interface would provide the
"virtualized hw-ptr".
Then how to expose this to apps is a bit more tricky. Semantically just
exposing this via snd_pcm_delay() would seem ok (as the info is needed for
a/v sync), but it risks breaking existing apps (as the returned delay can
be significantly higher than the overall ringbuffer size).
Alternatively, I'm missing some obvious and easy solution to this problem,
but I'm hoping that in that case someone will point it out to me. :)
PS On existing mechanism is snd_pcm_hw_params_get_fifo_size(). But
this is a fixed value, and very few apps seem to be using this (e.g.
to fine-tune their a/v sync in a portable manner).
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: snd_pcm_delay, hw buffers and driver api (v2)
2009-08-14 12:13 ` Clemens Ladisch
@ 2009-08-14 23:27 ` Kai Vehmanen
0 siblings, 0 replies; 6+ messages in thread
From: Kai Vehmanen @ 2009-08-14 23:27 UTC (permalink / raw)
To: Clemens Ladisch; +Cc: alsa-devel
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1546 bytes --]
Hi,
On Fri, 14 Aug 2009, Clemens Ladisch wrote:
> snd_pcm_delay() returns the filled part of the buffer plus
> the additional delay imposed by the device.
[...]
> The additional delay can be set by the driver in
> pcm_substream->runtime->delay. (Currently, only
> the USB audio driver bothers to set this.)
aa, now that's interesting, and I think that's just the missing piece I'm
looking for. I was looking at the 2.6.30.4 kernel, and couldn't find any
traces of 'runtime->delay', but oh yes, 2.6.31 tree indeed has
it - yay! :)
It would seem this was added by Takashi with commit "ALSA: Add extra delay
count in PCM" on 2009-05-05, so no wonder not too many drivers set it yet.
Hmm, but isn't it so that this extra delay is added properly to
snd_pcm_delay() result, when 'sync_ptr_ioctl==false' property is set for
the pcm (i.e. use SYNC_PTR ioctl instead of mmap control structures).
Attached is an alsa-lib patch attempting to fix this (as sufficient info
is not available in the mmap control block, always go via IOCTL_DELAY).
But otherwise this does look good and is just what I was looking for. When
using snd_pcm_status(), application can get all the information (avail,
delay) in one go. Of course one limitation is that the runtime->delay
updates are synced to driver events, not to application calling
snd_pcm_delay (unlike query of hw_ptr status via pointer driver callback),
but maybe this is not even needed in the end. Have to think about this
some more...
Thanks Clemens, James and Mark for the quick replies!
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/X-DIFF; NAME=patch-alsalib-pcmhw-always-use-ioctl-delay.diff, Size: 873 bytes --]
commit fc98ec2e631a6afa85e7505bc553824d7f6f56cc
Author: Kai Vehmanen <kvehmanen@eca.cx>
Date: Sat Aug 15 02:05:02 2009 +0300
pcm_hw: Always use SNDRV_PCM_IOCTL_DELAY
As the kernel drivers may adjust the delay with 'runtime->delay',
the SNDRV_PCM_IOCTL_DELAY ioctl must be always used when
calculating the snd_pcm_delay result.
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index c46d14f..4491099 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -523,11 +523,6 @@ static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
default:
return -EBADFD;
}
- if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
- *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
- else
- *delayp = snd_pcm_mmap_capture_avail(pcm);
- return 0;
}
if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) {
err = -errno;
[-- Attachment #3: Type: text/plain, Size: 160 bytes --]
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2009-08-14 23:27 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-13 21:35 snd_pcm_delay, hw buffers and driver api (v2) Kai Vehmanen
2009-08-13 21:57 ` Kai Vehmanen
2009-08-14 10:38 ` James Courtier-Dutton
2009-08-14 22:02 ` Kai Vehmanen
2009-08-14 12:13 ` Clemens Ladisch
2009-08-14 23:27 ` Kai Vehmanen
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.