blob: b35b332fbf3869c96dbca0d43ecbd475ea5db80f [file] [log] [blame]
mflodman@webrtc.org02270cd2015-02-06 13:10:191/*
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 17:08:3311#include "call/rtp_video_sender.h"
12
Harald Alvestrand93c9aa12024-09-02 20:55:5213#include <cstddef>
14#include <cstdint>
15#include <map>
kwiberg27f982b2016-03-01 19:52:3316#include <memory>
Harald Alvestrand93c9aa12024-09-02 20:55:5217#include <optional>
18#include <vector>
Sebastian Jansson3d4d94a2020-01-14 13:25:4119
Harald Alvestrand93c9aa12024-09-02 20:55:5220#include "api/array_view.h"
21#include "api/call/bitrate_allocation.h"
22#include "api/call/transport.h"
23#include "api/crypto/crypto_options.h"
Danil Chapovalovee27f382023-12-18 12:09:1224#include "api/environment/environment.h"
25#include "api/environment/environment_factory.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5226#include "api/frame_transformer_interface.h"
27#include "api/make_ref_counted.h"
28#include "api/rtp_parameters.h"
29#include "api/scoped_refptr.h"
Tony Herre9c6874602024-01-26 10:16:4530#include "api/test/mock_frame_transformer.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5231#include "api/test/network_emulation/network_emulation_interfaces.h"
32#include "api/transport/bitrate_settings.h"
33#include "api/transport/rtp/dependency_descriptor.h"
34#include "api/units/data_rate.h"
35#include "api/units/data_size.h"
36#include "api/units/time_delta.h"
37#include "api/units/timestamp.h"
38#include "api/video/encoded_image.h"
39#include "api/video/video_codec_type.h"
40#include "api/video/video_frame_type.h"
41#include "api/video_codecs/video_encoder.h"
42#include "call/rtp_config.h"
43#include "call/rtp_transport_config.h"
Stefan Holmerdbdb3a02018-07-17 14:03:4644#include "call/rtp_transport_controller_send.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5245#include "call/rtp_transport_controller_send_interface.h"
46#include "call/video_send_stream.h"
47#include "common_video/frame_counts.h"
48#include "common_video/generic_frame_descriptor/generic_frame_info.h"
49#include "modules/rtp_rtcp/include/report_block_data.h"
50#include "modules/rtp_rtcp/include/rtcp_statistics.h"
51#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
Erik Språng490d76c2019-05-07 16:29:1552#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
53#include "modules/rtp_rtcp/source/byte_io.h"
54#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
Danil Chapovalov2272f202020-02-18 11:09:4355#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
Erik Språng490d76c2019-05-07 16:29:1556#include "modules/rtp_rtcp/source/rtp_packet.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5257#include "modules/rtp_rtcp/source/rtp_sender_video.h"
58#include "modules/video_coding/codecs/interface/common_constants.h"
Stefan Holmer64be7fa2018-10-04 13:21:5559#include "modules/video_coding/fec_controller_default.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3160#include "modules/video_coding/include/video_codec_interface.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5261#include "rtc_base/buffer.h"
Stefan Holmerdbdb3a02018-07-17 14:03:4662#include "rtc_base/rate_limiter.h"
philipel626edea2024-03-19 08:38:0163#include "test/explicit_key_value_config.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3164#include "test/gmock.h"
65#include "test/gtest.h"
Stefan Holmerdbdb3a02018-07-17 14:03:4666#include "test/mock_transport.h"
Sebastian Jansson3d4d94a2020-01-14 13:25:4167#include "test/scenario/scenario.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5268#include "test/scenario/scenario_config.h"
Jonas Orelandc7f691a2022-03-09 14:12:0769#include "test/scoped_key_value_config.h"
Erik Språng00cc8362019-11-25 11:21:4670#include "test/time_controller/simulated_time_controller.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5271#include "video/config/video_encoder_config.h"
Stefan Holmerdbdb3a02018-07-17 14:03:4672#include "video/send_statistics_proxy.h"
mflodman@webrtc.org02270cd2015-02-06 13:10:1973
Emil Lundmark6c81a422022-05-18 15:13:3474namespace webrtc {
75namespace {
76
mflodman@webrtc.org02270cd2015-02-06 13:10:1977using ::testing::_;
Danil Chapovalov0f027282024-09-24 09:22:5578using ::testing::Ge;
79using ::testing::IsEmpty;
Brennan Waters51fccaf2024-10-16 19:04:2380using ::testing::IsNull;
mflodman@webrtc.org02270cd2015-02-06 13:10:1981using ::testing::NiceMock;
Brennan Waters51fccaf2024-10-16 19:04:2382using ::testing::NotNull;
Niels Möller949f0fd2019-01-29 08:44:2483using ::testing::SaveArg;
Danil Chapovalov2272f202020-02-18 11:09:4384using ::testing::SizeIs;
mflodman@webrtc.org02270cd2015-02-06 13:10:1985
Åsa Persson4bece9a2017-10-06 08:04:0486const int8_t kPayloadType = 96;
87const uint32_t kSsrc1 = 12345;
88const uint32_t kSsrc2 = 23456;
Erik Språng490d76c2019-05-07 16:29:1589const uint32_t kRtxSsrc1 = 34567;
90const uint32_t kRtxSsrc2 = 45678;
Åsa Persson4bece9a2017-10-06 08:04:0491const int16_t kInitialPictureId1 = 222;
92const int16_t kInitialPictureId2 = 44;
Niels Möllerbb894ff2018-03-15 11:28:5393const int16_t kInitialTl0PicIdx1 = 99;
94const int16_t kInitialTl0PicIdx2 = 199;
Stefan Holmerdbdb3a02018-07-17 14:03:4695const int64_t kRetransmitWindowSizeMs = 500;
Erik Språng845c6aa2019-05-29 11:02:2496const int kTransportsSequenceExtensionId = 7;
Danil Chapovalov2272f202020-02-18 11:09:4397const int kDependencyDescriptorExtensionId = 8;
Stefan Holmerdbdb3a02018-07-17 14:03:4698
99class MockRtcpIntraFrameObserver : public RtcpIntraFrameObserver {
100 public:
Danil Chapovalov9a5efe92020-05-14 20:06:18101 MOCK_METHOD(void, OnReceivedIntraFrameRequest, (uint32_t), (override));
Stefan Holmerdbdb3a02018-07-17 14:03:46102};
103
Stefan Holmerdbdb3a02018-07-17 14:03:46104RtpSenderObservers CreateObservers(
Stefan Holmerdbdb3a02018-07-17 14:03:46105 RtcpIntraFrameObserver* intra_frame_callback,
Henrik Boström87e3f9d2019-05-27 08:44:24106 ReportBlockDataObserver* report_block_data_observer,
Stefan Holmerdbdb3a02018-07-17 14:03:46107 StreamDataCountersCallback* rtp_stats,
108 BitrateStatisticsObserver* bitrate_observer,
109 FrameCountObserver* frame_count_observer,
Danil Chapovalov3aa951a2023-09-13 16:06:58110 RtcpPacketTypeCounterObserver* rtcp_type_observer) {
Stefan Holmerdbdb3a02018-07-17 14:03:46111 RtpSenderObservers observers;
Danil Chapovalov46882572023-09-08 14:58:16112 observers.rtcp_rtt_stats = nullptr;
Stefan Holmerdbdb3a02018-07-17 14:03:46113 observers.intra_frame_callback = intra_frame_callback;
Erik Språng490d76c2019-05-07 16:29:15114 observers.rtcp_loss_notification_observer = nullptr;
Henrik Boström87e3f9d2019-05-27 08:44:24115 observers.report_block_data_observer = report_block_data_observer;
Stefan Holmerdbdb3a02018-07-17 14:03:46116 observers.rtp_stats = rtp_stats;
117 observers.bitrate_observer = bitrate_observer;
118 observers.frame_count_observer = frame_count_observer;
119 observers.rtcp_type_observer = rtcp_type_observer;
Danil Chapovalov46882572023-09-08 14:58:16120 observers.send_packet_observer = nullptr;
Stefan Holmerdbdb3a02018-07-17 14:03:46121 return observers;
122}
123
Erik Språng490d76c2019-05-07 16:29:15124BitrateConstraints GetBitrateConfig() {
125 BitrateConstraints bitrate_config;
126 bitrate_config.min_bitrate_bps = 30000;
127 bitrate_config.start_bitrate_bps = 300000;
128 bitrate_config.max_bitrate_bps = 3000000;
129 return bitrate_config;
130}
131
132VideoSendStream::Config CreateVideoSendStreamConfig(
133 Transport* transport,
134 const std::vector<uint32_t>& ssrcs,
135 const std::vector<uint32_t>& rtx_ssrcs,
Jeremy Lecontef95278f2024-10-09 16:11:17136 int payload_type) {
Erik Språng490d76c2019-05-07 16:29:15137 VideoSendStream::Config config(transport);
138 config.rtp.ssrcs = ssrcs;
139 config.rtp.rtx.ssrcs = rtx_ssrcs;
140 config.rtp.payload_type = payload_type;
141 config.rtp.rtx.payload_type = payload_type + 1;
142 config.rtp.nack.rtp_history_ms = 1000;
Erik Språng845c6aa2019-05-29 11:02:24143 config.rtp.extensions.emplace_back(RtpExtension::kTransportSequenceNumberUri,
144 kTransportsSequenceExtensionId);
Danil Chapovalovd0321c52021-09-14 10:58:51145 config.rtp.extensions.emplace_back(RtpDependencyDescriptorExtension::Uri(),
Danil Chapovalov2272f202020-02-18 11:09:43146 kDependencyDescriptorExtensionId);
Danil Chapovalov748550d2021-04-29 09:42:54147 config.rtp.extmap_allow_mixed = true;
Erik Språng490d76c2019-05-07 16:29:15148 return config;
149}
150
Stefan Holmer9416ef82018-07-19 08:34:38151class RtpVideoSenderTestFixture {
Stefan Holmerdbdb3a02018-07-17 14:03:46152 public:
Stefan Holmer9416ef82018-07-19 08:34:38153 RtpVideoSenderTestFixture(
Stefan Holmerdbdb3a02018-07-17 14:03:46154 const std::vector<uint32_t>& ssrcs,
Erik Språng490d76c2019-05-07 16:29:15155 const std::vector<uint32_t>& rtx_ssrcs,
Stefan Holmerdbdb3a02018-07-17 14:03:46156 int payload_type,
Niels Möller949f0fd2019-01-29 08:44:24157 const std::map<uint32_t, RtpPayloadState>& suspended_payload_states,
Marina Cioceadc69fd22020-04-10 18:19:14158 FrameCountObserver* frame_count_observer,
Jonas Orelandc7f691a2022-03-09 14:12:07159 rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
Jonas Orelande62c2f22022-03-29 09:04:48160 const FieldTrialsView* field_trials = nullptr)
Danil Chapovalov0c626af2020-02-10 10:16:00161 : time_controller_(Timestamp::Millis(1000000)),
Danil Chapovalovee27f382023-12-18 12:09:12162 env_(CreateEnvironment(&field_trials_,
163 field_trials,
164 time_controller_.GetClock(),
165 time_controller_.CreateTaskQueueFactory())),
Erik Språng490d76c2019-05-07 16:29:15166 config_(CreateVideoSendStreamConfig(&transport_,
167 ssrcs,
168 rtx_ssrcs,
Jeremy Lecontef95278f2024-10-09 16:11:17169 payload_type)),
Erik Språng490d76c2019-05-07 16:29:15170 bitrate_config_(GetBitrateConfig()),
Henrik Boströmda4c1022022-11-15 14:45:41171 transport_controller_(
Danil Chapovalovee27f382023-12-18 12:09:12172 RtpTransportConfig{.env = env_, .bitrate_config = bitrate_config_}),
Erik Språng00cc8362019-11-25 11:21:46173 stats_proxy_(time_controller_.GetClock(),
Stefan Holmerdbdb3a02018-07-17 14:03:46174 config_,
Jonas Oreland8ca06132022-03-14 11:52:48175 VideoEncoderConfig::ContentType::kRealtimeVideo,
Danil Chapovalovee27f382023-12-18 12:09:12176 env_.field_trials()),
Erik Språng00cc8362019-11-25 11:21:46177 retransmission_rate_limiter_(time_controller_.GetClock(),
178 kRetransmitWindowSizeMs) {
Erik Språng7703f232020-09-14 09:03:13179 transport_controller_.EnsureStarted();
Mirko Bonadeif18f9202019-12-10 13:24:56180 std::map<uint32_t, RtpState> suspended_ssrcs;
181 router_ = std::make_unique<RtpVideoSender>(
Danil Chapovalov0f027282024-09-24 09:22:55182 env_, time_controller_.GetMainThread(), suspended_ssrcs,
183 suspended_payload_states, config_.rtp, config_.rtcp_report_interval_ms,
184 &transport_,
Danil Chapovalov46882572023-09-08 14:58:16185 CreateObservers(&encoder_feedback_, &stats_proxy_, &stats_proxy_,
Danil Chapovalov3aa951a2023-09-13 16:06:58186 &stats_proxy_, frame_count_observer, &stats_proxy_),
Xinyu Ma954fdb02024-07-26 22:09:09187 &transport_controller_, &retransmission_rate_limiter_,
Danil Chapovalov1d6bf312024-01-09 10:46:59188 std::make_unique<FecControllerDefault>(env_), nullptr, CryptoOptions{},
Xinyu Ma954fdb02024-07-26 22:09:09189 frame_transformer);
Stefan Holmerdbdb3a02018-07-17 14:03:46190 }
Marina Cioceadc69fd22020-04-10 18:19:14191
192 RtpVideoSenderTestFixture(
193 const std::vector<uint32_t>& ssrcs,
194 const std::vector<uint32_t>& rtx_ssrcs,
195 int payload_type,
196 const std::map<uint32_t, RtpPayloadState>& suspended_payload_states,
Jonas Orelandc7f691a2022-03-09 14:12:07197 FrameCountObserver* frame_count_observer,
Jonas Orelande62c2f22022-03-29 09:04:48198 const FieldTrialsView* field_trials = nullptr)
Marina Cioceadc69fd22020-04-10 18:19:14199 : RtpVideoSenderTestFixture(ssrcs,
200 rtx_ssrcs,
201 payload_type,
202 suspended_payload_states,
203 frame_count_observer,
Jonas Orelandc7f691a2022-03-09 14:12:07204 /*frame_transformer=*/nullptr,
205 field_trials) {}
Marina Cioceadc69fd22020-04-10 18:19:14206
Niels Möller949f0fd2019-01-29 08:44:24207 RtpVideoSenderTestFixture(
208 const std::vector<uint32_t>& ssrcs,
Erik Språng490d76c2019-05-07 16:29:15209 const std::vector<uint32_t>& rtx_ssrcs,
Niels Möller949f0fd2019-01-29 08:44:24210 int payload_type,
Jonas Orelandc7f691a2022-03-09 14:12:07211 const std::map<uint32_t, RtpPayloadState>& suspended_payload_states,
Jonas Orelande62c2f22022-03-29 09:04:48212 const FieldTrialsView* field_trials = nullptr)
Niels Möller949f0fd2019-01-29 08:44:24213 : RtpVideoSenderTestFixture(ssrcs,
Erik Språng490d76c2019-05-07 16:29:15214 rtx_ssrcs,
Niels Möller949f0fd2019-01-29 08:44:24215 payload_type,
216 suspended_payload_states,
Marina Cioceadc69fd22020-04-10 18:19:14217 /*frame_count_observer=*/nullptr,
Jonas Orelandc7f691a2022-03-09 14:12:07218 /*frame_transformer=*/nullptr,
219 field_trials) {}
Mirko Bonadeif18f9202019-12-10 13:24:56220
Per K979b6d62024-01-26 10:18:26221 ~RtpVideoSenderTestFixture() { SetSending(false); }
Tommi6fba6b72022-01-28 08:00:01222
Stefan Holmer9416ef82018-07-19 08:34:38223 RtpVideoSender* router() { return router_.get(); }
Erik Språng490d76c2019-05-07 16:29:15224 MockTransport& transport() { return transport_; }
Markus Handell486cc552019-12-03 13:37:28225 void AdvanceTime(TimeDelta delta) { time_controller_.AdvanceTime(delta); }
Stefan Holmerdbdb3a02018-07-17 14:03:46226
Per K979b6d62024-01-26 10:18:26227 void SetSending(bool sending) { router_->SetSending(sending); }
Tommi6fba6b72022-01-28 08:00:01228
Stefan Holmerdbdb3a02018-07-17 14:03:46229 private:
Jonas Orelandc7f691a2022-03-09 14:12:07230 test::ScopedKeyValueConfig field_trials_;
Stefan Holmerdbdb3a02018-07-17 14:03:46231 NiceMock<MockTransport> transport_;
Stefan Holmerdbdb3a02018-07-17 14:03:46232 NiceMock<MockRtcpIntraFrameObserver> encoder_feedback_;
Erik Språng00cc8362019-11-25 11:21:46233 GlobalSimulatedTimeController time_controller_;
Danil Chapovalovee27f382023-12-18 12:09:12234 Environment env_;
Stefan Holmerdbdb3a02018-07-17 14:03:46235 VideoSendStream::Config config_;
Stefan Holmerdbdb3a02018-07-17 14:03:46236 BitrateConstraints bitrate_config_;
237 RtpTransportControllerSend transport_controller_;
Stefan Holmerdbdb3a02018-07-17 14:03:46238 SendStatisticsProxy stats_proxy_;
239 RateLimiter retransmission_rate_limiter_;
Stefan Holmer9416ef82018-07-19 08:34:38240 std::unique_ptr<RtpVideoSender> router_;
Stefan Holmerdbdb3a02018-07-17 14:03:46241};
Jakob Ivarsson9a12ee52020-11-26 15:04:18242
243BitrateAllocationUpdate CreateBitrateAllocationUpdate(int target_bitrate_bps) {
244 BitrateAllocationUpdate update;
245 update.target_bitrate = DataRate::BitsPerSec(target_bitrate_bps);
246 update.round_trip_time = TimeDelta::Zero();
247 return update;
248}
249
Åsa Persson4bece9a2017-10-06 08:04:04250} // namespace
mflodman@webrtc.org02270cd2015-02-06 13:10:19251
Sebastian Jansson63470292019-02-01 09:13:43252TEST(RtpVideoSenderTest, SendOnOneModule) {
Niels Möller663844d2019-02-14 15:15:54253 constexpr uint8_t kPayload = 'a';
kjellander02b3d272016-04-20 12:05:54254 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:49255 encoded_image.SetRtpTimestamp(1);
kjellander02b3d272016-04-20 12:05:54256 encoded_image.capture_time_ms_ = 2;
Niels Möller8f7ce222019-03-21 14:43:58257 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 13:56:56258 encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
kjellander02b3d272016-04-20 12:05:54259
Erik Språng490d76c2019-05-07 16:29:15260 RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {});
Danil Chapovalov383f2cf2020-08-12 09:06:53261 EXPECT_NE(EncodedImageCallback::Result::OK,
262 test.router()->OnEncodedImage(encoded_image, nullptr).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19263
Per K979b6d62024-01-26 10:18:26264 test.SetSending(true);
Danil Chapovalov383f2cf2020-08-12 09:06:53265 EXPECT_EQ(EncodedImageCallback::Result::OK,
266 test.router()->OnEncodedImage(encoded_image, nullptr).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19267
Per K979b6d62024-01-26 10:18:26268 test.SetSending(false);
Danil Chapovalov383f2cf2020-08-12 09:06:53269 EXPECT_NE(EncodedImageCallback::Result::OK,
270 test.router()->OnEncodedImage(encoded_image, nullptr).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19271
Per K979b6d62024-01-26 10:18:26272 test.SetSending(true);
Danil Chapovalov383f2cf2020-08-12 09:06:53273 EXPECT_EQ(EncodedImageCallback::Result::OK,
274 test.router()->OnEncodedImage(encoded_image, nullptr).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19275}
276
Per K979b6d62024-01-26 10:18:26277TEST(RtpVideoSenderTest, OnEncodedImageReturnOkWhenSendingTrue) {
Niels Möller663844d2019-02-14 15:15:54278 constexpr uint8_t kPayload = 'a';
Niels Möllerd3b8c632018-08-27 13:33:42279 EncodedImage encoded_image_1;
Danil Chapovalov9c584832023-09-18 13:48:49280 encoded_image_1.SetRtpTimestamp(1);
Niels Möllerd3b8c632018-08-27 13:33:42281 encoded_image_1.capture_time_ms_ = 2;
Niels Möller8f7ce222019-03-21 14:43:58282 encoded_image_1._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 13:56:56283 encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
kjellander02b3d272016-04-20 12:05:54284
Erik Språng490d76c2019-05-07 16:29:15285 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
286 kPayloadType, {});
mflodman@webrtc.org02270cd2015-02-06 13:10:19287
Niels Möllerd3b8c632018-08-27 13:33:42288 CodecSpecificInfo codec_info;
Niels Möllerd3b8c632018-08-27 13:33:42289 codec_info.codecType = kVideoCodecVP8;
mflodman@webrtc.org02270cd2015-02-06 13:10:19290
Per K979b6d62024-01-26 10:18:26291 test.SetSending(true);
sergeyu2cb155a2016-11-04 18:39:29292 EXPECT_EQ(EncodedImageCallback::Result::OK,
Danil Chapovalov383f2cf2020-08-12 09:06:53293 test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19294
Niels Möllerd3b8c632018-08-27 13:33:42295 EncodedImage encoded_image_2(encoded_image_1);
Henrik Boström2e540a22023-02-15 13:48:09296 encoded_image_2.SetSimulcastIndex(1);
sergeyu2cb155a2016-11-04 18:39:29297 EXPECT_EQ(EncodedImageCallback::Result::OK,
Danil Chapovalov383f2cf2020-08-12 09:06:53298 test.router()->OnEncodedImage(encoded_image_2, &codec_info).error);
mflodman@webrtc.org02270cd2015-02-06 13:10:19299}
300
Per K979b6d62024-01-26 10:18:26301TEST(RtpVideoSenderTest, OnEncodedImageReturnErrorCodeWhenSendingFalse) {
Niels Möller663844d2019-02-14 15:15:54302 constexpr uint8_t kPayload = 'a';
Niels Möllerd3b8c632018-08-27 13:33:42303 EncodedImage encoded_image_1;
Danil Chapovalov9c584832023-09-18 13:48:49304 encoded_image_1.SetRtpTimestamp(1);
Niels Möllerd3b8c632018-08-27 13:33:42305 encoded_image_1.capture_time_ms_ = 2;
Niels Möller8f7ce222019-03-21 14:43:58306 encoded_image_1._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 13:56:56307 encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
Niels Möller77536a22019-01-15 07:50:01308
Niels Möllerd3b8c632018-08-27 13:33:42309 EncodedImage encoded_image_2(encoded_image_1);
Henrik Boström2e540a22023-02-15 13:48:09310 encoded_image_2.SetSimulcastIndex(1);
Stefan Holmerdbdb3a02018-07-17 14:03:46311
Erik Språng490d76c2019-05-07 16:29:15312 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
313 kPayloadType, {});
Niels Möllerd3b8c632018-08-27 13:33:42314 CodecSpecificInfo codec_info;
Niels Möllerd3b8c632018-08-27 13:33:42315 codec_info.codecType = kVideoCodecVP8;
Seth Hampsoncc7125f2018-02-02 16:46:16316
Per K979b6d62024-01-26 10:18:26317 // Setting rtp streams to inactive will turn the payload router to
Stefan Holmerdbdb3a02018-07-17 14:03:46318 // inactive.
Per K979b6d62024-01-26 10:18:26319 test.SetSending(false);
Seth Hampsoncc7125f2018-02-02 16:46:16320 // An incoming encoded image will not ask the module to send outgoing data
321 // because the payload router is inactive.
Seth Hampsoncc7125f2018-02-02 16:46:16322 EXPECT_NE(EncodedImageCallback::Result::OK,
Danil Chapovalov383f2cf2020-08-12 09:06:53323 test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
Seth Hampsoncc7125f2018-02-02 16:46:16324 EXPECT_NE(EncodedImageCallback::Result::OK,
Per K979b6d62024-01-26 10:18:26325 test.router()->OnEncodedImage(encoded_image_2, &codec_info).error);
Seth Hampsoncc7125f2018-02-02 16:46:16326}
327
Henrik Boström2e540a22023-02-15 13:48:09328TEST(RtpVideoSenderTest,
329 DiscardsHigherSimulcastFramesAfterLayerDisabledInVideoLayersAllocation) {
Per Kjellanderfb8641c2022-08-11 07:25:00330 constexpr uint8_t kPayload = 'a';
331 EncodedImage encoded_image_1;
Danil Chapovalov9c584832023-09-18 13:48:49332 encoded_image_1.SetRtpTimestamp(1);
Per Kjellanderfb8641c2022-08-11 07:25:00333 encoded_image_1.capture_time_ms_ = 2;
334 encoded_image_1._frameType = VideoFrameType::kVideoFrameKey;
335 encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
336 EncodedImage encoded_image_2(encoded_image_1);
Henrik Boström2e540a22023-02-15 13:48:09337 encoded_image_2.SetSimulcastIndex(1);
Per Kjellanderfb8641c2022-08-11 07:25:00338 CodecSpecificInfo codec_info;
339 codec_info.codecType = kVideoCodecVP8;
340 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
341 kPayloadType, {});
Per K979b6d62024-01-26 10:18:26342 test.SetSending(true);
Per Kjellanderfb8641c2022-08-11 07:25:00343 // A layer is sent on both rtp streams.
344 test.router()->OnVideoLayersAllocationUpdated(
345 {.active_spatial_layers = {{.rtp_stream_index = 0},
346 {.rtp_stream_index = 1}}});
347
348 EXPECT_EQ(EncodedImageCallback::Result::OK,
349 test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
350 EXPECT_EQ(EncodedImageCallback::Result::OK,
351 test.router()->OnEncodedImage(encoded_image_2, &codec_info).error);
352
353 // Only rtp stream index 0 is configured to send a stream.
354 test.router()->OnVideoLayersAllocationUpdated(
355 {.active_spatial_layers = {{.rtp_stream_index = 0}}});
Danil Chapovalov0f027282024-09-24 09:22:55356 test.AdvanceTime(TimeDelta::Millis(33));
Per Kjellanderfb8641c2022-08-11 07:25:00357 EXPECT_EQ(EncodedImageCallback::Result::OK,
358 test.router()->OnEncodedImage(encoded_image_1, &codec_info).error);
359 EXPECT_NE(EncodedImageCallback::Result::OK,
360 test.router()->OnEncodedImage(encoded_image_2, &codec_info).error);
361}
362
Sebastian Jansson63470292019-02-01 09:13:43363TEST(RtpVideoSenderTest, CreateWithNoPreviousStates) {
Erik Språng490d76c2019-05-07 16:29:15364 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
365 kPayloadType, {});
Per K979b6d62024-01-26 10:18:26366 test.SetSending(true);
Åsa Persson4bece9a2017-10-06 08:04:04367
368 std::map<uint32_t, RtpPayloadState> initial_states =
Stefan Holmerdbdb3a02018-07-17 14:03:46369 test.router()->GetRtpPayloadStates();
Åsa Persson4bece9a2017-10-06 08:04:04370 EXPECT_EQ(2u, initial_states.size());
371 EXPECT_NE(initial_states.find(kSsrc1), initial_states.end());
372 EXPECT_NE(initial_states.find(kSsrc2), initial_states.end());
373}
374
Sebastian Jansson63470292019-02-01 09:13:43375TEST(RtpVideoSenderTest, CreateWithPreviousStates) {
philipel25d31ec2018-08-08 14:33:01376 const int64_t kState1SharedFrameId = 123;
377 const int64_t kState2SharedFrameId = 234;
Åsa Persson4bece9a2017-10-06 08:04:04378 RtpPayloadState state1;
379 state1.picture_id = kInitialPictureId1;
Niels Möllerbb894ff2018-03-15 11:28:53380 state1.tl0_pic_idx = kInitialTl0PicIdx1;
philipel25d31ec2018-08-08 14:33:01381 state1.shared_frame_id = kState1SharedFrameId;
Åsa Persson4bece9a2017-10-06 08:04:04382 RtpPayloadState state2;
383 state2.picture_id = kInitialPictureId2;
Niels Möllerbb894ff2018-03-15 11:28:53384 state2.tl0_pic_idx = kInitialTl0PicIdx2;
philipel25d31ec2018-08-08 14:33:01385 state2.shared_frame_id = kState2SharedFrameId;
Åsa Persson4bece9a2017-10-06 08:04:04386 std::map<uint32_t, RtpPayloadState> states = {{kSsrc1, state1},
387 {kSsrc2, state2}};
388
Erik Språng490d76c2019-05-07 16:29:15389 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
390 kPayloadType, states);
Per K979b6d62024-01-26 10:18:26391 test.SetSending(true);
Åsa Persson4bece9a2017-10-06 08:04:04392
393 std::map<uint32_t, RtpPayloadState> initial_states =
Stefan Holmerdbdb3a02018-07-17 14:03:46394 test.router()->GetRtpPayloadStates();
Åsa Persson4bece9a2017-10-06 08:04:04395 EXPECT_EQ(2u, initial_states.size());
396 EXPECT_EQ(kInitialPictureId1, initial_states[kSsrc1].picture_id);
Niels Möllerbb894ff2018-03-15 11:28:53397 EXPECT_EQ(kInitialTl0PicIdx1, initial_states[kSsrc1].tl0_pic_idx);
Åsa Persson4bece9a2017-10-06 08:04:04398 EXPECT_EQ(kInitialPictureId2, initial_states[kSsrc2].picture_id);
Niels Möllerbb894ff2018-03-15 11:28:53399 EXPECT_EQ(kInitialTl0PicIdx2, initial_states[kSsrc2].tl0_pic_idx);
philipel25d31ec2018-08-08 14:33:01400 EXPECT_EQ(kState2SharedFrameId, initial_states[kSsrc1].shared_frame_id);
401 EXPECT_EQ(kState2SharedFrameId, initial_states[kSsrc2].shared_frame_id);
Åsa Persson4bece9a2017-10-06 08:04:04402}
Niels Möller949f0fd2019-01-29 08:44:24403
Sebastian Jansson63470292019-02-01 09:13:43404TEST(RtpVideoSenderTest, FrameCountCallbacks) {
Niels Möller949f0fd2019-01-29 08:44:24405 class MockFrameCountObserver : public FrameCountObserver {
406 public:
Danil Chapovalov9a5efe92020-05-14 20:06:18407 MOCK_METHOD(void,
408 FrameCountUpdated,
409 (const FrameCounts& frame_counts, uint32_t ssrc),
410 (override));
Niels Möller949f0fd2019-01-29 08:44:24411 } callback;
412
Erik Språng490d76c2019-05-07 16:29:15413 RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {},
414 &callback);
Niels Möller949f0fd2019-01-29 08:44:24415
Niels Möller663844d2019-02-14 15:15:54416 constexpr uint8_t kPayload = 'a';
Niels Möller949f0fd2019-01-29 08:44:24417 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:49418 encoded_image.SetRtpTimestamp(1);
Niels Möller949f0fd2019-01-29 08:44:24419 encoded_image.capture_time_ms_ = 2;
Niels Möller8f7ce222019-03-21 14:43:58420 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 13:56:56421 encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
Niels Möller949f0fd2019-01-29 08:44:24422
Niels Möller8f7ce222019-03-21 14:43:58423 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller949f0fd2019-01-29 08:44:24424
425 // No callbacks when not active.
426 EXPECT_CALL(callback, FrameCountUpdated).Times(0);
Danil Chapovalov383f2cf2020-08-12 09:06:53427 EXPECT_NE(EncodedImageCallback::Result::OK,
428 test.router()->OnEncodedImage(encoded_image, nullptr).error);
Mirko Bonadei6a489f22019-04-09 13:11:12429 ::testing::Mock::VerifyAndClearExpectations(&callback);
Niels Möller949f0fd2019-01-29 08:44:24430
Per K979b6d62024-01-26 10:18:26431 test.SetSending(true);
Niels Möller949f0fd2019-01-29 08:44:24432
433 FrameCounts frame_counts;
434 EXPECT_CALL(callback, FrameCountUpdated(_, kSsrc1))
435 .WillOnce(SaveArg<0>(&frame_counts));
Danil Chapovalov383f2cf2020-08-12 09:06:53436 EXPECT_EQ(EncodedImageCallback::Result::OK,
437 test.router()->OnEncodedImage(encoded_image, nullptr).error);
Niels Möller949f0fd2019-01-29 08:44:24438
439 EXPECT_EQ(1, frame_counts.key_frames);
440 EXPECT_EQ(0, frame_counts.delta_frames);
441
Mirko Bonadei6a489f22019-04-09 13:11:12442 ::testing::Mock::VerifyAndClearExpectations(&callback);
Niels Möller949f0fd2019-01-29 08:44:24443
Niels Möller8f7ce222019-03-21 14:43:58444 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
Niels Möller949f0fd2019-01-29 08:44:24445 EXPECT_CALL(callback, FrameCountUpdated(_, kSsrc1))
446 .WillOnce(SaveArg<0>(&frame_counts));
Danil Chapovalov383f2cf2020-08-12 09:06:53447 EXPECT_EQ(EncodedImageCallback::Result::OK,
448 test.router()->OnEncodedImage(encoded_image, nullptr).error);
Niels Möller949f0fd2019-01-29 08:44:24449
450 EXPECT_EQ(1, frame_counts.key_frames);
451 EXPECT_EQ(1, frame_counts.delta_frames);
452}
453
Erik Språng490d76c2019-05-07 16:29:15454// Integration test verifying that ack of packet via TransportFeedback means
Erik Språng845c6aa2019-05-29 11:02:24455// that the packet is removed from RtpPacketHistory and won't be retransmitted
Erik Språng490d76c2019-05-07 16:29:15456// again.
457TEST(RtpVideoSenderTest, DoesNotRetrasmitAckedPackets) {
Erik Språng490d76c2019-05-07 16:29:15458 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
459 kPayloadType, {});
Per K979b6d62024-01-26 10:18:26460 test.SetSending(true);
Erik Språng490d76c2019-05-07 16:29:15461
462 constexpr uint8_t kPayload = 'a';
463 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:49464 encoded_image.SetRtpTimestamp(1);
Erik Språng490d76c2019-05-07 16:29:15465 encoded_image.capture_time_ms_ = 2;
466 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möller4d504c72019-06-18 13:56:56467 encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
Erik Språng490d76c2019-05-07 16:29:15468
469 // Send two tiny images, mapping to two RTP packets. Capture sequence numbers.
Erik Språng490d76c2019-05-07 16:29:15470 std::vector<uint16_t> rtp_sequence_numbers;
471 std::vector<uint16_t> transport_sequence_numbers;
472 EXPECT_CALL(test.transport(), SendRtp)
473 .Times(2)
Danil Chapovalova68eb8c2020-02-17 15:13:14474 .WillRepeatedly([&rtp_sequence_numbers, &transport_sequence_numbers](
Harald Alvestrandd43af912023-08-15 11:41:45475 rtc::ArrayView<const uint8_t> packet,
Danil Chapovalova68eb8c2020-02-17 15:13:14476 const PacketOptions& options) {
477 RtpPacket rtp_packet;
Harald Alvestrandd43af912023-08-15 11:41:45478 EXPECT_TRUE(rtp_packet.Parse(packet));
Danil Chapovalova68eb8c2020-02-17 15:13:14479 rtp_sequence_numbers.push_back(rtp_packet.SequenceNumber());
480 transport_sequence_numbers.push_back(options.packet_id);
481 return true;
482 });
Danil Chapovalov383f2cf2020-08-12 09:06:53483 EXPECT_EQ(EncodedImageCallback::Result::OK,
484 test.router()->OnEncodedImage(encoded_image, nullptr).error);
Danil Chapovalov9c584832023-09-18 13:48:49485 encoded_image.SetRtpTimestamp(2);
Erik Språng490d76c2019-05-07 16:29:15486 encoded_image.capture_time_ms_ = 3;
Danil Chapovalov383f2cf2020-08-12 09:06:53487 EXPECT_EQ(EncodedImageCallback::Result::OK,
488 test.router()->OnEncodedImage(encoded_image, nullptr).error);
Erik Språngbd7046c2019-05-07 21:54:29489
Danil Chapovalov0c626af2020-02-10 10:16:00490 test.AdvanceTime(TimeDelta::Millis(33));
Erik Språng490d76c2019-05-07 16:29:15491
Erik Språng490d76c2019-05-07 16:29:15492 // Construct a NACK message for requesting retransmission of both packet.
493 rtcp::Nack nack;
494 nack.SetMediaSsrc(kSsrc1);
495 nack.SetPacketIds(rtp_sequence_numbers);
496 rtc::Buffer nack_buffer = nack.Build();
497
498 std::vector<uint16_t> retransmitted_rtp_sequence_numbers;
499 EXPECT_CALL(test.transport(), SendRtp)
500 .Times(2)
Danil Chapovalova68eb8c2020-02-17 15:13:14501 .WillRepeatedly([&retransmitted_rtp_sequence_numbers](
Harald Alvestrandd43af912023-08-15 11:41:45502 rtc::ArrayView<const uint8_t> packet,
Erik Språng490d76c2019-05-07 16:29:15503 const PacketOptions& options) {
504 RtpPacket rtp_packet;
Harald Alvestrandd43af912023-08-15 11:41:45505 EXPECT_TRUE(rtp_packet.Parse(packet));
Erik Språng490d76c2019-05-07 16:29:15506 EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
507 // Capture the retransmitted sequence number from the RTX header.
508 rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
509 retransmitted_rtp_sequence_numbers.push_back(
510 ByteReader<uint16_t>::ReadBigEndian(payload.data()));
Erik Språng490d76c2019-05-07 16:29:15511 return true;
512 });
513 test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
Danil Chapovalov0c626af2020-02-10 10:16:00514 test.AdvanceTime(TimeDelta::Millis(33));
Erik Språng490d76c2019-05-07 16:29:15515
516 // Verify that both packets were retransmitted.
517 EXPECT_EQ(retransmitted_rtp_sequence_numbers, rtp_sequence_numbers);
518
519 // Simulate transport feedback indicating fist packet received, next packet
Erik Språng00cc8362019-11-25 11:21:46520 // lost (not other way around as that would trigger early retransmit).
Sebastian Janssonf2988552019-10-29 16:18:51521 StreamFeedbackObserver::StreamPacketInfo lost_packet_feedback;
Erik Språng00cc8362019-11-25 11:21:46522 lost_packet_feedback.rtp_sequence_number = rtp_sequence_numbers[0];
Erik Språng490d76c2019-05-07 16:29:15523 lost_packet_feedback.ssrc = kSsrc1;
Sebastian Janssonf2988552019-10-29 16:18:51524 lost_packet_feedback.received = false;
Erik Språng6a0a5592021-06-15 17:04:24525 lost_packet_feedback.is_retransmission = false;
Erik Språng490d76c2019-05-07 16:29:15526
Erik Språng00cc8362019-11-25 11:21:46527 StreamFeedbackObserver::StreamPacketInfo received_packet_feedback;
528 received_packet_feedback.rtp_sequence_number = rtp_sequence_numbers[1];
529 received_packet_feedback.ssrc = kSsrc1;
530 received_packet_feedback.received = true;
Erik Språng6a0a5592021-06-15 17:04:24531 lost_packet_feedback.is_retransmission = false;
Erik Språng00cc8362019-11-25 11:21:46532
Sebastian Janssonf2988552019-10-29 16:18:51533 test.router()->OnPacketFeedbackVector(
Erik Språng00cc8362019-11-25 11:21:46534 {lost_packet_feedback, received_packet_feedback});
Erik Språng490d76c2019-05-07 16:29:15535
536 // Advance time to make sure retransmission would be allowed and try again.
537 // This time the retransmission should not happen for the first packet since
538 // the history has been notified of the ack and removed the packet. The
539 // second packet, included in the feedback but not marked as received, should
540 // still be retransmitted.
Danil Chapovalov0c626af2020-02-10 10:16:00541 test.AdvanceTime(TimeDelta::Millis(33));
Erik Språng490d76c2019-05-07 16:29:15542 EXPECT_CALL(test.transport(), SendRtp)
Harald Alvestrandd43af912023-08-15 11:41:45543 .WillOnce([&lost_packet_feedback](rtc::ArrayView<const uint8_t> packet,
Danil Chapovalova68eb8c2020-02-17 15:13:14544 const PacketOptions& options) {
Erik Språng490d76c2019-05-07 16:29:15545 RtpPacket rtp_packet;
Harald Alvestrandd43af912023-08-15 11:41:45546 EXPECT_TRUE(rtp_packet.Parse(packet));
Erik Språng490d76c2019-05-07 16:29:15547 EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
548 // Capture the retransmitted sequence number from the RTX header.
549 rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
550 EXPECT_EQ(lost_packet_feedback.rtp_sequence_number,
551 ByteReader<uint16_t>::ReadBigEndian(payload.data()));
Erik Språng490d76c2019-05-07 16:29:15552 return true;
553 });
554 test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
Danil Chapovalov0c626af2020-02-10 10:16:00555 test.AdvanceTime(TimeDelta::Millis(33));
Erik Språng490d76c2019-05-07 16:29:15556}
Erik Språng845c6aa2019-05-29 11:02:24557
Sebastian Jansson3d4d94a2020-01-14 13:25:41558// This tests that we utilize transport wide feedback to retransmit lost
Tommi6fba6b72022-01-28 08:00:01559// packets. This is tested by dropping all ordinary packets from a "lossy"
560// stream sent along with a secondary untouched stream. The transport wide
Sebastian Jansson3d4d94a2020-01-14 13:25:41561// feedback packets from the secondary stream allows the sending side to
562// detect and retreansmit the lost packets from the lossy stream.
563TEST(RtpVideoSenderTest, RetransmitsOnTransportWideLossInfo) {
564 int rtx_packets;
565 test::Scenario s(test_info_);
566 test::CallClientConfig call_conf;
567 // Keeping the bitrate fixed to avoid RTX due to probing.
Danil Chapovalovcad3e0e2020-02-17 17:46:07568 call_conf.transport.rates.max_rate = DataRate::KilobitsPerSec(300);
569 call_conf.transport.rates.start_rate = DataRate::KilobitsPerSec(300);
Sebastian Jansson3d4d94a2020-01-14 13:25:41570 test::NetworkSimulationConfig net_conf;
Danil Chapovalovcad3e0e2020-02-17 17:46:07571 net_conf.bandwidth = DataRate::KilobitsPerSec(300);
Sebastian Jansson3d4d94a2020-01-14 13:25:41572 auto send_node = s.CreateSimulationNode(net_conf);
Tommi3c9bcc12020-04-15 14:45:47573 auto* callee = s.CreateClient("return", call_conf);
Sebastian Jansson3d4d94a2020-01-14 13:25:41574 auto* route = s.CreateRoutes(s.CreateClient("send", call_conf), {send_node},
Tommi3c9bcc12020-04-15 14:45:47575 callee, {s.CreateSimulationNode(net_conf)});
Sebastian Jansson3d4d94a2020-01-14 13:25:41576
577 test::VideoStreamConfig lossy_config;
578 lossy_config.source.framerate = 5;
579 auto* lossy = s.CreateVideoStream(route->forward(), lossy_config);
580 // The secondary stream acts a driver for transport feedback messages,
581 // ensuring that lost packets on the lossy stream are retransmitted.
582 s.CreateVideoStream(route->forward(), test::VideoStreamConfig());
583
584 send_node->router()->SetFilter([&](const EmulatedIpPacket& packet) {
585 RtpPacket rtp;
586 if (rtp.Parse(packet.data)) {
587 // Drops all regular packets for the lossy stream and counts all RTX
588 // packets. Since no packets are let trough, NACKs can't be triggered
589 // by the receiving side.
590 if (lossy->send()->UsingSsrc(rtp.Ssrc())) {
591 return false;
592 } else if (lossy->send()->UsingRtxSsrc(rtp.Ssrc())) {
593 ++rtx_packets;
594 }
595 }
596 return true;
597 });
598
599 // Run for a short duration and reset counters to avoid counting RTX packets
600 // from initial probing.
Danil Chapovalov0c626af2020-02-10 10:16:00601 s.RunFor(TimeDelta::Seconds(1));
Sebastian Jansson3d4d94a2020-01-14 13:25:41602 rtx_packets = 0;
Tommi3c9bcc12020-04-15 14:45:47603 int decoded_baseline = 0;
604 callee->SendTask([&decoded_baseline, &lossy]() {
605 decoded_baseline = lossy->receive()->GetStats().frames_decoded;
606 });
Danil Chapovalov0c626af2020-02-10 10:16:00607 s.RunFor(TimeDelta::Seconds(1));
Sebastian Jansson3d4d94a2020-01-14 13:25:41608 // We expect both that RTX packets were sent and that an appropriate number of
609 // frames were received. This is somewhat redundant but reduces the risk of
610 // false positives in future regressions (e.g. RTX is send due to probing).
611 EXPECT_GE(rtx_packets, 1);
Tommi3c9bcc12020-04-15 14:45:47612 int frames_decoded = 0;
613 callee->SendTask([&decoded_baseline, &frames_decoded, &lossy]() {
614 frames_decoded =
615 lossy->receive()->GetStats().frames_decoded - decoded_baseline;
616 });
Sebastian Jansson3d4d94a2020-01-14 13:25:41617 EXPECT_EQ(frames_decoded, 5);
618}
619
Erik Språng845c6aa2019-05-29 11:02:24620// Integration test verifying that retransmissions are sent for packets which
621// can be detected as lost early, using transport wide feedback.
622TEST(RtpVideoSenderTest, EarlyRetransmits) {
Erik Språng845c6aa2019-05-29 11:02:24623 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
624 kPayloadType, {});
Per K979b6d62024-01-26 10:18:26625 test.SetSending(true);
Erik Språng845c6aa2019-05-29 11:02:24626
Niels Möllerb9bfe652019-10-03 06:43:53627 const uint8_t kPayload[1] = {'a'};
Erik Språng845c6aa2019-05-29 11:02:24628 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:49629 encoded_image.SetRtpTimestamp(1);
Erik Språng845c6aa2019-05-29 11:02:24630 encoded_image.capture_time_ms_ = 2;
631 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Niels Möllerb9bfe652019-10-03 06:43:53632 encoded_image.SetEncodedData(
633 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
Henrik Boström2e540a22023-02-15 13:48:09634 encoded_image.SetSimulcastIndex(0);
Erik Språng845c6aa2019-05-29 11:02:24635
636 CodecSpecificInfo codec_specific;
637 codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
638
639 // Send two tiny images, mapping to single RTP packets. Capture sequence
640 // numbers.
Erik Språng845c6aa2019-05-29 11:02:24641 uint16_t frame1_rtp_sequence_number = 0;
642 uint16_t frame1_transport_sequence_number = 0;
643 EXPECT_CALL(test.transport(), SendRtp)
Danil Chapovalova68eb8c2020-02-17 15:13:14644 .WillOnce(
645 [&frame1_rtp_sequence_number, &frame1_transport_sequence_number](
Harald Alvestrandd43af912023-08-15 11:41:45646 rtc::ArrayView<const uint8_t> packet,
Danil Chapovalova68eb8c2020-02-17 15:13:14647 const PacketOptions& options) {
648 RtpPacket rtp_packet;
Harald Alvestrandd43af912023-08-15 11:41:45649 EXPECT_TRUE(rtp_packet.Parse(packet));
Danil Chapovalova68eb8c2020-02-17 15:13:14650 frame1_rtp_sequence_number = rtp_packet.SequenceNumber();
651 frame1_transport_sequence_number = options.packet_id;
652 EXPECT_EQ(rtp_packet.Ssrc(), kSsrc1);
653 return true;
654 });
Danil Chapovalov383f2cf2020-08-12 09:06:53655 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
Erik Språng845c6aa2019-05-29 11:02:24656 EncodedImageCallback::Result::OK);
Erik Språng845c6aa2019-05-29 11:02:24657
Danil Chapovalov0c626af2020-02-10 10:16:00658 test.AdvanceTime(TimeDelta::Millis(33));
Erik Språng845c6aa2019-05-29 11:02:24659
660 uint16_t frame2_rtp_sequence_number = 0;
661 uint16_t frame2_transport_sequence_number = 0;
Henrik Boström2e540a22023-02-15 13:48:09662 encoded_image.SetSimulcastIndex(1);
Erik Språng845c6aa2019-05-29 11:02:24663 EXPECT_CALL(test.transport(), SendRtp)
Danil Chapovalova68eb8c2020-02-17 15:13:14664 .WillOnce(
665 [&frame2_rtp_sequence_number, &frame2_transport_sequence_number](
Harald Alvestrandd43af912023-08-15 11:41:45666 rtc::ArrayView<const uint8_t> packet,
Danil Chapovalova68eb8c2020-02-17 15:13:14667 const PacketOptions& options) {
668 RtpPacket rtp_packet;
Harald Alvestrandd43af912023-08-15 11:41:45669 EXPECT_TRUE(rtp_packet.Parse(packet));
Danil Chapovalova68eb8c2020-02-17 15:13:14670 frame2_rtp_sequence_number = rtp_packet.SequenceNumber();
671 frame2_transport_sequence_number = options.packet_id;
672 EXPECT_EQ(rtp_packet.Ssrc(), kSsrc2);
673 return true;
674 });
Danil Chapovalov383f2cf2020-08-12 09:06:53675 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
Erik Språng845c6aa2019-05-29 11:02:24676 EncodedImageCallback::Result::OK);
Danil Chapovalov0c626af2020-02-10 10:16:00677 test.AdvanceTime(TimeDelta::Millis(33));
Erik Språng845c6aa2019-05-29 11:02:24678
679 EXPECT_NE(frame1_transport_sequence_number, frame2_transport_sequence_number);
680
681 // Inject a transport feedback where the packet for the first frame is lost,
682 // expect a retransmission for it.
683 EXPECT_CALL(test.transport(), SendRtp)
Harald Alvestrandd43af912023-08-15 11:41:45684 .WillOnce([&frame1_rtp_sequence_number](
685 rtc::ArrayView<const uint8_t> packet,
686 const PacketOptions& options) {
Erik Språng845c6aa2019-05-29 11:02:24687 RtpPacket rtp_packet;
Harald Alvestrandd43af912023-08-15 11:41:45688 EXPECT_TRUE(rtp_packet.Parse(packet));
Sebastian Janssonf2988552019-10-29 16:18:51689 EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
Erik Språng845c6aa2019-05-29 11:02:24690
691 // Retransmitted sequence number from the RTX header should match
692 // the lost packet.
693 rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
694 EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(payload.data()),
695 frame1_rtp_sequence_number);
Erik Språng845c6aa2019-05-29 11:02:24696 return true;
697 });
698
Sebastian Janssonf2988552019-10-29 16:18:51699 StreamFeedbackObserver::StreamPacketInfo first_packet_feedback;
Erik Språng845c6aa2019-05-29 11:02:24700 first_packet_feedback.rtp_sequence_number = frame1_rtp_sequence_number;
701 first_packet_feedback.ssrc = kSsrc1;
Sebastian Janssonf2988552019-10-29 16:18:51702 first_packet_feedback.received = false;
Erik Språng6a0a5592021-06-15 17:04:24703 first_packet_feedback.is_retransmission = false;
Erik Språng845c6aa2019-05-29 11:02:24704
Sebastian Janssonf2988552019-10-29 16:18:51705 StreamFeedbackObserver::StreamPacketInfo second_packet_feedback;
706 second_packet_feedback.rtp_sequence_number = frame2_rtp_sequence_number;
707 second_packet_feedback.ssrc = kSsrc2;
708 second_packet_feedback.received = true;
Erik Språng6a0a5592021-06-15 17:04:24709 first_packet_feedback.is_retransmission = false;
Erik Språng845c6aa2019-05-29 11:02:24710
Sebastian Janssonf2988552019-10-29 16:18:51711 test.router()->OnPacketFeedbackVector(
712 {first_packet_feedback, second_packet_feedback});
Erik Språng845c6aa2019-05-29 11:02:24713
714 // Wait for pacer to run and send the RTX packet.
Danil Chapovalov0c626af2020-02-10 10:16:00715 test.AdvanceTime(TimeDelta::Millis(33));
Erik Språng845c6aa2019-05-29 11:02:24716}
Sebastian Janssoncf41eb12019-06-10 09:30:59717
Danil Chapovalov2272f202020-02-18 11:09:43718TEST(RtpVideoSenderTest, SupportsDependencyDescriptor) {
Danil Chapovalov2272f202020-02-18 11:09:43719 RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
Per K979b6d62024-01-26 10:18:26720 test.SetSending(true);
Danil Chapovalov2272f202020-02-18 11:09:43721
722 RtpHeaderExtensionMap extensions;
723 extensions.Register<RtpDependencyDescriptorExtension>(
724 kDependencyDescriptorExtensionId);
725 std::vector<RtpPacket> sent_packets;
726 ON_CALL(test.transport(), SendRtp)
Harald Alvestrandd43af912023-08-15 11:41:45727 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
Danil Chapovalov2272f202020-02-18 11:09:43728 const PacketOptions& options) {
729 sent_packets.emplace_back(&extensions);
Harald Alvestrandd43af912023-08-15 11:41:45730 EXPECT_TRUE(sent_packets.back().Parse(packet));
Danil Chapovalov2272f202020-02-18 11:09:43731 return true;
732 });
733
734 const uint8_t kPayload[1] = {'a'};
735 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:49736 encoded_image.SetRtpTimestamp(1);
Danil Chapovalov2272f202020-02-18 11:09:43737 encoded_image.capture_time_ms_ = 2;
738 encoded_image.SetEncodedData(
739 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
740
741 CodecSpecificInfo codec_specific;
742 codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
743 codec_specific.template_structure.emplace();
744 codec_specific.template_structure->num_decode_targets = 1;
745 codec_specific.template_structure->templates = {
Danil Chapovalov24263f42020-06-11 11:23:45746 FrameDependencyTemplate().T(0).Dtis("S"),
747 FrameDependencyTemplate().T(0).Dtis("S").FrameDiffs({2}),
748 FrameDependencyTemplate().T(1).Dtis("D").FrameDiffs({1}),
Danil Chapovalov2272f202020-02-18 11:09:43749 };
750
751 // Send two tiny images, mapping to single RTP packets.
752 // Send in key frame.
753 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
754 codec_specific.generic_frame_info =
755 GenericFrameInfo::Builder().T(0).Dtis("S").Build();
756 codec_specific.generic_frame_info->encoder_buffers = {{0, false, true}};
Danil Chapovalov383f2cf2020-08-12 09:06:53757 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
Danil Chapovalov2272f202020-02-18 11:09:43758 EncodedImageCallback::Result::OK);
759 test.AdvanceTime(TimeDelta::Millis(33));
760 ASSERT_THAT(sent_packets, SizeIs(1));
761 EXPECT_TRUE(
762 sent_packets.back().HasExtension<RtpDependencyDescriptorExtension>());
763
764 // Send in delta frame.
765 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
Florent Castelli8037fc62024-08-29 13:00:40766 codec_specific.template_structure = std::nullopt;
Danil Chapovalov2272f202020-02-18 11:09:43767 codec_specific.generic_frame_info =
768 GenericFrameInfo::Builder().T(1).Dtis("D").Build();
769 codec_specific.generic_frame_info->encoder_buffers = {{0, true, false}};
Danil Chapovalov383f2cf2020-08-12 09:06:53770 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
Danil Chapovalov2272f202020-02-18 11:09:43771 EncodedImageCallback::Result::OK);
772 test.AdvanceTime(TimeDelta::Millis(33));
773 ASSERT_THAT(sent_packets, SizeIs(2));
774 EXPECT_TRUE(
775 sent_packets.back().HasExtension<RtpDependencyDescriptorExtension>());
776}
777
philipel626edea2024-03-19 08:38:01778TEST(RtpVideoSenderTest, SimulcastIndependentFrameIds) {
779 test::ExplicitKeyValueConfig field_trials(
philipel626edea2024-03-19 08:38:01780 "WebRTC-GenericDescriptorAuth/Disabled/");
781 const std::map<uint32_t, RtpPayloadState> kPayloadStates = {
782 {kSsrc1, {.frame_id = 100}}, {kSsrc2, {.frame_id = 200}}};
783 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {}, kPayloadType,
784 kPayloadStates, &field_trials);
785 test.SetSending(true);
786
787 RtpHeaderExtensionMap extensions;
788 extensions.Register<RtpDependencyDescriptorExtension>(
789 kDependencyDescriptorExtensionId);
790 std::vector<RtpPacket> sent_packets;
791 ON_CALL(test.transport(), SendRtp)
792 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
793 const PacketOptions& options) {
794 sent_packets.emplace_back(&extensions);
795 EXPECT_TRUE(sent_packets.back().Parse(packet));
796 return true;
797 });
798
799 const uint8_t kPayload[1] = {'a'};
800 EncodedImage encoded_image;
801 encoded_image.SetEncodedData(
802 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
803
804 CodecSpecificInfo codec_specific;
805 codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
806 codec_specific.template_structure.emplace();
807 codec_specific.template_structure->num_decode_targets = 1;
808 codec_specific.template_structure->templates = {
809 FrameDependencyTemplate().T(0).Dtis("S"),
810 FrameDependencyTemplate().T(0).Dtis("S").FrameDiffs({1}),
811 };
812 codec_specific.generic_frame_info =
813 GenericFrameInfo::Builder().T(0).Dtis("S").Build();
814 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
815 codec_specific.generic_frame_info->encoder_buffers = {{0, false, true}};
816
817 encoded_image.SetSimulcastIndex(0);
818 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
819 EncodedImageCallback::Result::OK);
820 encoded_image.SetSimulcastIndex(1);
821 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
822 EncodedImageCallback::Result::OK);
823
824 test.AdvanceTime(TimeDelta::Millis(33));
825 ASSERT_THAT(sent_packets, SizeIs(2));
826 DependencyDescriptorMandatory dd_s0;
827 DependencyDescriptorMandatory dd_s1;
828 ASSERT_TRUE(
829 sent_packets[0].GetExtension<RtpDependencyDescriptorExtension>(&dd_s0));
830 ASSERT_TRUE(
831 sent_packets[1].GetExtension<RtpDependencyDescriptorExtension>(&dd_s1));
832 EXPECT_EQ(dd_s0.frame_number(), 100);
833 EXPECT_EQ(dd_s1.frame_number(), 200);
834}
835
836TEST(RtpVideoSenderTest,
837 SimulcastNoIndependentFrameIdsIfGenericDescriptorAuthIsEnabled) {
838 test::ExplicitKeyValueConfig field_trials(
philipel626edea2024-03-19 08:38:01839 "WebRTC-GenericDescriptorAuth/Enabled/");
840 const std::map<uint32_t, RtpPayloadState> kPayloadStates = {
841 {kSsrc1, {.shared_frame_id = 1000, .frame_id = 100}},
842 {kSsrc2, {.shared_frame_id = 1000, .frame_id = 200}}};
843 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {}, kPayloadType,
844 kPayloadStates, &field_trials);
845 test.SetSending(true);
846
847 RtpHeaderExtensionMap extensions;
848 extensions.Register<RtpDependencyDescriptorExtension>(
849 kDependencyDescriptorExtensionId);
850 std::vector<RtpPacket> sent_packets;
851 ON_CALL(test.transport(), SendRtp)
852 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
853 const PacketOptions& options) {
854 sent_packets.emplace_back(&extensions);
855 EXPECT_TRUE(sent_packets.back().Parse(packet));
856 return true;
857 });
858
859 const uint8_t kPayload[1] = {'a'};
860 EncodedImage encoded_image;
861 encoded_image.SetEncodedData(
862 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
863
864 CodecSpecificInfo codec_specific;
865 codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
866 codec_specific.template_structure.emplace();
867 codec_specific.template_structure->num_decode_targets = 1;
868 codec_specific.template_structure->templates = {
869 FrameDependencyTemplate().T(0).Dtis("S"),
870 FrameDependencyTemplate().T(0).Dtis("S").FrameDiffs({1}),
871 };
872 codec_specific.generic_frame_info =
873 GenericFrameInfo::Builder().T(0).Dtis("S").Build();
874 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
875 codec_specific.generic_frame_info->encoder_buffers = {{0, false, true}};
876
877 encoded_image.SetSimulcastIndex(0);
878 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
879 EncodedImageCallback::Result::OK);
880 encoded_image.SetSimulcastIndex(1);
881 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
882 EncodedImageCallback::Result::OK);
883
884 test.AdvanceTime(TimeDelta::Millis(33));
885 ASSERT_THAT(sent_packets, SizeIs(2));
886 DependencyDescriptorMandatory dd_s0;
887 DependencyDescriptorMandatory dd_s1;
888 ASSERT_TRUE(
889 sent_packets[0].GetExtension<RtpDependencyDescriptorExtension>(&dd_s0));
890 ASSERT_TRUE(
891 sent_packets[1].GetExtension<RtpDependencyDescriptorExtension>(&dd_s1));
892 EXPECT_EQ(dd_s0.frame_number(), 1001);
893 EXPECT_EQ(dd_s1.frame_number(), 1002);
894}
895
Emil Lundmark6c81a422022-05-18 15:13:34896TEST(RtpVideoSenderTest,
philipel98ed5402024-05-21 13:59:43897 SimulcastNoIndependentFrameIdsIfIndependentFrameIdsDisabled) {
898 test::ExplicitKeyValueConfig field_trials(
899 "WebRTC-Video-SimulcastIndependentFrameIds/Disabled/");
900 const std::map<uint32_t, RtpPayloadState> kPayloadStates = {
901 {kSsrc1, {.shared_frame_id = 1000, .frame_id = 100}},
902 {kSsrc2, {.shared_frame_id = 1000, .frame_id = 200}}};
903 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {}, kPayloadType,
904 kPayloadStates, &field_trials);
905 test.SetSending(true);
906
907 RtpHeaderExtensionMap extensions;
908 extensions.Register<RtpDependencyDescriptorExtension>(
909 kDependencyDescriptorExtensionId);
910 std::vector<RtpPacket> sent_packets;
911 ON_CALL(test.transport(), SendRtp)
912 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
913 const PacketOptions& options) {
914 sent_packets.emplace_back(&extensions);
915 EXPECT_TRUE(sent_packets.back().Parse(packet));
916 return true;
917 });
918
919 const uint8_t kPayload[1] = {'a'};
920 EncodedImage encoded_image;
921 encoded_image.SetEncodedData(
922 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
923
924 CodecSpecificInfo codec_specific;
925 codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
926 codec_specific.template_structure.emplace();
927 codec_specific.template_structure->num_decode_targets = 1;
928 codec_specific.template_structure->templates = {
929 FrameDependencyTemplate().T(0).Dtis("S"),
930 FrameDependencyTemplate().T(0).Dtis("S").FrameDiffs({1}),
931 };
932 codec_specific.generic_frame_info =
933 GenericFrameInfo::Builder().T(0).Dtis("S").Build();
934 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
935 codec_specific.generic_frame_info->encoder_buffers = {{0, false, true}};
936
937 encoded_image.SetSimulcastIndex(0);
938 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
939 EncodedImageCallback::Result::OK);
940 encoded_image.SetSimulcastIndex(1);
941 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
942 EncodedImageCallback::Result::OK);
943
944 test.AdvanceTime(TimeDelta::Millis(33));
945 ASSERT_THAT(sent_packets, SizeIs(2));
946 DependencyDescriptorMandatory dd_s0;
947 DependencyDescriptorMandatory dd_s1;
948 ASSERT_TRUE(
949 sent_packets[0].GetExtension<RtpDependencyDescriptorExtension>(&dd_s0));
950 ASSERT_TRUE(
951 sent_packets[1].GetExtension<RtpDependencyDescriptorExtension>(&dd_s1));
952 EXPECT_EQ(dd_s0.frame_number(), 1001);
953 EXPECT_EQ(dd_s1.frame_number(), 1002);
954}
955
956TEST(RtpVideoSenderTest,
Emil Lundmark6c81a422022-05-18 15:13:34957 SupportsDependencyDescriptorForVp8NotProvidedByEncoder) {
958 constexpr uint8_t kPayload[1] = {'a'};
959 RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
960 RtpHeaderExtensionMap extensions;
961 extensions.Register<RtpDependencyDescriptorExtension>(
962 kDependencyDescriptorExtensionId);
963 std::vector<RtpPacket> sent_packets;
964 ON_CALL(test.transport(), SendRtp)
965 .WillByDefault(
Harald Alvestrandd43af912023-08-15 11:41:45966 [&](rtc::ArrayView<const uint8_t> packet, const PacketOptions&) {
967 EXPECT_TRUE(sent_packets.emplace_back(&extensions).Parse(packet));
Emil Lundmark6c81a422022-05-18 15:13:34968 return true;
969 });
Per K979b6d62024-01-26 10:18:26970 test.SetSending(true);
Emil Lundmark6c81a422022-05-18 15:13:34971
972 EncodedImage key_frame_image;
973 key_frame_image._frameType = VideoFrameType::kVideoFrameKey;
974 key_frame_image.SetEncodedData(
975 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
976 CodecSpecificInfo key_frame_info;
977 key_frame_info.codecType = VideoCodecType::kVideoCodecVP8;
978 ASSERT_EQ(
979 test.router()->OnEncodedImage(key_frame_image, &key_frame_info).error,
980 EncodedImageCallback::Result::OK);
981
982 EncodedImage delta_image;
983 delta_image._frameType = VideoFrameType::kVideoFrameDelta;
984 delta_image.SetEncodedData(
985 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
986 CodecSpecificInfo delta_info;
987 delta_info.codecType = VideoCodecType::kVideoCodecVP8;
988 ASSERT_EQ(test.router()->OnEncodedImage(delta_image, &delta_info).error,
989 EncodedImageCallback::Result::OK);
990
991 test.AdvanceTime(TimeDelta::Millis(123));
992
993 DependencyDescriptor key_frame_dd;
994 DependencyDescriptor delta_dd;
995 ASSERT_THAT(sent_packets, SizeIs(2));
996 EXPECT_TRUE(sent_packets[0].GetExtension<RtpDependencyDescriptorExtension>(
997 /*structure=*/nullptr, &key_frame_dd));
998 EXPECT_TRUE(sent_packets[1].GetExtension<RtpDependencyDescriptorExtension>(
999 key_frame_dd.attached_structure.get(), &delta_dd));
1000}
1001
Danil Chapovalov0be18462021-01-20 11:11:291002TEST(RtpVideoSenderTest, SupportsDependencyDescriptorForVp9) {
1003 RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
Per K979b6d62024-01-26 10:18:261004 test.SetSending(true);
Danil Chapovalov0be18462021-01-20 11:11:291005
1006 RtpHeaderExtensionMap extensions;
1007 extensions.Register<RtpDependencyDescriptorExtension>(
1008 kDependencyDescriptorExtensionId);
1009 std::vector<RtpPacket> sent_packets;
1010 ON_CALL(test.transport(), SendRtp)
Harald Alvestrandd43af912023-08-15 11:41:451011 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
Danil Chapovalov0be18462021-01-20 11:11:291012 const PacketOptions& options) {
1013 sent_packets.emplace_back(&extensions);
Harald Alvestrandd43af912023-08-15 11:41:451014 EXPECT_TRUE(sent_packets.back().Parse(packet));
Danil Chapovalov0be18462021-01-20 11:11:291015 return true;
1016 });
1017
1018 const uint8_t kPayload[1] = {'a'};
1019 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:491020 encoded_image.SetRtpTimestamp(1);
Danil Chapovalov0be18462021-01-20 11:11:291021 encoded_image.capture_time_ms_ = 2;
1022 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1023 encoded_image.SetEncodedData(
1024 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
1025
1026 CodecSpecificInfo codec_specific;
1027 codec_specific.codecType = VideoCodecType::kVideoCodecVP9;
1028 codec_specific.template_structure.emplace();
1029 codec_specific.template_structure->num_decode_targets = 2;
1030 codec_specific.template_structure->templates = {
1031 FrameDependencyTemplate().S(0).Dtis("SS"),
1032 FrameDependencyTemplate().S(1).Dtis("-S").FrameDiffs({1}),
1033 };
1034
1035 // Send two tiny images, each mapping to single RTP packet.
1036 // Send in key frame for the base spatial layer.
1037 codec_specific.generic_frame_info =
1038 GenericFrameInfo::Builder().S(0).Dtis("SS").Build();
1039 codec_specific.generic_frame_info->encoder_buffers = {{0, false, true}};
1040 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1041 EncodedImageCallback::Result::OK);
1042 // Send in 2nd spatial layer.
Florent Castelli8037fc62024-08-29 13:00:401043 codec_specific.template_structure = std::nullopt;
Danil Chapovalov0be18462021-01-20 11:11:291044 codec_specific.generic_frame_info =
1045 GenericFrameInfo::Builder().S(1).Dtis("-S").Build();
1046 codec_specific.generic_frame_info->encoder_buffers = {{0, true, false},
1047 {1, false, true}};
1048 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1049 EncodedImageCallback::Result::OK);
1050
1051 test.AdvanceTime(TimeDelta::Millis(33));
1052 ASSERT_THAT(sent_packets, SizeIs(2));
1053 EXPECT_TRUE(sent_packets[0].HasExtension<RtpDependencyDescriptorExtension>());
1054 EXPECT_TRUE(sent_packets[1].HasExtension<RtpDependencyDescriptorExtension>());
1055}
1056
Danil Chapovalov748550d2021-04-29 09:42:541057TEST(RtpVideoSenderTest,
1058 SupportsDependencyDescriptorForVp9NotProvidedByEncoder) {
Danil Chapovalov748550d2021-04-29 09:42:541059 RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
Per K979b6d62024-01-26 10:18:261060 test.SetSending(true);
Danil Chapovalov748550d2021-04-29 09:42:541061
1062 RtpHeaderExtensionMap extensions;
1063 extensions.Register<RtpDependencyDescriptorExtension>(
1064 kDependencyDescriptorExtensionId);
1065 std::vector<RtpPacket> sent_packets;
1066 ON_CALL(test.transport(), SendRtp)
Harald Alvestrandd43af912023-08-15 11:41:451067 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
Danil Chapovalov748550d2021-04-29 09:42:541068 const PacketOptions& options) {
1069 sent_packets.emplace_back(&extensions);
Harald Alvestrandd43af912023-08-15 11:41:451070 EXPECT_TRUE(sent_packets.back().Parse(packet));
Danil Chapovalov748550d2021-04-29 09:42:541071 return true;
1072 });
1073
1074 const uint8_t kPayload[1] = {'a'};
1075 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:491076 encoded_image.SetRtpTimestamp(1);
Danil Chapovalov748550d2021-04-29 09:42:541077 encoded_image.capture_time_ms_ = 2;
1078 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1079 encoded_image._encodedWidth = 320;
1080 encoded_image._encodedHeight = 180;
1081 encoded_image.SetEncodedData(
1082 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
1083
1084 CodecSpecificInfo codec_specific;
1085 codec_specific.codecType = VideoCodecType::kVideoCodecVP9;
1086 codec_specific.codecSpecific.VP9.num_spatial_layers = 1;
1087 codec_specific.codecSpecific.VP9.temporal_idx = kNoTemporalIdx;
1088 codec_specific.codecSpecific.VP9.first_frame_in_picture = true;
1089 codec_specific.end_of_picture = true;
1090 codec_specific.codecSpecific.VP9.inter_pic_predicted = false;
1091
1092 // Send two tiny images, each mapping to single RTP packet.
1093 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1094 EncodedImageCallback::Result::OK);
1095
1096 // Send in 2nd picture.
1097 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
Danil Chapovalov9c584832023-09-18 13:48:491098 encoded_image.SetRtpTimestamp(3000);
Danil Chapovalov748550d2021-04-29 09:42:541099 codec_specific.codecSpecific.VP9.inter_pic_predicted = true;
1100 codec_specific.codecSpecific.VP9.num_ref_pics = 1;
1101 codec_specific.codecSpecific.VP9.p_diff[0] = 1;
1102 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1103 EncodedImageCallback::Result::OK);
1104
1105 test.AdvanceTime(TimeDelta::Millis(33));
1106 ASSERT_THAT(sent_packets, SizeIs(2));
1107 EXPECT_TRUE(sent_packets[0].HasExtension<RtpDependencyDescriptorExtension>());
1108 EXPECT_TRUE(sent_packets[1].HasExtension<RtpDependencyDescriptorExtension>());
1109}
1110
Brennan Waters51fccaf2024-10-16 19:04:231111TEST(RtpVideoSenderTest,
1112 SupportsDependencyDescriptorForH264NotProvidedByEncoder) {
1113 RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
1114 test.SetSending(true);
1115
1116 RtpHeaderExtensionMap extensions;
1117 extensions.Register<RtpDependencyDescriptorExtension>(
1118 kDependencyDescriptorExtensionId);
1119 std::vector<RtpPacket> sent_packets;
1120 EXPECT_CALL(test.transport(), SendRtp(_, _))
1121 .Times(2)
1122 .WillRepeatedly([&](rtc::ArrayView<const uint8_t> packet,
1123 const PacketOptions& options) -> bool {
1124 sent_packets.emplace_back(&extensions);
1125 EXPECT_TRUE(sent_packets.back().Parse(packet));
1126 return true;
1127 });
1128
1129 const uint8_t kPayload[1] = {'a'};
1130 EncodedImage encoded_image;
1131 encoded_image.SetRtpTimestamp(1);
1132 encoded_image.capture_time_ms_ = 2;
1133 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1134 encoded_image._encodedWidth = 320;
1135 encoded_image._encodedHeight = 180;
1136 encoded_image.SetEncodedData(
1137 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
1138
1139 CodecSpecificInfo codec_specific;
1140 codec_specific.codecType = VideoCodecType::kVideoCodecH264;
1141 codec_specific.codecSpecific.H264.temporal_idx = kNoTemporalIdx;
1142
1143 // Send two tiny images, each mapping to single RTP packet.
1144 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1145 EncodedImageCallback::Result::OK);
1146
1147 // Send in 2nd picture.
1148 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
1149 encoded_image.SetRtpTimestamp(3000);
1150 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1151 EncodedImageCallback::Result::OK);
1152
1153 test.AdvanceTime(TimeDelta::Millis(33));
1154
1155 ASSERT_THAT(sent_packets, SizeIs(2));
1156 DependencyDescriptor dd_key;
1157 // Key frame should have attached structure.
1158 EXPECT_TRUE(sent_packets[0].GetExtension<RtpDependencyDescriptorExtension>(
1159 nullptr, &dd_key));
1160 EXPECT_THAT(dd_key.attached_structure, NotNull());
1161 // Delta frame does not have attached structure.
1162 DependencyDescriptor dd_delta;
1163 EXPECT_TRUE(sent_packets[1].GetExtension<RtpDependencyDescriptorExtension>(
1164 dd_key.attached_structure.get(), &dd_delta));
1165 EXPECT_THAT(dd_delta.attached_structure, IsNull());
1166}
1167
philipel5b231de2021-09-01 13:21:161168TEST(RtpVideoSenderTest, GenerateDependecyDescriptorForGenericCodecs) {
Jonas Orelandc7f691a2022-03-09 14:12:071169 test::ScopedKeyValueConfig field_trials(
philipel5b231de2021-09-01 13:21:161170 "WebRTC-GenericCodecDependencyDescriptor/Enabled/");
Jonas Orelandc7f691a2022-03-09 14:12:071171 RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {}, &field_trials);
Per K979b6d62024-01-26 10:18:261172 test.SetSending(true);
philipel5b231de2021-09-01 13:21:161173
1174 RtpHeaderExtensionMap extensions;
1175 extensions.Register<RtpDependencyDescriptorExtension>(
1176 kDependencyDescriptorExtensionId);
1177 std::vector<RtpPacket> sent_packets;
1178 ON_CALL(test.transport(), SendRtp)
Harald Alvestrandd43af912023-08-15 11:41:451179 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
philipel5b231de2021-09-01 13:21:161180 const PacketOptions& options) {
1181 sent_packets.emplace_back(&extensions);
Harald Alvestrandd43af912023-08-15 11:41:451182 EXPECT_TRUE(sent_packets.back().Parse(packet));
philipel5b231de2021-09-01 13:21:161183 return true;
1184 });
1185
1186 const uint8_t kPayload[1] = {'a'};
1187 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:491188 encoded_image.SetRtpTimestamp(1);
philipel5b231de2021-09-01 13:21:161189 encoded_image.capture_time_ms_ = 2;
1190 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1191 encoded_image._encodedWidth = 320;
1192 encoded_image._encodedHeight = 180;
1193 encoded_image.SetEncodedData(
1194 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
1195
1196 CodecSpecificInfo codec_specific;
1197 codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
1198 codec_specific.end_of_picture = true;
1199
1200 // Send two tiny images, each mapping to single RTP packet.
1201 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1202 EncodedImageCallback::Result::OK);
1203
1204 // Send in 2nd picture.
1205 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
Danil Chapovalov9c584832023-09-18 13:48:491206 encoded_image.SetRtpTimestamp(3000);
philipel5b231de2021-09-01 13:21:161207 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
1208 EncodedImageCallback::Result::OK);
1209
1210 test.AdvanceTime(TimeDelta::Millis(33));
1211 ASSERT_THAT(sent_packets, SizeIs(2));
1212 EXPECT_TRUE(sent_packets[0].HasExtension<RtpDependencyDescriptorExtension>());
1213 EXPECT_TRUE(sent_packets[1].HasExtension<RtpDependencyDescriptorExtension>());
1214}
1215
Danil Chapovalov2272f202020-02-18 11:09:431216TEST(RtpVideoSenderTest, SupportsStoppingUsingDependencyDescriptor) {
Danil Chapovalov2272f202020-02-18 11:09:431217 RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {});
Per K979b6d62024-01-26 10:18:261218 test.SetSending(true);
Danil Chapovalov2272f202020-02-18 11:09:431219
1220 RtpHeaderExtensionMap extensions;
1221 extensions.Register<RtpDependencyDescriptorExtension>(
1222 kDependencyDescriptorExtensionId);
1223 std::vector<RtpPacket> sent_packets;
1224 ON_CALL(test.transport(), SendRtp)
Harald Alvestrandd43af912023-08-15 11:41:451225 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
Danil Chapovalov2272f202020-02-18 11:09:431226 const PacketOptions& options) {
1227 sent_packets.emplace_back(&extensions);
Harald Alvestrandd43af912023-08-15 11:41:451228 EXPECT_TRUE(sent_packets.back().Parse(packet));
Danil Chapovalov2272f202020-02-18 11:09:431229 return true;
1230 });
1231
1232 const uint8_t kPayload[1] = {'a'};
1233 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:491234 encoded_image.SetRtpTimestamp(1);
Danil Chapovalov2272f202020-02-18 11:09:431235 encoded_image.capture_time_ms_ = 2;
1236 encoded_image.SetEncodedData(
1237 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
1238
1239 CodecSpecificInfo codec_specific;
1240 codec_specific.codecType = VideoCodecType::kVideoCodecGeneric;
1241 codec_specific.template_structure.emplace();
1242 codec_specific.template_structure->num_decode_targets = 1;
1243 codec_specific.template_structure->templates = {
Danil Chapovalov24263f42020-06-11 11:23:451244 FrameDependencyTemplate().T(0).Dtis("S"),
1245 FrameDependencyTemplate().T(0).Dtis("S").FrameDiffs({2}),
1246 FrameDependencyTemplate().T(1).Dtis("D").FrameDiffs({1}),
Danil Chapovalov2272f202020-02-18 11:09:431247 };
1248
1249 // Send two tiny images, mapping to single RTP packets.
1250 // Send in a key frame.
1251 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1252 codec_specific.generic_frame_info =
1253 GenericFrameInfo::Builder().T(0).Dtis("S").Build();
1254 codec_specific.generic_frame_info->encoder_buffers = {{0, false, true}};
Danil Chapovalov383f2cf2020-08-12 09:06:531255 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
Danil Chapovalov2272f202020-02-18 11:09:431256 EncodedImageCallback::Result::OK);
1257 test.AdvanceTime(TimeDelta::Millis(33));
1258 ASSERT_THAT(sent_packets, SizeIs(1));
1259 EXPECT_TRUE(
1260 sent_packets.back().HasExtension<RtpDependencyDescriptorExtension>());
1261
1262 // Send in a new key frame without the support for the dependency descriptor.
1263 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
Florent Castelli8037fc62024-08-29 13:00:401264 codec_specific.template_structure = std::nullopt;
Danil Chapovalov383f2cf2020-08-12 09:06:531265 EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error,
Danil Chapovalov2272f202020-02-18 11:09:431266 EncodedImageCallback::Result::OK);
1267 test.AdvanceTime(TimeDelta::Millis(33));
1268 ASSERT_THAT(sent_packets, SizeIs(2));
1269 EXPECT_FALSE(
1270 sent_packets.back().HasExtension<RtpDependencyDescriptorExtension>());
1271}
1272
Jakob Ivarsson9a12ee52020-11-26 15:04:181273TEST(RtpVideoSenderTest, CanSetZeroBitrate) {
Sebastian Janssoncf41eb12019-06-10 09:30:591274 RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {});
Jakob Ivarsson9a12ee52020-11-26 15:04:181275 test.router()->OnBitrateUpdated(CreateBitrateAllocationUpdate(0),
1276 /*framerate*/ 0);
Sebastian Janssoncf41eb12019-06-10 09:30:591277}
Marina Cioceadc69fd22020-04-10 18:19:141278
1279TEST(RtpVideoSenderTest, SimulcastSenderRegistersFrameTransformers) {
Marina Cioceadc69fd22020-04-10 18:19:141280 rtc::scoped_refptr<MockFrameTransformer> transformer =
Tomas Gunnarssonc1d58912021-04-22 17:21:431281 rtc::make_ref_counted<MockFrameTransformer>();
Marina Cioceadc69fd22020-04-10 18:19:141282
1283 EXPECT_CALL(*transformer, RegisterTransformedFrameSinkCallback(_, kSsrc1));
1284 EXPECT_CALL(*transformer, RegisterTransformedFrameSinkCallback(_, kSsrc2));
1285 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
1286 kPayloadType, {}, nullptr, transformer);
1287
1288 EXPECT_CALL(*transformer, UnregisterTransformedFrameSinkCallback(kSsrc1));
1289 EXPECT_CALL(*transformer, UnregisterTransformedFrameSinkCallback(kSsrc2));
1290}
Jakob Ivarsson9a12ee52020-11-26 15:04:181291
1292TEST(RtpVideoSenderTest, OverheadIsSubtractedFromTargetBitrate) {
Jonas Orelandc7f691a2022-03-09 14:12:071293 test::ScopedKeyValueConfig field_trials(
Jakob Ivarsson9a12ee52020-11-26 15:04:181294 "WebRTC-Video-UseFrameRateForOverhead/Enabled/");
1295
1296 // TODO(jakobi): RTP header size should not be hard coded.
1297 constexpr uint32_t kRtpHeaderSizeBytes = 20;
1298 constexpr uint32_t kTransportPacketOverheadBytes = 40;
1299 constexpr uint32_t kOverheadPerPacketBytes =
1300 kRtpHeaderSizeBytes + kTransportPacketOverheadBytes;
Jonas Orelandc7f691a2022-03-09 14:12:071301 RtpVideoSenderTestFixture test({kSsrc1}, {}, kPayloadType, {}, &field_trials);
Jakob Ivarsson9a12ee52020-11-26 15:04:181302 test.router()->OnTransportOverheadChanged(kTransportPacketOverheadBytes);
Per K979b6d62024-01-26 10:18:261303 test.SetSending(true);
Jakob Ivarsson9a12ee52020-11-26 15:04:181304
1305 {
1306 test.router()->OnBitrateUpdated(CreateBitrateAllocationUpdate(300000),
1307 /*framerate*/ 15);
1308 // 1 packet per frame.
1309 EXPECT_EQ(test.router()->GetPayloadBitrateBps(),
1310 300000 - kOverheadPerPacketBytes * 8 * 30);
1311 }
1312 {
1313 test.router()->OnBitrateUpdated(CreateBitrateAllocationUpdate(150000),
1314 /*framerate*/ 15);
1315 // 1 packet per frame.
1316 EXPECT_EQ(test.router()->GetPayloadBitrateBps(),
1317 150000 - kOverheadPerPacketBytes * 8 * 15);
1318 }
1319 {
1320 test.router()->OnBitrateUpdated(CreateBitrateAllocationUpdate(1000000),
1321 /*framerate*/ 30);
1322 // 3 packets per frame.
1323 EXPECT_EQ(test.router()->GetPayloadBitrateBps(),
1324 1000000 - kOverheadPerPacketBytes * 8 * 30 * 3);
1325 }
1326}
1327
Erik Språng1b11b582022-12-09 20:38:441328TEST(RtpVideoSenderTest, ClearsPendingPacketsOnInactivation) {
1329 RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {});
Per K979b6d62024-01-26 10:18:261330 test.SetSending(true);
Erik Språng1b11b582022-12-09 20:38:441331
1332 RtpHeaderExtensionMap extensions;
1333 extensions.Register<RtpDependencyDescriptorExtension>(
1334 kDependencyDescriptorExtensionId);
1335 std::vector<RtpPacket> sent_packets;
1336 ON_CALL(test.transport(), SendRtp)
Harald Alvestrandd43af912023-08-15 11:41:451337 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
Erik Språng1b11b582022-12-09 20:38:441338 const PacketOptions& options) {
1339 sent_packets.emplace_back(&extensions);
Harald Alvestrandd43af912023-08-15 11:41:451340 EXPECT_TRUE(sent_packets.back().Parse(packet));
Erik Språng1b11b582022-12-09 20:38:441341 return true;
1342 });
1343
1344 // Set a very low bitrate.
1345 test.router()->OnBitrateUpdated(
Per Kb202bc12023-11-27 15:06:441346 CreateBitrateAllocationUpdate(/*rate_bps=*/10'000),
Erik Språng1b11b582022-12-09 20:38:441347 /*framerate=*/30);
1348
1349 // Create and send a large keyframe.
1350 const size_t kImageSizeBytes = 10000;
1351 constexpr uint8_t kPayload[kImageSizeBytes] = {'a'};
1352 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:491353 encoded_image.SetRtpTimestamp(1);
Erik Språng1b11b582022-12-09 20:38:441354 encoded_image.capture_time_ms_ = 2;
1355 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1356 encoded_image.SetEncodedData(
1357 EncodedImageBuffer::Create(kPayload, sizeof(kPayload)));
1358 EXPECT_EQ(test.router()
1359 ->OnEncodedImage(encoded_image, /*codec_specific=*/nullptr)
1360 .error,
1361 EncodedImageCallback::Result::OK);
1362
1363 // Advance time a small amount, check that sent data is only part of the
1364 // image.
1365 test.AdvanceTime(TimeDelta::Millis(5));
1366 DataSize transmittedPayload = DataSize::Zero();
1367 for (const RtpPacket& packet : sent_packets) {
1368 transmittedPayload += DataSize::Bytes(packet.payload_size());
1369 // Make sure we don't see the end of the frame.
1370 EXPECT_FALSE(packet.Marker());
1371 }
1372 EXPECT_GT(transmittedPayload, DataSize::Zero());
Per Kb202bc12023-11-27 15:06:441373 EXPECT_LT(transmittedPayload, DataSize::Bytes(kImageSizeBytes / 3));
Erik Språng1b11b582022-12-09 20:38:441374
1375 // Record the RTP timestamp of the first frame.
1376 const uint32_t first_frame_timestamp = sent_packets[0].Timestamp();
1377 sent_packets.clear();
1378
1379 // Disable the sending module and advance time slightly. No packets should be
1380 // sent.
Per K979b6d62024-01-26 10:18:261381 test.SetSending(false);
Erik Språng1b11b582022-12-09 20:38:441382 test.AdvanceTime(TimeDelta::Millis(20));
1383 EXPECT_TRUE(sent_packets.empty());
1384
1385 // Reactive the send module - any packets should have been removed, so nothing
1386 // should be transmitted.
Per K979b6d62024-01-26 10:18:261387 test.SetSending(true);
Erik Språng1b11b582022-12-09 20:38:441388 test.AdvanceTime(TimeDelta::Millis(33));
1389 EXPECT_TRUE(sent_packets.empty());
1390
1391 // Send a new frame.
Danil Chapovalov9c584832023-09-18 13:48:491392 encoded_image.SetRtpTimestamp(3);
Erik Språng1b11b582022-12-09 20:38:441393 encoded_image.capture_time_ms_ = 4;
1394 EXPECT_EQ(test.router()
1395 ->OnEncodedImage(encoded_image, /*codec_specific=*/nullptr)
1396 .error,
1397 EncodedImageCallback::Result::OK);
1398 test.AdvanceTime(TimeDelta::Millis(33));
1399
1400 // Advance time, check we get new packets - but only for the second frame.
1401 EXPECT_FALSE(sent_packets.empty());
1402 EXPECT_NE(sent_packets[0].Timestamp(), first_frame_timestamp);
1403}
1404
Danil Chapovalov0f027282024-09-24 09:22:551405TEST(RtpVideoSenderTest,
1406 ClearsPendingPacketsOnInactivationWithLayerAllocation) {
1407 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {}, kPayloadType, {});
1408 test.SetSending(true);
1409
1410 RtpHeaderExtensionMap extensions;
1411 extensions.Register<RtpDependencyDescriptorExtension>(
1412 kDependencyDescriptorExtensionId);
1413 std::vector<RtpPacket> sent_packets;
1414 ON_CALL(test.transport(), SendRtp)
1415 .WillByDefault([&](rtc::ArrayView<const uint8_t> packet,
1416 const PacketOptions& options) {
1417 sent_packets.emplace_back(&extensions);
1418 EXPECT_TRUE(sent_packets.back().Parse(packet));
1419 return true;
1420 });
1421
1422 // Set a very low bitrate.
1423 test.router()->OnBitrateUpdated(
1424 CreateBitrateAllocationUpdate(/*rate_bps=*/10'000),
1425 /*framerate=*/30);
1426
1427 // Create and send a large keyframe.
1428 constexpr uint8_t kImage[10'000] = {};
1429 EncodedImage encoded_image;
1430 encoded_image.SetSimulcastIndex(0);
1431 encoded_image.SetRtpTimestamp(1);
1432 encoded_image.capture_time_ms_ = 2;
1433 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1434 encoded_image.SetEncodedData(
1435 EncodedImageBuffer::Create(kImage, std::size(kImage)));
1436 EXPECT_EQ(test.router()
1437 ->OnEncodedImage(encoded_image, /*codec_specific=*/nullptr)
1438 .error,
1439 EncodedImageCallback::Result::OK);
1440
1441 // Advance time a small amount, check that sent data is only part of the
1442 // image.
1443 test.AdvanceTime(TimeDelta::Millis(5));
1444 DataSize transmitted_payload = DataSize::Zero();
1445 for (const RtpPacket& packet : sent_packets) {
1446 transmitted_payload += DataSize::Bytes(packet.payload_size());
1447 // Make sure we don't see the end of the frame.
1448 EXPECT_FALSE(packet.Marker());
1449 }
1450 EXPECT_GT(transmitted_payload, DataSize::Zero());
1451 EXPECT_LT(transmitted_payload, DataSize::Bytes(std::size(kImage)) / 3);
1452
1453 // Record the RTP timestamp of the first frame.
1454 const uint32_t first_frame_timestamp = sent_packets[0].Timestamp();
1455 sent_packets.clear();
1456
1457 // Disable the 1st sending module and advance time slightly. No packets should
1458 // be sent.
1459 test.router()->OnVideoLayersAllocationUpdated(
1460 {.active_spatial_layers = {{.rtp_stream_index = 1}}});
1461 test.AdvanceTime(TimeDelta::Millis(20));
1462 EXPECT_THAT(sent_packets, IsEmpty());
1463
1464 // Reactive the send module - any packets should have been removed, so nothing
1465 // should be transmitted.
1466 test.router()->OnVideoLayersAllocationUpdated(
1467 {.active_spatial_layers = {{.rtp_stream_index = 0},
1468 {.rtp_stream_index = 1}}});
1469 test.AdvanceTime(TimeDelta::Millis(33));
1470 EXPECT_THAT(sent_packets, IsEmpty());
1471
1472 // Send a new frame.
1473 encoded_image.SetRtpTimestamp(3);
1474 encoded_image.capture_time_ms_ = 4;
1475 EXPECT_EQ(test.router()
1476 ->OnEncodedImage(encoded_image, /*codec_specific=*/nullptr)
1477 .error,
1478 EncodedImageCallback::Result::OK);
1479 test.AdvanceTime(TimeDelta::Millis(33));
1480
1481 // Advance time, check we get new packets - but only for the second frame.
1482 ASSERT_THAT(sent_packets, SizeIs(Ge(1)));
1483 EXPECT_NE(sent_packets[0].Timestamp(), first_frame_timestamp);
1484}
1485
Ying Wang2d598532023-06-01 05:55:361486// Integration test verifying that when retransmission mode is set to
1487// kRetransmitBaseLayer,only base layer is retransmitted.
1488TEST(RtpVideoSenderTest, RetransmitsBaseLayerOnly) {
1489 RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
1490 kPayloadType, {});
Per K979b6d62024-01-26 10:18:261491 test.SetSending(true);
Ying Wang2d598532023-06-01 05:55:361492
1493 test.router()->SetRetransmissionMode(kRetransmitBaseLayer);
1494 constexpr uint8_t kPayload = 'a';
1495 EncodedImage encoded_image;
Danil Chapovalov9c584832023-09-18 13:48:491496 encoded_image.SetRtpTimestamp(1);
Ying Wang2d598532023-06-01 05:55:361497 encoded_image.capture_time_ms_ = 2;
1498 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
1499 encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
1500
1501 // Send two tiny images, mapping to two RTP packets. Capture sequence numbers.
1502 std::vector<uint16_t> rtp_sequence_numbers;
1503 std::vector<uint16_t> transport_sequence_numbers;
1504 std::vector<uint16_t> base_sequence_numbers;
1505 EXPECT_CALL(test.transport(), SendRtp)
1506 .Times(2)
1507 .WillRepeatedly([&rtp_sequence_numbers, &transport_sequence_numbers](
Harald Alvestrandd43af912023-08-15 11:41:451508 rtc::ArrayView<const uint8_t> packet,
Ying Wang2d598532023-06-01 05:55:361509 const PacketOptions& options) {
1510 RtpPacket rtp_packet;
Harald Alvestrandd43af912023-08-15 11:41:451511 EXPECT_TRUE(rtp_packet.Parse(packet));
Ying Wang2d598532023-06-01 05:55:361512 rtp_sequence_numbers.push_back(rtp_packet.SequenceNumber());
1513 transport_sequence_numbers.push_back(options.packet_id);
1514 return true;
1515 });
1516 CodecSpecificInfo key_codec_info;
1517 key_codec_info.codecType = kVideoCodecVP8;
1518 key_codec_info.codecSpecific.VP8.temporalIdx = 0;
1519 EXPECT_EQ(EncodedImageCallback::Result::OK,
1520 test.router()->OnEncodedImage(
1521 encoded_image, &key_codec_info).error);
Danil Chapovalov9c584832023-09-18 13:48:491522 encoded_image.SetRtpTimestamp(2);
Ying Wang2d598532023-06-01 05:55:361523 encoded_image.capture_time_ms_ = 3;
1524 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
1525 CodecSpecificInfo delta_codec_info;
1526 delta_codec_info.codecType = kVideoCodecVP8;
1527 delta_codec_info.codecSpecific.VP8.temporalIdx = 1;
1528 EXPECT_EQ(EncodedImageCallback::Result::OK,
1529 test.router()->OnEncodedImage(
1530 encoded_image, &delta_codec_info).error);
1531
1532 test.AdvanceTime(TimeDelta::Millis(33));
1533
1534 // Construct a NACK message for requesting retransmission of both packet.
1535 rtcp::Nack nack;
1536 nack.SetMediaSsrc(kSsrc1);
1537 nack.SetPacketIds(rtp_sequence_numbers);
1538 rtc::Buffer nack_buffer = nack.Build();
1539
1540 std::vector<uint16_t> retransmitted_rtp_sequence_numbers;
1541 EXPECT_CALL(test.transport(), SendRtp)
1542 .Times(1)
1543 .WillRepeatedly([&retransmitted_rtp_sequence_numbers](
Harald Alvestrandd43af912023-08-15 11:41:451544 rtc::ArrayView<const uint8_t> packet,
Ying Wang2d598532023-06-01 05:55:361545 const PacketOptions& options) {
1546 RtpPacket rtp_packet;
Harald Alvestrandd43af912023-08-15 11:41:451547 EXPECT_TRUE(rtp_packet.Parse(packet));
Ying Wang2d598532023-06-01 05:55:361548 EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1);
1549 // Capture the retransmitted sequence number from the RTX header.
1550 rtc::ArrayView<const uint8_t> payload = rtp_packet.payload();
1551 retransmitted_rtp_sequence_numbers.push_back(
1552 ByteReader<uint16_t>::ReadBigEndian(payload.data()));
1553 return true;
1554 });
1555 test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
1556 test.AdvanceTime(TimeDelta::Millis(33));
1557
1558 // Verify that only base layer packet was retransmitted.
1559 std::vector<uint16_t> base_rtp_sequence_numbers(rtp_sequence_numbers.begin(),
1560 rtp_sequence_numbers.begin() + 1);
1561 EXPECT_EQ(retransmitted_rtp_sequence_numbers, base_rtp_sequence_numbers);
1562}
1563
mflodman@webrtc.org02270cd2015-02-06 13:10:191564} // namespace webrtc