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