diff --git a/pc/peer_connection_simulcast_unittest.cc b/pc/peer_connection_simulcast_unittest.cc index 3b9d7c89aa..71b36029d3 100644 --- a/pc/peer_connection_simulcast_unittest.cc +++ b/pc/peer_connection_simulcast_unittest.cc @@ -18,6 +18,7 @@ #include #include "absl/algorithm/container.h" +#include "absl/strings/match.h" #include "absl/strings/string_view.h" #include "api/audio/audio_mixer.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" @@ -39,6 +40,7 @@ #include "api/video/video_codec_constants.h" #include "api/video_codecs/builtin_video_decoder_factory.h" #include "api/video_codecs/builtin_video_encoder_factory.h" +#include "media/base/media_constants.h" #include "media/base/rid_description.h" #include "media/base/stream_params.h" #include "modules/audio_device/include/audio_device.h" @@ -72,6 +74,7 @@ using ::testing::Ne; using ::testing::Pair; using ::testing::Property; using ::testing::SizeIs; +using ::testing::StartsWith; using cricket::MediaContentDescription; using cricket::RidDescription; @@ -120,6 +123,24 @@ std::vector CreateLayers(int num_layers, bool active) { } #endif +// RTX, RED and FEC are reliability mechanisms used in combinations with other +// codecs, but are not themselves a specific codec. Typically you don't want to +// filter these out of the list of codec preferences. +bool IsReliabilityMechanism(const webrtc::RtpCodecCapability& codec) { + return absl::EqualsIgnoreCase(codec.name, cricket::kRtxCodecName) || + absl::EqualsIgnoreCase(codec.name, cricket::kRedCodecName) || + absl::EqualsIgnoreCase(codec.name, cricket::kUlpfecCodecName); +} + +std::string GetCurrentCodecMimeType( + rtc::scoped_refptr report, + const webrtc::RTCOutboundRTPStreamStats& outbound_rtp) { + return outbound_rtp.codec_id.is_defined() + ? *report->GetAs(*outbound_rtp.codec_id) + ->mime_type + : ""; +} + } // namespace namespace webrtc { @@ -841,6 +862,28 @@ class PeerConnectionSimulcastWithMediaFlowTests return transceiver_or_error.value(); } + std::vector GetCapabilitiesAndRestrictToCodec( + rtc::scoped_refptr pc_wrapper, + absl::string_view codec_name) { + std::vector codecs = + pc_wrapper->pc_factory() + ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO) + .codecs; + codecs.erase(std::remove_if(codecs.begin(), codecs.end(), + [&codec_name](const RtpCodecCapability& codec) { + return !IsReliabilityMechanism(codec) && + !absl::EqualsIgnoreCase(codec.name, + codec_name); + }), + codecs.end()); + RTC_DCHECK(std::find_if(codecs.begin(), codecs.end(), + [&codec_name](const RtpCodecCapability& codec) { + return absl::EqualsIgnoreCase(codec.name, + codec_name); + }) != codecs.end()); + return codecs; + } + void ExchangeIceCandidates( rtc::scoped_refptr local_pc_wrapper, rtc::scoped_refptr remote_pc_wrapper) { @@ -886,6 +929,14 @@ class PeerConnectionSimulcastWithMediaFlowTests EXPECT_TRUE(Await({p1, p2})); } + rtc::scoped_refptr GetStats( + rtc::scoped_refptr pc_wrapper) { + auto callback = rtc::make_ref_counted(); + pc_wrapper->pc()->GetStats(callback.get()); + EXPECT_TRUE_WAIT(callback->called(), kDefaultTimeout.ms()); + return callback->report(); + } + bool HasOutboundRtpBytesSent( rtc::scoped_refptr pc_wrapper, size_t num_layers) { @@ -956,14 +1007,6 @@ class PeerConnectionSimulcastWithMediaFlowTests return true; } - rtc::scoped_refptr GetStats( - rtc::scoped_refptr pc_wrapper) { - auto callback = rtc::make_ref_counted(); - pc_wrapper->pc()->GetStats(callback.get()); - EXPECT_TRUE_WAIT(callback->called(), kDefaultTimeout.ms()); - return callback->report(); - } - rtc::PhysicalSocketServer pss_; std::unique_ptr background_thread_; }; @@ -971,14 +1014,18 @@ class PeerConnectionSimulcastWithMediaFlowTests // TODO(https://crbug.com/webrtc/14884): When VP9 simulast is supported, use // SetCodecPreferences() and pass a test like this with VP9. TEST_F(PeerConnectionSimulcastWithMediaFlowTests, - SimulcastSendsAllLayersWithDefaultCodec) { + SimulcastSendsAllLayersWithVP8) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); std::vector layers = CreateLayers({"f", "h", "q"}, true); - AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper, - layers); + rtc::scoped_refptr transceiver = + AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper, + layers); + std::vector codecs = + GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP8"); + transceiver->SetCodecPreferences(codecs); NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers); local_pc_wrapper->WaitForConnection(); @@ -987,6 +1034,20 @@ TEST_F(PeerConnectionSimulcastWithMediaFlowTests, // Wait until media is flowing on all three layers. EXPECT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 3u), kLongTimeoutForRampingUp.ms()); + // Verify codec and scalability mode. + rtc::scoped_refptr report = GetStats(local_pc_wrapper); + std::vector outbound_rtps = + report->GetStatsOfType(); + ASSERT_EQ(outbound_rtps.size(), 3u); + EXPECT_TRUE(absl::EqualsIgnoreCase( + GetCurrentCodecMimeType(report, *outbound_rtps[0]), "video/VP8")); + EXPECT_TRUE(absl::EqualsIgnoreCase( + GetCurrentCodecMimeType(report, *outbound_rtps[1]), "video/VP8")); + EXPECT_TRUE(absl::EqualsIgnoreCase( + GetCurrentCodecMimeType(report, *outbound_rtps[2]), "video/VP8")); + EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StartsWith("L1T")); + EXPECT_THAT(*outbound_rtps[1]->scalability_mode, StartsWith("L1T")); + EXPECT_THAT(*outbound_rtps[2]->scalability_mode, StartsWith("L1T")); } } // namespace webrtc