diff --git a/AUTHORS b/AUTHORS index 064e12611d..971987d9e3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -122,6 +122,7 @@ Satender Saroha Saul Kravitz Sergio Garcia Murillo Shaofan Qi +Shigemasa Watanabe Shuhai Peng Seija Silviu Caragea diff --git a/pc/rtp_sender.h b/pc/rtp_sender.h index 6c654ca65f..d8a4d8281a 100644 --- a/pc/rtp_sender.h +++ b/pc/rtp_sender.h @@ -105,6 +105,7 @@ class RtpSenderInternal : public RtpSenderInterface { // Used by the owning transceiver to inform the sender on the currently // selected codecs. virtual void SetSendCodecs(std::vector send_codecs) = 0; + virtual std::vector GetSendCodecs() const = 0; }; // Shared implementation for RtpSenderInternal interface. @@ -225,6 +226,9 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface { void SetSendCodecs(std::vector send_codecs) override { send_codecs_ = send_codecs; } + std::vector GetSendCodecs() const override { + return send_codecs_; + } protected: // If `set_streams_observer` is not null, it is invoked when SetStreams() diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc index 9d49296b67..5386fafabe 100644 --- a/pc/sdp_offer_answer.cc +++ b/pc/sdp_offer_answer.cc @@ -794,7 +794,17 @@ cricket::MediaDescriptionOptions GetMediaDescriptionOptionsForTransceiver( if (encoding.rid.empty()) { continue; } - send_rids.push_back(RidDescription(encoding.rid, RidDirection::kSend)); + auto send_rid = RidDescription(encoding.rid, RidDirection::kSend); + if (encoding.codec) { + auto send_codecs = transceiver->sender_internal()->GetSendCodecs(); + for (const cricket::Codec& codec : send_codecs) { + if (codec.MatchesRtpCodec(*encoding.codec)) { + send_rid.payload_types.push_back(codec.id); + break; + } + } + } + send_rids.push_back(send_rid); send_layers.AddLayer(SimulcastLayer(encoding.rid, !encoding.active)); } diff --git a/pc/sdp_offer_answer_unittest.cc b/pc/sdp_offer_answer_unittest.cc index 1ee5215947..3cbda98c14 100644 --- a/pc/sdp_offer_answer_unittest.cc +++ b/pc/sdp_offer_answer_unittest.cc @@ -41,7 +41,9 @@ #include "rtc_base/rtc_certificate_generator.h" #include "rtc_base/thread.h" #include "system_wrappers/include/metrics.h" +#include "test/gmock.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" // This file contains unit tests that relate to the behavior of the // SdpOfferAnswer module. @@ -87,7 +89,9 @@ class SdpOfferAnswerTest : public ::testing::Test { OpenH264DecoderTemplateAdapter, Dav1dDecoderTemplateAdapter>>(), nullptr /* audio_mixer */, - nullptr /* audio_processing */)) { + nullptr /* audio_processing */, + nullptr /* audio_frame_processor */, + std::make_unique(field_trials_, ""))) { metrics::Reset(); } @@ -108,7 +112,21 @@ class SdpOfferAnswerTest : public ::testing::Test { pc_factory_, result.MoveValue(), std::move(observer)); } + std::optional FindFirstSendCodecWithName( + cricket::MediaType media_type, + const std::string& name) const { + std::vector codecs = + pc_factory_->GetRtpSenderCapabilities(media_type).codecs; + for (const auto& codec : codecs) { + if (absl::EqualsIgnoreCase(codec.name, name)) { + return codec; + } + } + return std::nullopt; + } + protected: + test::ScopedKeyValueConfig field_trials_; std::unique_ptr signaling_thread_; rtc::scoped_refptr pc_factory_; @@ -610,6 +628,51 @@ TEST_F(SdpOfferAnswerTest, SimulcastAnswerWithNoRidsIsRejected) { EXPECT_TRUE(pc->SetRemoteDescription(std::move(rejected_answer))); } +TEST_F(SdpOfferAnswerTest, SimulcastOfferWithMixedCodec) { + test::ScopedKeyValueConfig field_trials( + field_trials_, "WebRTC-MixedCodecSimulcast/Enabled/"); + + auto pc = CreatePeerConnection(); + + std::optional vp8_codec = FindFirstSendCodecWithName( + cricket::MEDIA_TYPE_VIDEO, cricket::kVp8CodecName); + ASSERT_TRUE(vp8_codec); + std::optional vp9_codec = FindFirstSendCodecWithName( + cricket::MEDIA_TYPE_VIDEO, cricket::kVp9CodecName); + ASSERT_TRUE(vp9_codec); + + RtpTransceiverInit init; + RtpEncodingParameters rid1; + rid1.rid = "1"; + rid1.codec = *vp8_codec; + init.send_encodings.push_back(rid1); + RtpEncodingParameters rid2; + rid2.rid = "2"; + rid2.codec = *vp9_codec; + init.send_encodings.push_back(rid2); + + auto transceiver = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init); + auto offer = pc->CreateOffer(); + auto& offer_contents = offer->description()->contents(); + auto send_codecs = offer_contents[0].media_description()->codecs(); + // Verify that the serialized SDP includes pt=. + std::string sdp; + offer->ToString(&sdp); + EXPECT_THAT(sdp, testing::HasSubstr("a=rid:1 send pt=" + + std::to_string(send_codecs[0].id))); + EXPECT_THAT(sdp, testing::HasSubstr("a=rid:2 send pt=" + + std::to_string(send_codecs[1].id))); + // Verify that SDP containing pt= can be parsed correctly. + auto offer2 = CreateSessionDescription(SdpType::kOffer, sdp); + auto& offer_contents2 = offer2->description()->contents(); + auto send_rids2 = offer_contents2[0].media_description()->streams()[0].rids(); + auto send_codecs2 = offer_contents2[0].media_description()->codecs(); + EXPECT_EQ(send_rids2[0].payload_types.size(), 1u); + EXPECT_EQ(send_rids2[0].payload_types[0], send_codecs2[0].id); + EXPECT_EQ(send_rids2[1].payload_types.size(), 1u); + EXPECT_EQ(send_rids2[1].payload_types[0], send_codecs2[1].id); +} + TEST_F(SdpOfferAnswerTest, ExpectAllSsrcsSpecifiedInSsrcGroupFid) { auto pc = CreatePeerConnection(); std::string sdp = diff --git a/pc/test/mock_rtp_sender_internal.h b/pc/test/mock_rtp_sender_internal.h index 925e9ec910..a8ef817ed5 100644 --- a/pc/test/mock_rtp_sender_internal.h +++ b/pc/test/mock_rtp_sender_internal.h @@ -69,6 +69,10 @@ class MockRtpSenderInternal : public RtpSenderInternal { (const RtpParameters&), (override)); MOCK_METHOD(void, SetSendCodecs, (std::vector), (override)); + MOCK_METHOD(std::vector, + GetSendCodecs, + (), + (const, override)); MOCK_METHOD(rtc::scoped_refptr, GetDtmfSender, (),