blob: 90027bbc489ef5c87117407b0b40656a495b7a05 [file] [log] [blame]
nisseeed52bf2017-05-19 06:15:19 -07001/*
2 * Copyright (c) 2017 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "call/rtx_receive_stream.h"
Jonas Olssona4d87372019-07-05 19:08:33 +020012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "call/test/mock_rtp_packet_sink_interface.h"
14#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
15#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
16#include "modules/rtp_rtcp/source/rtp_packet_received.h"
17#include "test/gmock.h"
18#include "test/gtest.h"
nisseeed52bf2017-05-19 06:15:19 -070019
20namespace webrtc {
21
22namespace {
23
24using ::testing::_;
25using ::testing::StrictMock;
26
nisseeed52bf2017-05-19 06:15:19 -070027constexpr int kMediaPayloadType = 100;
28constexpr int kRtxPayloadType = 98;
nisse38644992017-08-30 04:16:40 -070029constexpr int kUnknownPayloadType = 90;
nisseeed52bf2017-05-19 06:15:19 -070030constexpr uint32_t kMediaSSRC = 0x3333333;
31constexpr uint16_t kMediaSeqno = 0x5657;
32
33constexpr uint8_t kRtxPacket[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +020034 0x80, // Version 2.
35 98, // Payload type.
36 0x12,
37 0x34, // Seqno.
38 0x11,
39 0x11,
40 0x11,
41 0x11, // Timestamp.
42 0x22,
43 0x22,
44 0x22,
45 0x22, // SSRC.
nisseeed52bf2017-05-19 06:15:19 -070046 // RTX header.
Jonas Olssona4d87372019-07-05 19:08:33 +020047 0x56,
48 0x57, // Orig seqno.
nisseeed52bf2017-05-19 06:15:19 -070049 // Payload.
50 0xee,
51};
52
Niels Möller28214cd2019-10-09 17:44:40 +020053constexpr uint8_t kRtxPacketWithPadding[] = {
54 0xa0, // Version 2, P set
55 98, // Payload type.
56 0x12,
57 0x34, // Seqno.
58 0x11,
59 0x11,
60 0x11,
61 0x11, // Timestamp.
62 0x22,
63 0x22,
64 0x22,
65 0x22, // SSRC.
66 // RTX header.
67 0x56,
68 0x57, // Orig seqno.
69 // Padding
70 0x1,
71};
72
nisseeed52bf2017-05-19 06:15:19 -070073constexpr uint8_t kRtxPacketWithCVO[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +020074 0x90, // Version 2, X set.
75 98, // Payload type.
76 0x12,
77 0x34, // Seqno.
78 0x11,
79 0x11,
80 0x11,
81 0x11, // Timestamp.
82 0x22,
83 0x22,
84 0x22,
85 0x22, // SSRC.
86 0xbe,
87 0xde,
88 0x00,
89 0x01, // Extension header.
90 0x30,
91 0x01,
92 0x00,
93 0x00, // 90 degree rotation.
nisseeed52bf2017-05-19 06:15:19 -070094 // RTX header.
Jonas Olssona4d87372019-07-05 19:08:33 +020095 0x56,
96 0x57, // Orig seqno.
nisseeed52bf2017-05-19 06:15:19 -070097 // Payload.
98 0xee,
99};
100
101std::map<int, int> PayloadTypeMapping() {
nisse38644992017-08-30 04:16:40 -0700102 const std::map<int, int> m = {{kRtxPayloadType, kMediaPayloadType}};
nisseeed52bf2017-05-19 06:15:19 -0700103 return m;
104}
105
106template <typename T>
107rtc::ArrayView<T> Truncate(rtc::ArrayView<T> a, size_t drop) {
108 return a.subview(0, a.size() - drop);
109}
110
111} // namespace
112
113TEST(RtxReceiveStreamTest, RestoresPacketPayload) {
114 StrictMock<MockRtpPacketSink> media_sink;
115 RtxReceiveStream rtx_sink(&media_sink, PayloadTypeMapping(), kMediaSSRC);
116 RtpPacketReceived rtx_packet;
117 EXPECT_TRUE(rtx_packet.Parse(rtc::ArrayView<const uint8_t>(kRtxPacket)));
118
Niels Möller28214cd2019-10-09 17:44:40 +0200119 EXPECT_CALL(media_sink, OnRtpPacket)
120 .WillOnce([](const RtpPacketReceived& packet) {
nisseeed52bf2017-05-19 06:15:19 -0700121 EXPECT_EQ(packet.SequenceNumber(), kMediaSeqno);
122 EXPECT_EQ(packet.Ssrc(), kMediaSSRC);
123 EXPECT_EQ(packet.PayloadType(), kMediaPayloadType);
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200124 EXPECT_THAT(packet.payload(), ::testing::ElementsAre(0xee));
Niels Möller28214cd2019-10-09 17:44:40 +0200125 });
nisseeed52bf2017-05-19 06:15:19 -0700126
127 rtx_sink.OnRtpPacket(rtx_packet);
128}
129
nisse38644992017-08-30 04:16:40 -0700130TEST(RtxReceiveStreamTest, SetsRecoveredFlag) {
131 StrictMock<MockRtpPacketSink> media_sink;
132 RtxReceiveStream rtx_sink(&media_sink, PayloadTypeMapping(), kMediaSSRC);
133 RtpPacketReceived rtx_packet;
134 EXPECT_TRUE(rtx_packet.Parse(rtc::ArrayView<const uint8_t>(kRtxPacket)));
135 EXPECT_FALSE(rtx_packet.recovered());
Niels Möller28214cd2019-10-09 17:44:40 +0200136 EXPECT_CALL(media_sink, OnRtpPacket)
137 .WillOnce([](const RtpPacketReceived& packet) {
nisse38644992017-08-30 04:16:40 -0700138 EXPECT_TRUE(packet.recovered());
Niels Möller28214cd2019-10-09 17:44:40 +0200139 });
nisse38644992017-08-30 04:16:40 -0700140
141 rtx_sink.OnRtpPacket(rtx_packet);
142}
143
nisseeed52bf2017-05-19 06:15:19 -0700144TEST(RtxReceiveStreamTest, IgnoresUnknownPayloadType) {
145 StrictMock<MockRtpPacketSink> media_sink;
nisse38644992017-08-30 04:16:40 -0700146 const std::map<int, int> payload_type_mapping = {
147 {kUnknownPayloadType, kMediaPayloadType}};
148
149 RtxReceiveStream rtx_sink(&media_sink, payload_type_mapping, kMediaSSRC);
nisseeed52bf2017-05-19 06:15:19 -0700150 RtpPacketReceived rtx_packet;
151 EXPECT_TRUE(rtx_packet.Parse(rtc::ArrayView<const uint8_t>(kRtxPacket)));
152 rtx_sink.OnRtpPacket(rtx_packet);
153}
154
155TEST(RtxReceiveStreamTest, IgnoresTruncatedPacket) {
156 StrictMock<MockRtpPacketSink> media_sink;
157 RtxReceiveStream rtx_sink(&media_sink, PayloadTypeMapping(), kMediaSSRC);
158 RtpPacketReceived rtx_packet;
159 EXPECT_TRUE(
160 rtx_packet.Parse(Truncate(rtc::ArrayView<const uint8_t>(kRtxPacket), 2)));
161 rtx_sink.OnRtpPacket(rtx_packet);
162}
163
164TEST(RtxReceiveStreamTest, CopiesRtpHeaderExtensions) {
165 StrictMock<MockRtpPacketSink> media_sink;
166 RtxReceiveStream rtx_sink(&media_sink, PayloadTypeMapping(), kMediaSSRC);
167 RtpHeaderExtensionMap extension_map;
168 extension_map.RegisterByType(3, kRtpExtensionVideoRotation);
169 RtpPacketReceived rtx_packet(&extension_map);
Yves Gerey665174f2018-06-19 15:03:05 +0200170 EXPECT_TRUE(
171 rtx_packet.Parse(rtc::ArrayView<const uint8_t>(kRtxPacketWithCVO)));
nisseeed52bf2017-05-19 06:15:19 -0700172
173 VideoRotation rotation = kVideoRotation_0;
174 EXPECT_TRUE(rtx_packet.GetExtension<VideoOrientation>(&rotation));
175 EXPECT_EQ(kVideoRotation_90, rotation);
176
Niels Möller28214cd2019-10-09 17:44:40 +0200177 EXPECT_CALL(media_sink, OnRtpPacket)
178 .WillOnce([](const RtpPacketReceived& packet) {
nisseeed52bf2017-05-19 06:15:19 -0700179 EXPECT_EQ(packet.SequenceNumber(), kMediaSeqno);
180 EXPECT_EQ(packet.Ssrc(), kMediaSSRC);
181 EXPECT_EQ(packet.PayloadType(), kMediaPayloadType);
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200182 EXPECT_THAT(packet.payload(), ::testing::ElementsAre(0xee));
nisseeed52bf2017-05-19 06:15:19 -0700183 VideoRotation rotation = kVideoRotation_0;
184 EXPECT_TRUE(packet.GetExtension<VideoOrientation>(&rotation));
185 EXPECT_EQ(rotation, kVideoRotation_90);
Niels Möller28214cd2019-10-09 17:44:40 +0200186 });
187
188 rtx_sink.OnRtpPacket(rtx_packet);
189}
190
191TEST(RtxReceiveStreamTest, SupportsLargePacket) {
192 StrictMock<MockRtpPacketSink> media_sink;
193 RtxReceiveStream rtx_sink(&media_sink, PayloadTypeMapping(), kMediaSSRC);
194 RtpPacketReceived rtx_packet;
195 constexpr int kRtxPacketSize = 2000;
196 constexpr int kRtxPayloadOffset = 14;
197 uint8_t large_rtx_packet[kRtxPacketSize];
198 memcpy(large_rtx_packet, kRtxPacket, sizeof(kRtxPacket));
199 rtc::ArrayView<uint8_t> payload(large_rtx_packet + kRtxPayloadOffset,
200 kRtxPacketSize - kRtxPayloadOffset);
201
202 // Fill payload.
203 for (size_t i = 0; i < payload.size(); i++) {
204 payload[i] = i;
205 }
206 EXPECT_TRUE(
207 rtx_packet.Parse(rtc::ArrayView<const uint8_t>(large_rtx_packet)));
208
209 EXPECT_CALL(media_sink, OnRtpPacket)
210 .WillOnce([&](const RtpPacketReceived& packet) {
211 EXPECT_EQ(packet.SequenceNumber(), kMediaSeqno);
212 EXPECT_EQ(packet.Ssrc(), kMediaSSRC);
213 EXPECT_EQ(packet.PayloadType(), kMediaPayloadType);
214 EXPECT_THAT(packet.payload(), ::testing::ElementsAreArray(payload));
215 });
216
217 rtx_sink.OnRtpPacket(rtx_packet);
218}
219
220TEST(RtxReceiveStreamTest, SupportsLargePacketWithPadding) {
221 StrictMock<MockRtpPacketSink> media_sink;
222 RtxReceiveStream rtx_sink(&media_sink, PayloadTypeMapping(), kMediaSSRC);
223 RtpPacketReceived rtx_packet;
224 constexpr int kRtxPacketSize = 2000;
225 constexpr int kRtxPayloadOffset = 14;
226 constexpr int kRtxPaddingSize = 50;
227 uint8_t large_rtx_packet[kRtxPacketSize];
228 memcpy(large_rtx_packet, kRtxPacketWithPadding,
229 sizeof(kRtxPacketWithPadding));
230 rtc::ArrayView<uint8_t> payload(
231 large_rtx_packet + kRtxPayloadOffset,
232 kRtxPacketSize - kRtxPayloadOffset - kRtxPaddingSize);
233 rtc::ArrayView<uint8_t> padding(
234 large_rtx_packet + kRtxPacketSize - kRtxPaddingSize, kRtxPaddingSize);
235
236 // Fill payload.
237 for (size_t i = 0; i < payload.size(); i++) {
238 payload[i] = i;
239 }
240 // Fill padding. Only value of last padding byte matters.
241 for (size_t i = 0; i < padding.size(); i++) {
242 padding[i] = kRtxPaddingSize;
243 }
244
245 EXPECT_TRUE(
246 rtx_packet.Parse(rtc::ArrayView<const uint8_t>(large_rtx_packet)));
247
248 EXPECT_CALL(media_sink, OnRtpPacket)
249 .WillOnce([&](const RtpPacketReceived& packet) {
250 EXPECT_EQ(packet.SequenceNumber(), kMediaSeqno);
251 EXPECT_EQ(packet.Ssrc(), kMediaSSRC);
252 EXPECT_EQ(packet.PayloadType(), kMediaPayloadType);
253 EXPECT_THAT(packet.payload(), ::testing::ElementsAreArray(payload));
254 });
nisseeed52bf2017-05-19 06:15:19 -0700255
256 rtx_sink.OnRtpPacket(rtx_packet);
257}
258
259} // namespace webrtc