1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2015 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 "call/rtp_video_sender.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <atomic>
14*d9f75844SAndroid Build Coastguard Worker #include <memory>
15*d9f75844SAndroid Build Coastguard Worker #include <string>
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker
18*d9f75844SAndroid Build Coastguard Worker #include "absl/functional/any_invocable.h"
19*d9f75844SAndroid Build Coastguard Worker #include "call/rtp_transport_controller_send.h"
20*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
21*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/byte_io.h"
22*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
23*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
24*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_packet.h"
25*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/fec_controller_default.h"
26*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/include/video_codec_interface.h"
27*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/rate_limiter.h"
28*d9f75844SAndroid Build Coastguard Worker #include "test/gmock.h"
29*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
30*d9f75844SAndroid Build Coastguard Worker #include "test/mock_frame_transformer.h"
31*d9f75844SAndroid Build Coastguard Worker #include "test/mock_transport.h"
32*d9f75844SAndroid Build Coastguard Worker #include "test/scenario/scenario.h"
33*d9f75844SAndroid Build Coastguard Worker #include "test/scoped_key_value_config.h"
34*d9f75844SAndroid Build Coastguard Worker #include "test/time_controller/simulated_time_controller.h"
35*d9f75844SAndroid Build Coastguard Worker #include "video/send_delay_stats.h"
36*d9f75844SAndroid Build Coastguard Worker #include "video/send_statistics_proxy.h"
37*d9f75844SAndroid Build Coastguard Worker
38*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
39*d9f75844SAndroid Build Coastguard Worker namespace {
40*d9f75844SAndroid Build Coastguard Worker
41*d9f75844SAndroid Build Coastguard Worker using ::testing::_;
42*d9f75844SAndroid Build Coastguard Worker using ::testing::NiceMock;
43*d9f75844SAndroid Build Coastguard Worker using ::testing::SaveArg;
44*d9f75844SAndroid Build Coastguard Worker using ::testing::SizeIs;
45*d9f75844SAndroid Build Coastguard Worker
46*d9f75844SAndroid Build Coastguard Worker const int8_t kPayloadType = 96;
47*d9f75844SAndroid Build Coastguard Worker const uint32_t kSsrc1 = 12345;
48*d9f75844SAndroid Build Coastguard Worker const uint32_t kSsrc2 = 23456;
49*d9f75844SAndroid Build Coastguard Worker const uint32_t kRtxSsrc1 = 34567;
50*d9f75844SAndroid Build Coastguard Worker const uint32_t kRtxSsrc2 = 45678;
51*d9f75844SAndroid Build Coastguard Worker const int16_t kInitialPictureId1 = 222;
52*d9f75844SAndroid Build Coastguard Worker const int16_t kInitialPictureId2 = 44;
53*d9f75844SAndroid Build Coastguard Worker const int16_t kInitialTl0PicIdx1 = 99;
54*d9f75844SAndroid Build Coastguard Worker const int16_t kInitialTl0PicIdx2 = 199;
55*d9f75844SAndroid Build Coastguard Worker const int64_t kRetransmitWindowSizeMs = 500;
56*d9f75844SAndroid Build Coastguard Worker const int kTransportsSequenceExtensionId = 7;
57*d9f75844SAndroid Build Coastguard Worker const int kDependencyDescriptorExtensionId = 8;
58*d9f75844SAndroid Build Coastguard Worker
59*d9f75844SAndroid Build Coastguard Worker class MockRtcpIntraFrameObserver : public RtcpIntraFrameObserver {
60*d9f75844SAndroid Build Coastguard Worker public:
61*d9f75844SAndroid Build Coastguard Worker MOCK_METHOD(void, OnReceivedIntraFrameRequest, (uint32_t), (override));
62*d9f75844SAndroid Build Coastguard Worker };
63*d9f75844SAndroid Build Coastguard Worker
CreateObservers(RtcpRttStats * rtcp_rtt_stats,RtcpIntraFrameObserver * intra_frame_callback,ReportBlockDataObserver * report_block_data_observer,StreamDataCountersCallback * rtp_stats,BitrateStatisticsObserver * bitrate_observer,FrameCountObserver * frame_count_observer,RtcpPacketTypeCounterObserver * rtcp_type_observer,SendSideDelayObserver * send_delay_observer,SendPacketObserver * send_packet_observer)64*d9f75844SAndroid Build Coastguard Worker RtpSenderObservers CreateObservers(
65*d9f75844SAndroid Build Coastguard Worker RtcpRttStats* rtcp_rtt_stats,
66*d9f75844SAndroid Build Coastguard Worker RtcpIntraFrameObserver* intra_frame_callback,
67*d9f75844SAndroid Build Coastguard Worker ReportBlockDataObserver* report_block_data_observer,
68*d9f75844SAndroid Build Coastguard Worker StreamDataCountersCallback* rtp_stats,
69*d9f75844SAndroid Build Coastguard Worker BitrateStatisticsObserver* bitrate_observer,
70*d9f75844SAndroid Build Coastguard Worker FrameCountObserver* frame_count_observer,
71*d9f75844SAndroid Build Coastguard Worker RtcpPacketTypeCounterObserver* rtcp_type_observer,
72*d9f75844SAndroid Build Coastguard Worker SendSideDelayObserver* send_delay_observer,
73*d9f75844SAndroid Build Coastguard Worker SendPacketObserver* send_packet_observer) {
74*d9f75844SAndroid Build Coastguard Worker RtpSenderObservers observers;
75*d9f75844SAndroid Build Coastguard Worker observers.rtcp_rtt_stats = rtcp_rtt_stats;
76*d9f75844SAndroid Build Coastguard Worker observers.intra_frame_callback = intra_frame_callback;
77*d9f75844SAndroid Build Coastguard Worker observers.rtcp_loss_notification_observer = nullptr;
78*d9f75844SAndroid Build Coastguard Worker observers.report_block_data_observer = report_block_data_observer;
79*d9f75844SAndroid Build Coastguard Worker observers.rtp_stats = rtp_stats;
80*d9f75844SAndroid Build Coastguard Worker observers.bitrate_observer = bitrate_observer;
81*d9f75844SAndroid Build Coastguard Worker observers.frame_count_observer = frame_count_observer;
82*d9f75844SAndroid Build Coastguard Worker observers.rtcp_type_observer = rtcp_type_observer;
83*d9f75844SAndroid Build Coastguard Worker observers.send_delay_observer = send_delay_observer;
84*d9f75844SAndroid Build Coastguard Worker observers.send_packet_observer = send_packet_observer;
85*d9f75844SAndroid Build Coastguard Worker return observers;
86*d9f75844SAndroid Build Coastguard Worker }
87*d9f75844SAndroid Build Coastguard Worker
GetBitrateConfig()88*d9f75844SAndroid Build Coastguard Worker BitrateConstraints GetBitrateConfig() {
89*d9f75844SAndroid Build Coastguard Worker BitrateConstraints bitrate_config;
90*d9f75844SAndroid Build Coastguard Worker bitrate_config.min_bitrate_bps = 30000;
91*d9f75844SAndroid Build Coastguard Worker bitrate_config.start_bitrate_bps = 300000;
92*d9f75844SAndroid Build Coastguard Worker bitrate_config.max_bitrate_bps = 3000000;
93*d9f75844SAndroid Build Coastguard Worker return bitrate_config;
94*d9f75844SAndroid Build Coastguard Worker }
95*d9f75844SAndroid Build Coastguard Worker
CreateVideoSendStreamConfig(Transport * transport,const std::vector<uint32_t> & ssrcs,const std::vector<uint32_t> & rtx_ssrcs,int payload_type)96*d9f75844SAndroid Build Coastguard Worker VideoSendStream::Config CreateVideoSendStreamConfig(
97*d9f75844SAndroid Build Coastguard Worker Transport* transport,
98*d9f75844SAndroid Build Coastguard Worker const std::vector<uint32_t>& ssrcs,
99*d9f75844SAndroid Build Coastguard Worker const std::vector<uint32_t>& rtx_ssrcs,
100*d9f75844SAndroid Build Coastguard Worker int payload_type) {
101*d9f75844SAndroid Build Coastguard Worker VideoSendStream::Config config(transport);
102*d9f75844SAndroid Build Coastguard Worker config.rtp.ssrcs = ssrcs;
103*d9f75844SAndroid Build Coastguard Worker config.rtp.rtx.ssrcs = rtx_ssrcs;
104*d9f75844SAndroid Build Coastguard Worker config.rtp.payload_type = payload_type;
105*d9f75844SAndroid Build Coastguard Worker config.rtp.rtx.payload_type = payload_type + 1;
106*d9f75844SAndroid Build Coastguard Worker config.rtp.nack.rtp_history_ms = 1000;
107*d9f75844SAndroid Build Coastguard Worker config.rtp.extensions.emplace_back(RtpExtension::kTransportSequenceNumberUri,
108*d9f75844SAndroid Build Coastguard Worker kTransportsSequenceExtensionId);
109*d9f75844SAndroid Build Coastguard Worker config.rtp.extensions.emplace_back(RtpDependencyDescriptorExtension::Uri(),
110*d9f75844SAndroid Build Coastguard Worker kDependencyDescriptorExtensionId);
111*d9f75844SAndroid Build Coastguard Worker config.rtp.extmap_allow_mixed = true;
112*d9f75844SAndroid Build Coastguard Worker return config;
113*d9f75844SAndroid Build Coastguard Worker }
114*d9f75844SAndroid Build Coastguard Worker
115*d9f75844SAndroid Build Coastguard Worker class RtpVideoSenderTestFixture {
116*d9f75844SAndroid Build Coastguard Worker public:
RtpVideoSenderTestFixture(const std::vector<uint32_t> & ssrcs,const std::vector<uint32_t> & rtx_ssrcs,int payload_type,const std::map<uint32_t,RtpPayloadState> & suspended_payload_states,FrameCountObserver * frame_count_observer,rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,const FieldTrialsView * field_trials=nullptr)117*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture(
118*d9f75844SAndroid Build Coastguard Worker const std::vector<uint32_t>& ssrcs,
119*d9f75844SAndroid Build Coastguard Worker const std::vector<uint32_t>& rtx_ssrcs,
120*d9f75844SAndroid Build Coastguard Worker int payload_type,
121*d9f75844SAndroid Build Coastguard Worker const std::map<uint32_t, RtpPayloadState>& suspended_payload_states,
122*d9f75844SAndroid Build Coastguard Worker FrameCountObserver* frame_count_observer,
123*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
124*d9f75844SAndroid Build Coastguard Worker const FieldTrialsView* field_trials = nullptr)
125*d9f75844SAndroid Build Coastguard Worker : time_controller_(Timestamp::Millis(1000000)),
126*d9f75844SAndroid Build Coastguard Worker config_(CreateVideoSendStreamConfig(&transport_,
127*d9f75844SAndroid Build Coastguard Worker ssrcs,
128*d9f75844SAndroid Build Coastguard Worker rtx_ssrcs,
129*d9f75844SAndroid Build Coastguard Worker payload_type)),
130*d9f75844SAndroid Build Coastguard Worker send_delay_stats_(time_controller_.GetClock()),
131*d9f75844SAndroid Build Coastguard Worker bitrate_config_(GetBitrateConfig()),
132*d9f75844SAndroid Build Coastguard Worker transport_controller_(
133*d9f75844SAndroid Build Coastguard Worker time_controller_.GetClock(),
134*d9f75844SAndroid Build Coastguard Worker RtpTransportConfig{
135*d9f75844SAndroid Build Coastguard Worker .bitrate_config = bitrate_config_,
136*d9f75844SAndroid Build Coastguard Worker .event_log = &event_log_,
137*d9f75844SAndroid Build Coastguard Worker .task_queue_factory = time_controller_.GetTaskQueueFactory(),
138*d9f75844SAndroid Build Coastguard Worker .trials = field_trials ? field_trials : &field_trials_,
139*d9f75844SAndroid Build Coastguard Worker }),
140*d9f75844SAndroid Build Coastguard Worker stats_proxy_(time_controller_.GetClock(),
141*d9f75844SAndroid Build Coastguard Worker config_,
142*d9f75844SAndroid Build Coastguard Worker VideoEncoderConfig::ContentType::kRealtimeVideo,
143*d9f75844SAndroid Build Coastguard Worker field_trials ? *field_trials : field_trials_),
144*d9f75844SAndroid Build Coastguard Worker retransmission_rate_limiter_(time_controller_.GetClock(),
145*d9f75844SAndroid Build Coastguard Worker kRetransmitWindowSizeMs) {
146*d9f75844SAndroid Build Coastguard Worker transport_controller_.EnsureStarted();
147*d9f75844SAndroid Build Coastguard Worker std::map<uint32_t, RtpState> suspended_ssrcs;
148*d9f75844SAndroid Build Coastguard Worker router_ = std::make_unique<RtpVideoSender>(
149*d9f75844SAndroid Build Coastguard Worker time_controller_.GetClock(), suspended_ssrcs, suspended_payload_states,
150*d9f75844SAndroid Build Coastguard Worker config_.rtp, config_.rtcp_report_interval_ms, &transport_,
151*d9f75844SAndroid Build Coastguard Worker CreateObservers(nullptr, &encoder_feedback_, &stats_proxy_,
152*d9f75844SAndroid Build Coastguard Worker &stats_proxy_, &stats_proxy_, frame_count_observer,
153*d9f75844SAndroid Build Coastguard Worker &stats_proxy_, &stats_proxy_, &send_delay_stats_),
154*d9f75844SAndroid Build Coastguard Worker &transport_controller_, &event_log_, &retransmission_rate_limiter_,
155*d9f75844SAndroid Build Coastguard Worker std::make_unique<FecControllerDefault>(time_controller_.GetClock()),
156*d9f75844SAndroid Build Coastguard Worker nullptr, CryptoOptions{}, frame_transformer,
157*d9f75844SAndroid Build Coastguard Worker field_trials ? *field_trials : field_trials_,
158*d9f75844SAndroid Build Coastguard Worker time_controller_.GetTaskQueueFactory());
159*d9f75844SAndroid Build Coastguard Worker }
160*d9f75844SAndroid Build Coastguard Worker
RtpVideoSenderTestFixture(const std::vector<uint32_t> & ssrcs,const std::vector<uint32_t> & rtx_ssrcs,int payload_type,const std::map<uint32_t,RtpPayloadState> & suspended_payload_states,FrameCountObserver * frame_count_observer,const FieldTrialsView * field_trials=nullptr)161*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture(
162*d9f75844SAndroid Build Coastguard Worker const std::vector<uint32_t>& ssrcs,
163*d9f75844SAndroid Build Coastguard Worker const std::vector<uint32_t>& rtx_ssrcs,
164*d9f75844SAndroid Build Coastguard Worker int payload_type,
165*d9f75844SAndroid Build Coastguard Worker const std::map<uint32_t, RtpPayloadState>& suspended_payload_states,
166*d9f75844SAndroid Build Coastguard Worker FrameCountObserver* frame_count_observer,
167*d9f75844SAndroid Build Coastguard Worker const FieldTrialsView* field_trials = nullptr)
168*d9f75844SAndroid Build Coastguard Worker : RtpVideoSenderTestFixture(ssrcs,
169*d9f75844SAndroid Build Coastguard Worker rtx_ssrcs,
170*d9f75844SAndroid Build Coastguard Worker payload_type,
171*d9f75844SAndroid Build Coastguard Worker suspended_payload_states,
172*d9f75844SAndroid Build Coastguard Worker frame_count_observer,
173*d9f75844SAndroid Build Coastguard Worker /*frame_transformer=*/nullptr,
174*d9f75844SAndroid Build Coastguard Worker field_trials) {}
175*d9f75844SAndroid Build Coastguard Worker
RtpVideoSenderTestFixture(const std::vector<uint32_t> & ssrcs,const std::vector<uint32_t> & rtx_ssrcs,int payload_type,const std::map<uint32_t,RtpPayloadState> & suspended_payload_states,const FieldTrialsView * field_trials=nullptr)176*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture(
177*d9f75844SAndroid Build Coastguard Worker const std::vector<uint32_t>& ssrcs,
178*d9f75844SAndroid Build Coastguard Worker const std::vector<uint32_t>& rtx_ssrcs,
179*d9f75844SAndroid Build Coastguard Worker int payload_type,
180*d9f75844SAndroid Build Coastguard Worker const std::map<uint32_t, RtpPayloadState>& suspended_payload_states,
181*d9f75844SAndroid Build Coastguard Worker const FieldTrialsView* field_trials = nullptr)
182*d9f75844SAndroid Build Coastguard Worker : RtpVideoSenderTestFixture(ssrcs,
183*d9f75844SAndroid Build Coastguard Worker rtx_ssrcs,
184*d9f75844SAndroid Build Coastguard Worker payload_type,
185*d9f75844SAndroid Build Coastguard Worker suspended_payload_states,
186*d9f75844SAndroid Build Coastguard Worker /*frame_count_observer=*/nullptr,
187*d9f75844SAndroid Build Coastguard Worker /*frame_transformer=*/nullptr,
188*d9f75844SAndroid Build Coastguard Worker field_trials) {}
189*d9f75844SAndroid Build Coastguard Worker
~RtpVideoSenderTestFixture()190*d9f75844SAndroid Build Coastguard Worker ~RtpVideoSenderTestFixture() { Stop(); }
191*d9f75844SAndroid Build Coastguard Worker
router()192*d9f75844SAndroid Build Coastguard Worker RtpVideoSender* router() { return router_.get(); }
transport()193*d9f75844SAndroid Build Coastguard Worker MockTransport& transport() { return transport_; }
AdvanceTime(TimeDelta delta)194*d9f75844SAndroid Build Coastguard Worker void AdvanceTime(TimeDelta delta) { time_controller_.AdvanceTime(delta); }
195*d9f75844SAndroid Build Coastguard Worker
Stop()196*d9f75844SAndroid Build Coastguard Worker void Stop() {
197*d9f75844SAndroid Build Coastguard Worker RunOnTransportQueue([&]() { router_->Stop(); });
198*d9f75844SAndroid Build Coastguard Worker }
199*d9f75844SAndroid Build Coastguard Worker
SetActiveModules(const std::vector<bool> & active_modules)200*d9f75844SAndroid Build Coastguard Worker void SetActiveModules(const std::vector<bool>& active_modules) {
201*d9f75844SAndroid Build Coastguard Worker RunOnTransportQueue([&]() { router_->SetActiveModules(active_modules); });
202*d9f75844SAndroid Build Coastguard Worker }
203*d9f75844SAndroid Build Coastguard Worker
204*d9f75844SAndroid Build Coastguard Worker // Several RtpVideoSender methods expect to be called on the task queue as
205*d9f75844SAndroid Build Coastguard Worker // owned by the send transport. While the SequenceChecker may pick up the
206*d9f75844SAndroid Build Coastguard Worker // default thread as the transport queue, explicit checks for the transport
207*d9f75844SAndroid Build Coastguard Worker // queue (not just using a SequenceChecker) aren't possible unless such a
208*d9f75844SAndroid Build Coastguard Worker // queue is actually active. So RunOnTransportQueue is a convenience function
209*d9f75844SAndroid Build Coastguard Worker // that allow for running a `task` on the transport queue, similar to
210*d9f75844SAndroid Build Coastguard Worker // SendTask().
RunOnTransportQueue(absl::AnyInvocable<void ()&&> task)211*d9f75844SAndroid Build Coastguard Worker void RunOnTransportQueue(absl::AnyInvocable<void() &&> task) {
212*d9f75844SAndroid Build Coastguard Worker transport_controller_.GetWorkerQueue()->RunOrPost(std::move(task));
213*d9f75844SAndroid Build Coastguard Worker AdvanceTime(TimeDelta::Zero());
214*d9f75844SAndroid Build Coastguard Worker }
215*d9f75844SAndroid Build Coastguard Worker
216*d9f75844SAndroid Build Coastguard Worker private:
217*d9f75844SAndroid Build Coastguard Worker test::ScopedKeyValueConfig field_trials_;
218*d9f75844SAndroid Build Coastguard Worker NiceMock<MockTransport> transport_;
219*d9f75844SAndroid Build Coastguard Worker NiceMock<MockRtcpIntraFrameObserver> encoder_feedback_;
220*d9f75844SAndroid Build Coastguard Worker GlobalSimulatedTimeController time_controller_;
221*d9f75844SAndroid Build Coastguard Worker RtcEventLogNull event_log_;
222*d9f75844SAndroid Build Coastguard Worker VideoSendStream::Config config_;
223*d9f75844SAndroid Build Coastguard Worker SendDelayStats send_delay_stats_;
224*d9f75844SAndroid Build Coastguard Worker BitrateConstraints bitrate_config_;
225*d9f75844SAndroid Build Coastguard Worker RtpTransportControllerSend transport_controller_;
226*d9f75844SAndroid Build Coastguard Worker SendStatisticsProxy stats_proxy_;
227*d9f75844SAndroid Build Coastguard Worker RateLimiter retransmission_rate_limiter_;
228*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<RtpVideoSender> router_;
229*d9f75844SAndroid Build Coastguard Worker };
230*d9f75844SAndroid Build Coastguard Worker
CreateBitrateAllocationUpdate(int target_bitrate_bps)231*d9f75844SAndroid Build Coastguard Worker BitrateAllocationUpdate CreateBitrateAllocationUpdate(int target_bitrate_bps) {
232*d9f75844SAndroid Build Coastguard Worker BitrateAllocationUpdate update;
233*d9f75844SAndroid Build Coastguard Worker update.target_bitrate = DataRate::BitsPerSec(target_bitrate_bps);
234*d9f75844SAndroid Build Coastguard Worker update.round_trip_time = TimeDelta::Zero();
235*d9f75844SAndroid Build Coastguard Worker return update;
236*d9f75844SAndroid Build Coastguard Worker }
237*d9f75844SAndroid Build Coastguard Worker
238*d9f75844SAndroid Build Coastguard Worker } // namespace
239*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,SendOnOneModule)240*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, SendOnOneModule) {
241*d9f75844SAndroid Build Coastguard Worker constexpr uint8_t kPayload = 'a';
242*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image;
243*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(1);
244*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 2;
245*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
246*d9f75844SAndroid Build Coastguard Worker encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
247*d9f75844SAndroid Build Coastguard Worker
248*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {});
249*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(EncodedImageCallback::Result::OK,
250*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image, nullptr).error);
251*d9f75844SAndroid Build Coastguard Worker
252*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
253*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
254*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image, nullptr).error);
255*d9f75844SAndroid Build Coastguard Worker
256*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({false});
257*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(EncodedImageCallback::Result::OK,
258*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image, nullptr).error);
259*d9f75844SAndroid Build Coastguard Worker
260*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
261*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
262*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image, nullptr).error);
263*d9f75844SAndroid Build Coastguard Worker }
264*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,SendSimulcastSetActive)265*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, SendSimulcastSetActive) {
266*d9f75844SAndroid Build Coastguard Worker constexpr uint8_t kPayload = 'a';
267*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image_1;
268*d9f75844SAndroid Build Coastguard Worker encoded_image_1.SetTimestamp(1);
269*d9f75844SAndroid Build Coastguard Worker encoded_image_1.capture_time_ms_ = 2;
270*d9f75844SAndroid Build Coastguard Worker encoded_image_1._frameType = VideoFrameType::kVideoFrameKey;
271*d9f75844SAndroid Build Coastguard Worker encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
272*d9f75844SAndroid Build Coastguard Worker
273*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
274*d9f75844SAndroid Build Coastguard Worker kPayloadType, {});
275*d9f75844SAndroid Build Coastguard Worker
276*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo codec_info;
277*d9f75844SAndroid Build Coastguard Worker codec_info.codecType = kVideoCodecVP8;
278*d9f75844SAndroid Build Coastguard Worker
279*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true, true});
280*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
281*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
282*d9f75844SAndroid Build Coastguard Worker
283*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image_2(encoded_image_1);
284*d9f75844SAndroid Build Coastguard Worker encoded_image_2.SetSpatialIndex(1);
285*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
286*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_2, &codec_info).error);
287*d9f75844SAndroid Build Coastguard Worker
288*d9f75844SAndroid Build Coastguard Worker // Inactive.
289*d9f75844SAndroid Build Coastguard Worker test.Stop();
290*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(EncodedImageCallback::Result::OK,
291*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
292*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(EncodedImageCallback::Result::OK,
293*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_2, &codec_info).error);
294*d9f75844SAndroid Build Coastguard Worker }
295*d9f75844SAndroid Build Coastguard Worker
296*d9f75844SAndroid Build Coastguard Worker // Tests how setting individual rtp modules to active affects the overall
297*d9f75844SAndroid Build Coastguard Worker // behavior of the payload router. First sets one module to active and checks
298*d9f75844SAndroid Build Coastguard Worker // that outgoing data can be sent on this module, and checks that no data can
299*d9f75844SAndroid Build Coastguard Worker // be sent if both modules are inactive.
TEST(RtpVideoSenderTest,SendSimulcastSetActiveModules)300*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, SendSimulcastSetActiveModules) {
301*d9f75844SAndroid Build Coastguard Worker constexpr uint8_t kPayload = 'a';
302*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image_1;
303*d9f75844SAndroid Build Coastguard Worker encoded_image_1.SetTimestamp(1);
304*d9f75844SAndroid Build Coastguard Worker encoded_image_1.capture_time_ms_ = 2;
305*d9f75844SAndroid Build Coastguard Worker encoded_image_1._frameType = VideoFrameType::kVideoFrameKey;
306*d9f75844SAndroid Build Coastguard Worker encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
307*d9f75844SAndroid Build Coastguard Worker
308*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image_2(encoded_image_1);
309*d9f75844SAndroid Build Coastguard Worker encoded_image_2.SetSpatialIndex(1);
310*d9f75844SAndroid Build Coastguard Worker
311*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
312*d9f75844SAndroid Build Coastguard Worker kPayloadType, {});
313*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo codec_info;
314*d9f75844SAndroid Build Coastguard Worker codec_info.codecType = kVideoCodecVP8;
315*d9f75844SAndroid Build Coastguard Worker
316*d9f75844SAndroid Build Coastguard Worker // Only setting one stream to active will still set the payload router to
317*d9f75844SAndroid Build Coastguard Worker // active and allow sending data on the active stream.
318*d9f75844SAndroid Build Coastguard Worker std::vector<bool> active_modules({true, false});
319*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules(active_modules);
320*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
321*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
322*d9f75844SAndroid Build Coastguard Worker
323*d9f75844SAndroid Build Coastguard Worker // Setting both streams to inactive will turn the payload router to
324*d9f75844SAndroid Build Coastguard Worker // inactive.
325*d9f75844SAndroid Build Coastguard Worker active_modules = {false, false};
326*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules(active_modules);
327*d9f75844SAndroid Build Coastguard Worker // An incoming encoded image will not ask the module to send outgoing data
328*d9f75844SAndroid Build Coastguard Worker // because the payload router is inactive.
329*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(EncodedImageCallback::Result::OK,
330*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
331*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(EncodedImageCallback::Result::OK,
332*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
333*d9f75844SAndroid Build Coastguard Worker }
334*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,DiscardsHigherSpatialVideoFramesAfterLayerDisabledInVideoLayersAllocation)335*d9f75844SAndroid Build Coastguard Worker TEST(
336*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTest,
337*d9f75844SAndroid Build Coastguard Worker DiscardsHigherSpatialVideoFramesAfterLayerDisabledInVideoLayersAllocation) {
338*d9f75844SAndroid Build Coastguard Worker constexpr uint8_t kPayload = 'a';
339*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image_1;
340*d9f75844SAndroid Build Coastguard Worker encoded_image_1.SetTimestamp(1);
341*d9f75844SAndroid Build Coastguard Worker encoded_image_1.capture_time_ms_ = 2;
342*d9f75844SAndroid Build Coastguard Worker encoded_image_1._frameType = VideoFrameType::kVideoFrameKey;
343*d9f75844SAndroid Build Coastguard Worker encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
344*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image_2(encoded_image_1);
345*d9f75844SAndroid Build Coastguard Worker encoded_image_2.SetSpatialIndex(1);
346*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo codec_info;
347*d9f75844SAndroid Build Coastguard Worker codec_info.codecType = kVideoCodecVP8;
348*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
349*d9f75844SAndroid Build Coastguard Worker kPayloadType, {});
350*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true, true});
351*d9f75844SAndroid Build Coastguard Worker // A layer is sent on both rtp streams.
352*d9f75844SAndroid Build Coastguard Worker test.router()->OnVideoLayersAllocationUpdated(
353*d9f75844SAndroid Build Coastguard Worker {.active_spatial_layers = {{.rtp_stream_index = 0},
354*d9f75844SAndroid Build Coastguard Worker {.rtp_stream_index = 1}}});
355*d9f75844SAndroid Build Coastguard Worker
356*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
357*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
358*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
359*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_2, &codec_info).error);
360*d9f75844SAndroid Build Coastguard Worker
361*d9f75844SAndroid Build Coastguard Worker // Only rtp stream index 0 is configured to send a stream.
362*d9f75844SAndroid Build Coastguard Worker test.router()->OnVideoLayersAllocationUpdated(
363*d9f75844SAndroid Build Coastguard Worker {.active_spatial_layers = {{.rtp_stream_index = 0}}});
364*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
365*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
366*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(EncodedImageCallback::Result::OK,
367*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image_2, &codec_info).error);
368*d9f75844SAndroid Build Coastguard Worker }
369*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,CreateWithNoPreviousStates)370*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, CreateWithNoPreviousStates) {
371*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
372*d9f75844SAndroid Build Coastguard Worker kPayloadType, {});
373*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true, true});
374*d9f75844SAndroid Build Coastguard Worker
375*d9f75844SAndroid Build Coastguard Worker std::map<uint32_t, RtpPayloadState> initial_states =
376*d9f75844SAndroid Build Coastguard Worker test.router()->GetRtpPayloadStates();
377*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(2u, initial_states.size());
378*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(initial_states.find(kSsrc1), initial_states.end());
379*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(initial_states.find(kSsrc2), initial_states.end());
380*d9f75844SAndroid Build Coastguard Worker }
381*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,CreateWithPreviousStates)382*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, CreateWithPreviousStates) {
383*d9f75844SAndroid Build Coastguard Worker const int64_t kState1SharedFrameId = 123;
384*d9f75844SAndroid Build Coastguard Worker const int64_t kState2SharedFrameId = 234;
385*d9f75844SAndroid Build Coastguard Worker RtpPayloadState state1;
386*d9f75844SAndroid Build Coastguard Worker state1.picture_id = kInitialPictureId1;
387*d9f75844SAndroid Build Coastguard Worker state1.tl0_pic_idx = kInitialTl0PicIdx1;
388*d9f75844SAndroid Build Coastguard Worker state1.shared_frame_id = kState1SharedFrameId;
389*d9f75844SAndroid Build Coastguard Worker RtpPayloadState state2;
390*d9f75844SAndroid Build Coastguard Worker state2.picture_id = kInitialPictureId2;
391*d9f75844SAndroid Build Coastguard Worker state2.tl0_pic_idx = kInitialTl0PicIdx2;
392*d9f75844SAndroid Build Coastguard Worker state2.shared_frame_id = kState2SharedFrameId;
393*d9f75844SAndroid Build Coastguard Worker std::map<uint32_t, RtpPayloadState> states = {{kSsrc1, state1},
394*d9f75844SAndroid Build Coastguard Worker {kSsrc2, state2}};
395*d9f75844SAndroid Build Coastguard Worker
396*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
397*d9f75844SAndroid Build Coastguard Worker kPayloadType, states);
398*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true, true});
399*d9f75844SAndroid Build Coastguard Worker
400*d9f75844SAndroid Build Coastguard Worker std::map<uint32_t, RtpPayloadState> initial_states =
401*d9f75844SAndroid Build Coastguard Worker test.router()->GetRtpPayloadStates();
402*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(2u, initial_states.size());
403*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kInitialPictureId1, initial_states[kSsrc1].picture_id);
404*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kInitialTl0PicIdx1, initial_states[kSsrc1].tl0_pic_idx);
405*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kInitialPictureId2, initial_states[kSsrc2].picture_id);
406*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kInitialTl0PicIdx2, initial_states[kSsrc2].tl0_pic_idx);
407*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kState2SharedFrameId, initial_states[kSsrc1].shared_frame_id);
408*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kState2SharedFrameId, initial_states[kSsrc2].shared_frame_id);
409*d9f75844SAndroid Build Coastguard Worker }
410*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,FrameCountCallbacks)411*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, FrameCountCallbacks) {
412*d9f75844SAndroid Build Coastguard Worker class MockFrameCountObserver : public FrameCountObserver {
413*d9f75844SAndroid Build Coastguard Worker public:
414*d9f75844SAndroid Build Coastguard Worker MOCK_METHOD(void,
415*d9f75844SAndroid Build Coastguard Worker FrameCountUpdated,
416*d9f75844SAndroid Build Coastguard Worker (const FrameCounts& frame_counts, uint32_t ssrc),
417*d9f75844SAndroid Build Coastguard Worker (override));
418*d9f75844SAndroid Build Coastguard Worker } callback;
419*d9f75844SAndroid Build Coastguard Worker
420*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {},
421*d9f75844SAndroid Build Coastguard Worker &callback);
422*d9f75844SAndroid Build Coastguard Worker
423*d9f75844SAndroid Build Coastguard Worker constexpr uint8_t kPayload = 'a';
424*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image;
425*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(1);
426*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 2;
427*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
428*d9f75844SAndroid Build Coastguard Worker encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
429*d9f75844SAndroid Build Coastguard Worker
430*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
431*d9f75844SAndroid Build Coastguard Worker
432*d9f75844SAndroid Build Coastguard Worker // No callbacks when not active.
433*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(callback, FrameCountUpdated).Times(0);
434*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(EncodedImageCallback::Result::OK,
435*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image, nullptr).error);
436*d9f75844SAndroid Build Coastguard Worker ::testing::Mock::VerifyAndClearExpectations(&callback);
437*d9f75844SAndroid Build Coastguard Worker
438*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
439*d9f75844SAndroid Build Coastguard Worker
440*d9f75844SAndroid Build Coastguard Worker FrameCounts frame_counts;
441*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(callback, FrameCountUpdated(_, kSsrc1))
442*d9f75844SAndroid Build Coastguard Worker .WillOnce(SaveArg<0>(&frame_counts));
443*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
444*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image, nullptr).error);
445*d9f75844SAndroid Build Coastguard Worker
446*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(1, frame_counts.key_frames);
447*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(0, frame_counts.delta_frames);
448*d9f75844SAndroid Build Coastguard Worker
449*d9f75844SAndroid Build Coastguard Worker ::testing::Mock::VerifyAndClearExpectations(&callback);
450*d9f75844SAndroid Build Coastguard Worker
451*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
452*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(callback, FrameCountUpdated(_, kSsrc1))
453*d9f75844SAndroid Build Coastguard Worker .WillOnce(SaveArg<0>(&frame_counts));
454*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
455*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image, nullptr).error);
456*d9f75844SAndroid Build Coastguard Worker
457*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(1, frame_counts.key_frames);
458*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(1, frame_counts.delta_frames);
459*d9f75844SAndroid Build Coastguard Worker }
460*d9f75844SAndroid Build Coastguard Worker
461*d9f75844SAndroid Build Coastguard Worker // Integration test verifying that ack of packet via TransportFeedback means
462*d9f75844SAndroid Build Coastguard Worker // that the packet is removed from RtpPacketHistory and won't be retransmitted
463*d9f75844SAndroid Build Coastguard Worker // again.
TEST(RtpVideoSenderTest,DoesNotRetrasmitAckedPackets)464*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, DoesNotRetrasmitAckedPackets) {
465*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
466*d9f75844SAndroid Build Coastguard Worker kPayloadType, {});
467*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true, true});
468*d9f75844SAndroid Build Coastguard Worker
469*d9f75844SAndroid Build Coastguard Worker constexpr uint8_t kPayload = 'a';
470*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image;
471*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(1);
472*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 2;
473*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
474*d9f75844SAndroid Build Coastguard Worker encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
475*d9f75844SAndroid Build Coastguard Worker
476*d9f75844SAndroid Build Coastguard Worker // Send two tiny images, mapping to two RTP packets. Capture sequence numbers.
477*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> rtp_sequence_numbers;
478*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> transport_sequence_numbers;
479*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(test.transport(), SendRtp)
480*d9f75844SAndroid Build Coastguard Worker .Times(2)
481*d9f75844SAndroid Build Coastguard Worker .WillRepeatedly([&rtp_sequence_numbers, &transport_sequence_numbers](
482*d9f75844SAndroid Build Coastguard Worker const uint8_t* packet, size_t length,
483*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
484*d9f75844SAndroid Build Coastguard Worker RtpPacket rtp_packet;
485*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(rtp_packet.Parse(packet, length));
486*d9f75844SAndroid Build Coastguard Worker rtp_sequence_numbers.push_back(rtp_packet.SequenceNumber());
487*d9f75844SAndroid Build Coastguard Worker transport_sequence_numbers.push_back(options.packet_id);
488*d9f75844SAndroid Build Coastguard Worker return true;
489*d9f75844SAndroid Build Coastguard Worker });
490*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
491*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image, nullptr).error);
492*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(2);
493*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 3;
494*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(EncodedImageCallback::Result::OK,
495*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(encoded_image, nullptr).error);
496*d9f75844SAndroid Build Coastguard Worker
497*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
498*d9f75844SAndroid Build Coastguard Worker
499*d9f75844SAndroid Build Coastguard Worker // Construct a NACK message for requesting retransmission of both packet.
500*d9f75844SAndroid Build Coastguard Worker rtcp::Nack nack;
501*d9f75844SAndroid Build Coastguard Worker nack.SetMediaSsrc(kSsrc1);
502*d9f75844SAndroid Build Coastguard Worker nack.SetPacketIds(rtp_sequence_numbers);
503*d9f75844SAndroid Build Coastguard Worker rtc::Buffer nack_buffer = nack.Build();
504*d9f75844SAndroid Build Coastguard Worker
505*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> retransmitted_rtp_sequence_numbers;
506*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(test.transport(), SendRtp)
507*d9f75844SAndroid Build Coastguard Worker .Times(2)
508*d9f75844SAndroid Build Coastguard Worker .WillRepeatedly([&retransmitted_rtp_sequence_numbers](
509*d9f75844SAndroid Build Coastguard Worker const uint8_t* packet, size_t length,
510*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
511*d9f75844SAndroid Build Coastguard Worker RtpPacket rtp_packet;
512*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(rtp_packet.Parse(packet, length));
513*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
514*d9f75844SAndroid Build Coastguard Worker // Capture the retransmitted sequence number from the RTX header.
515*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
516*d9f75844SAndroid Build Coastguard Worker retransmitted_rtp_sequence_numbers.push_back(
517*d9f75844SAndroid Build Coastguard Worker ByteReader<uint16_t>::ReadBigEndian(payload.data()));
518*d9f75844SAndroid Build Coastguard Worker return true;
519*d9f75844SAndroid Build Coastguard Worker });
520*d9f75844SAndroid Build Coastguard Worker test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
521*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
522*d9f75844SAndroid Build Coastguard Worker
523*d9f75844SAndroid Build Coastguard Worker // Verify that both packets were retransmitted.
524*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(retransmitted_rtp_sequence_numbers, rtp_sequence_numbers);
525*d9f75844SAndroid Build Coastguard Worker
526*d9f75844SAndroid Build Coastguard Worker // Simulate transport feedback indicating fist packet received, next packet
527*d9f75844SAndroid Build Coastguard Worker // lost (not other way around as that would trigger early retransmit).
528*d9f75844SAndroid Build Coastguard Worker StreamFeedbackObserver::StreamPacketInfo lost_packet_feedback;
529*d9f75844SAndroid Build Coastguard Worker lost_packet_feedback.rtp_sequence_number = rtp_sequence_numbers[0];
530*d9f75844SAndroid Build Coastguard Worker lost_packet_feedback.ssrc = kSsrc1;
531*d9f75844SAndroid Build Coastguard Worker lost_packet_feedback.received = false;
532*d9f75844SAndroid Build Coastguard Worker lost_packet_feedback.is_retransmission = false;
533*d9f75844SAndroid Build Coastguard Worker
534*d9f75844SAndroid Build Coastguard Worker StreamFeedbackObserver::StreamPacketInfo received_packet_feedback;
535*d9f75844SAndroid Build Coastguard Worker received_packet_feedback.rtp_sequence_number = rtp_sequence_numbers[1];
536*d9f75844SAndroid Build Coastguard Worker received_packet_feedback.ssrc = kSsrc1;
537*d9f75844SAndroid Build Coastguard Worker received_packet_feedback.received = true;
538*d9f75844SAndroid Build Coastguard Worker lost_packet_feedback.is_retransmission = false;
539*d9f75844SAndroid Build Coastguard Worker
540*d9f75844SAndroid Build Coastguard Worker test.router()->OnPacketFeedbackVector(
541*d9f75844SAndroid Build Coastguard Worker {lost_packet_feedback, received_packet_feedback});
542*d9f75844SAndroid Build Coastguard Worker
543*d9f75844SAndroid Build Coastguard Worker // Advance time to make sure retransmission would be allowed and try again.
544*d9f75844SAndroid Build Coastguard Worker // This time the retransmission should not happen for the first packet since
545*d9f75844SAndroid Build Coastguard Worker // the history has been notified of the ack and removed the packet. The
546*d9f75844SAndroid Build Coastguard Worker // second packet, included in the feedback but not marked as received, should
547*d9f75844SAndroid Build Coastguard Worker // still be retransmitted.
548*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
549*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(test.transport(), SendRtp)
550*d9f75844SAndroid Build Coastguard Worker .WillOnce([&lost_packet_feedback](const uint8_t* packet, size_t length,
551*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
552*d9f75844SAndroid Build Coastguard Worker RtpPacket rtp_packet;
553*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(rtp_packet.Parse(packet, length));
554*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
555*d9f75844SAndroid Build Coastguard Worker // Capture the retransmitted sequence number from the RTX header.
556*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
557*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(lost_packet_feedback.rtp_sequence_number,
558*d9f75844SAndroid Build Coastguard Worker ByteReader<uint16_t>::ReadBigEndian(payload.data()));
559*d9f75844SAndroid Build Coastguard Worker return true;
560*d9f75844SAndroid Build Coastguard Worker });
561*d9f75844SAndroid Build Coastguard Worker test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
562*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
563*d9f75844SAndroid Build Coastguard Worker }
564*d9f75844SAndroid Build Coastguard Worker
565*d9f75844SAndroid Build Coastguard Worker // This tests that we utilize transport wide feedback to retransmit lost
566*d9f75844SAndroid Build Coastguard Worker // packets. This is tested by dropping all ordinary packets from a "lossy"
567*d9f75844SAndroid Build Coastguard Worker // stream sent along with a secondary untouched stream. The transport wide
568*d9f75844SAndroid Build Coastguard Worker // feedback packets from the secondary stream allows the sending side to
569*d9f75844SAndroid Build Coastguard Worker // detect and retreansmit the lost packets from the lossy stream.
TEST(RtpVideoSenderTest,RetransmitsOnTransportWideLossInfo)570*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, RetransmitsOnTransportWideLossInfo) {
571*d9f75844SAndroid Build Coastguard Worker int rtx_packets;
572*d9f75844SAndroid Build Coastguard Worker test::Scenario s(test_info_);
573*d9f75844SAndroid Build Coastguard Worker test::CallClientConfig call_conf;
574*d9f75844SAndroid Build Coastguard Worker // Keeping the bitrate fixed to avoid RTX due to probing.
575*d9f75844SAndroid Build Coastguard Worker call_conf.transport.rates.max_rate = DataRate::KilobitsPerSec(300);
576*d9f75844SAndroid Build Coastguard Worker call_conf.transport.rates.start_rate = DataRate::KilobitsPerSec(300);
577*d9f75844SAndroid Build Coastguard Worker test::NetworkSimulationConfig net_conf;
578*d9f75844SAndroid Build Coastguard Worker net_conf.bandwidth = DataRate::KilobitsPerSec(300);
579*d9f75844SAndroid Build Coastguard Worker auto send_node = s.CreateSimulationNode(net_conf);
580*d9f75844SAndroid Build Coastguard Worker auto* callee = s.CreateClient("return", call_conf);
581*d9f75844SAndroid Build Coastguard Worker auto* route = s.CreateRoutes(s.CreateClient("send", call_conf), {send_node},
582*d9f75844SAndroid Build Coastguard Worker callee, {s.CreateSimulationNode(net_conf)});
583*d9f75844SAndroid Build Coastguard Worker
584*d9f75844SAndroid Build Coastguard Worker test::VideoStreamConfig lossy_config;
585*d9f75844SAndroid Build Coastguard Worker lossy_config.source.framerate = 5;
586*d9f75844SAndroid Build Coastguard Worker auto* lossy = s.CreateVideoStream(route->forward(), lossy_config);
587*d9f75844SAndroid Build Coastguard Worker // The secondary stream acts a driver for transport feedback messages,
588*d9f75844SAndroid Build Coastguard Worker // ensuring that lost packets on the lossy stream are retransmitted.
589*d9f75844SAndroid Build Coastguard Worker s.CreateVideoStream(route->forward(), test::VideoStreamConfig());
590*d9f75844SAndroid Build Coastguard Worker
591*d9f75844SAndroid Build Coastguard Worker send_node->router()->SetFilter([&](const EmulatedIpPacket& packet) {
592*d9f75844SAndroid Build Coastguard Worker RtpPacket rtp;
593*d9f75844SAndroid Build Coastguard Worker if (rtp.Parse(packet.data)) {
594*d9f75844SAndroid Build Coastguard Worker // Drops all regular packets for the lossy stream and counts all RTX
595*d9f75844SAndroid Build Coastguard Worker // packets. Since no packets are let trough, NACKs can't be triggered
596*d9f75844SAndroid Build Coastguard Worker // by the receiving side.
597*d9f75844SAndroid Build Coastguard Worker if (lossy->send()->UsingSsrc(rtp.Ssrc())) {
598*d9f75844SAndroid Build Coastguard Worker return false;
599*d9f75844SAndroid Build Coastguard Worker } else if (lossy->send()->UsingRtxSsrc(rtp.Ssrc())) {
600*d9f75844SAndroid Build Coastguard Worker ++rtx_packets;
601*d9f75844SAndroid Build Coastguard Worker }
602*d9f75844SAndroid Build Coastguard Worker }
603*d9f75844SAndroid Build Coastguard Worker return true;
604*d9f75844SAndroid Build Coastguard Worker });
605*d9f75844SAndroid Build Coastguard Worker
606*d9f75844SAndroid Build Coastguard Worker // Run for a short duration and reset counters to avoid counting RTX packets
607*d9f75844SAndroid Build Coastguard Worker // from initial probing.
608*d9f75844SAndroid Build Coastguard Worker s.RunFor(TimeDelta::Seconds(1));
609*d9f75844SAndroid Build Coastguard Worker rtx_packets = 0;
610*d9f75844SAndroid Build Coastguard Worker int decoded_baseline = 0;
611*d9f75844SAndroid Build Coastguard Worker callee->SendTask([&decoded_baseline, &lossy]() {
612*d9f75844SAndroid Build Coastguard Worker decoded_baseline = lossy->receive()->GetStats().frames_decoded;
613*d9f75844SAndroid Build Coastguard Worker });
614*d9f75844SAndroid Build Coastguard Worker s.RunFor(TimeDelta::Seconds(1));
615*d9f75844SAndroid Build Coastguard Worker // We expect both that RTX packets were sent and that an appropriate number of
616*d9f75844SAndroid Build Coastguard Worker // frames were received. This is somewhat redundant but reduces the risk of
617*d9f75844SAndroid Build Coastguard Worker // false positives in future regressions (e.g. RTX is send due to probing).
618*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(rtx_packets, 1);
619*d9f75844SAndroid Build Coastguard Worker int frames_decoded = 0;
620*d9f75844SAndroid Build Coastguard Worker callee->SendTask([&decoded_baseline, &frames_decoded, &lossy]() {
621*d9f75844SAndroid Build Coastguard Worker frames_decoded =
622*d9f75844SAndroid Build Coastguard Worker lossy->receive()->GetStats().frames_decoded - decoded_baseline;
623*d9f75844SAndroid Build Coastguard Worker });
624*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(frames_decoded, 5);
625*d9f75844SAndroid Build Coastguard Worker }
626*d9f75844SAndroid Build Coastguard Worker
627*d9f75844SAndroid Build Coastguard Worker // Integration test verifying that retransmissions are sent for packets which
628*d9f75844SAndroid Build Coastguard Worker // can be detected as lost early, using transport wide feedback.
TEST(RtpVideoSenderTest,EarlyRetransmits)629*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, EarlyRetransmits) {
630*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
631*d9f75844SAndroid Build Coastguard Worker kPayloadType, {});
632*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true, true});
633*d9f75844SAndroid Build Coastguard Worker
634*d9f75844SAndroid Build Coastguard Worker const uint8_t kPayload[1] = {'a'};
635*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image;
636*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(1);
637*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 2;
638*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
639*d9f75844SAndroid Build Coastguard Worker encoded_image.SetEncodedData(
640*d9f75844SAndroid Build Coastguard Worker EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
641*d9f75844SAndroid Build Coastguard Worker encoded_image.SetSpatialIndex(0);
642*d9f75844SAndroid Build Coastguard Worker
643*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo codec_specific;
644*d9f75844SAndroid Build Coastguard Worker codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
645*d9f75844SAndroid Build Coastguard Worker
646*d9f75844SAndroid Build Coastguard Worker // Send two tiny images, mapping to single RTP packets. Capture sequence
647*d9f75844SAndroid Build Coastguard Worker // numbers.
648*d9f75844SAndroid Build Coastguard Worker uint16_t frame1_rtp_sequence_number = 0;
649*d9f75844SAndroid Build Coastguard Worker uint16_t frame1_transport_sequence_number = 0;
650*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(test.transport(), SendRtp)
651*d9f75844SAndroid Build Coastguard Worker .WillOnce(
652*d9f75844SAndroid Build Coastguard Worker [&frame1_rtp_sequence_number, &frame1_transport_sequence_number](
653*d9f75844SAndroid Build Coastguard Worker const uint8_t* packet, size_t length,
654*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
655*d9f75844SAndroid Build Coastguard Worker RtpPacket rtp_packet;
656*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(rtp_packet.Parse(packet, length));
657*d9f75844SAndroid Build Coastguard Worker frame1_rtp_sequence_number = rtp_packet.SequenceNumber();
658*d9f75844SAndroid Build Coastguard Worker frame1_transport_sequence_number = options.packet_id;
659*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(rtp_packet.Ssrc(), kSsrc1);
660*d9f75844SAndroid Build Coastguard Worker return true;
661*d9f75844SAndroid Build Coastguard Worker });
662*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
663*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
664*d9f75844SAndroid Build Coastguard Worker
665*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
666*d9f75844SAndroid Build Coastguard Worker
667*d9f75844SAndroid Build Coastguard Worker uint16_t frame2_rtp_sequence_number = 0;
668*d9f75844SAndroid Build Coastguard Worker uint16_t frame2_transport_sequence_number = 0;
669*d9f75844SAndroid Build Coastguard Worker encoded_image.SetSpatialIndex(1);
670*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(test.transport(), SendRtp)
671*d9f75844SAndroid Build Coastguard Worker .WillOnce(
672*d9f75844SAndroid Build Coastguard Worker [&frame2_rtp_sequence_number, &frame2_transport_sequence_number](
673*d9f75844SAndroid Build Coastguard Worker const uint8_t* packet, size_t length,
674*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
675*d9f75844SAndroid Build Coastguard Worker RtpPacket rtp_packet;
676*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(rtp_packet.Parse(packet, length));
677*d9f75844SAndroid Build Coastguard Worker frame2_rtp_sequence_number = rtp_packet.SequenceNumber();
678*d9f75844SAndroid Build Coastguard Worker frame2_transport_sequence_number = options.packet_id;
679*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(rtp_packet.Ssrc(), kSsrc2);
680*d9f75844SAndroid Build Coastguard Worker return true;
681*d9f75844SAndroid Build Coastguard Worker });
682*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
683*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
684*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
685*d9f75844SAndroid Build Coastguard Worker
686*d9f75844SAndroid Build Coastguard Worker EXPECT_NE(frame1_transport_sequence_number, frame2_transport_sequence_number);
687*d9f75844SAndroid Build Coastguard Worker
688*d9f75844SAndroid Build Coastguard Worker // Inject a transport feedback where the packet for the first frame is lost,
689*d9f75844SAndroid Build Coastguard Worker // expect a retransmission for it.
690*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(test.transport(), SendRtp)
691*d9f75844SAndroid Build Coastguard Worker .WillOnce([&frame1_rtp_sequence_number](const uint8_t* packet,
692*d9f75844SAndroid Build Coastguard Worker size_t length,
693*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
694*d9f75844SAndroid Build Coastguard Worker RtpPacket rtp_packet;
695*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(rtp_packet.Parse(packet, length));
696*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
697*d9f75844SAndroid Build Coastguard Worker
698*d9f75844SAndroid Build Coastguard Worker // Retransmitted sequence number from the RTX header should match
699*d9f75844SAndroid Build Coastguard Worker // the lost packet.
700*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
701*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(payload.data()),
702*d9f75844SAndroid Build Coastguard Worker frame1_rtp_sequence_number);
703*d9f75844SAndroid Build Coastguard Worker return true;
704*d9f75844SAndroid Build Coastguard Worker });
705*d9f75844SAndroid Build Coastguard Worker
706*d9f75844SAndroid Build Coastguard Worker StreamFeedbackObserver::StreamPacketInfo first_packet_feedback;
707*d9f75844SAndroid Build Coastguard Worker first_packet_feedback.rtp_sequence_number = frame1_rtp_sequence_number;
708*d9f75844SAndroid Build Coastguard Worker first_packet_feedback.ssrc = kSsrc1;
709*d9f75844SAndroid Build Coastguard Worker first_packet_feedback.received = false;
710*d9f75844SAndroid Build Coastguard Worker first_packet_feedback.is_retransmission = false;
711*d9f75844SAndroid Build Coastguard Worker
712*d9f75844SAndroid Build Coastguard Worker StreamFeedbackObserver::StreamPacketInfo second_packet_feedback;
713*d9f75844SAndroid Build Coastguard Worker second_packet_feedback.rtp_sequence_number = frame2_rtp_sequence_number;
714*d9f75844SAndroid Build Coastguard Worker second_packet_feedback.ssrc = kSsrc2;
715*d9f75844SAndroid Build Coastguard Worker second_packet_feedback.received = true;
716*d9f75844SAndroid Build Coastguard Worker first_packet_feedback.is_retransmission = false;
717*d9f75844SAndroid Build Coastguard Worker
718*d9f75844SAndroid Build Coastguard Worker test.router()->OnPacketFeedbackVector(
719*d9f75844SAndroid Build Coastguard Worker {first_packet_feedback, second_packet_feedback});
720*d9f75844SAndroid Build Coastguard Worker
721*d9f75844SAndroid Build Coastguard Worker // Wait for pacer to run and send the RTX packet.
722*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
723*d9f75844SAndroid Build Coastguard Worker }
724*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,SupportsDependencyDescriptor)725*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, SupportsDependencyDescriptor) {
726*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
727*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
728*d9f75844SAndroid Build Coastguard Worker
729*d9f75844SAndroid Build Coastguard Worker RtpHeaderExtensionMap extensions;
730*d9f75844SAndroid Build Coastguard Worker extensions.Register<RtpDependencyDescriptorExtension>(
731*d9f75844SAndroid Build Coastguard Worker kDependencyDescriptorExtensionId);
732*d9f75844SAndroid Build Coastguard Worker std::vector<RtpPacket> sent_packets;
733*d9f75844SAndroid Build Coastguard Worker ON_CALL(test.transport(), SendRtp)
734*d9f75844SAndroid Build Coastguard Worker .WillByDefault([&](const uint8_t* packet, size_t length,
735*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
736*d9f75844SAndroid Build Coastguard Worker sent_packets.emplace_back(&extensions);
737*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets.back().Parse(packet, length));
738*d9f75844SAndroid Build Coastguard Worker return true;
739*d9f75844SAndroid Build Coastguard Worker });
740*d9f75844SAndroid Build Coastguard Worker
741*d9f75844SAndroid Build Coastguard Worker const uint8_t kPayload[1] = {'a'};
742*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image;
743*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(1);
744*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 2;
745*d9f75844SAndroid Build Coastguard Worker encoded_image.SetEncodedData(
746*d9f75844SAndroid Build Coastguard Worker EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
747*d9f75844SAndroid Build Coastguard Worker
748*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo codec_specific;
749*d9f75844SAndroid Build Coastguard Worker codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
750*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure.emplace();
751*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure->num_decode_targets = 1;
752*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure->templates = {
753*d9f75844SAndroid Build Coastguard Worker FrameDependencyTemplate().T(0).Dtis("S"),
754*d9f75844SAndroid Build Coastguard Worker FrameDependencyTemplate().T(0).Dtis("S").FrameDiffs({2}),
755*d9f75844SAndroid Build Coastguard Worker FrameDependencyTemplate().T(1).Dtis("D").FrameDiffs({1}),
756*d9f75844SAndroid Build Coastguard Worker };
757*d9f75844SAndroid Build Coastguard Worker
758*d9f75844SAndroid Build Coastguard Worker // Send two tiny images, mapping to single RTP packets.
759*d9f75844SAndroid Build Coastguard Worker // Send in key frame.
760*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
761*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info =
762*d9f75844SAndroid Build Coastguard Worker GenericFrameInfo::Builder().T(0).Dtis("S").Build();
763*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info->encoder_buffers = {{0, false, true}};
764*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
765*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
766*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
767*d9f75844SAndroid Build Coastguard Worker ASSERT_THAT(sent_packets, SizeIs(1));
768*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(
769*d9f75844SAndroid Build Coastguard Worker sent_packets.back().HasExtension<RtpDependencyDescriptorExtension>());
770*d9f75844SAndroid Build Coastguard Worker
771*d9f75844SAndroid Build Coastguard Worker // Send in delta frame.
772*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
773*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure = absl::nullopt;
774*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info =
775*d9f75844SAndroid Build Coastguard Worker GenericFrameInfo::Builder().T(1).Dtis("D").Build();
776*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info->encoder_buffers = {{0, true, false}};
777*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
778*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
779*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
780*d9f75844SAndroid Build Coastguard Worker ASSERT_THAT(sent_packets, SizeIs(2));
781*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(
782*d9f75844SAndroid Build Coastguard Worker sent_packets.back().HasExtension<RtpDependencyDescriptorExtension>());
783*d9f75844SAndroid Build Coastguard Worker }
784*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,SupportsDependencyDescriptorForVp8NotProvidedByEncoder)785*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest,
786*d9f75844SAndroid Build Coastguard Worker SupportsDependencyDescriptorForVp8NotProvidedByEncoder) {
787*d9f75844SAndroid Build Coastguard Worker constexpr uint8_t kPayload[1] = {'a'};
788*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
789*d9f75844SAndroid Build Coastguard Worker RtpHeaderExtensionMap extensions;
790*d9f75844SAndroid Build Coastguard Worker extensions.Register<RtpDependencyDescriptorExtension>(
791*d9f75844SAndroid Build Coastguard Worker kDependencyDescriptorExtensionId);
792*d9f75844SAndroid Build Coastguard Worker std::vector<RtpPacket> sent_packets;
793*d9f75844SAndroid Build Coastguard Worker ON_CALL(test.transport(), SendRtp)
794*d9f75844SAndroid Build Coastguard Worker .WillByDefault(
795*d9f75844SAndroid Build Coastguard Worker [&](const uint8_t* packet, size_t length, const PacketOptions&) {
796*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(
797*d9f75844SAndroid Build Coastguard Worker sent_packets.emplace_back(&extensions).Parse(packet, length));
798*d9f75844SAndroid Build Coastguard Worker return true;
799*d9f75844SAndroid Build Coastguard Worker });
800*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
801*d9f75844SAndroid Build Coastguard Worker
802*d9f75844SAndroid Build Coastguard Worker EncodedImage key_frame_image;
803*d9f75844SAndroid Build Coastguard Worker key_frame_image._frameType = VideoFrameType::kVideoFrameKey;
804*d9f75844SAndroid Build Coastguard Worker key_frame_image.SetEncodedData(
805*d9f75844SAndroid Build Coastguard Worker EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
806*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo key_frame_info;
807*d9f75844SAndroid Build Coastguard Worker key_frame_info.codecType = VideoCodecType::kVideoCodecVP8;
808*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ(
809*d9f75844SAndroid Build Coastguard Worker test.router()->OnEncodedImage(key_frame_image, &key_frame_info).error,
810*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
811*d9f75844SAndroid Build Coastguard Worker
812*d9f75844SAndroid Build Coastguard Worker EncodedImage delta_image;
813*d9f75844SAndroid Build Coastguard Worker delta_image._frameType = VideoFrameType::kVideoFrameDelta;
814*d9f75844SAndroid Build Coastguard Worker delta_image.SetEncodedData(
815*d9f75844SAndroid Build Coastguard Worker EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
816*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo delta_info;
817*d9f75844SAndroid Build Coastguard Worker delta_info.codecType = VideoCodecType::kVideoCodecVP8;
818*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ(test.router()->OnEncodedImage(delta_image, &delta_info).error,
819*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
820*d9f75844SAndroid Build Coastguard Worker
821*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(123));
822*d9f75844SAndroid Build Coastguard Worker
823*d9f75844SAndroid Build Coastguard Worker DependencyDescriptor key_frame_dd;
824*d9f75844SAndroid Build Coastguard Worker DependencyDescriptor delta_dd;
825*d9f75844SAndroid Build Coastguard Worker ASSERT_THAT(sent_packets, SizeIs(2));
826*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets[0].GetExtension<RtpDependencyDescriptorExtension>(
827*d9f75844SAndroid Build Coastguard Worker /*structure=*/nullptr, &key_frame_dd));
828*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets[1].GetExtension<RtpDependencyDescriptorExtension>(
829*d9f75844SAndroid Build Coastguard Worker key_frame_dd.attached_structure.get(), &delta_dd));
830*d9f75844SAndroid Build Coastguard Worker }
831*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,SupportsDependencyDescriptorForVp9)832*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, SupportsDependencyDescriptorForVp9) {
833*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
834*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
835*d9f75844SAndroid Build Coastguard Worker
836*d9f75844SAndroid Build Coastguard Worker RtpHeaderExtensionMap extensions;
837*d9f75844SAndroid Build Coastguard Worker extensions.Register<RtpDependencyDescriptorExtension>(
838*d9f75844SAndroid Build Coastguard Worker kDependencyDescriptorExtensionId);
839*d9f75844SAndroid Build Coastguard Worker std::vector<RtpPacket> sent_packets;
840*d9f75844SAndroid Build Coastguard Worker ON_CALL(test.transport(), SendRtp)
841*d9f75844SAndroid Build Coastguard Worker .WillByDefault([&](const uint8_t* packet, size_t length,
842*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
843*d9f75844SAndroid Build Coastguard Worker sent_packets.emplace_back(&extensions);
844*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets.back().Parse(packet, length));
845*d9f75844SAndroid Build Coastguard Worker return true;
846*d9f75844SAndroid Build Coastguard Worker });
847*d9f75844SAndroid Build Coastguard Worker
848*d9f75844SAndroid Build Coastguard Worker const uint8_t kPayload[1] = {'a'};
849*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image;
850*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(1);
851*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 2;
852*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
853*d9f75844SAndroid Build Coastguard Worker encoded_image.SetEncodedData(
854*d9f75844SAndroid Build Coastguard Worker EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
855*d9f75844SAndroid Build Coastguard Worker
856*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo codec_specific;
857*d9f75844SAndroid Build Coastguard Worker codec_specific.codecType = VideoCodecType::kVideoCodecVP9;
858*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure.emplace();
859*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure->num_decode_targets = 2;
860*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure->templates = {
861*d9f75844SAndroid Build Coastguard Worker FrameDependencyTemplate().S(0).Dtis("SS"),
862*d9f75844SAndroid Build Coastguard Worker FrameDependencyTemplate().S(1).Dtis("-S").FrameDiffs({1}),
863*d9f75844SAndroid Build Coastguard Worker };
864*d9f75844SAndroid Build Coastguard Worker
865*d9f75844SAndroid Build Coastguard Worker // Send two tiny images, each mapping to single RTP packet.
866*d9f75844SAndroid Build Coastguard Worker // Send in key frame for the base spatial layer.
867*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info =
868*d9f75844SAndroid Build Coastguard Worker GenericFrameInfo::Builder().S(0).Dtis("SS").Build();
869*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info->encoder_buffers = {{0, false, true}};
870*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
871*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
872*d9f75844SAndroid Build Coastguard Worker // Send in 2nd spatial layer.
873*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure = absl::nullopt;
874*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info =
875*d9f75844SAndroid Build Coastguard Worker GenericFrameInfo::Builder().S(1).Dtis("-S").Build();
876*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info->encoder_buffers = {{0, true, false},
877*d9f75844SAndroid Build Coastguard Worker {1, false, true}};
878*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
879*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
880*d9f75844SAndroid Build Coastguard Worker
881*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
882*d9f75844SAndroid Build Coastguard Worker ASSERT_THAT(sent_packets, SizeIs(2));
883*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets[0].HasExtension<RtpDependencyDescriptorExtension>());
884*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets[1].HasExtension<RtpDependencyDescriptorExtension>());
885*d9f75844SAndroid Build Coastguard Worker }
886*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,SupportsDependencyDescriptorForVp9NotProvidedByEncoder)887*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest,
888*d9f75844SAndroid Build Coastguard Worker SupportsDependencyDescriptorForVp9NotProvidedByEncoder) {
889*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
890*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
891*d9f75844SAndroid Build Coastguard Worker
892*d9f75844SAndroid Build Coastguard Worker RtpHeaderExtensionMap extensions;
893*d9f75844SAndroid Build Coastguard Worker extensions.Register<RtpDependencyDescriptorExtension>(
894*d9f75844SAndroid Build Coastguard Worker kDependencyDescriptorExtensionId);
895*d9f75844SAndroid Build Coastguard Worker std::vector<RtpPacket> sent_packets;
896*d9f75844SAndroid Build Coastguard Worker ON_CALL(test.transport(), SendRtp)
897*d9f75844SAndroid Build Coastguard Worker .WillByDefault([&](const uint8_t* packet, size_t length,
898*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
899*d9f75844SAndroid Build Coastguard Worker sent_packets.emplace_back(&extensions);
900*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets.back().Parse(packet, length));
901*d9f75844SAndroid Build Coastguard Worker return true;
902*d9f75844SAndroid Build Coastguard Worker });
903*d9f75844SAndroid Build Coastguard Worker
904*d9f75844SAndroid Build Coastguard Worker const uint8_t kPayload[1] = {'a'};
905*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image;
906*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(1);
907*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 2;
908*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
909*d9f75844SAndroid Build Coastguard Worker encoded_image._encodedWidth = 320;
910*d9f75844SAndroid Build Coastguard Worker encoded_image._encodedHeight = 180;
911*d9f75844SAndroid Build Coastguard Worker encoded_image.SetEncodedData(
912*d9f75844SAndroid Build Coastguard Worker EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
913*d9f75844SAndroid Build Coastguard Worker
914*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo codec_specific;
915*d9f75844SAndroid Build Coastguard Worker codec_specific.codecType = VideoCodecType::kVideoCodecVP9;
916*d9f75844SAndroid Build Coastguard Worker codec_specific.codecSpecific.VP9.num_spatial_layers = 1;
917*d9f75844SAndroid Build Coastguard Worker codec_specific.codecSpecific.VP9.temporal_idx = kNoTemporalIdx;
918*d9f75844SAndroid Build Coastguard Worker codec_specific.codecSpecific.VP9.first_frame_in_picture = true;
919*d9f75844SAndroid Build Coastguard Worker codec_specific.end_of_picture = true;
920*d9f75844SAndroid Build Coastguard Worker codec_specific.codecSpecific.VP9.inter_pic_predicted = false;
921*d9f75844SAndroid Build Coastguard Worker
922*d9f75844SAndroid Build Coastguard Worker // Send two tiny images, each mapping to single RTP packet.
923*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
924*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
925*d9f75844SAndroid Build Coastguard Worker
926*d9f75844SAndroid Build Coastguard Worker // Send in 2nd picture.
927*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
928*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(3000);
929*d9f75844SAndroid Build Coastguard Worker codec_specific.codecSpecific.VP9.inter_pic_predicted = true;
930*d9f75844SAndroid Build Coastguard Worker codec_specific.codecSpecific.VP9.num_ref_pics = 1;
931*d9f75844SAndroid Build Coastguard Worker codec_specific.codecSpecific.VP9.p_diff[0] = 1;
932*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
933*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
934*d9f75844SAndroid Build Coastguard Worker
935*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
936*d9f75844SAndroid Build Coastguard Worker ASSERT_THAT(sent_packets, SizeIs(2));
937*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets[0].HasExtension<RtpDependencyDescriptorExtension>());
938*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets[1].HasExtension<RtpDependencyDescriptorExtension>());
939*d9f75844SAndroid Build Coastguard Worker }
940*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,GenerateDependecyDescriptorForGenericCodecs)941*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, GenerateDependecyDescriptorForGenericCodecs) {
942*d9f75844SAndroid Build Coastguard Worker test::ScopedKeyValueConfig field_trials(
943*d9f75844SAndroid Build Coastguard Worker "WebRTC-GenericCodecDependencyDescriptor/Enabled/");
944*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {}, &field_trials);
945*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
946*d9f75844SAndroid Build Coastguard Worker
947*d9f75844SAndroid Build Coastguard Worker RtpHeaderExtensionMap extensions;
948*d9f75844SAndroid Build Coastguard Worker extensions.Register<RtpDependencyDescriptorExtension>(
949*d9f75844SAndroid Build Coastguard Worker kDependencyDescriptorExtensionId);
950*d9f75844SAndroid Build Coastguard Worker std::vector<RtpPacket> sent_packets;
951*d9f75844SAndroid Build Coastguard Worker ON_CALL(test.transport(), SendRtp)
952*d9f75844SAndroid Build Coastguard Worker .WillByDefault([&](const uint8_t* packet, size_t length,
953*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
954*d9f75844SAndroid Build Coastguard Worker sent_packets.emplace_back(&extensions);
955*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets.back().Parse(packet, length));
956*d9f75844SAndroid Build Coastguard Worker return true;
957*d9f75844SAndroid Build Coastguard Worker });
958*d9f75844SAndroid Build Coastguard Worker
959*d9f75844SAndroid Build Coastguard Worker const uint8_t kPayload[1] = {'a'};
960*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image;
961*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(1);
962*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 2;
963*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
964*d9f75844SAndroid Build Coastguard Worker encoded_image._encodedWidth = 320;
965*d9f75844SAndroid Build Coastguard Worker encoded_image._encodedHeight = 180;
966*d9f75844SAndroid Build Coastguard Worker encoded_image.SetEncodedData(
967*d9f75844SAndroid Build Coastguard Worker EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
968*d9f75844SAndroid Build Coastguard Worker
969*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo codec_specific;
970*d9f75844SAndroid Build Coastguard Worker codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
971*d9f75844SAndroid Build Coastguard Worker codec_specific.end_of_picture = true;
972*d9f75844SAndroid Build Coastguard Worker
973*d9f75844SAndroid Build Coastguard Worker // Send two tiny images, each mapping to single RTP packet.
974*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
975*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
976*d9f75844SAndroid Build Coastguard Worker
977*d9f75844SAndroid Build Coastguard Worker // Send in 2nd picture.
978*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
979*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(3000);
980*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
981*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
982*d9f75844SAndroid Build Coastguard Worker
983*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
984*d9f75844SAndroid Build Coastguard Worker ASSERT_THAT(sent_packets, SizeIs(2));
985*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets[0].HasExtension<RtpDependencyDescriptorExtension>());
986*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets[1].HasExtension<RtpDependencyDescriptorExtension>());
987*d9f75844SAndroid Build Coastguard Worker }
988*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,SupportsStoppingUsingDependencyDescriptor)989*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, SupportsStoppingUsingDependencyDescriptor) {
990*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
991*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
992*d9f75844SAndroid Build Coastguard Worker
993*d9f75844SAndroid Build Coastguard Worker RtpHeaderExtensionMap extensions;
994*d9f75844SAndroid Build Coastguard Worker extensions.Register<RtpDependencyDescriptorExtension>(
995*d9f75844SAndroid Build Coastguard Worker kDependencyDescriptorExtensionId);
996*d9f75844SAndroid Build Coastguard Worker std::vector<RtpPacket> sent_packets;
997*d9f75844SAndroid Build Coastguard Worker ON_CALL(test.transport(), SendRtp)
998*d9f75844SAndroid Build Coastguard Worker .WillByDefault([&](const uint8_t* packet, size_t length,
999*d9f75844SAndroid Build Coastguard Worker const PacketOptions& options) {
1000*d9f75844SAndroid Build Coastguard Worker sent_packets.emplace_back(&extensions);
1001*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(sent_packets.back().Parse(packet, length));
1002*d9f75844SAndroid Build Coastguard Worker return true;
1003*d9f75844SAndroid Build Coastguard Worker });
1004*d9f75844SAndroid Build Coastguard Worker
1005*d9f75844SAndroid Build Coastguard Worker const uint8_t kPayload[1] = {'a'};
1006*d9f75844SAndroid Build Coastguard Worker EncodedImage encoded_image;
1007*d9f75844SAndroid Build Coastguard Worker encoded_image.SetTimestamp(1);
1008*d9f75844SAndroid Build Coastguard Worker encoded_image.capture_time_ms_ = 2;
1009*d9f75844SAndroid Build Coastguard Worker encoded_image.SetEncodedData(
1010*d9f75844SAndroid Build Coastguard Worker EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
1011*d9f75844SAndroid Build Coastguard Worker
1012*d9f75844SAndroid Build Coastguard Worker CodecSpecificInfo codec_specific;
1013*d9f75844SAndroid Build Coastguard Worker codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
1014*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure.emplace();
1015*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure->num_decode_targets = 1;
1016*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure->templates = {
1017*d9f75844SAndroid Build Coastguard Worker FrameDependencyTemplate().T(0).Dtis("S"),
1018*d9f75844SAndroid Build Coastguard Worker FrameDependencyTemplate().T(0).Dtis("S").FrameDiffs({2}),
1019*d9f75844SAndroid Build Coastguard Worker FrameDependencyTemplate().T(1).Dtis("D").FrameDiffs({1}),
1020*d9f75844SAndroid Build Coastguard Worker };
1021*d9f75844SAndroid Build Coastguard Worker
1022*d9f75844SAndroid Build Coastguard Worker // Send two tiny images, mapping to single RTP packets.
1023*d9f75844SAndroid Build Coastguard Worker // Send in a key frame.
1024*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1025*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info =
1026*d9f75844SAndroid Build Coastguard Worker GenericFrameInfo::Builder().T(0).Dtis("S").Build();
1027*d9f75844SAndroid Build Coastguard Worker codec_specific.generic_frame_info->encoder_buffers = {{0, false, true}};
1028*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1029*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
1030*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
1031*d9f75844SAndroid Build Coastguard Worker ASSERT_THAT(sent_packets, SizeIs(1));
1032*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(
1033*d9f75844SAndroid Build Coastguard Worker sent_packets.back().HasExtension<RtpDependencyDescriptorExtension>());
1034*d9f75844SAndroid Build Coastguard Worker
1035*d9f75844SAndroid Build Coastguard Worker // Send in a new key frame without the support for the dependency descriptor.
1036*d9f75844SAndroid Build Coastguard Worker encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1037*d9f75844SAndroid Build Coastguard Worker codec_specific.template_structure = absl::nullopt;
1038*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1039*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result::OK);
1040*d9f75844SAndroid Build Coastguard Worker test.AdvanceTime(TimeDelta::Millis(33));
1041*d9f75844SAndroid Build Coastguard Worker ASSERT_THAT(sent_packets, SizeIs(2));
1042*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(
1043*d9f75844SAndroid Build Coastguard Worker sent_packets.back().HasExtension<RtpDependencyDescriptorExtension>());
1044*d9f75844SAndroid Build Coastguard Worker }
1045*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,CanSetZeroBitrate)1046*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, CanSetZeroBitrate) {
1047*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {});
1048*d9f75844SAndroid Build Coastguard Worker test.router()->OnBitrateUpdated(CreateBitrateAllocationUpdate(0),
1049*d9f75844SAndroid Build Coastguard Worker /*framerate*/ 0);
1050*d9f75844SAndroid Build Coastguard Worker }
1051*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,SimulcastSenderRegistersFrameTransformers)1052*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, SimulcastSenderRegistersFrameTransformers) {
1053*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<MockFrameTransformer> transformer =
1054*d9f75844SAndroid Build Coastguard Worker rtc::make_ref_counted<MockFrameTransformer>();
1055*d9f75844SAndroid Build Coastguard Worker
1056*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(*transformer, RegisterTransformedFrameSinkCallback(_, kSsrc1));
1057*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(*transformer, RegisterTransformedFrameSinkCallback(_, kSsrc2));
1058*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
1059*d9f75844SAndroid Build Coastguard Worker kPayloadType, {}, nullptr, transformer);
1060*d9f75844SAndroid Build Coastguard Worker
1061*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(*transformer, UnregisterTransformedFrameSinkCallback(kSsrc1));
1062*d9f75844SAndroid Build Coastguard Worker EXPECT_CALL(*transformer, UnregisterTransformedFrameSinkCallback(kSsrc2));
1063*d9f75844SAndroid Build Coastguard Worker }
1064*d9f75844SAndroid Build Coastguard Worker
TEST(RtpVideoSenderTest,OverheadIsSubtractedFromTargetBitrate)1065*d9f75844SAndroid Build Coastguard Worker TEST(RtpVideoSenderTest, OverheadIsSubtractedFromTargetBitrate) {
1066*d9f75844SAndroid Build Coastguard Worker test::ScopedKeyValueConfig field_trials(
1067*d9f75844SAndroid Build Coastguard Worker "WebRTC-Video-UseFrameRateForOverhead/Enabled/");
1068*d9f75844SAndroid Build Coastguard Worker
1069*d9f75844SAndroid Build Coastguard Worker // TODO(jakobi): RTP header size should not be hard coded.
1070*d9f75844SAndroid Build Coastguard Worker constexpr uint32_t kRtpHeaderSizeBytes = 20;
1071*d9f75844SAndroid Build Coastguard Worker constexpr uint32_t kTransportPacketOverheadBytes = 40;
1072*d9f75844SAndroid Build Coastguard Worker constexpr uint32_t kOverheadPerPacketBytes =
1073*d9f75844SAndroid Build Coastguard Worker kRtpHeaderSizeBytes + kTransportPacketOverheadBytes;
1074*d9f75844SAndroid Build Coastguard Worker RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {}, &field_trials);
1075*d9f75844SAndroid Build Coastguard Worker test.router()->OnTransportOverheadChanged(kTransportPacketOverheadBytes);
1076*d9f75844SAndroid Build Coastguard Worker test.SetActiveModules({true});
1077*d9f75844SAndroid Build Coastguard Worker
1078*d9f75844SAndroid Build Coastguard Worker {
1079*d9f75844SAndroid Build Coastguard Worker test.router()->OnBitrateUpdated(CreateBitrateAllocationUpdate(300000),
1080*d9f75844SAndroid Build Coastguard Worker /*framerate*/ 15);
1081*d9f75844SAndroid Build Coastguard Worker // 1 packet per frame.
1082*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->GetPayloadBitrateBps(),
1083*d9f75844SAndroid Build Coastguard Worker 300000 - kOverheadPerPacketBytes * 8 * 30);
1084*d9f75844SAndroid Build Coastguard Worker }
1085*d9f75844SAndroid Build Coastguard Worker {
1086*d9f75844SAndroid Build Coastguard Worker test.router()->OnBitrateUpdated(CreateBitrateAllocationUpdate(150000),
1087*d9f75844SAndroid Build Coastguard Worker /*framerate*/ 15);
1088*d9f75844SAndroid Build Coastguard Worker // 1 packet per frame.
1089*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->GetPayloadBitrateBps(),
1090*d9f75844SAndroid Build Coastguard Worker 150000 - kOverheadPerPacketBytes * 8 * 15);
1091*d9f75844SAndroid Build Coastguard Worker }
1092*d9f75844SAndroid Build Coastguard Worker {
1093*d9f75844SAndroid Build Coastguard Worker test.router()->OnBitrateUpdated(CreateBitrateAllocationUpdate(1000000),
1094*d9f75844SAndroid Build Coastguard Worker /*framerate*/ 30);
1095*d9f75844SAndroid Build Coastguard Worker // 3 packets per frame.
1096*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(test.router()->GetPayloadBitrateBps(),
1097*d9f75844SAndroid Build Coastguard Worker 1000000 - kOverheadPerPacketBytes * 8 * 30 * 3);
1098*d9f75844SAndroid Build Coastguard Worker }
1099*d9f75844SAndroid Build Coastguard Worker }
1100*d9f75844SAndroid Build Coastguard Worker
1101*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
1102