On 08/19/2011 10:34 PM, Rémi Denis-Courmont wrote:
Hello,
Le vendredi 19 août 2011 21:02:59 David Henningsson, vous avez écrit :
I've spent most the afternoon trying to figure out why VLC doesn't work
well with a large tlengths. I seem to have found suboptimal behaviour on
both the PulseAudio and VLC sides.
Nice.
What bothers me on the PulseAudio side is this call (in alsa-sink.c,
mmap_write):
pa_sink_render_into_full(u->sink,&chunk);
For this example, assume tlength is 500 ms and minreq is 50 ms. In
adjust latency mode (which I understand is recommended for power
efficiency), this is configured to the client's tlength/2 - minreq = 200
ms. The problem here is that if the client is filled up to only e g 130
ms, PulseAudio will take the 130 ms, the client will underrun, and hand
out 70 ms of silence. A better behaviour would be to write the 130 ms
that are available, and go to sleep until the 130 ms is almost up and
see if more data has come in at that time.
However, things are probably not as bad as it looks. If a new package
comes in from the client in time, I believe PulseAudio would rewind back
the 70 ms of silence and write the new data, and no glitch will be
heard. So the worst thing is actually the somewhat "false alarm" sent to
the client.
VLC currently assumes that a PulseAudio under-run event implies a
silence/glitch. It uses it as an opportunity to resync the audio stream...
this is not good if there was no actual under-run :-/
Agreed. PulseAudio should not send the underrun message if there is a
possibility that the client can avoid the underrun by sending more data.
Fixing that is quite complex though. :-(
However messing with PulseAudio's buffering mechanisms isn't giving me
warm and fuzzy feelings, at least not right before the 1.0 release :-D
So over to the VLC side. I started off with the current git head of VLC.
For the synchronisation, I believe the correct way is to do something like:
1) when the first packet arrives, notice its timestamp (pts), and set a
system timer to trigger at that point in time (i e trigger in i->pts -
mdate() usecs)
Yeah. That would certainly be better than the current zero padding of the
stream, especially when resuming from pause (i.e. PulseAudio uncorking).
But but, VLC does not have a mainloop. A timer is going to need a dedicated
thread. Or maybe libpulse can accept user timers in its threaded mainloop?
Yes you can, use the
pa_threaded_mainloop_get_api(vlc_pa_mainloop)->time_new() [1] function
to start a timer.
2) the callback from the system timer would then uncork/trigger the stream.
At that point, PulseAudio's buffer has been filled up by all the other
calls to Play that happened in between.
I did a quick hack myself: I didn't know how to do system timers in VLC
so I set it to check at every call to Play, if it was yet time to start
the stream. (And commented out the call to stream_resync.) That gave
good synchronisation as well as I could see (being layman on observing
synchronisation issues).
vlc_timer_*() functions. But I'd rather use the Pulse mainloop if possible.
For the buffering attributes, I tried setting tlength to 500 ms (note:
AOUT_MAX_PREPARE_TIME is actually 2000 ms, not 500 ms as I originally
thought).
Given an initial filled buffer as suggested above, that did not
underrun. That was with playing back a local video file.
I set minreq to AOUT_MIN_PREPARE_TIME (40 ms), which is mostly taken out
of the air.
However, given the reasoning above, if you want to be certain to avoid
the false underrun alarms as outlined in the PulseAudio section, I
believe a minreq of AOUT_MIN_PREPARE_TIME and tlength of
AOUT_MIN_PREPARE_TIME * 4 = 160 ms should be a relatively safe setting.
In my experience, larger tlength caused more underruns. But maybe that's
because VLC is more likely to be continuously late?
I think this is mostly because the "false alarm" problem on the
PulseAudio side. However, the problem is not linear, and the boundary
for where this starts to happen should be when tlength =
AOUT_MIN_PREPARE_TIME * 4 if minreq = AOUT_MIN_PREPARE_TIME.
Also remember to set the PA_STREAM_ADJUST_LATENCY flag.
It's not clear to me what this actually will do.
Without knowing all the details myself, there are differences in how the
buffering is done. The calculations above are based on setting the
PA_STREAM_ADJUST_LATENCY flag, which is also what most other
applications do these days. If the flag is not set things are calculated
differently - the hw stuff is done in larger chunks, which means more
false underruns (or rather, the boundary for when this starts to happen
is lower), and I *think* (not sure) that you're also more likely to be
affected by other streams (i e buffering behaviour changes when other
streams are played in parallel to yours).
Hopefully this gives a little insight in the current problems with VLC
and PulseAudio!
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
[1]
http://www.freedesktop.org/software/pulseaudio/doxygen/structpa__mainloop__api.html
_______________________________________________
pulseaudio-discuss mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss