audiobasesink: prerolling late with fixed latency and rtpbin -> unsynchronized output
I am having some troubles with synchronized audio output. On the receiving end, this is roughly my setup:
- Pipeline with
gst_pipeline_set_latency, let's say 2000ms
gst_pipeline_use_clockon sender and receiver is using a network clock (synchronized)
- rtpbin/rtpjitterbuffer with
latencyproperty set to 780ms,
Let's say I have two different devices:
- Device A has 10 alsa periods 100ms each (total 1000ms)
- Device B has 10 alsa periods 20ms each (total 200ms)
Let's say the sending side is a little delayed and sends out the first buffer (though it doesn't matter whether the delay is massive or almost 0). rtpjitterbuffer waits at least 780ms (its own
latency) before pushing out the first buffer. Let's say it took 5 seconds for the first buffer to arrive. It's timestamp is now e.g. 00:00:05.940 (rtpjitterbuffer added in it's latency of 780ms). The deadline timer now triggers it to be pushed downstream to alsasink. Since it is the first buffer, alsasink calls
gst_audio_base_sink_sync_latency, where it waits for the upstream latency (which happens to be rtpjitterbuffer's latency, and starting 1.16 +
processing-deadline), so 780ms. But because the pipeline was started 5+ seconds ago, it will always be a late preroll.
Shouldn't the preroll not only take the buffer's timestamp into account, but also wait until total latency - upstream latency, so it doesn't start writing way too early? Right now it waits the same amount of time on both devices, and since it's most likely a late preroll, not at all. But it also seems that once
gst_audio_base_sink_sync_latency returned, on device B it wouldn't wait 800ms longer and write into the ringbuffer at the wrong locations.
The end result is that both devices play totally out of sync initially, but eventually clock skew adjustments bring them in sync again. But when the delta is so big, it's pretty awful quality and countless clock skew corrections.
It seems that
gst_audio_base_sink_sync_latency should not be waiting merely until the upstream latency expired, but rather "fixed latency - upstream latency", and on top of that also account for the timestamp of the first packet? Or does
gst_audio_base_sink_render lack a wait on the clock if the timestamp is too far out (which would only be hit right after prerolling or after a resync)?
I think part of the problem is that the first buffer tends to be tiny (e.g. 1/10) of the total alsa buffer size (all periods), and because the ringbuffer thread is started at preroll it "sucks" in as many periods as possible, but only that first small buffer was written timely enough. Then, when the next buffer comes in, the ringbuffer thread has already inserted a bunch of silence, and this all leads to a bunch of choppy audio, and the clocks are way off.
I haven't had much success getting this to work properly. It feels like audiobasesink doesn't handle this correctly, but I don't know for sure. I'd appreciate any suggestions/ideas/hints.