blob: 530e9d064dc703a655c7dd00aa0392f4140ea0a2 [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +00001/*
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
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000011#include "webrtc/modules/audio_coding/neteq/payload_splitter.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000012
13#include <assert.h>
14
henrik.lundin84f8cd62016-04-26 07:45:16 -070015#include "webrtc/base/checks.h"
Henrik Lundind67a2192015-08-03 12:54:37 +020016#include "webrtc/base/logging.h"
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000017#include "webrtc/modules/audio_coding/neteq/decoder_database.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000018
19namespace webrtc {
20
21// The method loops through a list of packets {A, B, C, ...}. Each packet is
22// split into its corresponding RED payloads, {A1, A2, ...}, which is
23// temporarily held in the list |new_packets|.
24// When the first packet in |packet_list| has been processed, the orignal packet
25// is replaced by the new ones in |new_packets|, so that |packet_list| becomes:
26// {A1, A2, ..., B, C, ...}. The method then continues with B, and C, until all
27// the original packets have been replaced by their split payloads.
28int PayloadSplitter::SplitRed(PacketList* packet_list) {
29 int ret = kOK;
30 PacketList::iterator it = packet_list->begin();
31 while (it != packet_list->end()) {
32 PacketList new_packets; // An empty list to store the split packets in.
33 Packet* red_packet = (*it);
34 assert(red_packet->payload);
35 uint8_t* payload_ptr = red_packet->payload;
36
37 // Read RED headers (according to RFC 2198):
38 //
39 // 0 1 2 3
40 // 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
41 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 // |F| block PT | timestamp offset | block length |
43 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 // Last RED header:
45 // 0 1 2 3 4 5 6 7
46 // +-+-+-+-+-+-+-+-+
47 // |0| Block PT |
48 // +-+-+-+-+-+-+-+-+
49
50 bool last_block = false;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000051 size_t sum_length = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000052 while (!last_block) {
53 Packet* new_packet = new Packet;
54 new_packet->header = red_packet->header;
55 // Check the F bit. If F == 0, this was the last block.
56 last_block = ((*payload_ptr & 0x80) == 0);
57 // Bits 1 through 7 are payload type.
58 new_packet->header.payloadType = payload_ptr[0] & 0x7F;
59 if (last_block) {
60 // No more header data to read.
61 ++sum_length; // Account for RED header size of 1 byte.
62 new_packet->payload_length = red_packet->payload_length - sum_length;
63 new_packet->primary = true; // Last block is always primary.
64 payload_ptr += 1; // Advance to first payload byte.
65 } else {
66 // Bits 8 through 21 are timestamp offset.
67 int timestamp_offset = (payload_ptr[1] << 6) +
68 ((payload_ptr[2] & 0xFC) >> 2);
69 new_packet->header.timestamp = red_packet->header.timestamp -
70 timestamp_offset;
71 // Bits 22 through 31 are payload length.
72 new_packet->payload_length = ((payload_ptr[2] & 0x03) << 8) +
73 payload_ptr[3];
74 new_packet->primary = false;
75 payload_ptr += 4; // Advance to next RED header.
76 }
77 sum_length += new_packet->payload_length;
78 sum_length += 4; // Account for RED header size of 4 bytes.
79 // Store in new list of packets.
80 new_packets.push_back(new_packet);
81 }
82
83 // Populate the new packets with payload data.
84 // |payload_ptr| now points at the first payload byte.
85 PacketList::iterator new_it;
86 for (new_it = new_packets.begin(); new_it != new_packets.end(); ++new_it) {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000087 size_t payload_length = (*new_it)->payload_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000088 if (payload_ptr + payload_length >
89 red_packet->payload + red_packet->payload_length) {
90 // The block lengths in the RED headers do not match the overall packet
91 // length. Something is corrupt. Discard this and the remaining
92 // payloads from this packet.
Henrik Lundind67a2192015-08-03 12:54:37 +020093 LOG(LS_WARNING) << "SplitRed length mismatch";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000094 while (new_it != new_packets.end()) {
95 // Payload should not have been allocated yet.
96 assert(!(*new_it)->payload);
97 delete (*new_it);
98 new_it = new_packets.erase(new_it);
99 }
100 ret = kRedLengthMismatch;
101 break;
102 }
103 (*new_it)->payload = new uint8_t[payload_length];
104 memcpy((*new_it)->payload, payload_ptr, payload_length);
105 payload_ptr += payload_length;
106 }
107 // Reverse the order of the new packets, so that the primary payload is
108 // always first.
109 new_packets.reverse();
110 // Insert new packets into original list, before the element pointed to by
111 // iterator |it|.
112 packet_list->splice(it, new_packets, new_packets.begin(),
113 new_packets.end());
114 // Delete old packet payload.
115 delete [] (*it)->payload;
116 delete (*it);
117 // Remove |it| from the packet list. This operation effectively moves the
118 // iterator |it| to the next packet in the list. Thus, we do not have to
119 // increment it manually.
120 it = packet_list->erase(it);
121 }
122 return ret;
123}
124
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000125int PayloadSplitter::SplitFec(PacketList* packet_list,
126 DecoderDatabase* decoder_database) {
127 PacketList::iterator it = packet_list->begin();
128 // Iterate through all packets in |packet_list|.
129 while (it != packet_list->end()) {
130 Packet* packet = (*it); // Just to make the notation more intuitive.
131 // Get codec type for this payload.
132 uint8_t payload_type = packet->header.payloadType;
133 const DecoderDatabase::DecoderInfo* info =
134 decoder_database->GetDecoderInfo(payload_type);
135 if (!info) {
Henrik Lundind67a2192015-08-03 12:54:37 +0200136 LOG(LS_WARNING) << "SplitFec unknown payload type";
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000137 return kUnknownPayloadType;
138 }
139 // No splitting for a sync-packet.
140 if (packet->sync_packet) {
141 ++it;
142 continue;
143 }
144
145 // Not an FEC packet.
146 AudioDecoder* decoder = decoder_database->GetDecoder(payload_type);
ossu97ba30e2016-04-25 07:55:58 -0700147 // decoder should not return NULL, except for comfort noise payloads which
148 // are handled separately.
149 assert(decoder != NULL || decoder_database->IsComfortNoise(payload_type));
minyue@webrtc.org7549ff42014-04-02 15:03:01 +0000150 if (!decoder ||
151 !decoder->PacketHasFec(packet->payload, packet->payload_length)) {
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000152 ++it;
153 continue;
154 }
155
156 switch (info->codec_type) {
kwibergee1879c2015-10-29 06:20:28 -0700157 case NetEqDecoder::kDecoderOpus:
158 case NetEqDecoder::kDecoderOpus_2ch: {
minyue@webrtc.orga8cc3442015-02-13 14:01:54 +0000159 // The main payload of this packet should be decoded as a primary
160 // payload, even if it comes as a secondary payload in a RED packet.
161 packet->primary = true;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000162
minyue@webrtc.orga8cc3442015-02-13 14:01:54 +0000163 Packet* new_packet = new Packet;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000164 new_packet->header = packet->header;
165 int duration = decoder->
minyue@webrtc.org7549ff42014-04-02 15:03:01 +0000166 PacketDurationRedundant(packet->payload, packet->payload_length);
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000167 new_packet->header.timestamp -= duration;
168 new_packet->payload = new uint8_t[packet->payload_length];
169 memcpy(new_packet->payload, packet->payload, packet->payload_length);
170 new_packet->payload_length = packet->payload_length;
171 new_packet->primary = false;
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000172 new_packet->sync_packet = packet->sync_packet;
henrik.lundin84f8cd62016-04-26 07:45:16 -0700173 // Waiting time should not be set here.
174 RTC_DCHECK(!packet->waiting_time);
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000175
176 packet_list->insert(it, new_packet);
177 break;
178 }
179 default: {
Henrik Lundind67a2192015-08-03 12:54:37 +0200180 LOG(LS_WARNING) << "SplitFec wrong payload type";
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000181 return kFecSplitError;
182 }
183 }
184
185 ++it;
186 }
187 return kOK;
188}
189
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000190int PayloadSplitter::CheckRedPayloads(PacketList* packet_list,
191 const DecoderDatabase& decoder_database) {
192 PacketList::iterator it = packet_list->begin();
193 int main_payload_type = -1;
194 int num_deleted_packets = 0;
195 while (it != packet_list->end()) {
196 uint8_t this_payload_type = (*it)->header.payloadType;
197 if (!decoder_database.IsDtmf(this_payload_type) &&
198 !decoder_database.IsComfortNoise(this_payload_type)) {
199 if (main_payload_type == -1) {
200 // This is the first packet in the list which is non-DTMF non-CNG.
201 main_payload_type = this_payload_type;
202 } else {
203 if (this_payload_type != main_payload_type) {
204 // We do not allow redundant payloads of a different type.
205 // Discard this payload.
206 delete [] (*it)->payload;
207 delete (*it);
208 // Remove |it| from the packet list. This operation effectively
209 // moves the iterator |it| to the next packet in the list. Thus, we
210 // do not have to increment it manually.
211 it = packet_list->erase(it);
212 ++num_deleted_packets;
213 continue;
214 }
215 }
216 }
217 ++it;
218 }
219 return num_deleted_packets;
220}
221
222int PayloadSplitter::SplitAudio(PacketList* packet_list,
223 const DecoderDatabase& decoder_database) {
224 PacketList::iterator it = packet_list->begin();
225 // Iterate through all packets in |packet_list|.
226 while (it != packet_list->end()) {
227 Packet* packet = (*it); // Just to make the notation more intuitive.
228 // Get codec type for this payload.
229 const DecoderDatabase::DecoderInfo* info =
230 decoder_database.GetDecoderInfo(packet->header.payloadType);
231 if (!info) {
Henrik Lundind67a2192015-08-03 12:54:37 +0200232 LOG(LS_WARNING) << "SplitAudio unknown payload type";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000233 return kUnknownPayloadType;
234 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +0000235 // No splitting for a sync-packet.
236 if (packet->sync_packet) {
237 ++it;
238 continue;
239 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000240 PacketList new_packets;
241 switch (info->codec_type) {
kwibergee1879c2015-10-29 06:20:28 -0700242 case NetEqDecoder::kDecoderPCMu:
243 case NetEqDecoder::kDecoderPCMa: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000244 // 8 bytes per ms; 8 timestamps per ms.
245 SplitBySamples(packet, 8, 8, &new_packets);
246 break;
247 }
kwibergee1879c2015-10-29 06:20:28 -0700248 case NetEqDecoder::kDecoderPCMu_2ch:
249 case NetEqDecoder::kDecoderPCMa_2ch: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000250 // 2 * 8 bytes per ms; 8 timestamps per ms.
251 SplitBySamples(packet, 2 * 8, 8, &new_packets);
252 break;
253 }
kwibergee1879c2015-10-29 06:20:28 -0700254 case NetEqDecoder::kDecoderG722: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000255 // 8 bytes per ms; 16 timestamps per ms.
256 SplitBySamples(packet, 8, 16, &new_packets);
257 break;
258 }
kwibergee1879c2015-10-29 06:20:28 -0700259 case NetEqDecoder::kDecoderPCM16B: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000260 // 16 bytes per ms; 8 timestamps per ms.
261 SplitBySamples(packet, 16, 8, &new_packets);
262 break;
263 }
kwibergee1879c2015-10-29 06:20:28 -0700264 case NetEqDecoder::kDecoderPCM16Bwb: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000265 // 32 bytes per ms; 16 timestamps per ms.
266 SplitBySamples(packet, 32, 16, &new_packets);
267 break;
268 }
kwibergee1879c2015-10-29 06:20:28 -0700269 case NetEqDecoder::kDecoderPCM16Bswb32kHz: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000270 // 64 bytes per ms; 32 timestamps per ms.
271 SplitBySamples(packet, 64, 32, &new_packets);
272 break;
273 }
kwibergee1879c2015-10-29 06:20:28 -0700274 case NetEqDecoder::kDecoderPCM16Bswb48kHz: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000275 // 96 bytes per ms; 48 timestamps per ms.
276 SplitBySamples(packet, 96, 48, &new_packets);
277 break;
278 }
kwibergee1879c2015-10-29 06:20:28 -0700279 case NetEqDecoder::kDecoderPCM16B_2ch: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000280 // 2 * 16 bytes per ms; 8 timestamps per ms.
281 SplitBySamples(packet, 2 * 16, 8, &new_packets);
282 break;
283 }
kwibergee1879c2015-10-29 06:20:28 -0700284 case NetEqDecoder::kDecoderPCM16Bwb_2ch: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000285 // 2 * 32 bytes per ms; 16 timestamps per ms.
286 SplitBySamples(packet, 2 * 32, 16, &new_packets);
287 break;
288 }
kwibergee1879c2015-10-29 06:20:28 -0700289 case NetEqDecoder::kDecoderPCM16Bswb32kHz_2ch: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000290 // 2 * 64 bytes per ms; 32 timestamps per ms.
291 SplitBySamples(packet, 2 * 64, 32, &new_packets);
292 break;
293 }
kwibergee1879c2015-10-29 06:20:28 -0700294 case NetEqDecoder::kDecoderPCM16Bswb48kHz_2ch: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000295 // 2 * 96 bytes per ms; 48 timestamps per ms.
296 SplitBySamples(packet, 2 * 96, 48, &new_packets);
297 break;
298 }
kwibergee1879c2015-10-29 06:20:28 -0700299 case NetEqDecoder::kDecoderPCM16B_5ch: {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000300 // 5 * 16 bytes per ms; 8 timestamps per ms.
301 SplitBySamples(packet, 5 * 16, 8, &new_packets);
302 break;
303 }
kwibergee1879c2015-10-29 06:20:28 -0700304 case NetEqDecoder::kDecoderILBC: {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000305 size_t bytes_per_frame;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000306 int timestamps_per_frame;
307 if (packet->payload_length >= 950) {
Henrik Lundind67a2192015-08-03 12:54:37 +0200308 LOG(LS_WARNING) << "SplitAudio too large iLBC payload";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000309 return kTooLargePayload;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000310 }
311 if (packet->payload_length % 38 == 0) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000312 // 20 ms frames.
313 bytes_per_frame = 38;
314 timestamps_per_frame = 160;
315 } else if (packet->payload_length % 50 == 0) {
316 // 30 ms frames.
317 bytes_per_frame = 50;
318 timestamps_per_frame = 240;
319 } else {
Henrik Lundind67a2192015-08-03 12:54:37 +0200320 LOG(LS_WARNING) << "SplitAudio invalid iLBC payload";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000321 return kFrameSplitError;
322 }
323 int ret = SplitByFrames(packet, bytes_per_frame, timestamps_per_frame,
324 &new_packets);
325 if (ret < 0) {
326 return ret;
327 } else if (ret == kNoSplit) {
328 // Do not split at all. Simply advance to the next packet in the list.
329 ++it;
330 // We do not have any new packets to insert, and should not delete the
331 // old one. Skip the code after the switch case, and jump straight to
332 // the next packet in the while loop.
333 continue;
334 }
335 break;
336 }
337 default: {
338 // Do not split at all. Simply advance to the next packet in the list.
339 ++it;
340 // We do not have any new packets to insert, and should not delete the
341 // old one. Skip the code after the switch case, and jump straight to
342 // the next packet in the while loop.
343 continue;
344 }
345 }
346 // Insert new packets into original list, before the element pointed to by
347 // iterator |it|.
348 packet_list->splice(it, new_packets, new_packets.begin(),
349 new_packets.end());
350 // Delete old packet payload.
351 delete [] (*it)->payload;
352 delete (*it);
353 // Remove |it| from the packet list. This operation effectively moves the
354 // iterator |it| to the next packet in the list. Thus, we do not have to
355 // increment it manually.
356 it = packet_list->erase(it);
357 }
minyue@webrtc.orgb28bfa72014-03-21 12:07:40 +0000358 return kOK;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000359}
360
361void PayloadSplitter::SplitBySamples(const Packet* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000362 size_t bytes_per_ms,
363 uint32_t timestamps_per_ms,
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000364 PacketList* new_packets) {
365 assert(packet);
366 assert(new_packets);
367
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000368 size_t split_size_bytes = packet->payload_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000369
370 // Find a "chunk size" >= 20 ms and < 40 ms.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000371 size_t min_chunk_size = bytes_per_ms * 20;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000372 // Reduce the split size by half as long as |split_size_bytes| is at least
373 // twice the minimum chunk size (so that the resulting size is at least as
374 // large as the minimum chunk size).
375 while (split_size_bytes >= 2 * min_chunk_size) {
376 split_size_bytes >>= 1;
377 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000378 uint32_t timestamps_per_chunk = static_cast<uint32_t>(
379 split_size_bytes * timestamps_per_ms / bytes_per_ms);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000380 uint32_t timestamp = packet->header.timestamp;
381
382 uint8_t* payload_ptr = packet->payload;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000383 size_t len = packet->payload_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000384 while (len >= (2 * split_size_bytes)) {
385 Packet* new_packet = new Packet;
386 new_packet->payload_length = split_size_bytes;
387 new_packet->header = packet->header;
388 new_packet->header.timestamp = timestamp;
389 timestamp += timestamps_per_chunk;
390 new_packet->primary = packet->primary;
391 new_packet->payload = new uint8_t[split_size_bytes];
392 memcpy(new_packet->payload, payload_ptr, split_size_bytes);
393 payload_ptr += split_size_bytes;
394 new_packets->push_back(new_packet);
395 len -= split_size_bytes;
396 }
397
398 if (len > 0) {
399 Packet* new_packet = new Packet;
400 new_packet->payload_length = len;
401 new_packet->header = packet->header;
402 new_packet->header.timestamp = timestamp;
403 new_packet->primary = packet->primary;
404 new_packet->payload = new uint8_t[len];
405 memcpy(new_packet->payload, payload_ptr, len);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000406 new_packets->push_back(new_packet);
407 }
408}
409
410int PayloadSplitter::SplitByFrames(const Packet* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000411 size_t bytes_per_frame,
412 uint32_t timestamps_per_frame,
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000413 PacketList* new_packets) {
414 if (packet->payload_length % bytes_per_frame != 0) {
Henrik Lundind67a2192015-08-03 12:54:37 +0200415 LOG(LS_WARNING) << "SplitByFrames length mismatch";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000416 return kFrameSplitError;
417 }
418
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000419 if (packet->payload_length == bytes_per_frame) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000420 // Special case. Do not split the payload.
421 return kNoSplit;
422 }
423
424 uint32_t timestamp = packet->header.timestamp;
425 uint8_t* payload_ptr = packet->payload;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000426 size_t len = packet->payload_length;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000427 while (len > 0) {
428 assert(len >= bytes_per_frame);
429 Packet* new_packet = new Packet;
430 new_packet->payload_length = bytes_per_frame;
431 new_packet->header = packet->header;
432 new_packet->header.timestamp = timestamp;
433 timestamp += timestamps_per_frame;
434 new_packet->primary = packet->primary;
435 new_packet->payload = new uint8_t[bytes_per_frame];
436 memcpy(new_packet->payload, payload_ptr, bytes_per_frame);
437 payload_ptr += bytes_per_frame;
438 new_packets->push_back(new_packet);
439 len -= bytes_per_frame;
440 }
441 return kOK;
442}
443
444} // namespace webrtc