All of lore.kernel.org
 help / color / mirror / Atom feed
* 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.