diff --git a/pc/jsep_transport_controller.cc b/pc/jsep_transport_controller.cc index 4c351a69ef..e36ecafeed 100644 --- a/pc/jsep_transport_controller.cc +++ b/pc/jsep_transport_controller.cc @@ -854,6 +854,7 @@ RTCError JsepTransportController::ValidateContent( if (config_.rtcp_mux_policy == PeerConnectionInterface::kRtcpMuxPolicyRequire && content_info.type == cricket::MediaProtocolType::kRtp && + !content_info.bundle_only && !content_info.media_description()->rtcp_mux()) { return RTCError(RTCErrorType::INVALID_PARAMETER, "The m= section with mid='" + content_info.name + diff --git a/pc/jsep_transport_controller_unittest.cc b/pc/jsep_transport_controller_unittest.cc index 5cb138b8e9..8aecf63c5d 100644 --- a/pc/jsep_transport_controller_unittest.cc +++ b/pc/jsep_transport_controller_unittest.cc @@ -2701,4 +2701,30 @@ TEST_F(JsepTransportControllerTest, RollbackAndAddToDifferentBundleGroup) { EXPECT_EQ(mid2_transport, mid3_transport); } +// Test that a bundle-only offer without rtcp-mux in the bundle-only section +// is accepted. +TEST_F(JsepTransportControllerTest, BundleOnlySectionDoesNotNeedRtcpMux) { + CreateJsepTransportController(JsepTransportController::Config()); + cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE); + bundle_group.AddContentName(kAudioMid1); + bundle_group.AddContentName(kVideoMid1); + + auto offer = std::make_unique(); + AddAudioSection(offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); + AddVideoSection(offer.get(), kVideoMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); + offer->AddGroup(bundle_group); + + // Remove rtcp-mux and set bundle-only on the second content. + offer->contents()[1].media_description()->set_rtcp_mux(false); + offer->contents()[1].bundle_only = true; + + EXPECT_TRUE( + transport_controller_->SetRemoteDescription(SdpType::kOffer, offer.get()) + .ok()); +} + } // namespace webrtc diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index 3f99c96f4d..59d38727dc 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -2570,7 +2570,8 @@ bool PeerConnection::ValidateBundleSettings( const cricket::ContentInfo* content = (&*citer); RTC_DCHECK(content != NULL); auto it = bundle_groups_by_mid.find(content->name); - if (it != bundle_groups_by_mid.end() && !content->rejected && + if (it != bundle_groups_by_mid.end() && + !(content->rejected || content->bundle_only) && content->type == MediaProtocolType::kRtp) { if (!HasRtcpMuxEnabled(content)) return false; diff --git a/pc/peer_connection_jsep_unittest.cc b/pc/peer_connection_jsep_unittest.cc index 851d9257e0..1369253ad6 100644 --- a/pc/peer_connection_jsep_unittest.cc +++ b/pc/peer_connection_jsep_unittest.cc @@ -2405,4 +2405,17 @@ TEST_F(PeerConnectionJsepTest, EXPECT_TRUE(callee->CreateOfferAndSetAsLocal()); } +TEST_F(PeerConnectionJsepTest, BundleOnlySectionDoesNotNeedRtcpMux) { + auto caller = CreatePeerConnection(); + auto callee = CreatePeerConnection(); + caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO); + caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO); + auto offer = caller->CreateOffer(); + // Remove rtcp-mux and set bundle-only on the second content. + offer->description()->contents()[1].media_description()->set_rtcp_mux(false); + offer->description()->contents()[1].bundle_only = true; + + EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer))); +} + } // namespace webrtc