Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(187)

Side by Side Diff: webrtc/modules/audio_coding/neteq/payload_splitter_unittest.cc

Issue 2342443005: Moved Opus-specific payload splitting into AudioDecoderOpus. (Closed)
Patch Set: Some small fixes. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698