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