blob: 7935fac3894c1b2e32bbff6c9192e2b7f07817fb [file] [log] [blame]
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +00001/*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "call/rtp_video_sender.h"
12
Sebastian Jansson3d4d94a2020-01-14 14:25:41 +010013#include <atomic>
kwiberg27f982b2016-03-01 11:52:33 -080014#include <memory>
Åsa Persson4bece9a2017-10-06 10:04:04 +020015#include <string>
Sebastian Jansson3d4d94a2020-01-14 14:25:41 +010016
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020017#include "call/rtp_transport_controller_send.h"
Erik Språng490d76c2019-05-07 09:29:15 -070018#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
19#include "modules/rtp_rtcp/source/byte_io.h"
20#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
21#include "modules/rtp_rtcp/source/rtp_packet.h"
Stefan Holmer64be7fa2018-10-04 15:21:55 +020022#include "modules/video_coding/fec_controller_default.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "modules/video_coding/include/video_codec_interface.h"
Erik Språng490d76c2019-05-07 09:29:15 -070024#include "rtc_base/event.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020025#include "rtc_base/rate_limiter.h"
Åsa Persson4bece9a2017-10-06 10:04:04 +020026#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "test/gmock.h"
28#include "test/gtest.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020029#include "test/mock_transport.h"
Sebastian Jansson3d4d94a2020-01-14 14:25:41 +010030#include "test/scenario/scenario.h"
Erik Språng00cc8362019-11-25 12:21:46 +010031#include "test/time_controller/simulated_time_controller.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020032#include "video/call_stats.h"
33#include "video/send_delay_stats.h"
34#include "video/send_statistics_proxy.h"
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000035
36using ::testing::_;
Erik Språng490d76c2019-05-07 09:29:15 -070037using ::testing::Invoke;
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000038using ::testing::NiceMock;
Niels Möller949f0fd2019-01-29 09:44:24 +010039using ::testing::SaveArg;
Åsa Persson4bece9a2017-10-06 10:04:04 +020040using ::testing::Unused;
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000041
42namespace webrtc {
Åsa Persson4bece9a2017-10-06 10:04:04 +020043namespace {
44const int8_t kPayloadType = 96;
45const uint32_t kSsrc1 = 12345;
46const uint32_t kSsrc2 = 23456;
Erik Språng490d76c2019-05-07 09:29:15 -070047const uint32_t kRtxSsrc1 = 34567;
48const uint32_t kRtxSsrc2 = 45678;
Åsa Persson4bece9a2017-10-06 10:04:04 +020049const int16_t kInitialPictureId1 = 222;
50const int16_t kInitialPictureId2 = 44;
Niels Möllerbb894ff2018-03-15 12:28:53 +010051const int16_t kInitialTl0PicIdx1 = 99;
52const int16_t kInitialTl0PicIdx2 = 199;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020053const int64_t kRetransmitWindowSizeMs = 500;
Erik Språng845c6aa2019-05-29 13:02:24 +020054const int kTransportsSequenceExtensionId = 7;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020055
56class MockRtcpIntraFrameObserver : public RtcpIntraFrameObserver {
57 public:
58 MOCK_METHOD1(OnReceivedIntraFrameRequest, void(uint32_t));
59};
60
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020061RtpSenderObservers CreateObservers(
62 RtcpRttStats* rtcp_rtt_stats,
63 RtcpIntraFrameObserver* intra_frame_callback,
64 RtcpStatisticsCallback* rtcp_stats,
Henrik Boström87e3f9d2019-05-27 10:44:24 +020065 ReportBlockDataObserver* report_block_data_observer,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020066 StreamDataCountersCallback* rtp_stats,
67 BitrateStatisticsObserver* bitrate_observer,
68 FrameCountObserver* frame_count_observer,
69 RtcpPacketTypeCounterObserver* rtcp_type_observer,
70 SendSideDelayObserver* send_delay_observer,
Stefan Holmer64be7fa2018-10-04 15:21:55 +020071 SendPacketObserver* send_packet_observer) {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020072 RtpSenderObservers observers;
73 observers.rtcp_rtt_stats = rtcp_rtt_stats;
74 observers.intra_frame_callback = intra_frame_callback;
Erik Språng490d76c2019-05-07 09:29:15 -070075 observers.rtcp_loss_notification_observer = nullptr;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020076 observers.rtcp_stats = rtcp_stats;
Henrik Boström87e3f9d2019-05-27 10:44:24 +020077 observers.report_block_data_observer = report_block_data_observer;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020078 observers.rtp_stats = rtp_stats;
79 observers.bitrate_observer = bitrate_observer;
80 observers.frame_count_observer = frame_count_observer;
81 observers.rtcp_type_observer = rtcp_type_observer;
82 observers.send_delay_observer = send_delay_observer;
83 observers.send_packet_observer = send_packet_observer;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020084 return observers;
85}
86
Erik Språng490d76c2019-05-07 09:29:15 -070087BitrateConstraints GetBitrateConfig() {
88 BitrateConstraints bitrate_config;
89 bitrate_config.min_bitrate_bps = 30000;
90 bitrate_config.start_bitrate_bps = 300000;
91 bitrate_config.max_bitrate_bps = 3000000;
92 return bitrate_config;
93}
94
95VideoSendStream::Config CreateVideoSendStreamConfig(
96 Transport* transport,
97 const std::vector<uint32_t>& ssrcs,
98 const std::vector<uint32_t>& rtx_ssrcs,
99 int payload_type) {
100 VideoSendStream::Config config(transport);
101 config.rtp.ssrcs = ssrcs;
102 config.rtp.rtx.ssrcs = rtx_ssrcs;
103 config.rtp.payload_type = payload_type;
104 config.rtp.rtx.payload_type = payload_type + 1;
105 config.rtp.nack.rtp_history_ms = 1000;
Erik Språng845c6aa2019-05-29 13:02:24 +0200106 config.rtp.extensions.emplace_back(RtpExtension::kTransportSequenceNumberUri,
107 kTransportsSequenceExtensionId);
Erik Språng490d76c2019-05-07 09:29:15 -0700108 return config;
109}
110
Stefan Holmer9416ef82018-07-19 10:34:38 +0200111class RtpVideoSenderTestFixture {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200112 public:
Stefan Holmer9416ef82018-07-19 10:34:38 +0200113 RtpVideoSenderTestFixture(
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200114 const std::vector<uint32_t>& ssrcs,
Erik Språng490d76c2019-05-07 09:29:15 -0700115 const std::vector<uint32_t>& rtx_ssrcs,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200116 int payload_type,
Niels Möller949f0fd2019-01-29 09:44:24 +0100117 const std::map<uint32_t, RtpPayloadState>& suspended_payload_states,
118 FrameCountObserver* frame_count_observer)
Erik Språng00cc8362019-11-25 12:21:46 +0100119 : time_controller_(Timestamp::ms(1000000)),
Erik Språng490d76c2019-05-07 09:29:15 -0700120 config_(CreateVideoSendStreamConfig(&transport_,
121 ssrcs,
122 rtx_ssrcs,
123 payload_type)),
Erik Språng00cc8362019-11-25 12:21:46 +0100124 send_delay_stats_(time_controller_.GetClock()),
Erik Språng490d76c2019-05-07 09:29:15 -0700125 bitrate_config_(GetBitrateConfig()),
Erik Språng00cc8362019-11-25 12:21:46 +0100126 transport_controller_(time_controller_.GetClock(),
Sebastian Janssoned50e6c2019-03-01 14:45:21 +0100127 &event_log_,
128 nullptr,
Ying Wang0810a7c2019-04-10 13:48:24 +0200129 nullptr,
Sebastian Janssoned50e6c2019-03-01 14:45:21 +0100130 bitrate_config_,
131 ProcessThread::Create("PacerThread"),
Erik Språng00cc8362019-11-25 12:21:46 +0100132 time_controller_.GetTaskQueueFactory(),
Erik Språng662678d2019-11-15 17:18:52 +0100133 &field_trials_),
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200134 process_thread_(ProcessThread::Create("test_thread")),
Erik Språng00cc8362019-11-25 12:21:46 +0100135 call_stats_(time_controller_.GetClock(), process_thread_.get()),
136 stats_proxy_(time_controller_.GetClock(),
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200137 config_,
138 VideoEncoderConfig::ContentType::kRealtimeVideo),
Erik Språng00cc8362019-11-25 12:21:46 +0100139 retransmission_rate_limiter_(time_controller_.GetClock(),
140 kRetransmitWindowSizeMs) {
Mirko Bonadeif18f9202019-12-10 13:24:56 +0000141 std::map<uint32_t, RtpState> suspended_ssrcs;
142 router_ = std::make_unique<RtpVideoSender>(
143 time_controller_.GetClock(), suspended_ssrcs, suspended_payload_states,
144 config_.rtp, config_.rtcp_report_interval_ms, &transport_,
145 CreateObservers(&call_stats_, &encoder_feedback_, &stats_proxy_,
146 &stats_proxy_, &stats_proxy_, &stats_proxy_,
147 frame_count_observer, &stats_proxy_, &stats_proxy_,
148 &send_delay_stats_),
149 &transport_controller_, &event_log_, &retransmission_rate_limiter_,
150 std::make_unique<FecControllerDefault>(time_controller_.GetClock()),
151 nullptr, CryptoOptions{});
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200152 }
Niels Möller949f0fd2019-01-29 09:44:24 +0100153 RtpVideoSenderTestFixture(
154 const std::vector<uint32_t>& ssrcs,
Erik Språng490d76c2019-05-07 09:29:15 -0700155 const std::vector<uint32_t>& rtx_ssrcs,
Niels Möller949f0fd2019-01-29 09:44:24 +0100156 int payload_type,
157 const std::map<uint32_t, RtpPayloadState>& suspended_payload_states)
158 : RtpVideoSenderTestFixture(ssrcs,
Erik Språng490d76c2019-05-07 09:29:15 -0700159 rtx_ssrcs,
Niels Möller949f0fd2019-01-29 09:44:24 +0100160 payload_type,
161 suspended_payload_states,
162 /*frame_count_observer=*/nullptr) {}
Mirko Bonadeif18f9202019-12-10 13:24:56 +0000163
Stefan Holmer9416ef82018-07-19 10:34:38 +0200164 RtpVideoSender* router() { return router_.get(); }
Erik Språng490d76c2019-05-07 09:29:15 -0700165 MockTransport& transport() { return transport_; }
Markus Handell486cc552019-12-03 14:37:28 +0100166 void AdvanceTime(TimeDelta delta) { time_controller_.AdvanceTime(delta); }
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200167
168 private:
169 NiceMock<MockTransport> transport_;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200170 NiceMock<MockRtcpIntraFrameObserver> encoder_feedback_;
Erik Språng00cc8362019-11-25 12:21:46 +0100171 GlobalSimulatedTimeController time_controller_;
Danil Chapovalov83bbe912019-08-07 12:24:53 +0200172 RtcEventLogNull event_log_;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200173 VideoSendStream::Config config_;
174 SendDelayStats send_delay_stats_;
175 BitrateConstraints bitrate_config_;
Erik Språng662678d2019-11-15 17:18:52 +0100176 const FieldTrialBasedConfig field_trials_;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200177 RtpTransportControllerSend transport_controller_;
178 std::unique_ptr<ProcessThread> process_thread_;
179 CallStats call_stats_;
180 SendStatisticsProxy stats_proxy_;
181 RateLimiter retransmission_rate_limiter_;
Stefan Holmer9416ef82018-07-19 10:34:38 +0200182 std::unique_ptr<RtpVideoSender> router_;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200183};
Åsa Persson4bece9a2017-10-06 10:04:04 +0200184} // namespace
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000185
Sebastian Jansson63470292019-02-01 10:13:43 +0100186TEST(RtpVideoSenderTest, SendOnOneModule) {
Niels Möller663844d2019-02-14 16:15:54 +0100187 constexpr uint8_t kPayload = 'a';
kjellander02b3d272016-04-20 05:05:54 -0700188 EncodedImage encoded_image;
Niels Möller23775882018-08-16 10:24:12 +0200189 encoded_image.SetTimestamp(1);
kjellander02b3d272016-04-20 05:05:54 -0700190 encoded_image.capture_time_ms_ = 2;
Niels Möller8f7ce222019-03-21 15:43:58 +0100191 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 15:56:56 +0200192 encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
kjellander02b3d272016-04-20 05:05:54 -0700193
Erik Språng490d76c2019-05-07 09:29:15 -0700194 RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {});
sergeyu2cb155a2016-11-04 11:39:29 -0700195 EXPECT_NE(
196 EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200197 test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000198
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200199 test.router()->SetActive(true);
sergeyu2cb155a2016-11-04 11:39:29 -0700200 EXPECT_EQ(
201 EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200202 test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000203
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200204 test.router()->SetActive(false);
sergeyu2cb155a2016-11-04 11:39:29 -0700205 EXPECT_NE(
206 EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200207 test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000208
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200209 test.router()->SetActive(true);
sergeyu2cb155a2016-11-04 11:39:29 -0700210 EXPECT_EQ(
211 EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200212 test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000213}
214
Sebastian Jansson63470292019-02-01 10:13:43 +0100215TEST(RtpVideoSenderTest, SendSimulcastSetActive) {
Niels Möller663844d2019-02-14 16:15:54 +0100216 constexpr uint8_t kPayload = 'a';
Niels Möllerd3b8c632018-08-27 15:33:42 +0200217 EncodedImage encoded_image_1;
218 encoded_image_1.SetTimestamp(1);
219 encoded_image_1.capture_time_ms_ = 2;
Niels Möller8f7ce222019-03-21 15:43:58 +0100220 encoded_image_1._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 15:56:56 +0200221 encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
kjellander02b3d272016-04-20 05:05:54 -0700222
Erik Språng490d76c2019-05-07 09:29:15 -0700223 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
224 kPayloadType, {});
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000225
Niels Möllerd3b8c632018-08-27 15:33:42 +0200226 CodecSpecificInfo codec_info;
Niels Möllerd3b8c632018-08-27 15:33:42 +0200227 codec_info.codecType = kVideoCodecVP8;
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000228
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200229 test.router()->SetActive(true);
sergeyu2cb155a2016-11-04 11:39:29 -0700230 EXPECT_EQ(EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200231 test.router()
Niels Möllerd3b8c632018-08-27 15:33:42 +0200232 ->OnEncodedImage(encoded_image_1, &codec_info, nullptr)
sergeyu2cb155a2016-11-04 11:39:29 -0700233 .error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000234
Niels Möllerd3b8c632018-08-27 15:33:42 +0200235 EncodedImage encoded_image_2(encoded_image_1);
236 encoded_image_2.SetSpatialIndex(1);
sergeyu2cb155a2016-11-04 11:39:29 -0700237 EXPECT_EQ(EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200238 test.router()
Niels Möllerd3b8c632018-08-27 15:33:42 +0200239 ->OnEncodedImage(encoded_image_2, &codec_info, nullptr)
sergeyu2cb155a2016-11-04 11:39:29 -0700240 .error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000241
mflodman@webrtc.org50e28162015-02-23 07:45:11 +0000242 // Inactive.
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200243 test.router()->SetActive(false);
sergeyu2cb155a2016-11-04 11:39:29 -0700244 EXPECT_NE(EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200245 test.router()
Niels Möllerd3b8c632018-08-27 15:33:42 +0200246 ->OnEncodedImage(encoded_image_1, &codec_info, nullptr)
sergeyu2cb155a2016-11-04 11:39:29 -0700247 .error);
248 EXPECT_NE(EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200249 test.router()
Niels Möllerd3b8c632018-08-27 15:33:42 +0200250 ->OnEncodedImage(encoded_image_2, &codec_info, nullptr)
sergeyu2cb155a2016-11-04 11:39:29 -0700251 .error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000252}
253
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800254// Tests how setting individual rtp modules to active affects the overall
255// behavior of the payload router. First sets one module to active and checks
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200256// that outgoing data can be sent on this module, and checks that no data can
257// be sent if both modules are inactive.
Sebastian Jansson63470292019-02-01 10:13:43 +0100258TEST(RtpVideoSenderTest, SendSimulcastSetActiveModules) {
Niels Möller663844d2019-02-14 16:15:54 +0100259 constexpr uint8_t kPayload = 'a';
Niels Möllerd3b8c632018-08-27 15:33:42 +0200260 EncodedImage encoded_image_1;
261 encoded_image_1.SetTimestamp(1);
262 encoded_image_1.capture_time_ms_ = 2;
Niels Möller8f7ce222019-03-21 15:43:58 +0100263 encoded_image_1._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 15:56:56 +0200264 encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
Niels Möller77536a22019-01-15 08:50:01 +0100265
Niels Möllerd3b8c632018-08-27 15:33:42 +0200266 EncodedImage encoded_image_2(encoded_image_1);
267 encoded_image_2.SetSpatialIndex(1);
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200268
Erik Språng490d76c2019-05-07 09:29:15 -0700269 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
270 kPayloadType, {});
Niels Möllerd3b8c632018-08-27 15:33:42 +0200271 CodecSpecificInfo codec_info;
Niels Möllerd3b8c632018-08-27 15:33:42 +0200272 codec_info.codecType = kVideoCodecVP8;
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800273
274 // Only setting one stream to active will still set the payload router to
275 // active and allow sending data on the active stream.
276 std::vector<bool> active_modules({true, false});
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200277 test.router()->SetActiveModules(active_modules);
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800278 EXPECT_EQ(EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200279 test.router()
Niels Möllerd3b8c632018-08-27 15:33:42 +0200280 ->OnEncodedImage(encoded_image_1, &codec_info, nullptr)
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800281 .error);
282
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200283 // Setting both streams to inactive will turn the payload router to
284 // inactive.
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800285 active_modules = {false, false};
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200286 test.router()->SetActiveModules(active_modules);
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800287 // An incoming encoded image will not ask the module to send outgoing data
288 // because the payload router is inactive.
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800289 EXPECT_NE(EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200290 test.router()
Niels Möllerd3b8c632018-08-27 15:33:42 +0200291 ->OnEncodedImage(encoded_image_1, &codec_info, nullptr)
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800292 .error);
293 EXPECT_NE(EncodedImageCallback::Result::OK,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200294 test.router()
Niels Möllerd3b8c632018-08-27 15:33:42 +0200295 ->OnEncodedImage(encoded_image_1, &codec_info, nullptr)
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800296 .error);
297}
298
Sebastian Jansson63470292019-02-01 10:13:43 +0100299TEST(RtpVideoSenderTest, CreateWithNoPreviousStates) {
Erik Språng490d76c2019-05-07 09:29:15 -0700300 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
301 kPayloadType, {});
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200302 test.router()->SetActive(true);
Åsa Persson4bece9a2017-10-06 10:04:04 +0200303
304 std::map<uint32_t, RtpPayloadState> initial_states =
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200305 test.router()->GetRtpPayloadStates();
Åsa Persson4bece9a2017-10-06 10:04:04 +0200306 EXPECT_EQ(2u, initial_states.size());
307 EXPECT_NE(initial_states.find(kSsrc1), initial_states.end());
308 EXPECT_NE(initial_states.find(kSsrc2), initial_states.end());
309}
310
Sebastian Jansson63470292019-02-01 10:13:43 +0100311TEST(RtpVideoSenderTest, CreateWithPreviousStates) {
philipel25d31ec2018-08-08 16:33:01 +0200312 const int64_t kState1SharedFrameId = 123;
313 const int64_t kState2SharedFrameId = 234;
Åsa Persson4bece9a2017-10-06 10:04:04 +0200314 RtpPayloadState state1;
315 state1.picture_id = kInitialPictureId1;
Niels Möllerbb894ff2018-03-15 12:28:53 +0100316 state1.tl0_pic_idx = kInitialTl0PicIdx1;
philipel25d31ec2018-08-08 16:33:01 +0200317 state1.shared_frame_id = kState1SharedFrameId;
Åsa Persson4bece9a2017-10-06 10:04:04 +0200318 RtpPayloadState state2;
319 state2.picture_id = kInitialPictureId2;
Niels Möllerbb894ff2018-03-15 12:28:53 +0100320 state2.tl0_pic_idx = kInitialTl0PicIdx2;
philipel25d31ec2018-08-08 16:33:01 +0200321 state2.shared_frame_id = kState2SharedFrameId;
Åsa Persson4bece9a2017-10-06 10:04:04 +0200322 std::map<uint32_t, RtpPayloadState> states = {{kSsrc1, state1},
323 {kSsrc2, state2}};
324
Erik Språng490d76c2019-05-07 09:29:15 -0700325 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
326 kPayloadType, states);
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200327 test.router()->SetActive(true);
Åsa Persson4bece9a2017-10-06 10:04:04 +0200328
329 std::map<uint32_t, RtpPayloadState> initial_states =
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200330 test.router()->GetRtpPayloadStates();
Åsa Persson4bece9a2017-10-06 10:04:04 +0200331 EXPECT_EQ(2u, initial_states.size());
332 EXPECT_EQ(kInitialPictureId1, initial_states[kSsrc1].picture_id);
Niels Möllerbb894ff2018-03-15 12:28:53 +0100333 EXPECT_EQ(kInitialTl0PicIdx1, initial_states[kSsrc1].tl0_pic_idx);
Åsa Persson4bece9a2017-10-06 10:04:04 +0200334 EXPECT_EQ(kInitialPictureId2, initial_states[kSsrc2].picture_id);
Niels Möllerbb894ff2018-03-15 12:28:53 +0100335 EXPECT_EQ(kInitialTl0PicIdx2, initial_states[kSsrc2].tl0_pic_idx);
philipel25d31ec2018-08-08 16:33:01 +0200336 EXPECT_EQ(kState2SharedFrameId, initial_states[kSsrc1].shared_frame_id);
337 EXPECT_EQ(kState2SharedFrameId, initial_states[kSsrc2].shared_frame_id);
Åsa Persson4bece9a2017-10-06 10:04:04 +0200338}
Niels Möller949f0fd2019-01-29 09:44:24 +0100339
Sebastian Jansson63470292019-02-01 10:13:43 +0100340TEST(RtpVideoSenderTest, FrameCountCallbacks) {
Niels Möller949f0fd2019-01-29 09:44:24 +0100341 class MockFrameCountObserver : public FrameCountObserver {
342 public:
343 MOCK_METHOD2(FrameCountUpdated,
344 void(const FrameCounts& frame_counts, uint32_t ssrc));
345 } callback;
346
Erik Språng490d76c2019-05-07 09:29:15 -0700347 RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {},
348 &callback);
Niels Möller949f0fd2019-01-29 09:44:24 +0100349
Niels Möller663844d2019-02-14 16:15:54 +0100350 constexpr uint8_t kPayload = 'a';
Niels Möller949f0fd2019-01-29 09:44:24 +0100351 EncodedImage encoded_image;
352 encoded_image.SetTimestamp(1);
353 encoded_image.capture_time_ms_ = 2;
Niels Möller8f7ce222019-03-21 15:43:58 +0100354 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 15:56:56 +0200355 encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
Niels Möller949f0fd2019-01-29 09:44:24 +0100356
Niels Möller8f7ce222019-03-21 15:43:58 +0100357 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller949f0fd2019-01-29 09:44:24 +0100358
359 // No callbacks when not active.
360 EXPECT_CALL(callback, FrameCountUpdated).Times(0);
361 EXPECT_NE(
362 EncodedImageCallback::Result::OK,
363 test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200364 ::testing::Mock::VerifyAndClearExpectations(&callback);
Niels Möller949f0fd2019-01-29 09:44:24 +0100365
366 test.router()->SetActive(true);
367
368 FrameCounts frame_counts;
369 EXPECT_CALL(callback, FrameCountUpdated(_, kSsrc1))
370 .WillOnce(SaveArg<0>(&frame_counts));
371 EXPECT_EQ(
372 EncodedImageCallback::Result::OK,
373 test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
374
375 EXPECT_EQ(1, frame_counts.key_frames);
376 EXPECT_EQ(0, frame_counts.delta_frames);
377
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200378 ::testing::Mock::VerifyAndClearExpectations(&callback);
Niels Möller949f0fd2019-01-29 09:44:24 +0100379
Niels Möller8f7ce222019-03-21 15:43:58 +0100380 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
Niels Möller949f0fd2019-01-29 09:44:24 +0100381 EXPECT_CALL(callback, FrameCountUpdated(_, kSsrc1))
382 .WillOnce(SaveArg<0>(&frame_counts));
383 EXPECT_EQ(
384 EncodedImageCallback::Result::OK,
385 test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
386
387 EXPECT_EQ(1, frame_counts.key_frames);
388 EXPECT_EQ(1, frame_counts.delta_frames);
389}
390
Erik Språng490d76c2019-05-07 09:29:15 -0700391// Integration test verifying that ack of packet via TransportFeedback means
Erik Språng845c6aa2019-05-29 13:02:24 +0200392// that the packet is removed from RtpPacketHistory and won't be retransmitted
Erik Språng490d76c2019-05-07 09:29:15 -0700393// again.
394TEST(RtpVideoSenderTest, DoesNotRetrasmitAckedPackets) {
395 const int64_t kTimeoutMs = 500;
396
397 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
398 kPayloadType, {});
399 test.router()->SetActive(true);
400
401 constexpr uint8_t kPayload = 'a';
402 EncodedImage encoded_image;
403 encoded_image.SetTimestamp(1);
404 encoded_image.capture_time_ms_ = 2;
405 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 15:56:56 +0200406 encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
Erik Språng490d76c2019-05-07 09:29:15 -0700407
408 // Send two tiny images, mapping to two RTP packets. Capture sequence numbers.
409 rtc::Event event;
410 std::vector<uint16_t> rtp_sequence_numbers;
411 std::vector<uint16_t> transport_sequence_numbers;
412 EXPECT_CALL(test.transport(), SendRtp)
413 .Times(2)
414 .WillRepeatedly(
415 [&event, &rtp_sequence_numbers, &transport_sequence_numbers](
416 const uint8_t* packet, size_t length,
417 const PacketOptions& options) {
418 RtpPacket rtp_packet;
419 EXPECT_TRUE(rtp_packet.Parse(packet, length));
420 rtp_sequence_numbers.push_back(rtp_packet.SequenceNumber());
421 transport_sequence_numbers.push_back(options.packet_id);
422 if (transport_sequence_numbers.size() == 2) {
423 event.Set();
424 }
425 return true;
426 });
427 EXPECT_EQ(
428 EncodedImageCallback::Result::OK,
429 test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
430 encoded_image.SetTimestamp(2);
431 encoded_image.capture_time_ms_ = 3;
432 EXPECT_EQ(
433 EncodedImageCallback::Result::OK,
434 test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
Erik Språngbd7046c2019-05-07 14:54:29 -0700435
Erik Språng00cc8362019-11-25 12:21:46 +0100436 test.AdvanceTime(TimeDelta::ms(33));
Erik Språng490d76c2019-05-07 09:29:15 -0700437
438 ASSERT_TRUE(event.Wait(kTimeoutMs));
439
440 // Construct a NACK message for requesting retransmission of both packet.
441 rtcp::Nack nack;
442 nack.SetMediaSsrc(kSsrc1);
443 nack.SetPacketIds(rtp_sequence_numbers);
444 rtc::Buffer nack_buffer = nack.Build();
445
446 std::vector<uint16_t> retransmitted_rtp_sequence_numbers;
447 EXPECT_CALL(test.transport(), SendRtp)
448 .Times(2)
449 .WillRepeatedly([&event, &retransmitted_rtp_sequence_numbers](
450 const uint8_t* packet, size_t length,
451 const PacketOptions& options) {
452 RtpPacket rtp_packet;
453 EXPECT_TRUE(rtp_packet.Parse(packet, length));
454 EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
455 // Capture the retransmitted sequence number from the RTX header.
456 rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
457 retransmitted_rtp_sequence_numbers.push_back(
458 ByteReader<uint16_t>::ReadBigEndian(payload.data()));
459 if (retransmitted_rtp_sequence_numbers.size() == 2) {
460 event.Set();
461 }
462 return true;
463 });
464 test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
Erik Språng00cc8362019-11-25 12:21:46 +0100465 test.AdvanceTime(TimeDelta::ms(33));
Erik Språng490d76c2019-05-07 09:29:15 -0700466 ASSERT_TRUE(event.Wait(kTimeoutMs));
467
468 // Verify that both packets were retransmitted.
469 EXPECT_EQ(retransmitted_rtp_sequence_numbers, rtp_sequence_numbers);
470
471 // Simulate transport feedback indicating fist packet received, next packet
Erik Språng00cc8362019-11-25 12:21:46 +0100472 // lost (not other way around as that would trigger early retransmit).
Sebastian Janssonf2988552019-10-29 17:18:51 +0100473 StreamFeedbackObserver::StreamPacketInfo lost_packet_feedback;
Erik Språng00cc8362019-11-25 12:21:46 +0100474 lost_packet_feedback.rtp_sequence_number = rtp_sequence_numbers[0];
Erik Språng490d76c2019-05-07 09:29:15 -0700475 lost_packet_feedback.ssrc = kSsrc1;
Sebastian Janssonf2988552019-10-29 17:18:51 +0100476 lost_packet_feedback.received = false;
Erik Språng490d76c2019-05-07 09:29:15 -0700477
Erik Språng00cc8362019-11-25 12:21:46 +0100478 StreamFeedbackObserver::StreamPacketInfo received_packet_feedback;
479 received_packet_feedback.rtp_sequence_number = rtp_sequence_numbers[1];
480 received_packet_feedback.ssrc = kSsrc1;
481 received_packet_feedback.received = true;
482
Sebastian Janssonf2988552019-10-29 17:18:51 +0100483 test.router()->OnPacketFeedbackVector(
Erik Språng00cc8362019-11-25 12:21:46 +0100484 {lost_packet_feedback, received_packet_feedback});
Erik Språng490d76c2019-05-07 09:29:15 -0700485
486 // Advance time to make sure retransmission would be allowed and try again.
487 // This time the retransmission should not happen for the first packet since
488 // the history has been notified of the ack and removed the packet. The
489 // second packet, included in the feedback but not marked as received, should
490 // still be retransmitted.
Erik Språng00cc8362019-11-25 12:21:46 +0100491 test.AdvanceTime(TimeDelta::ms(33));
Erik Språng490d76c2019-05-07 09:29:15 -0700492 EXPECT_CALL(test.transport(), SendRtp)
493 .WillOnce([&event, &lost_packet_feedback](const uint8_t* packet,
494 size_t length,
495 const PacketOptions& options) {
496 RtpPacket rtp_packet;
497 EXPECT_TRUE(rtp_packet.Parse(packet, length));
498 EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
499 // Capture the retransmitted sequence number from the RTX header.
500 rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
501 EXPECT_EQ(lost_packet_feedback.rtp_sequence_number,
502 ByteReader<uint16_t>::ReadBigEndian(payload.data()));
503 event.Set();
504 return true;
505 });
506 test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
Erik Språng00cc8362019-11-25 12:21:46 +0100507 test.AdvanceTime(TimeDelta::ms(33));
Erik Språng490d76c2019-05-07 09:29:15 -0700508 ASSERT_TRUE(event.Wait(kTimeoutMs));
509}
Erik Språng845c6aa2019-05-29 13:02:24 +0200510
Sebastian Jansson3d4d94a2020-01-14 14:25:41 +0100511// This tests that we utilize transport wide feedback to retransmit lost
512// packets. This is tested by dropping all ordirary packets from a "lossy"
513// stream send along with an secondary untouched stream. The transport wide
514// feedback packets from the secondary stream allows the sending side to
515// detect and retreansmit the lost packets from the lossy stream.
516TEST(RtpVideoSenderTest, RetransmitsOnTransportWideLossInfo) {
517 int rtx_packets;
518 test::Scenario s(test_info_);
519 test::CallClientConfig call_conf;
520 // Keeping the bitrate fixed to avoid RTX due to probing.
521 call_conf.transport.rates.max_rate = DataRate::kbps(300);
522 call_conf.transport.rates.start_rate = DataRate::kbps(300);
523 test::NetworkSimulationConfig net_conf;
524 net_conf.bandwidth = DataRate::kbps(300);
525 auto send_node = s.CreateSimulationNode(net_conf);
526 auto* route = s.CreateRoutes(s.CreateClient("send", call_conf), {send_node},
527 s.CreateClient("return", call_conf),
528 {s.CreateSimulationNode(net_conf)});
529
530 test::VideoStreamConfig lossy_config;
531 lossy_config.source.framerate = 5;
532 auto* lossy = s.CreateVideoStream(route->forward(), lossy_config);
533 // The secondary stream acts a driver for transport feedback messages,
534 // ensuring that lost packets on the lossy stream are retransmitted.
535 s.CreateVideoStream(route->forward(), test::VideoStreamConfig());
536
537 send_node->router()->SetFilter([&](const EmulatedIpPacket& packet) {
538 RtpPacket rtp;
539 if (rtp.Parse(packet.data)) {
540 // Drops all regular packets for the lossy stream and counts all RTX
541 // packets. Since no packets are let trough, NACKs can't be triggered
542 // by the receiving side.
543 if (lossy->send()->UsingSsrc(rtp.Ssrc())) {
544 return false;
545 } else if (lossy->send()->UsingRtxSsrc(rtp.Ssrc())) {
546 ++rtx_packets;
547 }
548 }
549 return true;
550 });
551
552 // Run for a short duration and reset counters to avoid counting RTX packets
553 // from initial probing.
554 s.RunFor(TimeDelta::seconds(1));
555 rtx_packets = 0;
556 int decoded_baseline = lossy->receive()->GetStats().frames_decoded;
557 s.RunFor(TimeDelta::seconds(1));
558 // We expect both that RTX packets were sent and that an appropriate number of
559 // frames were received. This is somewhat redundant but reduces the risk of
560 // false positives in future regressions (e.g. RTX is send due to probing).
561 EXPECT_GE(rtx_packets, 1);
562 int frames_decoded =
563 lossy->receive()->GetStats().frames_decoded - decoded_baseline;
564 EXPECT_EQ(frames_decoded, 5);
565}
566
Erik Språng845c6aa2019-05-29 13:02:24 +0200567// Integration test verifying that retransmissions are sent for packets which
568// can be detected as lost early, using transport wide feedback.
569TEST(RtpVideoSenderTest, EarlyRetransmits) {
570 const int64_t kTimeoutMs = 500;
571
572 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
573 kPayloadType, {});
574 test.router()->SetActive(true);
575
Niels Möllerb9bfe652019-10-03 08:43:53 +0200576 const uint8_t kPayload[1] = {'a'};
Erik Språng845c6aa2019-05-29 13:02:24 +0200577 EncodedImage encoded_image;
578 encoded_image.SetTimestamp(1);
579 encoded_image.capture_time_ms_ = 2;
580 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möllerb9bfe652019-10-03 08:43:53 +0200581 encoded_image.SetEncodedData(
582 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
Erik Språng845c6aa2019-05-29 13:02:24 +0200583 encoded_image.SetSpatialIndex(0);
584
585 CodecSpecificInfo codec_specific;
586 codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
587
588 // Send two tiny images, mapping to single RTP packets. Capture sequence
589 // numbers.
590 rtc::Event event;
591 uint16_t frame1_rtp_sequence_number = 0;
592 uint16_t frame1_transport_sequence_number = 0;
593 EXPECT_CALL(test.transport(), SendRtp)
594 .WillOnce([&event, &frame1_rtp_sequence_number,
595 &frame1_transport_sequence_number](
596 const uint8_t* packet, size_t length,
597 const PacketOptions& options) {
598 RtpPacket rtp_packet;
599 EXPECT_TRUE(rtp_packet.Parse(packet, length));
600 frame1_rtp_sequence_number = rtp_packet.SequenceNumber();
601 frame1_transport_sequence_number = options.packet_id;
602 EXPECT_EQ(rtp_packet.Ssrc(), kSsrc1);
603 event.Set();
604 return true;
605 });
606 EXPECT_EQ(test.router()
607 ->OnEncodedImage(encoded_image, &codec_specific, nullptr)
608 .error,
609 EncodedImageCallback::Result::OK);
Erik Språng845c6aa2019-05-29 13:02:24 +0200610
Erik Språng00cc8362019-11-25 12:21:46 +0100611 test.AdvanceTime(TimeDelta::ms(33));
Erik Språng845c6aa2019-05-29 13:02:24 +0200612 ASSERT_TRUE(event.Wait(kTimeoutMs));
613
614 uint16_t frame2_rtp_sequence_number = 0;
615 uint16_t frame2_transport_sequence_number = 0;
616 encoded_image.SetSpatialIndex(1);
617 EXPECT_CALL(test.transport(), SendRtp)
618 .WillOnce([&event, &frame2_rtp_sequence_number,
619 &frame2_transport_sequence_number](
620 const uint8_t* packet, size_t length,
621 const PacketOptions& options) {
622 RtpPacket rtp_packet;
623 EXPECT_TRUE(rtp_packet.Parse(packet, length));
624 frame2_rtp_sequence_number = rtp_packet.SequenceNumber();
625 frame2_transport_sequence_number = options.packet_id;
626 EXPECT_EQ(rtp_packet.Ssrc(), kSsrc2);
627 event.Set();
628 return true;
629 });
630 EXPECT_EQ(test.router()
631 ->OnEncodedImage(encoded_image, &codec_specific, nullptr)
632 .error,
633 EncodedImageCallback::Result::OK);
Erik Språng00cc8362019-11-25 12:21:46 +0100634 test.AdvanceTime(TimeDelta::ms(33));
Erik Språng845c6aa2019-05-29 13:02:24 +0200635 ASSERT_TRUE(event.Wait(kTimeoutMs));
636
637 EXPECT_NE(frame1_transport_sequence_number, frame2_transport_sequence_number);
638
639 // Inject a transport feedback where the packet for the first frame is lost,
640 // expect a retransmission for it.
641 EXPECT_CALL(test.transport(), SendRtp)
642 .WillOnce([&event, &frame1_rtp_sequence_number](
643 const uint8_t* packet, size_t length,
644 const PacketOptions& options) {
645 RtpPacket rtp_packet;
646 EXPECT_TRUE(rtp_packet.Parse(packet, length));
Sebastian Janssonf2988552019-10-29 17:18:51 +0100647 EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
Erik Språng845c6aa2019-05-29 13:02:24 +0200648
649 // Retransmitted sequence number from the RTX header should match
650 // the lost packet.
651 rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
652 EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(payload.data()),
653 frame1_rtp_sequence_number);
654 event.Set();
655 return true;
656 });
657
Sebastian Janssonf2988552019-10-29 17:18:51 +0100658 StreamFeedbackObserver::StreamPacketInfo first_packet_feedback;
Erik Språng845c6aa2019-05-29 13:02:24 +0200659 first_packet_feedback.rtp_sequence_number = frame1_rtp_sequence_number;
660 first_packet_feedback.ssrc = kSsrc1;
Sebastian Janssonf2988552019-10-29 17:18:51 +0100661 first_packet_feedback.received = false;
Erik Språng845c6aa2019-05-29 13:02:24 +0200662
Sebastian Janssonf2988552019-10-29 17:18:51 +0100663 StreamFeedbackObserver::StreamPacketInfo second_packet_feedback;
664 second_packet_feedback.rtp_sequence_number = frame2_rtp_sequence_number;
665 second_packet_feedback.ssrc = kSsrc2;
666 second_packet_feedback.received = true;
Erik Språng845c6aa2019-05-29 13:02:24 +0200667
Sebastian Janssonf2988552019-10-29 17:18:51 +0100668 test.router()->OnPacketFeedbackVector(
669 {first_packet_feedback, second_packet_feedback});
Erik Språng845c6aa2019-05-29 13:02:24 +0200670
671 // Wait for pacer to run and send the RTX packet.
Erik Språng00cc8362019-11-25 12:21:46 +0100672 test.AdvanceTime(TimeDelta::ms(33));
Erik Språng845c6aa2019-05-29 13:02:24 +0200673 ASSERT_TRUE(event.Wait(kTimeoutMs));
674}
Sebastian Janssoncf41eb12019-06-10 11:30:59 +0200675
676TEST(RtpVideoSenderTest, CanSetZeroBitrateWithOverhead) {
677 test::ScopedFieldTrials trials("WebRTC-SendSideBwe-WithOverhead/Enabled/");
678 RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {});
Sebastian Jansson82ed2e82019-10-15 15:58:37 +0200679 BitrateAllocationUpdate update;
680 update.target_bitrate = DataRate::Zero();
681 update.packet_loss_ratio = 0;
682 update.round_trip_time = TimeDelta::Zero();
Sebastian Janssoncf41eb12019-06-10 11:30:59 +0200683
Sebastian Jansson82ed2e82019-10-15 15:58:37 +0200684 test.router()->OnBitrateUpdated(update, /*framerate*/ 0);
Sebastian Janssoncf41eb12019-06-10 11:30:59 +0200685}
686
687TEST(RtpVideoSenderTest, CanSetZeroBitrateWithoutOverhead) {
688 RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {});
689
Sebastian Jansson82ed2e82019-10-15 15:58:37 +0200690 BitrateAllocationUpdate update;
691 update.target_bitrate = DataRate::Zero();
692 update.packet_loss_ratio = 0;
693 update.round_trip_time = TimeDelta::Zero();
694
695 test.router()->OnBitrateUpdated(update, /*framerate*/ 0);
Sebastian Janssoncf41eb12019-06-10 11:30:59 +0200696}
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000697} // namespace webrtc