diff --git a/mediaengine.go b/mediaengine.go index 920f5c2ec5c..bc87c8b6036 100644 --- a/mediaengine.go +++ b/mediaengine.go @@ -68,6 +68,7 @@ type mediaEngineHeaderExtension struct { type MediaEngine struct { // If we have attempted to negotiate a codec type yet. negotiatedVideo, negotiatedAudio bool + negotiateMultiCodecs bool videoCodecs, audioCodecs []RTPCodecParameters negotiatedVideoCodecs, negotiatedAudioCodecs []RTPCodecParameters @@ -78,6 +79,22 @@ type MediaEngine struct { mu sync.RWMutex } +// SetMultiCodecNegotiation enables or disables the negotiation of multiple codecs. +func (m *MediaEngine) SetMultiCodecNegotiation(negotiateMultiCodecs bool) { + m.mu.Lock() + defer m.mu.Unlock() + + m.negotiateMultiCodecs = negotiateMultiCodecs +} + +// MultiCodecNegotiation returns the current state of the negotiation of multiple codecs. +func (m *MediaEngine) MultiCodecNegotiation() bool { + m.mu.RLock() + defer m.mu.RUnlock() + + return m.negotiateMultiCodecs +} + // RegisterDefaultCodecs registers the default codecs supported by Pion WebRTC. // RegisterDefaultCodecs is not safe for concurrent use. func (m *MediaEngine) RegisterDefaultCodecs() error { @@ -596,9 +613,9 @@ func (m *MediaEngine) updateFromRemoteDescription(desc sdp.SessionDescription) e } switch { - case !m.negotiatedAudio && typ == RTPCodecTypeAudio: + case (!m.negotiatedAudio || m.negotiateMultiCodecs) && typ == RTPCodecTypeAudio: m.negotiatedAudio = true - case !m.negotiatedVideo && typ == RTPCodecTypeVideo: + case (!m.negotiatedVideo || m.negotiateMultiCodecs) && typ == RTPCodecTypeVideo: m.negotiatedVideo = true default: // update header extesions from remote sdp if codec is negotiated, Firefox diff --git a/mediaengine_test.go b/mediaengine_test.go index 7f0ae392781..64d740c6eb9 100644 --- a/mediaengine_test.go +++ b/mediaengine_test.go @@ -876,3 +876,68 @@ a=rtcp-fb:96 nack runTest(t, true) }) } + +func TestMultiCodecNegotiation(t *testing.T) { + const offerSdp = `v=0 +o=- 781500112831855234 6 IN IP4 127.0.0.1 +s=- +t=0 0 +a=group:BUNDLE 0 1 2 3 +a=extmap-allow-mixed +a=msid-semantic: WMS be0216be-f3d8-40ca-a624-379edf70f1c9 +m=application 53555 UDP/DTLS/SCTP webrtc-datachannel +a=mid:0 +a=sctp-port:5000 +a=max-message-size:262144 +m=video 9 UDP/TLS/RTP/SAVPF 98 +a=mid:1 +a=sendonly +a=msid:be0216be-f3d8-40ca-a624-379edf70f1c9 3d032b3b-ffe5-48ec-b783-21375668d1c3 +a=rtcp-mux +a=rtcp-rsize +a=rtpmap:98 VP9/90000 +a=rtcp-fb:98 goog-remb +a=rtcp-fb:98 transport-cc +a=rtcp-fb:98 ccm fir +a=rtcp-fb:98 nack +a=rtcp-fb:98 nack pli +a=fmtp:98 profile-id=0 +a=rid:q send +a=rid:h send +a=simulcast:send q;h +m=video 9 UDP/TLS/RTP/SAVPF 96 +a=mid:2 +a=sendonly +a=msid:6ff05509-be96-4ef1-a74f-425e14720983 16d5d7fe-d076-4718-9ca9-ec62b4543727 +a=rtcp-mux +a=rtcp-rsize +a=rtpmap:96 VP8/90000 +a=rtcp-fb:96 goog-remb +a=rtcp-fb:96 transport-cc +a=rtcp-fb:96 ccm fir +a=rtcp-fb:96 nack +a=rtcp-fb:96 nack pli +a=ssrc:4281768245 cname:JDM9GNMEg+9To6K7 +a=ssrc:4281768245 msid:6ff05509-be96-4ef1-a74f-425e14720983 16d5d7fe-d076-4718-9ca9-ec62b4543727 +` + mustParse := func(raw string) sdp.SessionDescription { + s := sdp.SessionDescription{} + assert.NoError(t, s.Unmarshal([]byte(raw))) + + return s + } + t.Run("Multi codec negotiation disabled", func(t *testing.T) { + mediaEngine := MediaEngine{} + assert.NoError(t, mediaEngine.RegisterDefaultCodecs()) + assert.NoError(t, mediaEngine.updateFromRemoteDescription(mustParse(offerSdp))) + assert.Len(t, mediaEngine.negotiatedVideoCodecs, 1) + }) + t.Run("Multi codec negotiation enabled", func(t *testing.T) { + mediaEngine := MediaEngine{} + mediaEngine.SetMultiCodecNegotiation(true) + assert.True(t, mediaEngine.MultiCodecNegotiation()) + assert.NoError(t, mediaEngine.RegisterDefaultCodecs()) + assert.NoError(t, mediaEngine.updateFromRemoteDescription(mustParse(offerSdp))) + assert.Len(t, mediaEngine.negotiatedVideoCodecs, 2) + }) +}