Add killswitch for receive-only setCodecPreferences change
Adds a killswitch WebRTC-SetCodecPreferences-ReceiveOnlyFilterInsteadOfThrow to accompany the spec-change to throw when codec capabilities are taken from the RtpSender instead of the RtpReceiver. With the killswitch triggered, such codecs will be filtered. BUG=webrtc:15396 Change-Id: I7d27111c72085eb7a7b2a1e66d0a08d12883ce17 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/341460 Reviewed-by: Florent Castelli <orphis@webrtc.org> Commit-Queue: Philipp Hancke <phancke@microsoft.com> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41845}
This commit is contained in:
parent
16ac10d9f7
commit
a5cd6643f6
@ -131,6 +131,9 @@ ACTIVE_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([
|
||||
FieldTrial('WebRTC-SendPacketsOnWorkerThread',
|
||||
'webrtc:14502',
|
||||
date(2024, 4, 1)),
|
||||
FieldTrial('WebRTC-SetCodecPreferences-ReceiveOnlyFilterInsteadOfThrow',
|
||||
'webrtc:15396',
|
||||
date(2024, 12, 1)),
|
||||
FieldTrial('WebRTC-SrtpRemoveReceiveStream',
|
||||
'webrtc:15604',
|
||||
date(2024, 10, 1)),
|
||||
|
||||
@ -176,19 +176,19 @@ class PeerConnectionMediaBaseTest : public ::testing::Test {
|
||||
EnableFakeMedia(factory_dependencies, std::move(media_engine));
|
||||
factory_dependencies.event_log_factory =
|
||||
std::make_unique<RtcEventLogFactory>();
|
||||
|
||||
factory_dependencies.trials = std::move(field_trials_);
|
||||
auto pc_factory =
|
||||
CreateModularPeerConnectionFactory(std::move(factory_dependencies));
|
||||
|
||||
auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
|
||||
rtc::Thread::Current(),
|
||||
std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()),
|
||||
&field_trials_);
|
||||
std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()), nullptr);
|
||||
auto observer = std::make_unique<MockPeerConnectionObserver>();
|
||||
auto modified_config = config;
|
||||
modified_config.sdp_semantics = sdp_semantics_;
|
||||
PeerConnectionDependencies pc_dependencies(observer.get());
|
||||
pc_dependencies.allocator = std::move(fake_port_allocator);
|
||||
|
||||
auto result = pc_factory->CreatePeerConnectionOrError(
|
||||
modified_config, std::move(pc_dependencies));
|
||||
if (!result.ok()) {
|
||||
@ -253,7 +253,7 @@ class PeerConnectionMediaBaseTest : public ::testing::Test {
|
||||
return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
|
||||
}
|
||||
|
||||
test::ScopedKeyValueConfig field_trials_;
|
||||
std::unique_ptr<test::ScopedKeyValueConfig> field_trials_;
|
||||
std::unique_ptr<rtc::VirtualSocketServer> vss_;
|
||||
rtc::AutoSocketServerThread main_;
|
||||
const SdpSemantics sdp_semantics_;
|
||||
@ -1640,6 +1640,25 @@ TEST_F(PeerConnectionMediaTestUnifiedPlan,
|
||||
EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionMediaTestUnifiedPlan,
|
||||
SetCodecPreferencesAudioSendOnlyKillswitch) {
|
||||
field_trials_ = std::make_unique<test::ScopedKeyValueConfig>(
|
||||
"WebRTC-SetCodecPreferences-ReceiveOnlyFilterInsteadOfThrow/Disabled/");
|
||||
auto fake_engine = std::make_unique<FakeMediaEngine>();
|
||||
auto send_codecs = fake_engine->voice().send_codecs();
|
||||
send_codecs.push_back(cricket::CreateAudioCodec(send_codecs.back().id + 1,
|
||||
"send_only_codec", 0, 1));
|
||||
fake_engine->SetAudioSendCodecs(send_codecs);
|
||||
|
||||
auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
|
||||
|
||||
auto transceiver = caller->pc()->GetTransceivers().front();
|
||||
auto send_capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
|
||||
cricket::MediaType::MEDIA_TYPE_AUDIO);
|
||||
|
||||
EXPECT_TRUE(transceiver->SetCodecPreferences(send_capabilities.codecs).ok());
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionMediaTestUnifiedPlan,
|
||||
SetCodecPreferencesVideoRejectsAudioCodec) {
|
||||
auto caller = CreatePeerConnectionWithVideo();
|
||||
@ -1734,6 +1753,25 @@ TEST_F(PeerConnectionMediaTestUnifiedPlan,
|
||||
EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionMediaTestUnifiedPlan,
|
||||
SetCodecPreferencesVideoSendOnlyKillswitch) {
|
||||
field_trials_ = std::make_unique<test::ScopedKeyValueConfig>(
|
||||
"WebRTC-SetCodecPreferences-ReceiveOnlyFilterInsteadOfThrow/Disabled/");
|
||||
auto fake_engine = std::make_unique<FakeMediaEngine>();
|
||||
auto send_codecs = fake_engine->voice().send_codecs();
|
||||
send_codecs.push_back(
|
||||
cricket::CreateVideoCodec(send_codecs.back().id + 1, "send_only_codec"));
|
||||
fake_engine->SetAudioSendCodecs(send_codecs);
|
||||
|
||||
auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
|
||||
|
||||
auto transceiver = caller->pc()->GetTransceivers().front();
|
||||
auto send_capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
|
||||
cricket::MediaType::MEDIA_TYPE_AUDIO);
|
||||
|
||||
EXPECT_TRUE(transceiver->SetCodecPreferences(send_capabilities.codecs).ok());
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionMediaTestUnifiedPlan,
|
||||
SetCodecPreferencesVideoCodecDuplicatesRemoved) {
|
||||
auto caller = CreatePeerConnectionWithVideo();
|
||||
|
||||
@ -40,16 +40,17 @@ namespace webrtc {
|
||||
namespace {
|
||||
|
||||
RTCError VerifyCodecPreferences(
|
||||
const std::vector<RtpCodecCapability>& codecs,
|
||||
const std::vector<cricket::Codec>& recv_codecs) {
|
||||
const std::vector<RtpCodecCapability>& unfiltered_codecs,
|
||||
const std::vector<cricket::Codec>& recv_codecs,
|
||||
const FieldTrialsView& field_trials) {
|
||||
// If the intersection between codecs and
|
||||
// RTCRtpSender.getCapabilities(kind).codecs or the intersection between
|
||||
// codecs and RTCRtpReceiver.getCapabilities(kind).codecs contains only
|
||||
// contains RTX, RED, FEC or CN codecs or is an empty set, throw
|
||||
// RTCRtpReceiver.getCapabilities(kind).codecs only contains RTX, RED, FEC
|
||||
// codecs or Comfort Noise codecs or is an empty set, throw
|
||||
// InvalidModificationError.
|
||||
// This ensures that we always have something to offer, regardless of
|
||||
// transceiver.direction.
|
||||
|
||||
// TODO(fippo): clean up the filtering killswitch
|
||||
std::vector<RtpCodecCapability> codecs = unfiltered_codecs;
|
||||
if (!absl::c_any_of(codecs, [&recv_codecs](const RtpCodecCapability& codec) {
|
||||
return codec.IsMediaCodec() &&
|
||||
absl::c_any_of(recv_codecs,
|
||||
@ -71,10 +72,26 @@ RTCError VerifyCodecPreferences(
|
||||
return codec.MatchesRtpCodec(codec_preference);
|
||||
});
|
||||
if (!is_recv_codec) {
|
||||
if (!field_trials.IsDisabled(
|
||||
"WebRTC-SetCodecPreferences-ReceiveOnlyFilterInsteadOfThrow")) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
std::string("Invalid codec preferences: invalid codec with name \"") +
|
||||
std::string(
|
||||
"Invalid codec preferences: invalid codec with name \"") +
|
||||
codec_preference.name + "\".");
|
||||
} else {
|
||||
// Killswitch behavior: filter out any codec not in receive codecs.
|
||||
codecs.erase(std::remove_if(
|
||||
codecs.begin(), codecs.end(),
|
||||
[&recv_codecs](const RtpCodecCapability& codec) {
|
||||
return codec.IsMediaCodec() &&
|
||||
!absl::c_any_of(
|
||||
recv_codecs,
|
||||
[&codec](const cricket::Codec& recv_codec) {
|
||||
return recv_codec.MatchesRtpCodec(codec);
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -670,7 +687,8 @@ RTCError RtpTransceiver::SetCodecPreferences(
|
||||
} else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
|
||||
recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
|
||||
}
|
||||
result = VerifyCodecPreferences(codecs, recv_codecs);
|
||||
result = VerifyCodecPreferences(codecs, recv_codecs,
|
||||
context()->env().field_trials());
|
||||
|
||||
if (result.ok()) {
|
||||
codec_preferences_ = codecs;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user