[alsa-devel] On non-rewindability of resamplers

Alexander E. Patrakov patrakov at gmail.com
Sat May 10 15:16:20 CEST 2014

10.05.2014 06:46, Raymond Yau wrote:
>  >
>  >
>  > I acknowledge that there was some confusion regarding the precise
> meaning of the flag (especially given three possible situations -
> accurate to just one period, accurate to better than one period but
> worse than one sample, accurate to one sample), and I am not the
> authority here.
> Can this granularity be measured by
> 1) open a playback stream with 2 or more periods
> 2) fill the full buffer and start playback
> 3) check the value returned by snd_pcm_rewindable () is half of period
> at half period time interval
> 4) repeat the test with 1/4 , 1/8,..., period time interval

Yes and no.

Instead of what you are proposing above, I wrote a loop that repeatedly 
calls snd_pcm_rewindable() 7000000 times and prints the result if it 
differs from the previous one. With snd-hda-intel (PCH), hw plugin, 
stereo, S16_LE, 48 kHz, 6 periods, and a period size of 1024, I get this:

Rewindable: 6119, loop iteration: 0
Rewindable: 5119, loop iteration: 5389434

So snd_pcm_rewindable() can return weird values that are updated every 
period size or so. As such, I wouldn't believe its return value out of 
the box even for hw devices. At loop iteration 5389433, the CPU chewed 
enough time for almost one period, but snd_pcm_rewindable() said that 
almost 6 periods are rewindable. Probably a missing sync_ptr() 
somewhere, or a documentation bug.

With snd_pcm_avail() inserted (which does synchronize the position) 
before each call to snd_pcm_rewindable(), I get:

Rewindable: 6119, loop iteration: 0
Rewindable: 6112, loop iteration: 2
Rewindable: 6104, loop iteration: 42
Rewindable: 6096, loop iteration: 76
Rewindable: 6088, loop iteration: 125
Rewindable: 6080, loop iteration: 173
Rewindable: 6072, loop iteration: 222
Rewindable: 6064, loop iteration: 270

(and an underrun in the end).

With 4 channels:

Rewindable: 6112, loop iteration: 0
Rewindable: 6108, loop iteration: 2
Rewindable: 6104, loop iteration: 14
Rewindable: 6100, loop iteration: 36
Rewindable: 6096, loop iteration: 58
Rewindable: 6092, loop iteration: 63

With 8 channels:

Rewindable: 6104, loop iteration: 0
Rewindable: 6098, loop iteration: 1
Rewindable: 6096, loop iteration: 2
Rewindable: 6094, loop iteration: 9
Rewindable: 6092, loop iteration: 24
Rewindable: 6090, loop iteration: 32
Rewindable: 6088, loop iteration: 41

So on my snd-hda-intel, the granularity of the pointer is 32 bytes.

For Haswell HDMI (on another snd-hda-intel), stereo, S16_LE:

Rewindable: 6128, loop iteration: 0
Rewindable: 6112, loop iteration: 129
Rewindable: 6096, loop iteration: 339
Rewindable: 6080, loop iteration: 551
Rewindable: 6064, loop iteration: 753
Rewindable: 6048, loop iteration: 966
Rewindable: 6032, loop iteration: 1180

so the resulting granularity is 64 bytes.

An unfortunate observation is that, without snd_pcm_avail(), even on hw 
just after an underrun snd_pcm_rewindable() can return negative numbers 
such as -16 or -25 that lead to nonsense error codes (EBUSY or ENOTTY).

>  > In addition, there seems to be some confusion here between the
> hardware periods (which are always 256 samples) and the period size in
> hw params. If I understand the other emails correctly, regardless of
> what the user set in hw_params, the reported position on ymfpci will be
> accurate to within 256 samples.
>  >
> http://www.alsa-project.org/~tiwai/writing-an-alsa-driver/ch05s06.html#pcm-interface-operators-pointer-callback
> This callback is called when the PCM middle layer inquires the current
> hardware position on the buffer. The position must be returned in
> frames, ranging from 0 to buffer_size - 1.
> This does not implies all drivers must give accurate position at any
> time, some drivers may use timer interrupt and increase the pointer by
> one periods

That's why we have snd_pcm_htimestamp().

