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