xref: /aosp_15_r20/external/webrtc/call/rtp_video_sender_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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