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
This commit is contained in:
Raja Subramanian
2025-09-10 18:28:36 +05:30
committed by GitHub
parent fc995533e1
commit eee2001a31
9 changed files with 235 additions and 157 deletions
+19 -16
View File
@@ -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)
}
+24 -5
View File
@@ -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()
+70 -124
View File
@@ -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
}
+81 -9
View File
@@ -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 {
+2
View File
@@ -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
}
@@ -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)]
+1 -1
View File
@@ -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) {
+8
View File
@@ -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 {
+2 -2
View File
@@ -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...)