xref: /aosp_15_r20/external/webrtc/pc/peer_connection_field_trial_tests.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 // This file contains tests that verify that field trials do what they're
12 // supposed to do.
13 
14 #include <set>
15 
16 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
17 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
18 #include "api/create_peerconnection_factory.h"
19 #include "api/peer_connection_interface.h"
20 #include "api/stats/rtcstats_objects.h"
21 #include "api/task_queue/default_task_queue_factory.h"
22 #include "api/video_codecs/builtin_video_decoder_factory.h"
23 #include "api/video_codecs/builtin_video_encoder_factory.h"
24 #include "media/engine/webrtc_media_engine.h"
25 #include "media/engine/webrtc_media_engine_defaults.h"
26 #include "pc/peer_connection_wrapper.h"
27 #include "pc/session_description.h"
28 #include "pc/test/fake_audio_capture_module.h"
29 #include "pc/test/frame_generator_capturer_video_track_source.h"
30 #include "pc/test/peer_connection_test_wrapper.h"
31 #include "rtc_base/gunit.h"
32 #include "rtc_base/internal/default_socket_server.h"
33 #include "rtc_base/physical_socket_server.h"
34 #include "rtc_base/thread.h"
35 #include "test/gtest.h"
36 #include "test/scoped_key_value_config.h"
37 
38 #ifdef WEBRTC_ANDROID
39 #include "pc/test/android_test_initializer.h"
40 #endif
41 
42 namespace webrtc {
43 
44 namespace {
45 static const int kDefaultTimeoutMs = 5000;
46 
AddIceCandidates(PeerConnectionWrapper * peer,std::vector<const IceCandidateInterface * > candidates)47 bool AddIceCandidates(PeerConnectionWrapper* peer,
48                       std::vector<const IceCandidateInterface*> candidates) {
49   for (const auto candidate : candidates) {
50     if (!peer->pc()->AddIceCandidate(candidate)) {
51       return false;
52     }
53   }
54   return true;
55 }
56 }  // namespace
57 
58 using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
59 
60 class PeerConnectionFieldTrialTest : public ::testing::Test {
61  protected:
62   typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
63 
PeerConnectionFieldTrialTest()64   PeerConnectionFieldTrialTest()
65       : clock_(Clock::GetRealTimeClock()),
66         socket_server_(rtc::CreateDefaultSocketServer()),
67         main_thread_(socket_server_.get()) {
68 #ifdef WEBRTC_ANDROID
69     InitializeAndroidObjects();
70 #endif
71     webrtc::PeerConnectionInterface::IceServer ice_server;
72     ice_server.uri = "stun:stun.l.google.com:19302";
73     config_.servers.push_back(ice_server);
74     config_.sdp_semantics = SdpSemantics::kUnifiedPlan;
75   }
76 
TearDown()77   void TearDown() override { pc_factory_ = nullptr; }
78 
CreatePCFactory(std::unique_ptr<FieldTrialsView> field_trials)79   void CreatePCFactory(std::unique_ptr<FieldTrialsView> field_trials) {
80     PeerConnectionFactoryDependencies pcf_deps;
81     pcf_deps.signaling_thread = rtc::Thread::Current();
82     pcf_deps.trials = std::move(field_trials);
83     pcf_deps.task_queue_factory = CreateDefaultTaskQueueFactory();
84     pcf_deps.call_factory = webrtc::CreateCallFactory();
85     cricket::MediaEngineDependencies media_deps;
86     media_deps.task_queue_factory = pcf_deps.task_queue_factory.get();
87     media_deps.adm = FakeAudioCaptureModule::Create();
88     media_deps.trials = pcf_deps.trials.get();
89     webrtc::SetMediaEngineDefaults(&media_deps);
90     pcf_deps.media_engine = cricket::CreateMediaEngine(std::move(media_deps));
91     pc_factory_ = CreateModularPeerConnectionFactory(std::move(pcf_deps));
92 
93     // Allow ADAPTER_TYPE_LOOPBACK to create PeerConnections with loopback in
94     // this test.
95     RTC_DCHECK(pc_factory_);
96     PeerConnectionFactoryInterface::Options options;
97     options.network_ignore_mask = 0;
98     pc_factory_->SetOptions(options);
99   }
100 
CreatePeerConnection()101   WrapperPtr CreatePeerConnection() {
102     auto observer = std::make_unique<MockPeerConnectionObserver>();
103     auto result = pc_factory_->CreatePeerConnectionOrError(
104         config_, PeerConnectionDependencies(observer.get()));
105     RTC_CHECK(result.ok());
106 
107     observer->SetPeerConnectionInterface(result.value().get());
108     return std::make_unique<PeerConnectionWrapper>(
109         pc_factory_, result.MoveValue(), std::move(observer));
110   }
111 
112   Clock* const clock_;
113   std::unique_ptr<rtc::SocketServer> socket_server_;
114   rtc::AutoSocketServerThread main_thread_;
115   rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
116   webrtc::PeerConnectionInterface::RTCConfiguration config_;
117 };
118 
119 // Tests for the dependency descriptor field trial. The dependency descriptor
120 // field trial is implemented in media/engine/webrtc_video_engine.cc.
TEST_F(PeerConnectionFieldTrialTest,EnableDependencyDescriptorAdvertised)121 TEST_F(PeerConnectionFieldTrialTest, EnableDependencyDescriptorAdvertised) {
122   std::unique_ptr<test::ScopedKeyValueConfig> field_trials =
123       std::make_unique<test::ScopedKeyValueConfig>(
124           "WebRTC-DependencyDescriptorAdvertised/Enabled/");
125   CreatePCFactory(std::move(field_trials));
126 
127   WrapperPtr caller = CreatePeerConnection();
128   caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
129 
130   auto offer = caller->CreateOffer();
131   auto contents1 = offer->description()->contents();
132   ASSERT_EQ(1u, contents1.size());
133 
134   const cricket::MediaContentDescription* media_description1 =
135       contents1[0].media_description();
136   EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
137   const cricket::RtpHeaderExtensions& rtp_header_extensions1 =
138       media_description1->rtp_header_extensions();
139 
140   bool found = absl::c_find_if(rtp_header_extensions1,
141                                [](const webrtc::RtpExtension& rtp_extension) {
142                                  return rtp_extension.uri ==
143                                         RtpExtension::kDependencyDescriptorUri;
144                                }) != rtp_header_extensions1.end();
145   EXPECT_TRUE(found);
146 }
147 
148 // Tests that dependency descriptor RTP header extensions can be exchanged
149 // via SDP munging, even if dependency descriptor field trial is disabled.
TEST_F(PeerConnectionFieldTrialTest,InjectDependencyDescriptor)150 TEST_F(PeerConnectionFieldTrialTest, InjectDependencyDescriptor) {
151   std::unique_ptr<test::ScopedKeyValueConfig> field_trials =
152       std::make_unique<test::ScopedKeyValueConfig>(
153           "WebRTC-DependencyDescriptorAdvertised/Disabled/");
154   CreatePCFactory(std::move(field_trials));
155 
156   WrapperPtr caller = CreatePeerConnection();
157   WrapperPtr callee = CreatePeerConnection();
158   caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
159 
160   auto offer = caller->CreateOffer();
161   cricket::ContentInfos& contents1 = offer->description()->contents();
162   ASSERT_EQ(1u, contents1.size());
163 
164   cricket::MediaContentDescription* media_description1 =
165       contents1[0].media_description();
166   EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
167   cricket::RtpHeaderExtensions rtp_header_extensions1 =
168       media_description1->rtp_header_extensions();
169 
170   bool found1 = absl::c_find_if(rtp_header_extensions1,
171                                 [](const webrtc::RtpExtension& rtp_extension) {
172                                   return rtp_extension.uri ==
173                                          RtpExtension::kDependencyDescriptorUri;
174                                 }) != rtp_header_extensions1.end();
175   EXPECT_FALSE(found1);
176 
177   std::set<int> existing_ids;
178   for (const webrtc::RtpExtension& rtp_extension : rtp_header_extensions1) {
179     existing_ids.insert(rtp_extension.id);
180   }
181 
182   // Find the currently unused RTP header extension ID.
183   int insert_id = 1;
184   std::set<int>::const_iterator iter = existing_ids.begin();
185   while (true) {
186     if (iter == existing_ids.end()) {
187       break;
188     }
189     if (*iter != insert_id) {
190       break;
191     }
192     insert_id++;
193     iter++;
194   }
195 
196   rtp_header_extensions1.emplace_back(RtpExtension::kDependencyDescriptorUri,
197                                       insert_id);
198   media_description1->set_rtp_header_extensions(rtp_header_extensions1);
199 
200   caller->SetLocalDescription(offer->Clone());
201 
202   ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
203   auto answer = callee->CreateAnswer();
204 
205   cricket::ContentInfos& contents2 = answer->description()->contents();
206   ASSERT_EQ(1u, contents2.size());
207 
208   cricket::MediaContentDescription* media_description2 =
209       contents2[0].media_description();
210   EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description2->type());
211   cricket::RtpHeaderExtensions rtp_header_extensions2 =
212       media_description2->rtp_header_extensions();
213 
214   bool found2 = absl::c_find_if(rtp_header_extensions2,
215                                 [](const webrtc::RtpExtension& rtp_extension) {
216                                   return rtp_extension.uri ==
217                                          RtpExtension::kDependencyDescriptorUri;
218                                 }) != rtp_header_extensions2.end();
219   EXPECT_TRUE(found2);
220 }
221 
222 // Test that the ability to emulate degraded networks works without crashing.
TEST_F(PeerConnectionFieldTrialTest,ApplyFakeNetworkConfig)223 TEST_F(PeerConnectionFieldTrialTest, ApplyFakeNetworkConfig) {
224   std::unique_ptr<test::ScopedKeyValueConfig> field_trials =
225       std::make_unique<test::ScopedKeyValueConfig>(
226           "WebRTC-FakeNetworkSendConfig/link_capacity_kbps:500/"
227           "WebRTC-FakeNetworkReceiveConfig/loss_percent:1/");
228 
229   CreatePCFactory(std::move(field_trials));
230 
231   WrapperPtr caller = CreatePeerConnection();
232   BitrateSettings bitrate_settings;
233   bitrate_settings.start_bitrate_bps = 1'000'000;
234   bitrate_settings.max_bitrate_bps = 1'000'000;
235   caller->pc()->SetBitrate(bitrate_settings);
236   FrameGeneratorCapturerVideoTrackSource::Config config;
237   auto video_track_source =
238       rtc::make_ref_counted<FrameGeneratorCapturerVideoTrackSource>(
239           config, clock_, /*is_screencast=*/false);
240   caller->AddTrack(
241       pc_factory_->CreateVideoTrack("v", video_track_source.get()));
242   WrapperPtr callee = CreatePeerConnection();
243 
244   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
245   ASSERT_TRUE(
246       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
247 
248   // Do the SDP negotiation, and also exchange ice candidates.
249   ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
250   ASSERT_TRUE_WAIT(
251       caller->signaling_state() == PeerConnectionInterface::kStable,
252       kDefaultTimeoutMs);
253   ASSERT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeoutMs);
254   ASSERT_TRUE_WAIT(callee->IsIceGatheringDone(), kDefaultTimeoutMs);
255 
256   // Connect an ICE candidate pairs.
257   ASSERT_TRUE(
258       AddIceCandidates(callee.get(), caller->observer()->GetAllCandidates()));
259   ASSERT_TRUE(
260       AddIceCandidates(caller.get(), callee->observer()->GetAllCandidates()));
261 
262   // This means that ICE and DTLS are connected.
263   ASSERT_TRUE_WAIT(callee->IsIceConnected(), kDefaultTimeoutMs);
264   ASSERT_TRUE_WAIT(caller->IsIceConnected(), kDefaultTimeoutMs);
265 
266   // Send packets for kDefaultTimeoutMs
267   WAIT(false, kDefaultTimeoutMs);
268 
269   std::vector<const RTCOutboundRTPStreamStats*> outbound_rtp_stats =
270       caller->GetStats()->GetStatsOfType<RTCOutboundRTPStreamStats>();
271   ASSERT_GE(outbound_rtp_stats.size(), 1u);
272   ASSERT_TRUE(outbound_rtp_stats[0]->target_bitrate.is_defined());
273   // Link capacity is limited to 500k, so BWE is expected to be close to 500k.
274   ASSERT_LE(*outbound_rtp_stats[0]->target_bitrate, 500'000 * 1.1);
275 }
276 
277 }  // namespace webrtc
278