Do not force codec regression between opus and red. (#3980)

The following scenario produced silence audio in egress
1. JS SDK publishing audio/red
2. Egress joins
3. Egress picks the RED primary receiver -> this converts RED to Opus in SFU
4. At the same time, codec regression is triggered back to the publisher. Publisher switches to publishing audio/opus and stops audio/red.
5. But, egress is still attached to audio/red and pulls down only silence.

Fix by checking if the negotiated codec needs publish before sending
subscribed codec udpate.
This commit is contained in:
Raja Subramanian authored and GitHub committed 2025-10-04 00:17:17 +05:30
1 parent 3bd20ddb28
commit c7f625d626
2 files changed
+14 -5

No files matched your search

+1 -1
View File
@@ -433,7 +433,7 @@ func (t *SubscribedTrack) OnRttUpdate(rtt uint32) {
}
func (t *SubscribedTrack) OnCodecNegotiated(codec webrtc.RTPCodecCapability) {
if !t.params.WrappedReceiver.DetermineReceiver(codec) {
if isAvailable, needsPublish := t.params.WrappedReceiver.DetermineReceiver(codec); !isAvailable || !needsPublish {
return
}
+13 -4
View File
@@ -88,8 +88,13 @@ func (r *WrappedReceiver) StreamID() string {
return r.params.StreamId
}
// DetermineReceiver determines the receiver of negotiated codec and return if there is a match
func (r *WrappedReceiver) DetermineReceiver(codec webrtc.RTPCodecCapability) bool {
// DetermineReceiver determines the receiver of negotiated codec and returns
//
// isAvailable: returns true if given codec is a potential codec from publisher or if an existing published codec can be translated
// needsPublish: indicates if the codec is needed from publisher, some combinations can be achieved via codec translation internally,
//
// example: unecrypted opus -> RED translation and vice-versa can be done without the need for publisher to send the other codec.
func (r *WrappedReceiver) DetermineReceiver(codec webrtc.RTPCodecCapability) (isAvailable bool, needsPublish bool) {
r.lock.Lock()
codecMimeType := mime.NormalizeMimeType(codec.MimeType)
@@ -98,6 +103,8 @@ func (r *WrappedReceiver) DetermineReceiver(codec webrtc.RTPCodecCapability) boo
receiverMimeType := receiver.Mime()
if receiverMimeType == codecMimeType {
trackReceiver = receiver
isAvailable = true
needsPublish = true
break
}
@@ -105,9 +112,11 @@ func (r *WrappedReceiver) DetermineReceiver(codec webrtc.RTPCodecCapability) boo
if receiverMimeType == mime.MimeTypeRED && codecMimeType == mime.MimeTypeOpus {
// audio opus/red can match opus only
trackReceiver = receiver.GetPrimaryReceiverForRed()
isAvailable = true
break
} else if receiverMimeType == mime.MimeTypeOpus && codecMimeType == mime.MimeTypeRED {
trackReceiver = receiver.GetRedReceiver()
isAvailable = true
break
}
}
@@ -115,7 +124,7 @@ func (r *WrappedReceiver) DetermineReceiver(codec webrtc.RTPCodecCapability) boo
if trackReceiver == nil {
r.lock.Unlock()
r.params.Logger.Warnw("can't determine receiver for codec", nil, "codec", codec.MimeType)
return false
return
}
r.TrackReceiver = trackReceiver
@@ -127,7 +136,7 @@ func (r *WrappedReceiver) DetermineReceiver(codec webrtc.RTPCodecCapability) boo
trackReceiver.AddOnReady(f)
}
return true
return
}
func (r *WrappedReceiver) Codecs() []webrtc.RTPCodecParameters {