fix(audio): bound playout depth to stop voice latency ratcheting up
Latency between speakers grew to multiple seconds and only reset on rejoining voice. Root cause was the receiver playout logic, not the codec settings: the playout clock free-ran in real time while the sender omitted silence from its timestamps (and set no header flags), and the only correction snapped the clock to the *oldest* buffered frame — which could only ever add standing latency. target_depth_ms_ was computed but never enforced, so latency could only grow or reset. Fix: bound playout against the stream's leading edge (newest frame). (Re)seed to the leading edge on start/marker/starve (no prebuffer, so latency stays low), and frame-skip catch-up trims any backlog beyond target+hysteresis — the missing downward force. Hardening: sender now stamps kFlagMarker (talkspurt start) and kFlagDtx, consumed on recv for clean resync; adaptive late-drop window; EWMA outlier rejection so silence gaps/stragglers don't poison the estimate; duplicate counting and ring-underrun diagnostics. New test_jitter_depth asserts depth stays bounded (<200ms) while arrivals outrun playback. ctest --preset dev green (27/27). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -110,11 +110,14 @@ int main() {
|
||||
}
|
||||
CHECK(energy == 0); // capped PLC = silence
|
||||
|
||||
// 5) Resumption: push a fresh real frame — PLC streak resets, audio returns.
|
||||
// 5) Resumption: push a fresh real frame — PLC streak resets, audio returns. marker=true is
|
||||
// what the real sender stamps on the first frame after a silence (talkspurt restart); it
|
||||
// makes the playout clock reseed to this leading edge immediately (no prebuffer delay).
|
||||
voicecat::audio::JitterBuffer::Frame f2;
|
||||
f2.seq = 1;
|
||||
f2.timestamp = 200000; // far ahead — playout-clock re-sync snaps to it
|
||||
f2.timestamp = 200000; // far ahead — playout-clock reseeds to it
|
||||
f2.fec_present = false;
|
||||
f2.marker = true;
|
||||
f2.payload.assign(opus_buf, opus_buf + opus_len);
|
||||
engine.push_recv_frame(ssrc, std::move(f2));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user