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 :-/
> 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?
> 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?
> Also remember to set the PA_STREAM_ADJUST_LATENCY flag.
It's not clear to me what this actually will do.
> Hopefully this gives a little insight in the current problems with VLC
> and PulseAudio!
--
Rémi Denis-Courmont
http://www.remlab.net/http://fi.linkedin.com/in/remidenis