> http://www.alsa-project.org/~tiwai/writing-an-alsa-driver/ch05s07.html#pcm-interface-interrupt-handler-boundary
> High frequency timer interrupts
> This happens when the hardware doesn't generate interrupts at the period
> boundary but issues timer interrupts at a fixed timer rate (e.g. es1968
> or ymfpci drivers). In this case, you need to check the current hardware
> position and accumulate the processed sample length at each interrupt.
> When the accumulated size exceeds the period size, call
> snd_pcm_period_elapsed() and reset the accumulator.

This clears the confusion.

> I am also confuse about ymfpci really use timer interrupts.

Well, that's easy. According to your own words, the card sends an 
interrupt every 256 samples and has no real notion of the user-defined 
period size. From ALSA viewpoint, this 256-sample interrupt is just a 
timer (but not a timer that is managed through functions that have 
"timer" in the name).

<snip information on the OSS DSP_CAP_REALTIME and DSP_CAP_BATCH 
capability bits>

> http://thread.gmane.org/gmane.linux.alsa.devel/5597

Interesting, but does not really clarify anything.

>  > hw_ptr granularity is defined only by period_bytes_min (and
> additional constraints if any).

Well, this disagrees with my experiments. For S16_LE stereo, 
snd_pcm_hw_params_get_period_size_min() says 32 samples for both PCH and 
HDMI, while the measured granularity is different (8 and 16 samples).

> https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/commit/sound/soc?id=c0de42bf595238e9dd593405ebc2992cc8470732
> hw.period_bytes_min = 256;
> hw.fifo_size = dma_data->fifo_size;
> Does soc drivers transfer audio in 256 bytes ?
> seem twice the values of snd-hda-Intel (pcie bus)

No comment on this, I am not an expert in this area.

>  >
>  > PulseAudio has the following consideration here: if the card cannot
> report the position accurately, we need to disable the timestamp-based
> scheduling, as this breaks module-combine-sink (or any successor of it),
> because it relies on very accurate estimations of the actual sample rate
> ratio between two non-identical cards.
>  >
> https://bugs.freedesktop.org/show_bug.cgi?id=47899

This is something to investigate, I am not ready to provide any useful 
comment. Although in comment #2 bluetooth is mentioned, and this is 
indeed an example where even somewhat accurate timing information is not 

> if you want to hear sound from two snd-hda-intel at the same time using
> combined sink, you may need driver provide the output delay in hda codec
> Audio Function Group Capabilities
> Output Delay is a four bit value representing the number of samples
> between when the sample is received from the Link and when it appears as
> an analog signal at the pin. This may be a “typical” value. If this is
> 0, the widgets along the critical path should be queried, and each
> individual widget must report its individual delay.
> Figure 85. Audio Function Group Capabilities Response Format
> Audio Widget Capabilities
> Delay indicates the number of sample delays through the widget. This may
> be 0 if the delay value in the Audio Function Parameters is supplied to
> represent the entire path.
> http://git.kernel.org/cgit/linux/kernel/git/tiwai/hda-emu.git/tree/codecs
> some hda codecs report delay in audio output/input widgets and the
> ranges of delay vary from 3 to 13 samples, hda_proc.c did not show
> output/input delay in the audio function group

Interesting, implementable for someone with the skills in this area, but 
probably not relevant for the above freedesktop bug. What you are 
talking about is just a constant offset in the snd_pcm_delay() return 
values. That's bad, but I guess not bad enough for PulseAudio to 
stutter. What PulseAudio doesn't tolerate is jitter.

> Does it mean that pulseaudio need to add back the difference of output
> delay of two hda codecs ?


> If yes, this look like combined sink is also not rewindable too when
> difference of  output delay is not zero

Indeed, it is not fully rewindable. But what's worse is that the 
combined sink contains a variable-rate resampler that is used in order 
to compensate adaptively for slightly different sample rates of the two 

> http://git.alsa-project.org/?p=alsa-plugins.git;a=blob;f=doc/upmix.txt;hb=HEAD
> for upmix plugin, this mean that snd_pcm_rewindable may need to return
> zero when user specify delay > 0 if you want "glitch free" rewind

Absolutely correct.

> Other pulseaudio modules seen does not support rewind (e.g. jack,
> tunnel, Bluetooth,...
> http://git.alsa-project.org/?p=alsa-plugins.git;a=tree
> Other alsa plugins (e.g. Jack, oss,...) seem not support rewind

Jack is interesting here: it is the only ioplug-based plugin which sets 
mmap_rw = 1. As such, ALSA treats it as something that has mmapped 
buffer with the same semantics as an ordinary hardware sound card, and 
performs rewinds using this buffer. There is also a "hardware" position 
callback. The actual transfer of samples from that buffer to JACK is 
performed in a separate realtime thread which is implicitly created in 
jack_activate(). The porition is updated every JACK period.

The whole construction should support rewinds, with the non-rewindable 
remainder being one JACK period (which may be different from one ALSA 
period). If the JACK period is 256 samples, this plugin should behave 
very much like one voice of ymfpci.

However, there is still a bug (possibly fixable). While running my test 
program over this plugin does produce silence, it produces a wrong 
amount of silence. As if there is something wrong with 
snd_pcm_jack_poll_revents() or snd_pcm_jack_pointer(). I have not tested 
this patch yet, although I should:


As for ioplug-based plugins with mmap_rw = 0, they are indeed not 
rewindable at all.

> How about route and plug plugins ?

Route should in theory support rewind, but there may be bugs. The best 
way to test is to run a program that I attached to an earlier message in 
this thread and listen - any non-silence indicates a non-rewindable plugin.

Plug is not really a plugin, it just inserts other plugins and then 
disappears. It can insert adpcm and rate plugins which are not really 

>  >
>  > For cards that are not batch, it will attempt to set both the period
> size and the buffer size to something large (tsched_size, the default is
> 2s) and let the driver adjust that to something more sensible for the
> card. I think that in practice this means periods_min, although it is
> never mentioned explicitly in PulseAudio source.
> it does not  mean all drivers uses periods_min when applicaition did not
> explicitly set  period , period time or period bytes
> http://git.alsa-project.org/?p=alsa-lib.git;a=commit;h=09879a4bb58199f64abcb8df506f917c8efc2383
> Some driver 's period_bytes_max can be less than (buffer_bytes_max /
> periods_min)

Please see this code and make your own conclusions.


PulseAudio does try several strategies, among those is "set nothing at 
all if everything else failed".

>  >
>  > For batch cards, the desired period (or, in PA speak, "fragment")
> time and the number of periods come from the config, of course subject
> to adjustments made by the ALSA library to fit the hardware requirements.
> as long as the application use two periods , no safe rewind is possible
> as the application need to keep at least two periods fill in the buffer
> if the pointer is not accurate.

Correct if we use the viewpoint that the pointer granularity is one 
period for such cards. Which is not the case for ymfpci and for USB audio.

> do you mean that pulseaudio still perform rewind when using AC3
> passthrough on Didital playback device ?

I don't know.

> if not , the value of snd_pcm_rewindable() of digital playback device
> depends on whether  no audio  bit is set or not

While I understand the idea, I would like to see more details. The only 
consideration that comes to my mind is that it should not be possible to 
rewind into the middle of the currently playing IEC 61937 frame. But 
there are also stupid receivers (e.g. JVC TH-A25) that mute their 
outputs if a non-IEC-wrapped DTS stream (as found on DTS CDs) is coming 
with AES0 = 6.

>  >The defaults are:
>  >
>  > ; default-fragments = 4
>  > ; default-fragment-size-msec = 25
>  >
>  >
> Does this mean that pulseaudio use this values for all sound card
> including hda when user specify this value ?

This is the default for all cards that are autodetected as incompatible 
with tsched or where the user configured tsched=0. These defaults can 
still be overridden with module-alsa-card parameters.

> Seem the values are comment out and not used by pulseaudio as default ,
> users have to explicitly set these in the following report

The commented-out values are used by default when PulseAudio decides 
that it needs a traditional (not tsched based) playback model. They are 
in the source:


> https://bugs.launchpad.net/ubuntu/+source/pulseaudio/+bug/428619/comments/96

The key in that comment is the explicit tsched=0. Without tsched=0, 
these settings are not used.

Alexander E. Patrakov

More information about the Alsa-devel mailing list