xref: /aosp_15_r20/external/webrtc/pc/peer_connection_adaptation_integrationtest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2020 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 #include <stdint.h>
12 
13 #include <memory>
14 #include <string>
15 
16 #include "absl/types/optional.h"
17 #include "api/adaptation/resource.h"
18 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
19 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
20 #include "api/media_stream_interface.h"
21 #include "api/peer_connection_interface.h"
22 #include "api/rtc_error.h"
23 #include "api/rtp_parameters.h"
24 #include "api/rtp_sender_interface.h"
25 #include "api/scoped_refptr.h"
26 #include "api/video/video_source_interface.h"
27 #include "call/adaptation/test/fake_resource.h"
28 #include "pc/test/fake_periodic_video_source.h"
29 #include "pc/test/fake_periodic_video_track_source.h"
30 #include "pc/test/peer_connection_test_wrapper.h"
31 #include "rtc_base/checks.h"
32 #include "rtc_base/gunit.h"
33 #include "rtc_base/thread.h"
34 #include "rtc_base/time_utils.h"
35 #include "rtc_base/virtual_socket_server.h"
36 #include "test/gtest.h"
37 
38 namespace webrtc {
39 
40 const int64_t kDefaultTimeoutMs = 5000;
41 
42 struct TrackWithPeriodicSource {
43   rtc::scoped_refptr<VideoTrackInterface> track;
44   rtc::scoped_refptr<FakePeriodicVideoTrackSource> periodic_track_source;
45 };
46 
47 // Performs an O/A exchange and waits until the signaling state is stable again.
Negotiate(rtc::scoped_refptr<PeerConnectionTestWrapper> caller,rtc::scoped_refptr<PeerConnectionTestWrapper> callee)48 void Negotiate(rtc::scoped_refptr<PeerConnectionTestWrapper> caller,
49                rtc::scoped_refptr<PeerConnectionTestWrapper> callee) {
50   // Wire up callbacks and listeners such that a full O/A is performed in
51   // response to CreateOffer().
52   PeerConnectionTestWrapper::Connect(caller.get(), callee.get());
53   caller->CreateOffer(PeerConnectionInterface::RTCOfferAnswerOptions());
54   caller->WaitForNegotiation();
55 }
56 
CreateTrackWithPeriodicSource(rtc::scoped_refptr<PeerConnectionFactoryInterface> factory)57 TrackWithPeriodicSource CreateTrackWithPeriodicSource(
58     rtc::scoped_refptr<PeerConnectionFactoryInterface> factory) {
59   FakePeriodicVideoSource::Config periodic_track_source_config;
60   periodic_track_source_config.frame_interval_ms = 100;
61   periodic_track_source_config.timestamp_offset_ms = rtc::TimeMillis();
62   rtc::scoped_refptr<FakePeriodicVideoTrackSource> periodic_track_source =
63       rtc::make_ref_counted<FakePeriodicVideoTrackSource>(
64           periodic_track_source_config, /* remote */ false);
65   TrackWithPeriodicSource track_with_source;
66   track_with_source.track =
67       factory->CreateVideoTrack("PeriodicTrack", periodic_track_source.get());
68   track_with_source.periodic_track_source = periodic_track_source;
69   return track_with_source;
70 }
71 
72 // Triggers overuse and obtains VideoSinkWants. Adaptation processing happens in
73 // parallel and this function makes no guarantee that the returnd VideoSinkWants
74 // have yet to reflect the overuse signal. Used together with EXPECT_TRUE_WAIT
75 // to "spam overuse until a change is observed".
TriggerOveruseAndGetSinkWants(rtc::scoped_refptr<FakeResource> fake_resource,const FakePeriodicVideoSource & source)76 rtc::VideoSinkWants TriggerOveruseAndGetSinkWants(
77     rtc::scoped_refptr<FakeResource> fake_resource,
78     const FakePeriodicVideoSource& source) {
79   fake_resource->SetUsageState(ResourceUsageState::kOveruse);
80   return source.wants();
81 }
82 
83 class PeerConnectionAdaptationIntegrationTest : public ::testing::Test {
84  public:
PeerConnectionAdaptationIntegrationTest()85   PeerConnectionAdaptationIntegrationTest()
86       : virtual_socket_server_(),
87         network_thread_(new rtc::Thread(&virtual_socket_server_)),
88         worker_thread_(rtc::Thread::Create()) {
89     RTC_CHECK(network_thread_->Start());
90     RTC_CHECK(worker_thread_->Start());
91   }
92 
CreatePcWrapper(const char * name)93   rtc::scoped_refptr<PeerConnectionTestWrapper> CreatePcWrapper(
94       const char* name) {
95     rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper =
96         rtc::make_ref_counted<PeerConnectionTestWrapper>(
97             name, &virtual_socket_server_, network_thread_.get(),
98             worker_thread_.get());
99     PeerConnectionInterface::RTCConfiguration config;
100     config.sdp_semantics = SdpSemantics::kUnifiedPlan;
101     EXPECT_TRUE(pc_wrapper->CreatePc(config, CreateBuiltinAudioEncoderFactory(),
102                                      CreateBuiltinAudioDecoderFactory()));
103     return pc_wrapper;
104   }
105 
106  protected:
107   rtc::VirtualSocketServer virtual_socket_server_;
108   std::unique_ptr<rtc::Thread> network_thread_;
109   std::unique_ptr<rtc::Thread> worker_thread_;
110 };
111 
TEST_F(PeerConnectionAdaptationIntegrationTest,ResouceInjectedAfterNegotiationCausesReductionInResolution)112 TEST_F(PeerConnectionAdaptationIntegrationTest,
113        ResouceInjectedAfterNegotiationCausesReductionInResolution) {
114   auto caller_wrapper = CreatePcWrapper("caller");
115   auto caller = caller_wrapper->pc();
116   auto callee_wrapper = CreatePcWrapper("callee");
117 
118   // Adding a track and negotiating ensures that a VideoSendStream exists.
119   TrackWithPeriodicSource track_with_source =
120       CreateTrackWithPeriodicSource(caller_wrapper->pc_factory());
121   auto sender = caller->AddTrack(track_with_source.track, {}).value();
122   Negotiate(caller_wrapper, callee_wrapper);
123   // Prefer degrading resolution.
124   auto parameters = sender->GetParameters();
125   parameters.degradation_preference = DegradationPreference::MAINTAIN_FRAMERATE;
126   sender->SetParameters(parameters);
127 
128   const auto& source =
129       track_with_source.periodic_track_source->fake_periodic_source();
130   int pixel_count_before_overuse = source.wants().max_pixel_count;
131 
132   // Inject a fake resource and spam kOveruse until resolution becomes limited.
133   auto fake_resource = FakeResource::Create("FakeResource");
134   caller->AddAdaptationResource(fake_resource);
135   EXPECT_TRUE_WAIT(
136       TriggerOveruseAndGetSinkWants(fake_resource, source).max_pixel_count <
137           pixel_count_before_overuse,
138       kDefaultTimeoutMs);
139 }
140 
TEST_F(PeerConnectionAdaptationIntegrationTest,ResouceInjectedBeforeNegotiationCausesReductionInResolution)141 TEST_F(PeerConnectionAdaptationIntegrationTest,
142        ResouceInjectedBeforeNegotiationCausesReductionInResolution) {
143   auto caller_wrapper = CreatePcWrapper("caller");
144   auto caller = caller_wrapper->pc();
145   auto callee_wrapper = CreatePcWrapper("callee");
146 
147   // Inject a fake resource before adding any tracks or negotiating.
148   auto fake_resource = FakeResource::Create("FakeResource");
149   caller->AddAdaptationResource(fake_resource);
150 
151   // Adding a track and negotiating ensures that a VideoSendStream exists.
152   TrackWithPeriodicSource track_with_source =
153       CreateTrackWithPeriodicSource(caller_wrapper->pc_factory());
154   auto sender = caller->AddTrack(track_with_source.track, {}).value();
155   Negotiate(caller_wrapper, callee_wrapper);
156   // Prefer degrading resolution.
157   auto parameters = sender->GetParameters();
158   parameters.degradation_preference = DegradationPreference::MAINTAIN_FRAMERATE;
159   sender->SetParameters(parameters);
160 
161   const auto& source =
162       track_with_source.periodic_track_source->fake_periodic_source();
163   int pixel_count_before_overuse = source.wants().max_pixel_count;
164 
165   // Spam kOveruse until resolution becomes limited.
166   EXPECT_TRUE_WAIT(
167       TriggerOveruseAndGetSinkWants(fake_resource, source).max_pixel_count <
168           pixel_count_before_overuse,
169       kDefaultTimeoutMs);
170 }
171 
172 }  // namespace webrtc
173