1 /*
2 * Copyright (c) 2012 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
11 // Unit tests for RedPayloadSplitter class.
12
13 #include "modules/audio_coding/neteq/red_payload_splitter.h"
14
15 #include <assert.h>
16
17 #include <memory>
18 #include <utility> // pair
19
20 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
21 #include "modules/audio_coding/neteq/mock/mock_decoder_database.h"
22 #include "modules/audio_coding/neteq/packet.h"
23 #include "rtc_base/numerics/safe_conversions.h"
24 #include "test/gtest.h"
25 #include "test/mock_audio_decoder_factory.h"
26
27 using ::testing::Return;
28 using ::testing::ReturnNull;
29
30 namespace webrtc {
31
32 static const int kRedPayloadType = 100;
33 static const size_t kPayloadLength = 10;
34 static const size_t kRedHeaderLength = 4; // 4 bytes RED header.
35 static const uint16_t kSequenceNumber = 0;
36 static const uint32_t kBaseTimestamp = 0x12345678;
37
38 // A possible Opus packet that contains FEC is the following.
39 // The frame is 20 ms in duration.
40 //
41 // 0 1 2 3
42 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
43 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 // |0|0|0|0|1|0|0|0|x|1|x|x|x|x|x|x|x| |
45 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
46 // | Compressed frame 1 (N-2 bytes)... :
47 // : |
48 // | |
49 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
CreateOpusFecPayload(uint8_t * payload,size_t payload_length,uint8_t payload_value)50 void CreateOpusFecPayload(uint8_t* payload,
51 size_t payload_length,
52 uint8_t payload_value) {
53 if (payload_length < 2) {
54 return;
55 }
56 payload[0] = 0x08;
57 payload[1] = 0x40;
58 memset(&payload[2], payload_value, payload_length - 2);
59 }
60
61 // RED headers (according to RFC 2198):
62 //
63 // 0 1 2 3
64 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
65 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66 // |F| block PT | timestamp offset | block length |
67 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68 //
69 // Last RED header:
70 // 0 1 2 3 4 5 6 7
71 // +-+-+-+-+-+-+-+-+
72 // |0| Block PT |
73 // +-+-+-+-+-+-+-+-+
74
75 // Creates a RED packet, with |num_payloads| payloads, with payload types given
76 // by the values in array |payload_types| (which must be of length
77 // |num_payloads|). Each redundant payload is |timestamp_offset| samples
78 // "behind" the the previous payload.
CreateRedPayload(size_t num_payloads,uint8_t * payload_types,int timestamp_offset,bool embed_opus_fec=false)79 Packet CreateRedPayload(size_t num_payloads,
80 uint8_t* payload_types,
81 int timestamp_offset,
82 bool embed_opus_fec = false) {
83 Packet packet;
84 packet.payload_type = kRedPayloadType;
85 packet.timestamp = kBaseTimestamp;
86 packet.sequence_number = kSequenceNumber;
87 packet.payload.SetSize((kPayloadLength + 1) +
88 (num_payloads - 1) *
89 (kPayloadLength + kRedHeaderLength));
90 uint8_t* payload_ptr = packet.payload.data();
91 for (size_t i = 0; i < num_payloads; ++i) {
92 // Write the RED headers.
93 if (i == num_payloads - 1) {
94 // Special case for last payload.
95 *payload_ptr = payload_types[i] & 0x7F; // F = 0;
96 ++payload_ptr;
97 break;
98 }
99 *payload_ptr = payload_types[i] & 0x7F;
100 // Not the last block; set F = 1.
101 *payload_ptr |= 0x80;
102 ++payload_ptr;
103 int this_offset = rtc::checked_cast<int>(
104 (num_payloads - i - 1) * timestamp_offset);
105 *payload_ptr = this_offset >> 6;
106 ++payload_ptr;
107 assert(kPayloadLength <= 1023); // Max length described by 10 bits.
108 *payload_ptr = ((this_offset & 0x3F) << 2) | (kPayloadLength >> 8);
109 ++payload_ptr;
110 *payload_ptr = kPayloadLength & 0xFF;
111 ++payload_ptr;
112 }
113 for (size_t i = 0; i < num_payloads; ++i) {
114 // Write |i| to all bytes in each payload.
115 if (embed_opus_fec) {
116 CreateOpusFecPayload(payload_ptr, kPayloadLength,
117 static_cast<uint8_t>(i));
118 } else {
119 memset(payload_ptr, static_cast<int>(i), kPayloadLength);
120 }
121 payload_ptr += kPayloadLength;
122 }
123 return packet;
124 }
125
126 // Create a packet with all payload bytes set to |payload_value|.
CreatePacket(uint8_t payload_type,size_t payload_length,uint8_t payload_value,bool opus_fec=false)127 Packet CreatePacket(uint8_t payload_type,
128 size_t payload_length,
129 uint8_t payload_value,
130 bool opus_fec = false) {
131 Packet packet;
132 packet.payload_type = payload_type;
133 packet.timestamp = kBaseTimestamp;
134 packet.sequence_number = kSequenceNumber;
135 packet.payload.SetSize(payload_length);
136 if (opus_fec) {
137 CreateOpusFecPayload(packet.payload.data(), packet.payload.size(),
138 payload_value);
139 } else {
140 memset(packet.payload.data(), payload_value, packet.payload.size());
141 }
142 return packet;
143 }
144
145 // Checks that |packet| has the attributes given in the remaining parameters.
VerifyPacket(const Packet & packet,size_t payload_length,uint8_t payload_type,uint16_t sequence_number,uint32_t timestamp,uint8_t payload_value,Packet::Priority priority)146 void VerifyPacket(const Packet& packet,
147 size_t payload_length,
148 uint8_t payload_type,
149 uint16_t sequence_number,
150 uint32_t timestamp,
151 uint8_t payload_value,
152 Packet::Priority priority) {
153 EXPECT_EQ(payload_length, packet.payload.size());
154 EXPECT_EQ(payload_type, packet.payload_type);
155 EXPECT_EQ(sequence_number, packet.sequence_number);
156 EXPECT_EQ(timestamp, packet.timestamp);
157 EXPECT_EQ(priority, packet.priority);
158 ASSERT_FALSE(packet.payload.empty());
159 for (size_t i = 0; i < packet.payload.size(); ++i) {
160 ASSERT_EQ(payload_value, packet.payload.data()[i]);
161 }
162 }
163
VerifyPacket(const Packet & packet,size_t payload_length,uint8_t payload_type,uint16_t sequence_number,uint32_t timestamp,uint8_t payload_value,bool primary)164 void VerifyPacket(const Packet& packet,
165 size_t payload_length,
166 uint8_t payload_type,
167 uint16_t sequence_number,
168 uint32_t timestamp,
169 uint8_t payload_value,
170 bool primary) {
171 return VerifyPacket(packet, payload_length, payload_type, sequence_number,
172 timestamp, payload_value,
173 Packet::Priority{0, primary ? 0 : 1});
174 }
175
176 // Start of test definitions.
177
TEST(RedPayloadSplitter,CreateAndDestroy)178 TEST(RedPayloadSplitter, CreateAndDestroy) {
179 RedPayloadSplitter* splitter = new RedPayloadSplitter;
180 delete splitter;
181 }
182
183 // Packet A is split into A1 and A2.
TEST(RedPayloadSplitter,OnePacketTwoPayloads)184 TEST(RedPayloadSplitter, OnePacketTwoPayloads) {
185 uint8_t payload_types[] = {0, 0};
186 const int kTimestampOffset = 160;
187 PacketList packet_list;
188 packet_list.push_back(CreateRedPayload(2, payload_types, kTimestampOffset));
189 RedPayloadSplitter splitter;
190 EXPECT_TRUE(splitter.SplitRed(&packet_list));
191 ASSERT_EQ(2u, packet_list.size());
192 // Check first packet. The first in list should always be the primary payload.
193 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[1],
194 kSequenceNumber, kBaseTimestamp, 1, true);
195 packet_list.pop_front();
196 // Check second packet.
197 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
198 kSequenceNumber, kBaseTimestamp - kTimestampOffset, 0, false);
199 }
200
201 // Packets A and B are not split at all. Only the RED header in each packet is
202 // removed.
TEST(RedPayloadSplitter,TwoPacketsOnePayload)203 TEST(RedPayloadSplitter, TwoPacketsOnePayload) {
204 uint8_t payload_types[] = {0};
205 const int kTimestampOffset = 160;
206 // Create first packet, with a single RED payload.
207 PacketList packet_list;
208 packet_list.push_back(CreateRedPayload(1, payload_types, kTimestampOffset));
209 // Create second packet, with a single RED payload.
210 {
211 Packet packet = CreateRedPayload(1, payload_types, kTimestampOffset);
212 // Manually change timestamp and sequence number of second packet.
213 packet.timestamp += kTimestampOffset;
214 packet.sequence_number++;
215 packet_list.push_back(std::move(packet));
216 }
217 RedPayloadSplitter splitter;
218 EXPECT_TRUE(splitter.SplitRed(&packet_list));
219 ASSERT_EQ(2u, packet_list.size());
220 // Check first packet.
221 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
222 kSequenceNumber, kBaseTimestamp, 0, true);
223 packet_list.pop_front();
224 // Check second packet.
225 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
226 kSequenceNumber + 1, kBaseTimestamp + kTimestampOffset, 0, true);
227 }
228
229 // Packets A and B are split into packets A1, A2, A3, B1, B2, B3, with
230 // attributes as follows:
231 //
232 // A1* A2 A3 B1* B2 B3
233 // Payload type 0 1 2 0 1 2
234 // Timestamp b b-o b-2o b+o b b-o
235 // Sequence number 0 0 0 1 1 1
236 //
237 // b = kBaseTimestamp, o = kTimestampOffset, * = primary.
TEST(RedPayloadSplitter,TwoPacketsThreePayloads)238 TEST(RedPayloadSplitter, TwoPacketsThreePayloads) {
239 uint8_t payload_types[] = {2, 1, 0}; // Primary is the last one.
240 const int kTimestampOffset = 160;
241 // Create first packet, with 3 RED payloads.
242 PacketList packet_list;
243 packet_list.push_back(CreateRedPayload(3, payload_types, kTimestampOffset));
244 // Create first packet, with 3 RED payloads.
245 {
246 Packet packet = CreateRedPayload(3, payload_types, kTimestampOffset);
247 // Manually change timestamp and sequence number of second packet.
248 packet.timestamp += kTimestampOffset;
249 packet.sequence_number++;
250 packet_list.push_back(std::move(packet));
251 }
252 RedPayloadSplitter splitter;
253 EXPECT_TRUE(splitter.SplitRed(&packet_list));
254 ASSERT_EQ(6u, packet_list.size());
255 // Check first packet, A1.
256 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[2],
257 kSequenceNumber, kBaseTimestamp, 2, {0, 0});
258 packet_list.pop_front();
259 // Check second packet, A2.
260 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[1],
261 kSequenceNumber, kBaseTimestamp - kTimestampOffset, 1, {0, 1});
262 packet_list.pop_front();
263 // Check third packet, A3.
264 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
265 kSequenceNumber, kBaseTimestamp - 2 * kTimestampOffset, 0,
266 {0, 2});
267 packet_list.pop_front();
268 // Check fourth packet, B1.
269 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[2],
270 kSequenceNumber + 1, kBaseTimestamp + kTimestampOffset, 2,
271 {0, 0});
272 packet_list.pop_front();
273 // Check fifth packet, B2.
274 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[1],
275 kSequenceNumber + 1, kBaseTimestamp, 1, {0, 1});
276 packet_list.pop_front();
277 // Check sixth packet, B3.
278 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
279 kSequenceNumber + 1, kBaseTimestamp - kTimestampOffset, 0,
280 {0, 2});
281 }
282
283 // Creates a list with 4 packets with these payload types:
284 // 0 = CNGnb
285 // 1 = PCMu
286 // 2 = DTMF (AVT)
287 // 3 = iLBC
288 // We expect the method CheckRedPayloads to discard the iLBC packet, since it
289 // is a non-CNG, non-DTMF payload of another type than the first speech payload
290 // found in the list (which is PCMu).
TEST(RedPayloadSplitter,CheckRedPayloads)291 TEST(RedPayloadSplitter, CheckRedPayloads) {
292 PacketList packet_list;
293 for (uint8_t i = 0; i <= 3; ++i) {
294 // Create packet with payload type |i|, payload length 10 bytes, all 0.
295 packet_list.push_back(CreatePacket(i, 10, 0));
296 }
297
298 // Use a real DecoderDatabase object here instead of a mock, since it is
299 // easier to just register the payload types and let the actual implementation
300 // do its job.
301 DecoderDatabase decoder_database(
302 new rtc::RefCountedObject<MockAudioDecoderFactory>);
303 decoder_database.RegisterPayload(0, NetEqDecoder::kDecoderCNGnb, "cng-nb");
304 decoder_database.RegisterPayload(1, NetEqDecoder::kDecoderPCMu, "pcmu");
305 decoder_database.RegisterPayload(2, NetEqDecoder::kDecoderAVT, "avt");
306 decoder_database.RegisterPayload(3, NetEqDecoder::kDecoderILBC, "ilbc");
307
308 RedPayloadSplitter splitter;
309 splitter.CheckRedPayloads(&packet_list, decoder_database);
310
311 ASSERT_EQ(3u, packet_list.size()); // Should have dropped the last packet.
312 // Verify packets. The loop verifies that payload types 0, 1, and 2 are in the
313 // list.
314 for (int i = 0; i <= 2; ++i) {
315 VerifyPacket(packet_list.front(), 10, i, kSequenceNumber, kBaseTimestamp, 0,
316 true);
317 packet_list.pop_front();
318 }
319 EXPECT_TRUE(packet_list.empty());
320 }
321
322 // Packet A is split into A1, A2 and A3. But the length parameter is off, so
323 // the last payloads should be discarded.
TEST(RedPayloadSplitter,WrongPayloadLength)324 TEST(RedPayloadSplitter, WrongPayloadLength) {
325 uint8_t payload_types[] = {0, 0, 0};
326 const int kTimestampOffset = 160;
327 PacketList packet_list;
328 {
329 Packet packet = CreateRedPayload(3, payload_types, kTimestampOffset);
330 // Manually tamper with the payload length of the packet.
331 // This is one byte too short for the second payload (out of three).
332 // We expect only the first payload to be returned.
333 packet.payload.SetSize(packet.payload.size() - (kPayloadLength + 1));
334 packet_list.push_back(std::move(packet));
335 }
336 RedPayloadSplitter splitter;
337 EXPECT_FALSE(splitter.SplitRed(&packet_list));
338 ASSERT_EQ(1u, packet_list.size());
339 // Check first packet.
340 VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
341 kSequenceNumber, kBaseTimestamp - 2 * kTimestampOffset, 0,
342 {0, 2});
343 packet_list.pop_front();
344 }
345
346 } // namespace webrtc
347