diff --git a/pc/rtp_transceiver.cc b/pc/rtp_transceiver.cc index 34d744a3bb..de31b2e36a 100644 --- a/pc/rtp_transceiver.cc +++ b/pc/rtp_transceiver.cc @@ -171,6 +171,35 @@ RtpTransceiver::RtpTransceiver( : media_engine()->voice().send_codecs()); senders_.push_back(sender); receivers_.push_back(receiver); + + // Set default header extensions depending on whether simulcast/SVC is used. + RtpParameters parameters = sender->internal()->GetParametersInternal(); + bool uses_simulcast = parameters.encodings.size() > 1; + bool uses_svc = !parameters.encodings.empty() && + parameters.encodings[0].scalability_mode.has_value() && + parameters.encodings[0].scalability_mode != + ScalabilityModeToString(ScalabilityMode::kL1T1); + if (uses_simulcast || uses_svc) { + // Enable DD and VLA extensions, can be deactivated by the API. + // Skip this if the GFD extension was enabled via field trial + // for backward compability reasons. + bool uses_gfd = + absl::c_find_if( + header_extensions_to_negotiate_, + [](const RtpHeaderExtensionCapability& ext) { + return ext.uri == RtpExtension::kGenericFrameDescriptorUri00 && + ext.direction != webrtc::RtpTransceiverDirection::kStopped; + }) != header_extensions_to_negotiate_.end(); + if (!uses_gfd) { + for (RtpHeaderExtensionCapability& ext : + header_extensions_to_negotiate_) { + if (ext.uri == RtpExtension::kVideoLayersAllocationUri || + ext.uri == RtpExtension::kDependencyDescriptorUri) { + ext.direction = RtpTransceiverDirection::kSendRecv; + } + } + } + } } RtpTransceiver::~RtpTransceiver() { diff --git a/pc/rtp_transceiver_unittest.cc b/pc/rtp_transceiver_unittest.cc index d75e964509..b6dc7b2bb9 100644 --- a/pc/rtp_transceiver_unittest.cc +++ b/pc/rtp_transceiver_unittest.cc @@ -481,6 +481,81 @@ TEST_F(RtpTransceiverTestForHeaderExtensions, RtpTransceiverDirection::kStopped))); } +TEST_F(RtpTransceiverTestForHeaderExtensions, + SimulcastOrSvcEnablesExtensionsByDefault) { + std::vector extensions = { + {RtpExtension::kDependencyDescriptorUri, 1, + RtpTransceiverDirection::kStopped}, + {RtpExtension::kVideoLayersAllocationUri, 2, + RtpTransceiverDirection::kStopped}, + }; + + // Default is stopped. + auto sender = rtc::make_ref_counted(); + auto transceiver = rtc::make_ref_counted( + RtpSenderProxyWithInternal::Create( + rtc::Thread::Current(), sender), + RtpReceiverProxyWithInternal::Create( + rtc::Thread::Current(), rtc::Thread::Current(), receiver_), + context(), extensions, + /* on_negotiation_needed= */ [] {}); + std::vector header_extensions = + transceiver->GetHeaderExtensionsToNegotiate(); + ASSERT_EQ(header_extensions.size(), 2u); + EXPECT_EQ(header_extensions[0].uri, RtpExtension::kDependencyDescriptorUri); + EXPECT_EQ(header_extensions[0].direction, RtpTransceiverDirection::kStopped); + EXPECT_EQ(header_extensions[1].uri, RtpExtension::kVideoLayersAllocationUri); + EXPECT_EQ(header_extensions[1].direction, RtpTransceiverDirection::kStopped); + + // Simulcast, i.e. more than one encoding. + RtpParameters simulcast_parameters; + simulcast_parameters.encodings.resize(2); + auto simulcast_sender = rtc::make_ref_counted(); + EXPECT_CALL(*simulcast_sender, GetParametersInternal()) + .WillRepeatedly(Return(simulcast_parameters)); + auto simulcast_transceiver = rtc::make_ref_counted( + RtpSenderProxyWithInternal::Create( + rtc::Thread::Current(), simulcast_sender), + RtpReceiverProxyWithInternal::Create( + rtc::Thread::Current(), rtc::Thread::Current(), receiver_), + context(), extensions, + /* on_negotiation_needed= */ [] {}); + auto simulcast_extensions = + simulcast_transceiver->GetHeaderExtensionsToNegotiate(); + ASSERT_EQ(simulcast_extensions.size(), 2u); + EXPECT_EQ(simulcast_extensions[0].uri, + RtpExtension::kDependencyDescriptorUri); + EXPECT_EQ(simulcast_extensions[0].direction, + RtpTransceiverDirection::kSendRecv); + EXPECT_EQ(simulcast_extensions[1].uri, + RtpExtension::kVideoLayersAllocationUri); + EXPECT_EQ(simulcast_extensions[1].direction, + RtpTransceiverDirection::kSendRecv); + + // SVC, a single encoding with a scalabilityMode other than L1T1. + webrtc::RtpParameters svc_parameters; + svc_parameters.encodings.resize(1); + svc_parameters.encodings[0].scalability_mode = "L3T3"; + + auto svc_sender = rtc::make_ref_counted(); + EXPECT_CALL(*svc_sender, GetParametersInternal()) + .WillRepeatedly(Return(svc_parameters)); + auto svc_transceiver = rtc::make_ref_counted( + RtpSenderProxyWithInternal::Create( + rtc::Thread::Current(), svc_sender), + RtpReceiverProxyWithInternal::Create( + rtc::Thread::Current(), rtc::Thread::Current(), receiver_), + context(), extensions, + /* on_negotiation_needed= */ [] {}); + std::vector svc_extensions = + svc_transceiver->GetHeaderExtensionsToNegotiate(); + ASSERT_EQ(svc_extensions.size(), 2u); + EXPECT_EQ(svc_extensions[0].uri, RtpExtension::kDependencyDescriptorUri); + EXPECT_EQ(svc_extensions[0].direction, RtpTransceiverDirection::kSendRecv); + EXPECT_EQ(svc_extensions[1].uri, RtpExtension::kVideoLayersAllocationUri); + EXPECT_EQ(svc_extensions[1].direction, RtpTransceiverDirection::kSendRecv); +} + } // namespace } // namespace webrtc