OLD | NEW |
| (Empty) |
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 PayloadSplitter class. | |
12 | |
13 #include "webrtc/modules/audio_coding/neteq/payload_splitter.h" | |
14 | |
15 #include <assert.h> | |
16 | |
17 #include <memory> | |
18 #include <utility> // pair | |
19 | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 #include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h" | |
22 #include "webrtc/modules/audio_coding/codecs/mock/mock_audio_decoder_factory.h" | |
23 #include "webrtc/modules/audio_coding/neteq/mock/mock_decoder_database.h" | |
24 #include "webrtc/modules/audio_coding/neteq/packet.h" | |
25 | |
26 using ::testing::Return; | |
27 using ::testing::ReturnNull; | |
28 | |
29 namespace webrtc { | |
30 | |
31 static const int kRedPayloadType = 100; | |
32 static const size_t kPayloadLength = 10; | |
33 static const size_t kRedHeaderLength = 4; // 4 bytes RED header. | |
34 static const uint16_t kSequenceNumber = 0; | |
35 static const uint32_t kBaseTimestamp = 0x12345678; | |
36 | |
37 // A possible Opus packet that contains FEC is the following. | |
38 // The frame is 20 ms in duration. | |
39 // | |
40 // 0 1 2 3 | |
41 // 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 | |
42 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
43 // |0|0|0|0|1|0|0|0|x|1|x|x|x|x|x|x|x| | | |
44 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | |
45 // | Compressed frame 1 (N-2 bytes)... : | |
46 // : | | |
47 // | | | |
48 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
49 void CreateOpusFecPayload(uint8_t* payload, size_t payload_length, | |
50 uint8_t payload_value) { | |
51 if (payload_length < 2) { | |
52 return; | |
53 } | |
54 payload[0] = 0x08; | |
55 payload[1] = 0x40; | |
56 memset(&payload[2], payload_value, payload_length - 2); | |
57 } | |
58 | |
59 // RED headers (according to RFC 2198): | |
60 // | |
61 // 0 1 2 3 | |
62 // 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 | |
63 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
64 // |F| block PT | timestamp offset | block length | | |
65 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
66 // | |
67 // Last RED header: | |
68 // 0 1 2 3 4 5 6 7 | |
69 // +-+-+-+-+-+-+-+-+ | |
70 // |0| Block PT | | |
71 // +-+-+-+-+-+-+-+-+ | |
72 | |
73 // Creates a RED packet, with |num_payloads| payloads, with payload types given | |
74 // by the values in array |payload_types| (which must be of length | |
75 // |num_payloads|). Each redundant payload is |timestamp_offset| samples | |
76 // "behind" the the previous payload. | |
77 Packet* CreateRedPayload(size_t num_payloads, | |
78 uint8_t* payload_types, | |
79 int timestamp_offset, | |
80 bool embed_opus_fec = false) { | |
81 Packet* packet = new Packet; | |
82 packet->header.payloadType = kRedPayloadType; | |
83 packet->header.timestamp = kBaseTimestamp; | |
84 packet->header.sequenceNumber = kSequenceNumber; | |
85 packet->payload.SetSize((kPayloadLength + 1) + | |
86 (num_payloads - 1) * | |
87 (kPayloadLength + kRedHeaderLength)); | |
88 uint8_t* payload_ptr = packet->payload.data(); | |
89 for (size_t i = 0; i < num_payloads; ++i) { | |
90 // Write the RED headers. | |
91 if (i == num_payloads - 1) { | |
92 // Special case for last payload. | |
93 *payload_ptr = payload_types[i] & 0x7F; // F = 0; | |
94 ++payload_ptr; | |
95 break; | |
96 } | |
97 *payload_ptr = payload_types[i] & 0x7F; | |
98 // Not the last block; set F = 1. | |
99 *payload_ptr |= 0x80; | |
100 ++payload_ptr; | |
101 int this_offset = (num_payloads - i - 1) * timestamp_offset; | |
102 *payload_ptr = this_offset >> 6; | |
103 ++payload_ptr; | |
104 assert(kPayloadLength <= 1023); // Max length described by 10 bits. | |
105 *payload_ptr = ((this_offset & 0x3F) << 2) | (kPayloadLength >> 8); | |
106 ++payload_ptr; | |
107 *payload_ptr = kPayloadLength & 0xFF; | |
108 ++payload_ptr; | |
109 } | |
110 for (size_t i = 0; i < num_payloads; ++i) { | |
111 // Write |i| to all bytes in each payload. | |
112 if (embed_opus_fec) { | |
113 CreateOpusFecPayload(payload_ptr, kPayloadLength, | |
114 static_cast<uint8_t>(i)); | |
115 } else { | |
116 memset(payload_ptr, static_cast<int>(i), kPayloadLength); | |
117 } | |
118 payload_ptr += kPayloadLength; | |
119 } | |
120 return packet; | |
121 } | |
122 | |
123 // Create a packet with all payload bytes set to |payload_value|. | |
124 Packet* CreatePacket(uint8_t payload_type, size_t payload_length, | |
125 uint8_t payload_value, bool opus_fec = false) { | |
126 Packet* packet = new Packet; | |
127 packet->header.payloadType = payload_type; | |
128 packet->header.timestamp = kBaseTimestamp; | |
129 packet->header.sequenceNumber = kSequenceNumber; | |
130 packet->payload.SetSize(payload_length); | |
131 if (opus_fec) { | |
132 CreateOpusFecPayload(packet->payload.data(), packet->payload.size(), | |
133 payload_value); | |
134 } else { | |
135 memset(packet->payload.data(), payload_value, packet->payload.size()); | |
136 } | |
137 return packet; | |
138 } | |
139 | |
140 // Checks that |packet| has the attributes given in the remaining parameters. | |
141 void VerifyPacket(const Packet* packet, | |
142 size_t payload_length, | |
143 uint8_t payload_type, | |
144 uint16_t sequence_number, | |
145 uint32_t timestamp, | |
146 uint8_t payload_value, | |
147 bool primary = true) { | |
148 EXPECT_EQ(payload_length, packet->payload.size()); | |
149 EXPECT_EQ(payload_type, packet->header.payloadType); | |
150 EXPECT_EQ(sequence_number, packet->header.sequenceNumber); | |
151 EXPECT_EQ(timestamp, packet->header.timestamp); | |
152 EXPECT_EQ(primary, packet->primary); | |
153 ASSERT_FALSE(packet->payload.empty()); | |
154 for (size_t i = 0; i < packet->payload.size(); ++i) { | |
155 ASSERT_EQ(payload_value, packet->payload.data()[i]); | |
156 } | |
157 } | |
158 | |
159 // Start of test definitions. | |
160 | |
161 TEST(PayloadSplitter, CreateAndDestroy) { | |
162 PayloadSplitter* splitter = new PayloadSplitter; | |
163 delete splitter; | |
164 } | |
165 | |
166 // Packet A is split into A1 and A2. | |
167 TEST(RedPayloadSplitter, OnePacketTwoPayloads) { | |
168 uint8_t payload_types[] = {0, 0}; | |
169 const int kTimestampOffset = 160; | |
170 Packet* packet = CreateRedPayload(2, payload_types, kTimestampOffset); | |
171 PacketList packet_list; | |
172 packet_list.push_back(packet); | |
173 PayloadSplitter splitter; | |
174 EXPECT_EQ(PayloadSplitter::kOK, splitter.SplitRed(&packet_list)); | |
175 ASSERT_EQ(2u, packet_list.size()); | |
176 // Check first packet. The first in list should always be the primary payload. | |
177 packet = packet_list.front(); | |
178 VerifyPacket(packet, kPayloadLength, payload_types[1], kSequenceNumber, | |
179 kBaseTimestamp, 1, true); | |
180 delete packet; | |
181 packet_list.pop_front(); | |
182 // Check second packet. | |
183 packet = packet_list.front(); | |
184 VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber, | |
185 kBaseTimestamp - kTimestampOffset, 0, false); | |
186 delete packet; | |
187 } | |
188 | |
189 // Packets A and B are not split at all. Only the RED header in each packet is | |
190 // removed. | |
191 TEST(RedPayloadSplitter, TwoPacketsOnePayload) { | |
192 uint8_t payload_types[] = {0}; | |
193 const int kTimestampOffset = 160; | |
194 // Create first packet, with a single RED payload. | |
195 Packet* packet = CreateRedPayload(1, payload_types, kTimestampOffset); | |
196 PacketList packet_list; | |
197 packet_list.push_back(packet); | |
198 // Create second packet, with a single RED payload. | |
199 packet = CreateRedPayload(1, payload_types, kTimestampOffset); | |
200 // Manually change timestamp and sequence number of second packet. | |
201 packet->header.timestamp += kTimestampOffset; | |
202 packet->header.sequenceNumber++; | |
203 packet_list.push_back(packet); | |
204 PayloadSplitter splitter; | |
205 EXPECT_EQ(PayloadSplitter::kOK, splitter.SplitRed(&packet_list)); | |
206 ASSERT_EQ(2u, packet_list.size()); | |
207 // Check first packet. | |
208 packet = packet_list.front(); | |
209 VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber, | |
210 kBaseTimestamp, 0, true); | |
211 delete packet; | |
212 packet_list.pop_front(); | |
213 // Check second packet. | |
214 packet = packet_list.front(); | |
215 VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber + 1, | |
216 kBaseTimestamp + kTimestampOffset, 0, true); | |
217 delete packet; | |
218 } | |
219 | |
220 // Packets A and B are split into packets A1, A2, A3, B1, B2, B3, with | |
221 // attributes as follows: | |
222 // | |
223 // A1* A2 A3 B1* B2 B3 | |
224 // Payload type 0 1 2 0 1 2 | |
225 // Timestamp b b-o b-2o b+o b b-o | |
226 // Sequence number 0 0 0 1 1 1 | |
227 // | |
228 // b = kBaseTimestamp, o = kTimestampOffset, * = primary. | |
229 TEST(RedPayloadSplitter, TwoPacketsThreePayloads) { | |
230 uint8_t payload_types[] = {2, 1, 0}; // Primary is the last one. | |
231 const int kTimestampOffset = 160; | |
232 // Create first packet, with 3 RED payloads. | |
233 Packet* packet = CreateRedPayload(3, payload_types, kTimestampOffset); | |
234 PacketList packet_list; | |
235 packet_list.push_back(packet); | |
236 // Create first packet, with 3 RED payloads. | |
237 packet = CreateRedPayload(3, payload_types, kTimestampOffset); | |
238 // Manually change timestamp and sequence number of second packet. | |
239 packet->header.timestamp += kTimestampOffset; | |
240 packet->header.sequenceNumber++; | |
241 packet_list.push_back(packet); | |
242 PayloadSplitter splitter; | |
243 EXPECT_EQ(PayloadSplitter::kOK, splitter.SplitRed(&packet_list)); | |
244 ASSERT_EQ(6u, packet_list.size()); | |
245 // Check first packet, A1. | |
246 packet = packet_list.front(); | |
247 VerifyPacket(packet, kPayloadLength, payload_types[2], kSequenceNumber, | |
248 kBaseTimestamp, 2, true); | |
249 delete packet; | |
250 packet_list.pop_front(); | |
251 // Check second packet, A2. | |
252 packet = packet_list.front(); | |
253 VerifyPacket(packet, kPayloadLength, payload_types[1], kSequenceNumber, | |
254 kBaseTimestamp - kTimestampOffset, 1, false); | |
255 delete packet; | |
256 packet_list.pop_front(); | |
257 // Check third packet, A3. | |
258 packet = packet_list.front(); | |
259 VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber, | |
260 kBaseTimestamp - 2 * kTimestampOffset, 0, false); | |
261 delete packet; | |
262 packet_list.pop_front(); | |
263 // Check fourth packet, B1. | |
264 packet = packet_list.front(); | |
265 VerifyPacket(packet, kPayloadLength, payload_types[2], kSequenceNumber + 1, | |
266 kBaseTimestamp + kTimestampOffset, 2, true); | |
267 delete packet; | |
268 packet_list.pop_front(); | |
269 // Check fifth packet, B2. | |
270 packet = packet_list.front(); | |
271 VerifyPacket(packet, kPayloadLength, payload_types[1], kSequenceNumber + 1, | |
272 kBaseTimestamp, 1, false); | |
273 delete packet; | |
274 packet_list.pop_front(); | |
275 // Check sixth packet, B3. | |
276 packet = packet_list.front(); | |
277 VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber + 1, | |
278 kBaseTimestamp - kTimestampOffset, 0, false); | |
279 delete packet; | |
280 } | |
281 | |
282 // Creates a list with 4 packets with these payload types: | |
283 // 0 = CNGnb | |
284 // 1 = PCMu | |
285 // 2 = DTMF (AVT) | |
286 // 3 = iLBC | |
287 // We expect the method CheckRedPayloads to discard the iLBC packet, since it | |
288 // is a non-CNG, non-DTMF payload of another type than the first speech payload | |
289 // found in the list (which is PCMu). | |
290 TEST(RedPayloadSplitter, CheckRedPayloads) { | |
291 PacketList packet_list; | |
292 for (uint8_t i = 0; i <= 3; ++i) { | |
293 // Create packet with payload type |i|, payload length 10 bytes, all 0. | |
294 Packet* packet = CreatePacket(i, 10, 0); | |
295 packet_list.push_back(packet); | |
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 PayloadSplitter 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 Packet* packet = packet_list.front(); | |
316 VerifyPacket(packet, 10, i, kSequenceNumber, kBaseTimestamp, 0, true); | |
317 delete packet; | |
318 packet_list.pop_front(); | |
319 } | |
320 EXPECT_TRUE(packet_list.empty()); | |
321 } | |
322 | |
323 // Packet A is split into A1, A2 and A3. But the length parameter is off, so | |
324 // the last payloads should be discarded. | |
325 TEST(RedPayloadSplitter, WrongPayloadLength) { | |
326 uint8_t payload_types[] = {0, 0, 0}; | |
327 const int kTimestampOffset = 160; | |
328 Packet* packet = CreateRedPayload(3, payload_types, kTimestampOffset); | |
329 // Manually tamper with the payload length of the packet. | |
330 // This is one byte too short for the second payload (out of three). | |
331 // We expect only the first payload to be returned. | |
332 packet->payload.SetSize(packet->payload.size() - (kPayloadLength + 1)); | |
333 PacketList packet_list; | |
334 packet_list.push_back(packet); | |
335 PayloadSplitter splitter; | |
336 EXPECT_EQ(PayloadSplitter::kRedLengthMismatch, | |
337 splitter.SplitRed(&packet_list)); | |
338 ASSERT_EQ(1u, packet_list.size()); | |
339 // Check first packet. | |
340 packet = packet_list.front(); | |
341 VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber, | |
342 kBaseTimestamp - 2 * kTimestampOffset, 0, false); | |
343 delete packet; | |
344 packet_list.pop_front(); | |
345 } | |
346 | |
347 TEST(FecPayloadSplitter, MixedPayload) { | |
348 PacketList packet_list; | |
349 DecoderDatabase decoder_database(CreateBuiltinAudioDecoderFactory()); | |
350 | |
351 decoder_database.RegisterPayload(0, NetEqDecoder::kDecoderOpus, "opus"); | |
352 decoder_database.RegisterPayload(1, NetEqDecoder::kDecoderPCMu, "pcmu"); | |
353 | |
354 Packet* packet = CreatePacket(0, 10, 0xFF, true); | |
355 packet_list.push_back(packet); | |
356 | |
357 packet = CreatePacket(0, 10, 0); // Non-FEC Opus payload. | |
358 packet_list.push_back(packet); | |
359 | |
360 packet = CreatePacket(1, 10, 0); // Non-Opus payload. | |
361 packet_list.push_back(packet); | |
362 | |
363 PayloadSplitter splitter; | |
364 EXPECT_EQ(PayloadSplitter::kOK, | |
365 splitter.SplitFec(&packet_list, &decoder_database)); | |
366 EXPECT_EQ(4u, packet_list.size()); | |
367 | |
368 // Check first packet. | |
369 packet = packet_list.front(); | |
370 EXPECT_EQ(0, packet->header.payloadType); | |
371 EXPECT_EQ(kBaseTimestamp - 20 * 48, packet->header.timestamp); | |
372 EXPECT_EQ(10U, packet->payload.size()); | |
373 EXPECT_FALSE(packet->primary); | |
374 delete packet; | |
375 packet_list.pop_front(); | |
376 | |
377 // Check second packet. | |
378 packet = packet_list.front(); | |
379 EXPECT_EQ(0, packet->header.payloadType); | |
380 EXPECT_EQ(kBaseTimestamp, packet->header.timestamp); | |
381 EXPECT_EQ(10U, packet->payload.size()); | |
382 EXPECT_TRUE(packet->primary); | |
383 delete packet; | |
384 packet_list.pop_front(); | |
385 | |
386 // Check third packet. | |
387 packet = packet_list.front(); | |
388 VerifyPacket(packet, 10, 0, kSequenceNumber, kBaseTimestamp, 0, true); | |
389 delete packet; | |
390 packet_list.pop_front(); | |
391 | |
392 // Check fourth packet. | |
393 packet = packet_list.front(); | |
394 VerifyPacket(packet, 10, 1, kSequenceNumber, kBaseTimestamp, 0, true); | |
395 delete packet; | |
396 } | |
397 | |
398 TEST(FecPayloadSplitter, EmbedFecInRed) { | |
399 PacketList packet_list; | |
400 DecoderDatabase decoder_database(CreateBuiltinAudioDecoderFactory()); | |
401 | |
402 const int kTimestampOffset = 20 * 48; // 20 ms * 48 kHz. | |
403 uint8_t payload_types[] = {0, 0}; | |
404 decoder_database.RegisterPayload(0, NetEqDecoder::kDecoderOpus, "opus"); | |
405 Packet* packet = CreateRedPayload(2, payload_types, kTimestampOffset, true); | |
406 packet_list.push_back(packet); | |
407 | |
408 PayloadSplitter splitter; | |
409 EXPECT_EQ(PayloadSplitter::kOK, | |
410 splitter.SplitRed(&packet_list)); | |
411 EXPECT_EQ(PayloadSplitter::kOK, | |
412 splitter.SplitFec(&packet_list, &decoder_database)); | |
413 | |
414 EXPECT_EQ(4u, packet_list.size()); | |
415 | |
416 // Check first packet. FEC packet copied from primary payload in RED. | |
417 packet = packet_list.front(); | |
418 EXPECT_EQ(0, packet->header.payloadType); | |
419 EXPECT_EQ(kBaseTimestamp - kTimestampOffset, packet->header.timestamp); | |
420 EXPECT_EQ(kPayloadLength, packet->payload.size()); | |
421 EXPECT_FALSE(packet->primary); | |
422 EXPECT_EQ(packet->payload[3], 1); | |
423 delete packet; | |
424 packet_list.pop_front(); | |
425 | |
426 // Check second packet. Normal packet copied from primary payload in RED. | |
427 packet = packet_list.front(); | |
428 EXPECT_EQ(0, packet->header.payloadType); | |
429 EXPECT_EQ(kBaseTimestamp, packet->header.timestamp); | |
430 EXPECT_EQ(kPayloadLength, packet->payload.size()); | |
431 EXPECT_TRUE(packet->primary); | |
432 EXPECT_EQ(packet->payload[3], 1); | |
433 delete packet; | |
434 packet_list.pop_front(); | |
435 | |
436 // Check third packet. FEC packet copied from secondary payload in RED. | |
437 packet = packet_list.front(); | |
438 EXPECT_EQ(0, packet->header.payloadType); | |
439 EXPECT_EQ(kBaseTimestamp - 2 * kTimestampOffset, packet->header.timestamp); | |
440 EXPECT_EQ(kPayloadLength, packet->payload.size()); | |
441 EXPECT_FALSE(packet->primary); | |
442 EXPECT_EQ(packet->payload[3], 0); | |
443 delete packet; | |
444 packet_list.pop_front(); | |
445 | |
446 // Check fourth packet. Normal packet copied from primary payload in RED. | |
447 packet = packet_list.front(); | |
448 EXPECT_EQ(0, packet->header.payloadType); | |
449 EXPECT_EQ(kBaseTimestamp - kTimestampOffset, packet->header.timestamp); | |
450 EXPECT_EQ(kPayloadLength, packet->payload.size()); | |
451 EXPECT_TRUE(packet->primary); | |
452 EXPECT_EQ(packet->payload[3], 0); | |
453 delete packet; | |
454 packet_list.pop_front(); | |
455 } | |
456 | |
457 } // namespace webrtc | |
OLD | NEW |