From eee2001a319314ddc695da78d2745d6bbe279200 Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Wed, 10 Sep 2025 18:28:36 +0530 Subject: [PATCH] Set publisher codec preferences after setting remote description (#3913) * Set publisher codec preferences after setting remote description Munging SDP prior to setting remote description was becoming problematic in single peer connection mode. In that mode, it is possible that a subscribe track m-section is added which sets the fmtp of H.265 to a value that is different from when that client publishes. That gets locked in as negotiated codecs when pion processes remote description. Later when the client publishes H.265, the H.265 does only partial match. So, if we munge offer and send it to SetRemoteDescription, the H.265 does only a partial match due to different fmtp line and that gets put at the end of the list. So, the answer does not enforce the preferred codec. Changing pion to put partial match up front is more risky given other projects. So, switch codec preferences to after remote description is set and directly operate on transceiver which is a better place to make these changes without munging SDP. This fixes the case of - firefox joins first - Chrome preferring H.265 joining next. This causes a subscribe track m-section (for firefox's tracks) to be created first. So, the preferred codec munging was not working. Works after this change. * clean up * mage generate * test * clean up --- pkg/rtc/participant.go | 35 ++-- pkg/rtc/participant_internal_test.go | 29 ++- pkg/rtc/participant_sdp.go | 194 +++++++----------- pkg/rtc/transport.go | 90 +++++++- pkg/rtc/transport/handler.go | 2 + .../transport/transportfakes/fake_handler.go | 28 +++ pkg/rtc/transport_test.go | 2 +- pkg/rtc/transportmanager.go | 8 + pkg/sfu/downtrack.go | 4 +- 9 files changed, 235 insertions(+), 157 deletions(-) diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index aec54d291..f2866a411 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -1259,22 +1259,6 @@ func (p *ParticipantImpl) HandleOffer(sd *livekit.SessionDescription) error { } } - unmatchAudios, unmatchVideos := p.populateSdpCid(parsedOffer) - parsedOffer = p.setCodecPreferencesForPublisher(parsedOffer, unmatchAudios, unmatchVideos) - p.updateRidsFromSDP(parsedOffer, unmatchVideos) - - // put together munged offer after setting codec preferences - bytes, err := parsedOffer.Marshal() - if err != nil { - lgr.Errorw("failed to marshal offer", err, "parsedOffer", parsedOffer) - return err - } - - offer = webrtc.SessionDescription{ - Type: offer.Type, - SDP: string(bytes), - } - err = p.TransportManager.HandleOffer(offer, offerId, p.MigrateState() == types.MigrateStateInit) if err != nil { lgr.Warnw("could not handle offer", err, "mungedOffer", offer) @@ -1291,6 +1275,21 @@ func (p *ParticipantImpl) HandleOffer(sd *livekit.SessionDescription) error { return nil } +func (p *ParticipantImpl) onPublisherSetRemoteDescription() { + offer := p.TransportManager.LastPublisherOfferPending() + parsedOffer, err := offer.Unmarshal() + if err != nil { + p.pubLogger.Warnw("could not parse offer", err) + return + } + + // set publish codec preferences after remote description is set + // and required transceivers are created + unmatchAudios, unmatchVideos := p.populateSdpCid(parsedOffer) + p.setCodecPreferencesForPublisher(parsedOffer, unmatchAudios, unmatchVideos) + p.updateRidsFromSDP(parsedOffer, unmatchVideos) +} + func (p *ParticipantImpl) onPublisherAnswer(answer webrtc.SessionDescription, answerId uint32) error { if p.IsClosed() || p.IsDisconnected() { return nil @@ -1921,6 +1920,10 @@ type PublisherTransportHandler struct { AnyTransportHandler } +func (h PublisherTransportHandler) OnSetRemoteDescriptionOffer() { + h.p.onPublisherSetRemoteDescription() +} + func (h PublisherTransportHandler) OnAnswer(sd webrtc.SessionDescription, answerId uint32) error { return h.p.onPublisherAnswer(sd, answerId) } diff --git a/pkg/rtc/participant_internal_test.go b/pkg/rtc/participant_internal_test.go index ea1201777..7bf05045e 100644 --- a/pkg/rtc/participant_internal_test.go +++ b/pkg/rtc/participant_internal_test.go @@ -625,8 +625,12 @@ func TestPreferAudioCodecForRed(t *testing.T) { participant.SetMigrateState(types.MigrateStateComplete) me := webrtc.MediaEngine{} - me.RegisterDefaultCodecs() - require.NoError(t, me.RegisterCodec(RedCodecParameters, webrtc.RTPCodecTypeAudio)) + opusCodecParameters := OpusCodecParameters + opusCodecParameters.RTPCodecCapability.RTCPFeedback = []webrtc.RTCPFeedback{{Type: webrtc.TypeRTCPFBNACK}} + require.NoError(t, me.RegisterCodec(opusCodecParameters, webrtc.RTPCodecTypeAudio)) + redCodecParameters := RedCodecParameters + redCodecParameters.RTPCodecCapability.RTCPFeedback = []webrtc.RTCPFeedback{{Type: webrtc.TypeRTCPFBNACK}} + require.NoError(t, me.RegisterCodec(redCodecParameters, webrtc.RTPCodecTypeAudio)) api := webrtc.NewAPI(webrtc.WithMediaEngine(&me)) pc, err := api.NewPeerConnection(webrtc.Configuration{}) @@ -641,9 +645,17 @@ func TestPreferAudioCodecForRed(t *testing.T) { DisableRed: disableRed, Cid: trackCid, }) - track, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: "audio/opus"}, trackCid, trackCid) + track, err := webrtc.NewTrackLocalStaticRTP( + webrtc.RTPCodecCapability{MimeType: "audio/opus"}, + trackCid, + trackCid, + ) require.NoError(t, err) - transceiver, err := pc.AddTransceiverFromTrack(track, webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionSendrecv}) + + transceiver, err := pc.AddTransceiverFromTrack( + track, + webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionSendrecv}, + ) require.NoError(t, err) codecs := transceiver.Sender().GetParameters().Codecs for i, c := range codecs { @@ -683,7 +695,14 @@ func TestPreferAudioCodecForRed(t *testing.T) { Id: offerId, }) - require.Eventually(t, func() bool { return answerReceived.Load() && answerIdReceived.Load() == offerId }, 5*time.Second, 10*time.Millisecond) + require.Eventually( + t, + func() bool { + return answerReceived.Load() && answerIdReceived.Load() == offerId + }, + 5*time.Second, + 10*time.Millisecond, + ) var redPreferred bool parsed, err := answer.Unmarshal() diff --git a/pkg/rtc/participant_sdp.go b/pkg/rtc/participant_sdp.go index 0904b78c1..8dd5a4725 100644 --- a/pkg/rtc/participant_sdp.go +++ b/pkg/rtc/participant_sdp.go @@ -163,7 +163,7 @@ func (p *ParticipantImpl) populateSdpCid(parsedOffer *sdp.SessionDescription) ([ unmatchVideos, err := p.TransportManager.GetUnmatchMediaForOffer(parsedOffer, "video") if err != nil { - p.pubLogger.Warnw("could not get unmatch audios", err) + p.pubLogger.Warnw("could not get unmatch videos", err) return nil, nil } @@ -176,108 +176,41 @@ func (p *ParticipantImpl) setCodecPreferencesForPublisher( parsedOffer *sdp.SessionDescription, unmatchAudios []*sdp.MediaDescription, unmatchVideos []*sdp.MediaDescription, -) *sdp.SessionDescription { - parsedOffer, unprocessedUnmatchAudios := p.setCodecPreferencesForPublisherMedia( +) { + unprocessedUnmatchAudios := p.setCodecPreferencesForPublisherMedia( parsedOffer, unmatchAudios, livekit.TrackType_AUDIO, ) - parsedOffer = p.setCodecPreferencesOpusRedForPublisher(parsedOffer, unprocessedUnmatchAudios) - parsedOffer, _ = p.setCodecPreferencesForPublisherMedia( + p.setCodecPreferencesOpusRedForPublisher(parsedOffer, unprocessedUnmatchAudios) + _ = p.setCodecPreferencesForPublisherMedia( parsedOffer, unmatchVideos, livekit.TrackType_VIDEO, ) - return parsedOffer -} - -func (p *ParticipantImpl) setCodecPreferencesOpusRedForPublisher( - parsedOffer *sdp.SessionDescription, - unmatchAudios []*sdp.MediaDescription, -) *sdp.SessionDescription { - for _, unmatchAudio := range unmatchAudios { - streamID, ok := lksdp.ExtractStreamID(unmatchAudio) - if !ok { - continue - } - - p.pendingTracksLock.RLock() - _, ti, _, _, _ := p.getPendingTrack(streamID, livekit.TrackType_AUDIO, false) - p.pendingTracksLock.RUnlock() - if ti == nil { - continue - } - - codecs, err := lksdp.CodecsFromMediaDescription(unmatchAudio) - if err != nil { - p.pubLogger.Errorw( - "extract codecs from media section failed", err, - "media", unmatchAudio, - "parsedOffer", parsedOffer, - ) - continue - } - - var opusPayload uint8 - for _, codec := range codecs { - if mime.IsMimeTypeCodecStringOpus(codec.Name) { - opusPayload = codec.PayloadType - break - } - } - if opusPayload == 0 { - continue - } - - // if RED is disabled for this track, don't prefer RED codec in offer - var preferredCodecs, leftCodecs []string - for _, codec := range codecs { - // codec contain opus/red - if !ti.DisableRed && mime.IsMimeTypeCodecStringRED(codec.Name) && strings.Contains(codec.Fmtp, strconv.FormatInt(int64(opusPayload), 10)) { - preferredCodecs = append(preferredCodecs, strconv.FormatInt(int64(codec.PayloadType), 10)) - } else { - leftCodecs = append(leftCodecs, strconv.FormatInt(int64(codec.PayloadType), 10)) - } - } - - // ensure nack enabled for audio in publisher offer - var nackFound bool - for _, attr := range unmatchAudio.Attributes { - if attr.Key == "rtcp-fb" && strings.Contains(attr.Value, fmt.Sprintf("%d nack", opusPayload)) { - nackFound = true - break - } - } - if !nackFound { - unmatchAudio.Attributes = append(unmatchAudio.Attributes, sdp.Attribute{ - Key: "rtcp-fb", - Value: fmt.Sprintf("%d nack", opusPayload), - }) - } - - // no opus/red found - if len(preferredCodecs) == 0 { - continue - } - - unmatchAudio.MediaName.Formats = append(unmatchAudio.MediaName.Formats[:0], preferredCodecs...) - unmatchAudio.MediaName.Formats = append(unmatchAudio.MediaName.Formats, leftCodecs...) - } - - return parsedOffer } func (p *ParticipantImpl) setCodecPreferencesForPublisherMedia( parsedOffer *sdp.SessionDescription, unmatches []*sdp.MediaDescription, trackType livekit.TrackType, -) (*sdp.SessionDescription, []*sdp.MediaDescription) { +) []*sdp.MediaDescription { unprocessed := make([]*sdp.MediaDescription, 0, len(unmatches)) - // unmatched media is pending for publish, set codec preference for _, unmatch := range unmatches { var ti *livekit.TrackInfo var mimeType string + mid := lksdp.GetMidValue(unmatch) + if mid == "" { + unprocessed = append(unprocessed, unmatch) + continue + } + transceiver := p.TransportManager.GetPublisherRTPTransceiver(mid) + if transceiver == nil { + unprocessed = append(unprocessed, unmatch) + continue + } + streamID, ok := lksdp.ExtractStreamID(unmatch) if !ok { unprocessed = append(unprocessed, unmatch) @@ -313,61 +246,74 @@ func (p *ParticipantImpl) setCodecPreferencesForPublisherMedia( continue } - codecs, err := lksdp.CodecsFromMediaDescription(unmatch) + configureReceiverCodecs( + transceiver, + mimeType, + p.params.ClientInfo.ComplyWithCodecOrderInSDPAnswer(), + ) + } + + return unprocessed +} + +func (p *ParticipantImpl) setCodecPreferencesOpusRedForPublisher( + parsedOffer *sdp.SessionDescription, + unmatchAudios []*sdp.MediaDescription, +) { + for _, unmatchAudio := range unmatchAudios { + mid := lksdp.GetMidValue(unmatchAudio) + if mid == "" { + continue + } + transceiver := p.TransportManager.GetPublisherRTPTransceiver(mid) + if transceiver == nil { + continue + } + + streamID, ok := lksdp.ExtractStreamID(unmatchAudio) + if !ok { + continue + } + + p.pendingTracksLock.RLock() + _, ti, _, _, _ := p.getPendingTrack(streamID, livekit.TrackType_AUDIO, false) + p.pendingTracksLock.RUnlock() + if ti == nil { + continue + } + + codecs, err := lksdp.CodecsFromMediaDescription(unmatchAudio) if err != nil { p.pubLogger.Errorw( "extract codecs from media section failed", err, - "media", unmatch, + "media", unmatchAudio, "parsedOffer", parsedOffer, ) - unprocessed = append(unprocessed, unmatch) continue } - var codecIdx int - var preferredCodecs, leftCodecs []string - for idx, c := range codecs { - if mime.GetMimeTypeCodec(mimeType) == mime.NormalizeMimeTypeCodec(c.Name) { - preferredCodecs = append(preferredCodecs, strconv.FormatInt(int64(c.PayloadType), 10)) - codecIdx = idx - } else { - leftCodecs = append(leftCodecs, strconv.FormatInt(int64(c.PayloadType), 10)) + var opusPayload uint8 + for _, codec := range codecs { + if mime.IsMimeTypeCodecStringOpus(codec.Name) { + opusPayload = codec.PayloadType + break } } - - // could not find preferred mime in the offer - if len(preferredCodecs) == 0 { - unprocessed = append(unprocessed, unmatch) + if opusPayload == 0 { continue } - unmatch.MediaName.Formats = append(unmatch.MediaName.Formats[:0], preferredCodecs...) - if trackType == livekit.TrackType_VIDEO { - // if the client don't comply with codec order in SDP answer, only keep preferred codecs to force client to use it - if p.params.ClientInfo.ComplyWithCodecOrderInSDPAnswer() { - unmatch.MediaName.Formats = append(unmatch.MediaName.Formats, leftCodecs...) + // if RED is disabled for this track, don't prefer RED codec in offer + for _, codec := range codecs { + // codec contain opus/red + if !ti.DisableRed && + mime.IsMimeTypeCodecStringRED(codec.Name) && + strings.Contains(codec.Fmtp, strconv.FormatInt(int64(opusPayload), 10)) { + configureReceiverCodecs(transceiver, "audio/red", true) + break } - } else { - // ensure nack enabled for audio in publisher offer - var nackFound bool - for _, attr := range unmatch.Attributes { - if attr.Key == "rtcp-fb" && strings.Contains(attr.Value, fmt.Sprintf("%d nack", codecs[codecIdx].PayloadType)) { - nackFound = true - break - } - } - if !nackFound { - unmatch.Attributes = append(unmatch.Attributes, sdp.Attribute{ - Key: "rtcp-fb", - Value: fmt.Sprintf("%d nack", codecs[codecIdx].PayloadType), - }) - } - - unmatch.MediaName.Formats = append(unmatch.MediaName.Formats, leftCodecs...) } } - - return parsedOffer, unprocessed } // configure publisher answer for audio track's dtx and stereo settings @@ -419,7 +365,7 @@ func (p *ParticipantImpl) configurePublisherAnswer(answer webrtc.SessionDescript } } - if ti == nil || (ti.DisableDtx && !ti.Stereo) { + if ti == nil || (ti.DisableDtx && !slices.Contains(ti.AudioFeatures, livekit.AudioTrackFeature_TF_STEREO)) { // no need to configure continue } diff --git a/pkg/rtc/transport.go b/pkg/rtc/transport.go index 43c32d09a..e593d01a9 100644 --- a/pkg/rtc/transport.go +++ b/pkg/rtc/transport.go @@ -956,9 +956,9 @@ func (t *PCTransport) AddTrack( return } - configureTransceiverCodecs(transceiver, enabledCodecs, rtcpFeedbackConfig, !t.params.IsOfferer) + configureSenderCodecs(transceiver, enabledCodecs, rtcpFeedbackConfig, !t.params.IsOfferer) if trackLocal.Kind() == webrtc.RTPCodecTypeAudio { - configureAudioTransceiver(transceiver, params.Stereo, !params.Red || !t.params.ClientInfo.SupportsAudioRED()) + configureSenderAudio(transceiver, params.Stereo, !params.Red || !t.params.ClientInfo.SupportsAudioRED()) } t.adjustNumOutstandingMedia(transceiver) return @@ -981,9 +981,9 @@ func (t *PCTransport) AddTransceiverFromTrack( return } - configureTransceiverCodecs(transceiver, enabledCodecs, rtcpFeedbackConfig, !t.params.IsOfferer) + configureSenderCodecs(transceiver, enabledCodecs, rtcpFeedbackConfig, !t.params.IsOfferer) if trackLocal.Kind() == webrtc.RTPCodecTypeAudio { - configureAudioTransceiver(transceiver, params.Stereo, !params.Red || !t.params.ClientInfo.SupportsAudioRED()) + configureSenderAudio(transceiver, params.Stereo, !params.Red || !t.params.ClientInfo.SupportsAudioRED()) } t.adjustNumOutstandingMedia(transceiver) return @@ -1020,6 +1020,16 @@ func (t *PCTransport) CurrentRemoteDescription() *webrtc.SessionDescription { return &rd } +func (t *PCTransport) PendingRemoteDescription() *webrtc.SessionDescription { + prd := t.pc.PendingRemoteDescription() + if prd == nil { + return nil + } + + rd := *prd + return &rd +} + func (t *PCTransport) GetMid(rtpReceiver *webrtc.RTPReceiver) string { for _, tr := range t.pc.GetTransceivers() { if tr.Receiver() == rtpReceiver { @@ -1030,6 +1040,16 @@ func (t *PCTransport) GetMid(rtpReceiver *webrtc.RTPReceiver) string { return "" } +func (t *PCTransport) GetRTPTransceiver(mid string) *webrtc.RTPTransceiver { + for _, tr := range t.pc.GetTransceivers() { + if tr.Mid() == mid { + return tr + } + } + + return nil +} + func (t *PCTransport) GetRTPReceiver(mid string) *webrtc.RTPReceiver { for _, tr := range t.pc.GetTransceivers() { if tr.Mid() == mid { @@ -2124,6 +2144,7 @@ func (t *PCTransport) handleICEGatheringCompleteAnswerer() error { if err := t.setRemoteDescription(offer); err != nil { return err } + t.params.Handler.OnSetRemoteDescriptionOffer() return t.createAndSendAnswer() } @@ -2643,6 +2664,8 @@ func (t *PCTransport) handleRemoteOfferReceived(sd *webrtc.SessionDescription, o if err := t.setRemoteDescription(*sd); err != nil { return err } + t.params.Handler.OnSetRemoteDescriptionOffer() + rtxRepairs := nonSimulcastRTXRepairsFromSDP(parsed, t.params.Logger) if len(rtxRepairs) > 0 { t.params.Logger.Debugw("rtx pairs found from sdp", "ssrcs", rtxRepairs) @@ -2805,7 +2828,7 @@ func (t *PCTransport) outputAndClearICEStats() { // configure subscriber transceiver for audio stereo and nack // pion doesn't support per transciver codec configuration, so the nack of this session will be disabled // forever once it is first disabled by a transceiver. -func configureAudioTransceiver(tr *webrtc.RTPTransceiver, stereo bool, nack bool) { +func configureSenderAudio(tr *webrtc.RTPTransceiver, stereo bool, nack bool) { sender := tr.Sender() if sender == nil { return @@ -2834,13 +2857,14 @@ func configureAudioTransceiver(tr *webrtc.RTPTransceiver, stereo bool, nack bool tr.SetCodecPreferences(configCodecs) } -// In single peer connection mode, set up enebled codecs, -// the config provides config of direction, for publisher peer connection, it is publish enabled codecs -// and for subscriber peer connection, it is subscribe enabled codecs. +// In single peer connection mode, set up enebled codecs for sender. +// The config provides config of direction. +// For publisher peer connection those are publish enabled codecs +// and for subscriber peer connection those are subscribe enabled codecs. // // But, in single peer connection mode, if setting up a transceiver where the media is // flowing in the other direction, the other direction codec config needs to be set. -func configureTransceiverCodecs( +func configureSenderCodecs( tr *webrtc.RTPTransceiver, enabledCodecs []*livekit.Codec, rtcpFeedbackConfig RTCPFeedbackConfig, @@ -2864,6 +2888,54 @@ func configureTransceiverCodecs( tr.SetCodecPreferences(filteredCodecs) } +func configureReceiverCodecs( + tr *webrtc.RTPTransceiver, + preferredMimeType string, + compliesWithCodecOrderInSDPAnswer bool, +) { + receiver := tr.Receiver() + if receiver == nil { + return + } + + var preferredCodecs, leftCodecs []webrtc.RTPCodecParameters + for _, c := range receiver.GetParameters().Codecs { + if tr.Kind() == webrtc.RTPCodecTypeAudio { + nackFound := false + for _, fb := range c.RTCPFeedback { + if fb.Type == webrtc.TypeRTCPFBNACK { + nackFound = true + break + } + } + + if !nackFound { + c.RTCPFeedback = append(c.RTCPFeedback, webrtc.RTCPFeedback{Type: webrtc.TypeRTCPFBNACK}) + } + } + + if mime.GetMimeTypeCodec(preferredMimeType) == mime.GetMimeTypeCodec(c.RTPCodecCapability.MimeType) { + preferredCodecs = append(preferredCodecs, c) + } else { + leftCodecs = append(leftCodecs, c) + } + } + if len(preferredCodecs) == 0 { + return + } + + reorderedCodecs := append([]webrtc.RTPCodecParameters{}, preferredCodecs...) + if tr.Kind() == webrtc.RTPCodecTypeVideo { + // if the client don't comply with codec order in SDP answer, only keep preferred codecs to force client to use it + if compliesWithCodecOrderInSDPAnswer { + reorderedCodecs = append(reorderedCodecs, leftCodecs...) + } + } else { + reorderedCodecs = append(reorderedCodecs, leftCodecs...) + } + tr.SetCodecPreferences(reorderedCodecs) +} + func nonSimulcastRTXRepairsFromSDP(s *sdp.SessionDescription, logger logger.Logger) map[uint32]uint32 { rtxRepairFlows := map[uint32]uint32{} for _, media := range s.MediaDescriptions { diff --git a/pkg/rtc/transport/handler.go b/pkg/rtc/transport/handler.go index 72c4cc9b7..8abd0fbb5 100644 --- a/pkg/rtc/transport/handler.go +++ b/pkg/rtc/transport/handler.go @@ -43,6 +43,7 @@ type Handler interface { OnDataMessageUnlabeled(data []byte) OnDataSendError(err error) OnOffer(sd webrtc.SessionDescription, offerId uint32) error + OnSetRemoteDescriptionOffer() OnAnswer(sd webrtc.SessionDescription, answerId uint32) error OnNegotiationStateChanged(state NegotiationState) OnNegotiationFailed() @@ -65,6 +66,7 @@ func (h UnimplementedHandler) OnDataSendError(err error) func (h UnimplementedHandler) OnOffer(sd webrtc.SessionDescription, offerId uint32) error { return ErrNoOfferHandler } +func (h UnimplementedHandler) OnSetRemoteDescriptionOffer() {} func (h UnimplementedHandler) OnAnswer(sd webrtc.SessionDescription, answerId uint32) error { return ErrNoAnswerHandler } diff --git a/pkg/rtc/transport/transportfakes/fake_handler.go b/pkg/rtc/transport/transportfakes/fake_handler.go index 17151a70e..5ac5f381e 100644 --- a/pkg/rtc/transport/transportfakes/fake_handler.go +++ b/pkg/rtc/transport/transportfakes/fake_handler.go @@ -87,6 +87,10 @@ type FakeHandler struct { onOfferReturnsOnCall map[int]struct { result1 error } + OnSetRemoteDescriptionOfferStub func() + onSetRemoteDescriptionOfferMutex sync.RWMutex + onSetRemoteDescriptionOfferArgsForCall []struct { + } OnStreamStateChangeStub func(*streamallocator.StreamStateUpdate) error onStreamStateChangeMutex sync.RWMutex onStreamStateChangeArgsForCall []struct { @@ -550,6 +554,30 @@ func (fake *FakeHandler) OnOfferReturnsOnCall(i int, result1 error) { }{result1} } +func (fake *FakeHandler) OnSetRemoteDescriptionOffer() { + fake.onSetRemoteDescriptionOfferMutex.Lock() + fake.onSetRemoteDescriptionOfferArgsForCall = append(fake.onSetRemoteDescriptionOfferArgsForCall, struct { + }{}) + stub := fake.OnSetRemoteDescriptionOfferStub + fake.recordInvocation("OnSetRemoteDescriptionOffer", []interface{}{}) + fake.onSetRemoteDescriptionOfferMutex.Unlock() + if stub != nil { + fake.OnSetRemoteDescriptionOfferStub() + } +} + +func (fake *FakeHandler) OnSetRemoteDescriptionOfferCallCount() int { + fake.onSetRemoteDescriptionOfferMutex.RLock() + defer fake.onSetRemoteDescriptionOfferMutex.RUnlock() + return len(fake.onSetRemoteDescriptionOfferArgsForCall) +} + +func (fake *FakeHandler) OnSetRemoteDescriptionOfferCalls(stub func()) { + fake.onSetRemoteDescriptionOfferMutex.Lock() + defer fake.onSetRemoteDescriptionOfferMutex.Unlock() + fake.OnSetRemoteDescriptionOfferStub = stub +} + func (fake *FakeHandler) OnStreamStateChange(arg1 *streamallocator.StreamStateUpdate) error { fake.onStreamStateChangeMutex.Lock() ret, specificReturn := fake.onStreamStateChangeReturnsOnCall[len(fake.onStreamStateChangeArgsForCall)] diff --git a/pkg/rtc/transport_test.go b/pkg/rtc/transport_test.go index 0cc9ea56a..1deb43eab 100644 --- a/pkg/rtc/transport_test.go +++ b/pkg/rtc/transport_test.go @@ -617,7 +617,7 @@ func TestConfigureAudioTransceiver(t *testing.T) { tr, err := pc.AddTransceiverFromKind(webrtc.RTPCodecTypeAudio, webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionSendonly}) require.NoError(t, err) - configureAudioTransceiver(tr, testcase.stereo, testcase.nack) + configureSenderAudio(tr, testcase.stereo, testcase.nack) codecs := tr.Sender().GetParameters().Codecs for _, codec := range codecs { if mime.IsMimeTypeStringOpus(codec.MimeType) { diff --git a/pkg/rtc/transportmanager.go b/pkg/rtc/transportmanager.go index 68bcfb63f..367b949e0 100644 --- a/pkg/rtc/transportmanager.go +++ b/pkg/rtc/transportmanager.go @@ -224,6 +224,10 @@ func (t *TransportManager) GetPublisherMid(rtpReceiver *webrtc.RTPReceiver) stri return t.publisher.GetMid(rtpReceiver) } +func (t *TransportManager) GetPublisherRTPTransceiver(mid string) *webrtc.RTPTransceiver { + return t.publisher.GetRTPTransceiver(mid) +} + func (t *TransportManager) GetPublisherRTPReceiver(mid string) *webrtc.RTPReceiver { return t.publisher.GetRTPReceiver(mid) } @@ -451,6 +455,10 @@ func (t *TransportManager) LastPublisherOffer() *webrtc.SessionDescription { return t.publisher.CurrentRemoteDescription() } +func (t *TransportManager) LastPublisherOfferPending() *webrtc.SessionDescription { + return t.publisher.PendingRemoteDescription() +} + func (t *TransportManager) HandleOffer(offer webrtc.SessionDescription, offerId uint32, shouldPend bool) error { t.lock.Lock() if shouldPend { diff --git a/pkg/sfu/downtrack.go b/pkg/sfu/downtrack.go index 19a097907..96cef2b8e 100644 --- a/pkg/sfu/downtrack.go +++ b/pkg/sfu/downtrack.go @@ -542,8 +542,8 @@ func (d *DownTrack) Bind(t webrtc.TrackLocalContext) (webrtc.RTPCodecParameters, d.payloadTypeRTX.Store(uint32(utils.FindRTXPayloadType(codec.PayloadType, d.negotiatedCodecParameters))) logFields = append( logFields, - "payloadType", d.payloadType, - "payloadTypeRTX", d.payloadTypeRTX, + "payloadType", d.payloadType.Load(), + "payloadTypeRTX", d.payloadTypeRTX.Load(), "codecParameters", d.negotiatedCodecParameters, ) d.params.Logger.Debugw("DownTrack.Bind", logFields...)