Skip to content

fix: rebuild lost audio frames instead of dropping them - #8

Merged
dangusev merged 2 commits into
mainfrom
fix/opus-rebuild-lost-frames
Sep 22, 2026
Merged

dangusev merged 2 commits into
mainfrom
fix/opus-rebuild-lost-frames

Conversation

@dangusev

Copy link
Copy Markdown
Collaborator
  • next_pcm decoded whatever arrived and ignored RTP sequence numbers, so a lost packet silently shortened the PCM timeline and left the Opus decoder's prediction state desynced for the frames that followed.

  • Track the sequence number per audio track and emit frames for every packets.

  • The frame directly before an arriving packet comes from its in-band FEC copy

  • anything lost earlier has no copy left, so libopus builds a replacement.

  • Gaps longer than 10 packets reset the state, which keeps a reordered or wrapped sequence number from generating thousands of frames.

  • A rebuilt frame is as long as the output buffer, so it is requested at the stream's own frame size rather than the 120 ms maximum.

- next_pcm decoded whatever arrived and ignored RTP sequence numbers, so a
  lost packet silently shortened the PCM timeline and left the Opus decoder's prediction state desynced for the frames that followed.

- Track the sequence number per audio track and emit frames for every packets.
- The frame directly before an arriving packet comes from its in-band FEC copy
- anything lost earlier has no copy left, so libopus builds a replacement.
- Gaps longer than 10 packets reset the state, which keeps a reordered or wrapped sequence number from generating thousands of frames.

- A rebuilt frame is as long as the output buffer, so it is requested at the stream's own frame size rather than the 120 ms maximum.
- The sequence number was tracked as the previous arrival, so a packet arriving after the one that overtook it was decoded a second time: its frame had already gone out, rebuilt from the overtaking packet. The mark also moved backwards, which made every following packet rebuild frames that were already emitted. Four packets on the wire produced six frames.

- Treat the sequence number as a high water mark and drop anything older than it. A wrapped 16 bit number reads as behind when the distance is over half the range.
@dangusev
dangusev merged commit 9226aa0 into main Sep 22, 2026
3 checks passed
@dangusev
dangusev deleted the fix/opus-rebuild-lost-frames branch September 22, 2026 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant