blob: a542333cf87c8bf2a3f3ba70b97a25665a5fb400 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
tina.legrand@webrtc.orgdf697752012-02-08 10:22:21 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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/*
12 * Implementation of the actual packet buffer data structure.
13 */
14
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +000015#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000016#include "packet_buffer.h"
17
18#include <string.h> /* to define NULL */
19
20#include "signal_processing_library.h"
21
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +000022#include "mcu_dsp_common.h"
23
niklase@google.com470e71d2011-07-07 08:21:25 +000024#include "neteq_error_codes.h"
25
26#ifdef NETEQ_DELAY_LOGGING
27/* special code for offline delay logging */
28#include "delay_logging.h"
29#include <stdio.h>
30
31extern FILE *delay_fid2; /* file pointer to delay log file */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000032extern uint32_t tot_received_packets;
niklase@google.com470e71d2011-07-07 08:21:25 +000033#endif /* NETEQ_DELAY_LOGGING */
34
35
36int WebRtcNetEQ_PacketBufferInit(PacketBuf_t *bufferInst, int maxNoOfPackets,
pbos@webrtc.org0946a562013-04-09 00:28:06 +000037 int16_t *pw16_memory, int memorySize)
niklase@google.com470e71d2011-07-07 08:21:25 +000038{
39 int i;
40 int pos = 0;
41
42 /* Sanity check */
43 if ((memorySize < PBUFFER_MIN_MEMORY_SIZE) || (pw16_memory == NULL)
44 || (maxNoOfPackets < 2) || (maxNoOfPackets > 600))
45 {
46 /* Invalid parameters */
47 return (PBUFFER_INIT_ERROR);
48 }
49
50 /* Clear the buffer instance */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000051 WebRtcSpl_MemSetW16((int16_t*) bufferInst, 0,
52 sizeof(PacketBuf_t) / sizeof(int16_t));
niklase@google.com470e71d2011-07-07 08:21:25 +000053
54 /* Clear the buffer memory */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000055 WebRtcSpl_MemSetW16((int16_t*) pw16_memory, 0, memorySize);
niklase@google.com470e71d2011-07-07 08:21:25 +000056
57 /* Set maximum number of packets */
58 bufferInst->maxInsertPositions = maxNoOfPackets;
59
60 /* Initialize array pointers */
61 /* After each pointer has been set, the index pos is advanced to point immediately
62 * after the the recently allocated vector. Note that one step for the pos index
pbos@webrtc.org0946a562013-04-09 00:28:06 +000063 * corresponds to a int16_t.
niklase@google.com470e71d2011-07-07 08:21:25 +000064 */
65
pbos@webrtc.org0946a562013-04-09 00:28:06 +000066 bufferInst->timeStamp = (uint32_t*) &pw16_memory[pos];
67 pos += maxNoOfPackets << 1; /* advance maxNoOfPackets * uint32_t */
niklase@google.com470e71d2011-07-07 08:21:25 +000068
pbos@webrtc.org0946a562013-04-09 00:28:06 +000069 bufferInst->payloadLocation = (int16_t**) &pw16_memory[pos];
70 pos += maxNoOfPackets * (sizeof(int16_t*) / sizeof(int16_t)); /* advance */
niklase@google.com470e71d2011-07-07 08:21:25 +000071
pbos@webrtc.org0946a562013-04-09 00:28:06 +000072 bufferInst->seqNumber = (uint16_t*) &pw16_memory[pos];
73 pos += maxNoOfPackets; /* advance maxNoOfPackets * uint16_t */
niklase@google.com470e71d2011-07-07 08:21:25 +000074
75 bufferInst->payloadType = &pw16_memory[pos];
pbos@webrtc.org0946a562013-04-09 00:28:06 +000076 pos += maxNoOfPackets; /* advance maxNoOfPackets * int16_t */
niklase@google.com470e71d2011-07-07 08:21:25 +000077
78 bufferInst->payloadLengthBytes = &pw16_memory[pos];
pbos@webrtc.org0946a562013-04-09 00:28:06 +000079 pos += maxNoOfPackets; /* advance maxNoOfPackets * int16_t */
niklase@google.com470e71d2011-07-07 08:21:25 +000080
81 bufferInst->rcuPlCntr = &pw16_memory[pos];
pbos@webrtc.org0946a562013-04-09 00:28:06 +000082 pos += maxNoOfPackets; /* advance maxNoOfPackets * int16_t */
niklase@google.com470e71d2011-07-07 08:21:25 +000083
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +000084 bufferInst->waitingTime = (int*) (&pw16_memory[pos]);
85 /* Advance maxNoOfPackets * sizeof(waitingTime element). */
86 pos += maxNoOfPackets *
87 sizeof(*bufferInst->waitingTime) / sizeof(*pw16_memory);
88
niklase@google.com470e71d2011-07-07 08:21:25 +000089 /* The payload memory starts after the slot arrays */
90 bufferInst->startPayloadMemory = &pw16_memory[pos];
91 bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
92 bufferInst->memorySizeW16 = (memorySize - pos); /* Remaining memory */
93
94 /* Initialize each payload slot as empty with infinite delay */
95 for (i = 0; i < bufferInst->maxInsertPositions; i++)
96 {
97 bufferInst->payloadType[i] = -1;
98 }
99
100 /* Reset buffer parameters */
101 bufferInst->numPacketsInBuffer = 0;
102 bufferInst->packSizeSamples = 0;
103 bufferInst->insertPosition = 0;
104
105 /* Reset buffer statistics */
106 bufferInst->discardedPackets = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000107
108 return (0);
109}
110
111
112int WebRtcNetEQ_PacketBufferFlush(PacketBuf_t *bufferInst)
113{
114 int i;
115
116 /* Sanity check */
117 if (bufferInst->startPayloadMemory == NULL)
118 {
119 /* Packet buffer has not been initialized */
120 /* Don't do the flushing operation, since we do not
121 know the state of the struct variables */
122 return (0);
123 }
124
niklase@google.com470e71d2011-07-07 08:21:25 +0000125 /* Set all payload lengths to zero */
126 WebRtcSpl_MemSetW16(bufferInst->payloadLengthBytes, 0, bufferInst->maxInsertPositions);
127
128 /* Reset buffer variables */
129 bufferInst->numPacketsInBuffer = 0;
130 bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
131 bufferInst->insertPosition = 0;
132
133 /* Clear all slots, starting with the last one */
134 for (i = (bufferInst->maxInsertPositions - 1); i >= 0; i--)
135 {
136 bufferInst->payloadType[i] = -1;
137 bufferInst->timeStamp[i] = 0;
138 bufferInst->seqNumber[i] = 0;
139 }
140
141 return (0);
142}
143
144
145int WebRtcNetEQ_PacketBufferInsert(PacketBuf_t *bufferInst, const RTPPacket_t *RTPpacket,
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000146 int16_t *flushed, int av_sync)
niklase@google.com470e71d2011-07-07 08:21:25 +0000147{
148 int nextPos;
149 int i;
150
151#ifdef NETEQ_DELAY_LOGGING
152 /* special code for offline delay logging */
153 int temp_var;
154#endif /* NETEQ_DELAY_LOGGING */
155
156 /* Initialize to "no flush" */
157 *flushed = 0;
158
159 /* Sanity check */
160 if (bufferInst->startPayloadMemory == NULL)
161 {
162 /* packet buffer has not been initialized */
163 return (-1);
164 }
165
166 /* Sanity check for payload length
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000167 (payloadLen in bytes and memory size in int16_t) */
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 if ((RTPpacket->payloadLen > (bufferInst->memorySizeW16 << 1)) || (RTPpacket->payloadLen
169 <= 0))
170 {
171 /* faulty or too long payload length */
172 return (-1);
173 }
174
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000175 /* If we are in AV-sync mode, there is a risk that we have inserted a sync
176 * packet but now received the real version of it. Or because of some timing
177 * we might be overwriting a true payload with sync (I'm not sure why this
178 * should happen in regular case, but in some FEC enabled case happens).
179 * Go through packets and delete the sync version of the packet in hand. Or
180 * if this is sync packet and the regular version of it exists in the buffer
181 * refrain from inserting.
182 *
183 * TODO(turajs): Could we get this for free if we had set the RCU-counter of
184 * the sync packet to a number larger than 2?
185 */
186 if (av_sync) {
187 for (i = 0; i < bufferInst->maxInsertPositions; ++i) {
188 /* Check if sequence numbers match and the payload actually exists. */
189 if (bufferInst->seqNumber[i] == RTPpacket->seqNumber &&
190 bufferInst->payloadLengthBytes[i] > 0) {
191 if (WebRtcNetEQ_IsSyncPayload(RTPpacket->payload,
192 RTPpacket->payloadLen)) {
193 return 0;
194 }
195
196 if (WebRtcNetEQ_IsSyncPayload(bufferInst->payloadLocation[i],
197 bufferInst->payloadLengthBytes[i])) {
198 /* Clear the position in the buffer. */
199 bufferInst->payloadType[i] = -1;
200 bufferInst->payloadLengthBytes[i] = 0;
201
202 /* Reduce packet counter by one. */
203 bufferInst->numPacketsInBuffer--;
204 /* TODO(turajs) if this is the latest packet better we rewind
205 * insertPosition and related variables. */
206 break; /* There should be only one match. */
207 }
208 }
209 }
210 }
211
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 /* Find a position in the buffer for this packet */
213 if (bufferInst->numPacketsInBuffer != 0)
214 {
215 /* Get the next slot */
216 bufferInst->insertPosition++;
217 if (bufferInst->insertPosition >= bufferInst->maxInsertPositions)
218 {
219 /* "Wrap around" and start from the beginning */
220 bufferInst->insertPosition = 0;
221 }
222
223 /* Check if there is enough space for the new packet */
224 if (bufferInst->currentMemoryPos + ((RTPpacket->payloadLen + 1) >> 1)
225 >= &bufferInst->startPayloadMemory[bufferInst->memorySizeW16])
226 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000227 int16_t *tempMemAddress;
niklase@google.com470e71d2011-07-07 08:21:25 +0000228
229 /*
230 * Payload does not fit at the end of the memory, put it in the beginning
231 * instead
232 */
233 bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
234
235 /*
236 * Now, we must search for the next non-empty payload,
237 * finding the one with the lowest start address for the payload
238 */
239 tempMemAddress = &bufferInst->startPayloadMemory[bufferInst->memorySizeW16];
240 nextPos = -1;
241
242 /* Loop through all slots again */
243 for (i = 0; i < bufferInst->maxInsertPositions; i++)
244 {
245 /* Look for the non-empty slot with the lowest
246 payload location address */
247 if (bufferInst->payloadLengthBytes[i] != 0 && bufferInst->payloadLocation[i]
248 < tempMemAddress)
249 {
250 tempMemAddress = bufferInst->payloadLocation[i];
251 nextPos = i;
252 }
253 }
254
255 /* Check that we did find a previous payload */
256 if (nextPos == -1)
257 {
258 /* The buffer is corrupt => flush and return error */
259 WebRtcNetEQ_PacketBufferFlush(bufferInst);
260 *flushed = 1;
261 return (-1);
262 }
263 }
264 else
265 {
266 /* Payload fits at the end of memory. */
267
268 /* Find the next non-empty slot. */
269 nextPos = bufferInst->insertPosition + 1;
270
271 /* Increase nextPos until a non-empty slot is found or end of array is encountered*/
272 while ((bufferInst->payloadLengthBytes[nextPos] == 0) && (nextPos
273 < bufferInst->maxInsertPositions))
274 {
275 nextPos++;
276 }
277
278 if (nextPos == bufferInst->maxInsertPositions)
279 {
280 /*
281 * Reached the end of the array, so there must be a packet in the first
282 * position instead
283 */
284 nextPos = 0;
285
286 /* Increase nextPos until a non-empty slot is found */
287 while (bufferInst->payloadLengthBytes[nextPos] == 0)
288 {
289 nextPos++;
290 }
291 }
292 } /* end if-else */
293
294 /*
295 * Check if the new payload will extend into a payload later in memory.
296 * If so, the buffer is full.
297 */
298 if ((bufferInst->currentMemoryPos <= bufferInst->payloadLocation[nextPos])
299 && ((&bufferInst->currentMemoryPos[(RTPpacket->payloadLen + 1) >> 1])
300 > bufferInst->payloadLocation[nextPos]))
301 {
302 /* Buffer is full, so the buffer must be flushed */
303 WebRtcNetEQ_PacketBufferFlush(bufferInst);
304 *flushed = 1;
305 }
306
307 if (bufferInst->payloadLengthBytes[bufferInst->insertPosition] != 0)
308 {
309 /* All positions are already taken and entire buffer should be flushed */
310 WebRtcNetEQ_PacketBufferFlush(bufferInst);
311 *flushed = 1;
312 }
313
314 }
315 else
316 {
317 /* Buffer is empty, just insert the packet at the beginning */
318 bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
319 bufferInst->insertPosition = 0;
320 }
321
322 /* Insert packet in the found position */
323 if (RTPpacket->starts_byte1 == 0)
324 {
325 /* Payload is 16-bit aligned => just copy it */
326
sergeyu@chromium.orgbd4a2fe2013-05-03 18:11:36 +0000327 WEBRTC_SPL_MEMCPY_W8(bufferInst->currentMemoryPos,
328 RTPpacket->payload, RTPpacket->payloadLen);
niklase@google.com470e71d2011-07-07 08:21:25 +0000329 }
330 else
331 {
332 /* Payload is not 16-bit aligned => align it during copy operation */
333 for (i = 0; i < RTPpacket->payloadLen; i++)
334 {
335 /* copy the (i+1)-th byte to the i-th byte */
336
337 WEBRTC_SPL_SET_BYTE(bufferInst->currentMemoryPos,
338 (WEBRTC_SPL_GET_BYTE(RTPpacket->payload, (i + 1))), i);
339 }
340 }
341
342 /* Copy the packet information */
343 bufferInst->payloadLocation[bufferInst->insertPosition] = bufferInst->currentMemoryPos;
344 bufferInst->payloadLengthBytes[bufferInst->insertPosition] = RTPpacket->payloadLen;
345 bufferInst->payloadType[bufferInst->insertPosition] = RTPpacket->payloadType;
346 bufferInst->seqNumber[bufferInst->insertPosition] = RTPpacket->seqNumber;
347 bufferInst->timeStamp[bufferInst->insertPosition] = RTPpacket->timeStamp;
348 bufferInst->rcuPlCntr[bufferInst->insertPosition] = RTPpacket->rcuPlCntr;
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000349 bufferInst->waitingTime[bufferInst->insertPosition] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000350 /* Update buffer parameters */
351 bufferInst->numPacketsInBuffer++;
352 bufferInst->currentMemoryPos += (RTPpacket->payloadLen + 1) >> 1;
353
354#ifdef NETEQ_DELAY_LOGGING
355 /* special code for offline delay logging */
356 if (*flushed)
357 {
358 temp_var = NETEQ_DELAY_LOGGING_SIGNAL_FLUSH;
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000359 if (fwrite(&temp_var, sizeof(int), 1, delay_fid2) != 1) {
360 return -1;
361 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000362 }
363 temp_var = NETEQ_DELAY_LOGGING_SIGNAL_RECIN;
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000364 if ((fwrite(&temp_var, sizeof(int),
365 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000366 (fwrite(&RTPpacket->timeStamp, sizeof(uint32_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000367 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000368 (fwrite(&RTPpacket->seqNumber, sizeof(uint16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000369 1, delay_fid2) != 1) ||
370 (fwrite(&RTPpacket->payloadType, sizeof(int),
371 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000372 (fwrite(&RTPpacket->payloadLen, sizeof(int16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000373 1, delay_fid2) != 1)) {
374 return -1;
375 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000376 tot_received_packets++;
377#endif /* NETEQ_DELAY_LOGGING */
378
379 return (0);
380}
381
382
383int WebRtcNetEQ_PacketBufferExtract(PacketBuf_t *bufferInst, RTPPacket_t *RTPpacket,
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000384 int bufferPosition, int *waitingTime)
niklase@google.com470e71d2011-07-07 08:21:25 +0000385{
386
387 /* Sanity check */
388 if (bufferInst->startPayloadMemory == NULL)
389 {
390 /* packet buffer has not been initialized */
391 return (PBUFFER_NOT_INITIALIZED);
392 }
393
394 if (bufferPosition < 0 || bufferPosition >= bufferInst->maxInsertPositions)
395 {
396 /* buffer position is outside valid range */
397 return (NETEQ_OTHER_ERROR);
398 }
399
400 /* Check that there is a valid payload in the specified position */
401 if (bufferInst->payloadLengthBytes[bufferPosition] <= 0)
402 {
403 /* The position does not contain a valid payload */
404 RTPpacket->payloadLen = 0; /* Set zero length */
405 return (PBUFFER_NONEXISTING_PACKET); /* Return error */
406 }
407
408 /* Payload exists => extract payload data */
409
410 /* Copy the actual data payload to RTP packet struct */
411
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000412 WEBRTC_SPL_MEMCPY_W16((int16_t*) RTPpacket->payload,
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 bufferInst->payloadLocation[bufferPosition],
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000414 (bufferInst->payloadLengthBytes[bufferPosition] + 1) >> 1); /*length in int16_t*/
niklase@google.com470e71d2011-07-07 08:21:25 +0000415
416 /* Copy payload parameters */
417 RTPpacket->payloadLen = bufferInst->payloadLengthBytes[bufferPosition];
418 RTPpacket->payloadType = bufferInst->payloadType[bufferPosition];
419 RTPpacket->seqNumber = bufferInst->seqNumber[bufferPosition];
420 RTPpacket->timeStamp = bufferInst->timeStamp[bufferPosition];
421 RTPpacket->rcuPlCntr = bufferInst->rcuPlCntr[bufferPosition];
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000422 *waitingTime = bufferInst->waitingTime[bufferPosition];
niklase@google.com470e71d2011-07-07 08:21:25 +0000423 RTPpacket->starts_byte1 = 0; /* payload is 16-bit aligned */
424
425 /* Clear the position in the packet buffer */
426 bufferInst->payloadType[bufferPosition] = -1;
427 bufferInst->payloadLengthBytes[bufferPosition] = 0;
428 bufferInst->seqNumber[bufferPosition] = 0;
429 bufferInst->timeStamp[bufferPosition] = 0;
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000430 bufferInst->waitingTime[bufferPosition] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000431 bufferInst->payloadLocation[bufferPosition] = bufferInst->startPayloadMemory;
432
433 /* Reduce packet counter with one */
434 bufferInst->numPacketsInBuffer--;
435
436 return (0);
437}
438
kma@webrtc.org89a10002012-01-30 15:37:33 +0000439int WebRtcNetEQ_PacketBufferFindLowestTimestamp(PacketBuf_t* buffer_inst,
440 uint32_t current_time_stamp,
441 uint32_t* time_stamp,
442 int* buffer_position,
443 int erase_old_packets,
444 int16_t* payload_type) {
445 int32_t time_stamp_diff = WEBRTC_SPL_WORD32_MAX; /* Smallest diff found. */
446 int32_t new_diff;
447 int i;
448 int16_t rcu_payload_cntr;
kma@webrtc.org89a10002012-01-30 15:37:33 +0000449 if (buffer_inst->startPayloadMemory == NULL) {
450 /* Packet buffer has not been initialized. */
451 return PBUFFER_NOT_INITIALIZED;
452 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000453
kma@webrtc.org89a10002012-01-30 15:37:33 +0000454 /* Initialize all return values. */
455 *time_stamp = 0;
456 *payload_type = -1; /* Indicates that no packet was found. */
457 *buffer_position = -1; /* Indicates that no packet was found. */
458 rcu_payload_cntr = WEBRTC_SPL_WORD16_MAX; /* Indicates no packet found. */
niklase@google.com470e71d2011-07-07 08:21:25 +0000459
kma@webrtc.org89a10002012-01-30 15:37:33 +0000460 /* Check if buffer is empty. */
461 if (buffer_inst->numPacketsInBuffer <= 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000462 return 0;
kma@webrtc.org89a10002012-01-30 15:37:33 +0000463 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000464
kma@webrtc.org89a10002012-01-30 15:37:33 +0000465 /* Loop through all slots in buffer. */
466 if (erase_old_packets) { /* If old payloads should be discarded. */
467 for (i = 0; i < buffer_inst->maxInsertPositions; ++i) {
468 /* Calculate difference between this slot and current_time_stamp. */
469 new_diff = (int32_t)(buffer_inst->timeStamp[i] - current_time_stamp);
470
471 /* Check if payload should be discarded. */
472 if ((new_diff < 0) /* Payload is too old */
473 && (new_diff > -30000) /* Account for TS wrap-around. */
474 && (buffer_inst->payloadLengthBytes[i] > 0)) { /* Payload exists. */
475 /* Throw away old packet. */
476
477 /* Clear the position in the buffer. */
478 buffer_inst->payloadType[i] = -1;
479 buffer_inst->payloadLengthBytes[i] = 0;
480
481 /* Reduce packet counter by one. */
482 buffer_inst->numPacketsInBuffer--;
483 /* Increase discard counter for in-call statistics. */
484 buffer_inst->discardedPackets++;
485 } else if (((new_diff < time_stamp_diff)
486 || ((new_diff == time_stamp_diff)
487 && (buffer_inst->rcuPlCntr[i] < rcu_payload_cntr)))
488 && (buffer_inst->payloadLengthBytes[i] > 0)) {
489 /* New diff is smaller than previous diffs or we have a candidate with a
490 * time stamp as previous candidate but better RCU-counter;
491 * and the payload exists.
492 */
493 /* Save this position as the best candidate. */
494 *buffer_position = i;
495 time_stamp_diff = new_diff;
496 *payload_type = buffer_inst->payloadType[i];
497 rcu_payload_cntr = buffer_inst->rcuPlCntr[i];
498 }
499 }
500 } else {
501 for (i = 0; i < buffer_inst->maxInsertPositions; ++i) {
502 /* Calculate difference between this slot and current_time_stamp. */
503 new_diff = (int32_t)(buffer_inst->timeStamp[i] - current_time_stamp);
504
505 /* Check if this is the oldest packet. */
506 if (((new_diff < time_stamp_diff)
507 || ((new_diff == time_stamp_diff)
508 && (buffer_inst->rcuPlCntr[i] < rcu_payload_cntr)))
509 && (buffer_inst->payloadLengthBytes[i] > 0)) {
510 /* New diff is smaller than previous diffs or we have a candidate with a
511 * time_stamp as previous candidate but better RCU-counter;
512 * and the payload exists.
513 */
514 /* Save this position as the best candidate. */
515 *buffer_position = i;
516 time_stamp_diff = new_diff;
517 *payload_type = buffer_inst->payloadType[i];
518 rcu_payload_cntr = buffer_inst->rcuPlCntr[i];
519 }
520 }
521 }
522
523 /* Check that we did find a real position. */
524 if (*buffer_position >= 0) {
525 /* Get the time_stamp for the best position. */
526 *time_stamp = buffer_inst->timeStamp[*buffer_position];
527 }
528
529 return 0;
530}
niklase@google.com470e71d2011-07-07 08:21:25 +0000531
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000532int WebRtcNetEQ_PacketBufferGetPacketSize(const PacketBuf_t* buffer_inst,
533 int buffer_pos,
534 const CodecDbInst_t* codec_database,
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000535 int codec_pos, int last_duration,
536 int av_sync) {
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000537 if (codec_database->funcDurationEst[codec_pos] == NULL) {
538 return last_duration;
539 }
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000540
541 if (av_sync != 0 &&
542 WebRtcNetEQ_IsSyncPayload(buffer_inst->payloadLocation[buffer_pos],
543 buffer_inst->payloadLengthBytes[buffer_pos])) {
544 // In AV-sync and sync payload, report |last_duration| as current duration.
545 return last_duration;
546 }
547
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000548 return (*codec_database->funcDurationEst[codec_pos])(
549 codec_database->codec_state[codec_pos],
550 (const uint8_t *)buffer_inst->payloadLocation[buffer_pos],
551 buffer_inst->payloadLengthBytes[buffer_pos]);
552}
niklase@google.com470e71d2011-07-07 08:21:25 +0000553
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000554int32_t WebRtcNetEQ_PacketBufferGetSize(const PacketBuf_t* buffer_inst,
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000555 const CodecDbInst_t* codec_database,
556 int av_sync) {
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000557 int i, count;
558 int last_duration;
559 int last_codec_pos;
560 int last_payload_type;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000561 int32_t size_samples;
niklase@google.com470e71d2011-07-07 08:21:25 +0000562
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000563 count = 0;
564 last_duration = buffer_inst->packSizeSamples;
565 last_codec_pos = -1;
566 last_payload_type = -1;
567 size_samples = 0;
568
569 /* Loop through all slots in the buffer */
570 for (i = 0; i < buffer_inst->maxInsertPositions; i++) {
571 /* Only count the packets with non-zero size */
572 if (buffer_inst->payloadLengthBytes[i] != 0) {
573 int payload_type;
574 int codec_pos;
575 /* Figure out the codec database entry for this payload_type. */
576 payload_type = buffer_inst->payloadType[i];
577 /* Remember the last one, to avoid the database search. */
578 if(payload_type == last_payload_type) {
579 codec_pos = last_codec_pos;
580 }
581 else {
582 codec_pos = WebRtcNetEQ_DbGetCodec(codec_database,
583 payload_type);
584 if (codec_pos >= 0) {
585 codec_pos = codec_database->position[codec_pos];
niklase@google.com470e71d2011-07-07 08:21:25 +0000586 }
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000587 }
588 last_codec_pos = codec_pos;
589 last_payload_type = payload_type;
590 if (codec_pos >= 0) {
591 /*
592 * Right now WebRtcNetEQ_PacketBufferGetPacketSize either always
593 * returns last_duration or always computes the real duration without
594 * looking at last_duration. If an implementation really wanted to use
595 * last_duration to compute a changing duration, we would have to
596 * iterate through the packets in chronological order by timestamp.
597 */
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000598 /* Check for error before setting. */
599 int temp_last_duration = WebRtcNetEQ_PacketBufferGetPacketSize(
600 buffer_inst, i, codec_database, codec_pos,
601 last_duration, av_sync);
602 if (temp_last_duration >= 0)
603 last_duration = temp_last_duration;
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000604 }
605 /* Add in the size of this packet. */
606 size_samples += last_duration;
607 count++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000608 }
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000609 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000610
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000611 /* Sanity check; size cannot be negative */
612 if (size_samples < 0) {
613 size_samples = 0;
614 }
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000615 return size_samples;
niklase@google.com470e71d2011-07-07 08:21:25 +0000616}
617
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000618void WebRtcNetEQ_IncrementWaitingTimes(PacketBuf_t *buffer_inst) {
619 int i;
620 /* Loop through all slots in the buffer. */
621 for (i = 0; i < buffer_inst->maxInsertPositions; ++i) {
622 /* Only increment waiting time for the packets with non-zero size. */
623 if (buffer_inst->payloadLengthBytes[i] != 0) {
624 buffer_inst->waitingTime[i]++;
625 }
626 }
627}
niklase@google.com470e71d2011-07-07 08:21:25 +0000628
629int WebRtcNetEQ_GetDefaultCodecSettings(const enum WebRtcNetEQDecoder *codecID,
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +0000630 int noOfCodecs, int *maxBytes,
631 int *maxSlots,
632 int* per_slot_overhead_bytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000633{
634 int i;
635 int ok = 0;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000636 int16_t w16_tmp;
637 int16_t codecBytes;
638 int16_t codecBuffers;
niklase@google.com470e71d2011-07-07 08:21:25 +0000639
640 /* Initialize return variables to zero */
641 *maxBytes = 0;
642 *maxSlots = 0;
643
644 /* Loop through all codecs supplied to function */
645 for (i = 0; i < noOfCodecs; i++)
646 {
647 /* Find current codec and set parameters accordingly */
648
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000649 if ((codecID[i] == kDecoderPCMu) || (codecID[i] == kDecoderPCMu_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000650 {
651 codecBytes = 1680; /* Up to 210ms @ 64kbps */
652 codecBuffers = 30; /* Down to 5ms frames */
653 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000654 else if ((codecID[i] == kDecoderPCMa) ||
655 (codecID[i] == kDecoderPCMa_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 {
657 codecBytes = 1680; /* Up to 210ms @ 64kbps */
658 codecBuffers = 30; /* Down to 5ms frames */
659 }
660 else if (codecID[i] == kDecoderILBC)
661 {
662 codecBytes = 380; /* 200ms @ 15.2kbps (20ms frames) */
663 codecBuffers = 10;
664 }
665 else if (codecID[i] == kDecoderISAC)
666 {
667 codecBytes = 960; /* 240ms @ 32kbps (60ms frames) */
668 codecBuffers = 8;
669 }
turaj@webrtc.orgb0dff122012-12-03 17:43:52 +0000670 else if ((codecID[i] == kDecoderISACswb) ||
671 (codecID[i] == kDecoderISACfb))
niklase@google.com470e71d2011-07-07 08:21:25 +0000672 {
673 codecBytes = 1560; /* 240ms @ 52kbps (30ms frames) */
674 codecBuffers = 8;
675 }
tina.legrand@webrtc.orgc4590582012-11-28 12:23:29 +0000676 else if (codecID[i] == kDecoderOpus)
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000677 {
678 codecBytes = 15300; /* 240ms @ 510kbps (60ms frames) */
679 codecBuffers = 30; /* Replicating the value for PCMu/a */
680 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000681 else if ((codecID[i] == kDecoderPCM16B) ||
682 (codecID[i] == kDecoderPCM16B_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000683 {
684 codecBytes = 3360; /* 210ms */
685 codecBuffers = 15;
686 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000687 else if ((codecID[i] == kDecoderPCM16Bwb) ||
688 (codecID[i] == kDecoderPCM16Bwb_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000689 {
690 codecBytes = 6720; /* 210ms */
691 codecBuffers = 15;
692 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000693 else if ((codecID[i] == kDecoderPCM16Bswb32kHz) ||
694 (codecID[i] == kDecoderPCM16Bswb32kHz_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 {
696 codecBytes = 13440; /* 210ms */
697 codecBuffers = 15;
698 }
699 else if (codecID[i] == kDecoderPCM16Bswb48kHz)
700 {
701 codecBytes = 20160; /* 210ms */
702 codecBuffers = 15;
703 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000704 else if ((codecID[i] == kDecoderG722) ||
705 (codecID[i] == kDecoderG722_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000706 {
707 codecBytes = 1680; /* 210ms @ 64kbps */
708 codecBuffers = 15;
709 }
710 else if (codecID[i] == kDecoderRED)
711 {
712 codecBytes = 0; /* Should not be max... */
713 codecBuffers = 0;
714 }
715 else if (codecID[i] == kDecoderAVT)
716 {
717 codecBytes = 0; /* Should not be max... */
718 codecBuffers = 0;
719 }
720 else if (codecID[i] == kDecoderCNG)
721 {
722 codecBytes = 0; /* Should not be max... */
723 codecBuffers = 0;
724 }
725 else if (codecID[i] == kDecoderG729)
726 {
727 codecBytes = 210; /* 210ms @ 8kbps */
728 codecBuffers = 20; /* max 200ms supported for 10ms frames */
729 }
730 else if (codecID[i] == kDecoderG729_1)
731 {
732 codecBytes = 840; /* 210ms @ 32kbps */
733 codecBuffers = 10; /* max 200ms supported for 20ms frames */
734 }
735 else if (codecID[i] == kDecoderG726_16)
736 {
737 codecBytes = 400; /* 200ms @ 16kbps */
738 codecBuffers = 10;
739 }
740 else if (codecID[i] == kDecoderG726_24)
741 {
742 codecBytes = 600; /* 200ms @ 24kbps */
743 codecBuffers = 10;
744 }
745 else if (codecID[i] == kDecoderG726_32)
746 {
747 codecBytes = 800; /* 200ms @ 32kbps */
748 codecBuffers = 10;
749 }
750 else if (codecID[i] == kDecoderG726_40)
751 {
752 codecBytes = 1000; /* 200ms @ 40kbps */
753 codecBuffers = 10;
754 }
755 else if (codecID[i] == kDecoderG722_1_16)
756 {
757 codecBytes = 420; /* 210ms @ 16kbps */
758 codecBuffers = 10;
759 }
760 else if (codecID[i] == kDecoderG722_1_24)
761 {
762 codecBytes = 630; /* 210ms @ 24kbps */
763 codecBuffers = 10;
764 }
765 else if (codecID[i] == kDecoderG722_1_32)
766 {
767 codecBytes = 840; /* 210ms @ 32kbps */
768 codecBuffers = 10;
769 }
770 else if (codecID[i] == kDecoderG722_1C_24)
771 {
772 codecBytes = 630; /* 210ms @ 24kbps */
773 codecBuffers = 10;
774 }
775 else if (codecID[i] == kDecoderG722_1C_32)
776 {
777 codecBytes = 840; /* 210ms @ 32kbps */
778 codecBuffers = 10;
779 }
780 else if (codecID[i] == kDecoderG722_1C_48)
781 {
782 codecBytes = 1260; /* 210ms @ 48kbps */
783 codecBuffers = 10;
784 }
785 else if (codecID[i] == kDecoderSPEEX_8)
786 {
787 codecBytes = 1250; /* 210ms @ 50kbps */
788 codecBuffers = 10;
789 }
790 else if (codecID[i] == kDecoderSPEEX_16)
791 {
792 codecBytes = 1250; /* 210ms @ 50kbps */
793 codecBuffers = 10;
794 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000795 else if ((codecID[i] == kDecoderCELT_32) ||
796 (codecID[i] == kDecoderCELT_32_2ch))
tina.legrand@webrtc.orgdf697752012-02-08 10:22:21 +0000797 {
798 codecBytes = 1250; /* 210ms @ 50kbps */
799 codecBuffers = 10;
800 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000801 else if (codecID[i] == kDecoderGSMFR)
802 {
803 codecBytes = 340; /* 200ms */
804 codecBuffers = 10;
805 }
806 else if (codecID[i] == kDecoderAMR)
807 {
808 codecBytes = 384; /* 240ms @ 12.2kbps+headers (60ms frames) */
809 codecBuffers = 10;
810 }
811 else if (codecID[i] == kDecoderAMRWB)
812 {
813 codecBytes = 744;
814 codecBuffers = 10;
815 }
816 else if (codecID[i] == kDecoderArbitrary)
817 {
818 codecBytes = 6720; /* Assume worst case uncompressed WB 210ms */
819 codecBuffers = 15;
820 }
821 else
822 {
823 /*Unknow codec */
824 codecBytes = 0;
825 codecBuffers = 0;
826 ok = CODEC_DB_UNKNOWN_CODEC;
827 }
828
829 /* Update max variables */
830 *maxBytes = WEBRTC_SPL_MAX((*maxBytes), codecBytes);
831 *maxSlots = WEBRTC_SPL_MAX((*maxSlots), codecBuffers);
832
833 } /* end of for loop */
834
835 /*
836 * Add size needed by the additional pointers for each slot inside struct,
837 * as indicated on each line below.
838 */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000839 w16_tmp = (sizeof(uint32_t) /* timeStamp */
840 + sizeof(int16_t*) /* payloadLocation */
841 + sizeof(uint16_t) /* seqNumber */
842 + sizeof(int16_t) /* payloadType */
843 + sizeof(int16_t) /* payloadLengthBytes */
844 + sizeof(int16_t) /* rcuPlCntr */
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000845 + sizeof(int)); /* waitingTime */
niklase@google.com470e71d2011-07-07 08:21:25 +0000846 /* Add the extra size per slot to the memory count */
847 *maxBytes += w16_tmp * (*maxSlots);
848
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +0000849 *per_slot_overhead_bytes = w16_tmp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 return ok;
851}