Repository navigation
Conversation
jleal52
force-pushed
the
fixed-egress-ssrc-audio-player
branch
from
October 8, 2026 04:46
14438ae to
068cf66
Compare
With `fixed egress SSRC`, forwarded media keeps one SSRC towards the recipient, but an audio player on the same media (e.g. the mixer of an `audio-player=force` conference) sent under its own random SSRC. A WebRTC receiver without signalled SSRCs binds to the newest one and does not go back: audio went silent after leaving a conference. - media_player_set_sink(): send under the fixed egress SSRC; on every (re)start continue from the egress ext_seq and zero seq_diff. The player numbers its packets as mp->seq + seq_diff and advances seq_diff itself. - media_player_add_packet(): set fixed_rebase on the egress entry so that forwarded media re-bases its numbering on ext_seq when it resumes. - media_packet_rtp_out(): no fixed-SSRC sequence bookkeeping while an audio player is active on the sink. Those packets are decoded into the mix buffer; re-basing seq_diff on each of them corrupted the player's output. The decoders that feed the audio player no longer move seq_diff since 4fad5b8 ("a stream the audio player consumes keeps the sender's numbers"), which this relies on: with a fixed egress SSRC that offset is the one the player sends under. auto-daemon-tests-inject.pl: under a fixed egress SSRC the injection now reaches A under that SSRC, so B's packets are told from the player's by B's timestamps, and the sequence is checked continuous across the injection too. Known residual: a supplemental (telephone-event) packet forwarded while the player runs goes out with an arbitrary sequence number.
This was referenced Nov 6, 2026
jleal52
force-pushed
the
fixed-egress-ssrc-audio-player
branch
from
November 6, 2026 09:11
d1a5036 to
1ecbbae
Compare
Member
This seems a bit like a deal breaker to me. This will land on my desk to fix when inevitably somebody complains about it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Needs #2237 merged first (or together). With this change the audio player sends under the shared fixed egress entry, which makes the send-timer RTCP lock inversion fixed there easy to hit: without it the extended inject tests deadlocked in 1 of 3 runs (in "SRTP under the sender key with a fixed egress SSRC ..."), with it in none.
Problem
With
fixed egress SSRCforwarded media keeps one SSRC towards the recipient, but an audio player on the same media (e.g. the mixer of anaudio-player=forceconference) sends under its own random SSRC. A WebRTC receiver without signalled SSRCs binds to the newest SSRC and does not go back to one it has already replaced: after leaving the conference the browser receives packets but plays nothing.Change
media_player_set_sink(): the player sends under the fixed egress SSRC. On every (re)start it continues from the egressext_seqand zeroesseq_diff(the player numbers its packets asmp->seq + seq_diffand advancesseq_diffitself).media_player_add_packet(): setsfixed_rebaseon the egress SSRC entry;media_packet_rtp_out()re-bases forwarded media onext_seqwhen the player stops.media_packet_rtp_out(): no fixed-SSRC sequence bookkeeping whileaudio_player_is_active()on the sink. Those packets are decoded into the mix buffer; re-basingseq_diffon each of them corrupted the player's output numbering.auto-daemon-tests-inject.pl: under a fixed egress SSRC the injection now reaches A under that SSRC, so the fixed-egress subtests tell B's packets from the player's by B's timestamps (which pass through unchanged; the player runs its own clock), check that the injection does arrive under the fixed SSRC, and check the sequence continuous across the injection too (it was only checked without injection).Receiver sees one SSRC with continuous sequence numbers: forwarded → mixed → forwarded. This is the fixed-egress-SSRC side of 4fad5b8: without a fixed SSRC the sender's packets keep their own numbers and the receiver sees a forward gap per injection; with it, the stream is re-based at every change of source (as
auto-daemon-tests-inject.plalready expects), and the player is now one more source under the same SSRC. Resuming at the sender's numbers instead could land behind the player's last number, a backward step that SRTP replay protection punishes.Known residual: a supplemental (telephone-event) packet forwarded while the player runs goes out with an arbitrary sequence number.
Rebased on current master
seq_diffadjustment for handlers that decode into the audio player) is dropped: 4fad5b8 (decode_only, A stream the audio player consumes keeps the sender's sequence numbers #2209) does the same, and also covers the DTX discard. This change relies on it: with a fixed egress SSRC the offset those decoders used to move is the one the player sends under.phc->mp.ssrc_outcheck is gone from the fixed-SSRC condition, as in 44722ed.Testing
make asan-checkpasses on this branch alone, and so doesdaemon-tests-ssrcwithRTPENGINE_EXTENDED_TESTS=1.daemon-tests-injectwithRTPENGINE_EXTENDED_TESTS=1passes the fixed-egress subtests in every run; the only failures seen are the timing-dependent "ten consecutive expected PCM frames" checks (e.g. "standalone playback stopped after injection"), which fail intermittently on unmodified master as well. Originally verified with packet captures in a WebRTC deployment (Chrome agents ⇄ rtpengine ⇄ SIP trunk,fixed egress SSRCon the answers towards the browser): call, consult, three-way conference withaudio-player=force, remove a member, re-conference in the same call, hold/resume, switch, blind and attended transfer. Sequence numbers towards the browser are continuous in all cases.