blob: 39f40ef4ab07afac5d771343bfe8270608a3c23c [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
15#include "packet_buffer.h"
16
17#include <string.h> /* to define NULL */
18
19#include "signal_processing_library.h"
20
21#include "neteq_error_codes.h"
22
23#ifdef NETEQ_DELAY_LOGGING
24/* special code for offline delay logging */
25#include "delay_logging.h"
26#include <stdio.h>
27
28extern FILE *delay_fid2; /* file pointer to delay log file */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000029extern uint32_t tot_received_packets;
niklase@google.com470e71d2011-07-07 08:21:25 +000030#endif /* NETEQ_DELAY_LOGGING */
31
32
33int WebRtcNetEQ_PacketBufferInit(PacketBuf_t *bufferInst, int maxNoOfPackets,
pbos@webrtc.org0946a562013-04-09 00:28:06 +000034 int16_t *pw16_memory, int memorySize)
niklase@google.com470e71d2011-07-07 08:21:25 +000035{
36 int i;
37 int pos = 0;
38
39 /* Sanity check */
40 if ((memorySize < PBUFFER_MIN_MEMORY_SIZE) || (pw16_memory == NULL)
41 || (maxNoOfPackets < 2) || (maxNoOfPackets > 600))
42 {
43 /* Invalid parameters */
44 return (PBUFFER_INIT_ERROR);
45 }
46
47 /* Clear the buffer instance */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000048 WebRtcSpl_MemSetW16((int16_t*) bufferInst, 0,
49 sizeof(PacketBuf_t) / sizeof(int16_t));
niklase@google.com470e71d2011-07-07 08:21:25 +000050
51 /* Clear the buffer memory */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000052 WebRtcSpl_MemSetW16((int16_t*) pw16_memory, 0, memorySize);
niklase@google.com470e71d2011-07-07 08:21:25 +000053
54 /* Set maximum number of packets */
55 bufferInst->maxInsertPositions = maxNoOfPackets;
56
57 /* Initialize array pointers */
58 /* After each pointer has been set, the index pos is advanced to point immediately
59 * after the the recently allocated vector. Note that one step for the pos index
pbos@webrtc.org0946a562013-04-09 00:28:06 +000060 * corresponds to a int16_t.
niklase@google.com470e71d2011-07-07 08:21:25 +000061 */
62
pbos@webrtc.org0946a562013-04-09 00:28:06 +000063 bufferInst->timeStamp = (uint32_t*) &pw16_memory[pos];
64 pos += maxNoOfPackets << 1; /* advance maxNoOfPackets * uint32_t */
niklase@google.com470e71d2011-07-07 08:21:25 +000065
pbos@webrtc.org0946a562013-04-09 00:28:06 +000066 bufferInst->payloadLocation = (int16_t**) &pw16_memory[pos];
67 pos += maxNoOfPackets * (sizeof(int16_t*) / sizeof(int16_t)); /* advance */
niklase@google.com470e71d2011-07-07 08:21:25 +000068
pbos@webrtc.org0946a562013-04-09 00:28:06 +000069 bufferInst->seqNumber = (uint16_t*) &pw16_memory[pos];
70 pos += maxNoOfPackets; /* advance maxNoOfPackets * uint16_t */
niklase@google.com470e71d2011-07-07 08:21:25 +000071
72 bufferInst->payloadType = &pw16_memory[pos];
pbos@webrtc.org0946a562013-04-09 00:28:06 +000073 pos += maxNoOfPackets; /* advance maxNoOfPackets * int16_t */
niklase@google.com470e71d2011-07-07 08:21:25 +000074
75 bufferInst->payloadLengthBytes = &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->rcuPlCntr = &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
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +000081 bufferInst->waitingTime = (int*) (&pw16_memory[pos]);
82 /* Advance maxNoOfPackets * sizeof(waitingTime element). */
83 pos += maxNoOfPackets *
84 sizeof(*bufferInst->waitingTime) / sizeof(*pw16_memory);
85
niklase@google.com470e71d2011-07-07 08:21:25 +000086 /* The payload memory starts after the slot arrays */
87 bufferInst->startPayloadMemory = &pw16_memory[pos];
88 bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
89 bufferInst->memorySizeW16 = (memorySize - pos); /* Remaining memory */
90
91 /* Initialize each payload slot as empty with infinite delay */
92 for (i = 0; i < bufferInst->maxInsertPositions; i++)
93 {
94 bufferInst->payloadType[i] = -1;
95 }
96
97 /* Reset buffer parameters */
98 bufferInst->numPacketsInBuffer = 0;
99 bufferInst->packSizeSamples = 0;
100 bufferInst->insertPosition = 0;
101
102 /* Reset buffer statistics */
103 bufferInst->discardedPackets = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000104
105 return (0);
106}
107
108
109int WebRtcNetEQ_PacketBufferFlush(PacketBuf_t *bufferInst)
110{
111 int i;
112
113 /* Sanity check */
114 if (bufferInst->startPayloadMemory == NULL)
115 {
116 /* Packet buffer has not been initialized */
117 /* Don't do the flushing operation, since we do not
118 know the state of the struct variables */
119 return (0);
120 }
121
niklase@google.com470e71d2011-07-07 08:21:25 +0000122 /* Set all payload lengths to zero */
123 WebRtcSpl_MemSetW16(bufferInst->payloadLengthBytes, 0, bufferInst->maxInsertPositions);
124
125 /* Reset buffer variables */
126 bufferInst->numPacketsInBuffer = 0;
127 bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
128 bufferInst->insertPosition = 0;
129
130 /* Clear all slots, starting with the last one */
131 for (i = (bufferInst->maxInsertPositions - 1); i >= 0; i--)
132 {
133 bufferInst->payloadType[i] = -1;
134 bufferInst->timeStamp[i] = 0;
135 bufferInst->seqNumber[i] = 0;
136 }
137
138 return (0);
139}
140
141
142int WebRtcNetEQ_PacketBufferInsert(PacketBuf_t *bufferInst, const RTPPacket_t *RTPpacket,
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000143 int16_t *flushed)
niklase@google.com470e71d2011-07-07 08:21:25 +0000144{
145 int nextPos;
146 int i;
147
148#ifdef NETEQ_DELAY_LOGGING
149 /* special code for offline delay logging */
150 int temp_var;
151#endif /* NETEQ_DELAY_LOGGING */
152
153 /* Initialize to "no flush" */
154 *flushed = 0;
155
156 /* Sanity check */
157 if (bufferInst->startPayloadMemory == NULL)
158 {
159 /* packet buffer has not been initialized */
160 return (-1);
161 }
162
163 /* Sanity check for payload length
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000164 (payloadLen in bytes and memory size in int16_t) */
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 if ((RTPpacket->payloadLen > (bufferInst->memorySizeW16 << 1)) || (RTPpacket->payloadLen
166 <= 0))
167 {
168 /* faulty or too long payload length */
169 return (-1);
170 }
171
172 /* Find a position in the buffer for this packet */
173 if (bufferInst->numPacketsInBuffer != 0)
174 {
175 /* Get the next slot */
176 bufferInst->insertPosition++;
177 if (bufferInst->insertPosition >= bufferInst->maxInsertPositions)
178 {
179 /* "Wrap around" and start from the beginning */
180 bufferInst->insertPosition = 0;
181 }
182
183 /* Check if there is enough space for the new packet */
184 if (bufferInst->currentMemoryPos + ((RTPpacket->payloadLen + 1) >> 1)
185 >= &bufferInst->startPayloadMemory[bufferInst->memorySizeW16])
186 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000187 int16_t *tempMemAddress;
niklase@google.com470e71d2011-07-07 08:21:25 +0000188
189 /*
190 * Payload does not fit at the end of the memory, put it in the beginning
191 * instead
192 */
193 bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
194
195 /*
196 * Now, we must search for the next non-empty payload,
197 * finding the one with the lowest start address for the payload
198 */
199 tempMemAddress = &bufferInst->startPayloadMemory[bufferInst->memorySizeW16];
200 nextPos = -1;
201
202 /* Loop through all slots again */
203 for (i = 0; i < bufferInst->maxInsertPositions; i++)
204 {
205 /* Look for the non-empty slot with the lowest
206 payload location address */
207 if (bufferInst->payloadLengthBytes[i] != 0 && bufferInst->payloadLocation[i]
208 < tempMemAddress)
209 {
210 tempMemAddress = bufferInst->payloadLocation[i];
211 nextPos = i;
212 }
213 }
214
215 /* Check that we did find a previous payload */
216 if (nextPos == -1)
217 {
218 /* The buffer is corrupt => flush and return error */
219 WebRtcNetEQ_PacketBufferFlush(bufferInst);
220 *flushed = 1;
221 return (-1);
222 }
223 }
224 else
225 {
226 /* Payload fits at the end of memory. */
227
228 /* Find the next non-empty slot. */
229 nextPos = bufferInst->insertPosition + 1;
230
231 /* Increase nextPos until a non-empty slot is found or end of array is encountered*/
232 while ((bufferInst->payloadLengthBytes[nextPos] == 0) && (nextPos
233 < bufferInst->maxInsertPositions))
234 {
235 nextPos++;
236 }
237
238 if (nextPos == bufferInst->maxInsertPositions)
239 {
240 /*
241 * Reached the end of the array, so there must be a packet in the first
242 * position instead
243 */
244 nextPos = 0;
245
246 /* Increase nextPos until a non-empty slot is found */
247 while (bufferInst->payloadLengthBytes[nextPos] == 0)
248 {
249 nextPos++;
250 }
251 }
252 } /* end if-else */
253
254 /*
255 * Check if the new payload will extend into a payload later in memory.
256 * If so, the buffer is full.
257 */
258 if ((bufferInst->currentMemoryPos <= bufferInst->payloadLocation[nextPos])
259 && ((&bufferInst->currentMemoryPos[(RTPpacket->payloadLen + 1) >> 1])
260 > bufferInst->payloadLocation[nextPos]))
261 {
262 /* Buffer is full, so the buffer must be flushed */
263 WebRtcNetEQ_PacketBufferFlush(bufferInst);
264 *flushed = 1;
265 }
266
267 if (bufferInst->payloadLengthBytes[bufferInst->insertPosition] != 0)
268 {
269 /* All positions are already taken and entire buffer should be flushed */
270 WebRtcNetEQ_PacketBufferFlush(bufferInst);
271 *flushed = 1;
272 }
273
274 }
275 else
276 {
277 /* Buffer is empty, just insert the packet at the beginning */
278 bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
279 bufferInst->insertPosition = 0;
280 }
281
282 /* Insert packet in the found position */
283 if (RTPpacket->starts_byte1 == 0)
284 {
285 /* Payload is 16-bit aligned => just copy it */
286
287 WEBRTC_SPL_MEMCPY_W16(bufferInst->currentMemoryPos,
288 RTPpacket->payload, (RTPpacket->payloadLen + 1) >> 1);
289 }
290 else
291 {
292 /* Payload is not 16-bit aligned => align it during copy operation */
293 for (i = 0; i < RTPpacket->payloadLen; i++)
294 {
295 /* copy the (i+1)-th byte to the i-th byte */
296
297 WEBRTC_SPL_SET_BYTE(bufferInst->currentMemoryPos,
298 (WEBRTC_SPL_GET_BYTE(RTPpacket->payload, (i + 1))), i);
299 }
300 }
301
302 /* Copy the packet information */
303 bufferInst->payloadLocation[bufferInst->insertPosition] = bufferInst->currentMemoryPos;
304 bufferInst->payloadLengthBytes[bufferInst->insertPosition] = RTPpacket->payloadLen;
305 bufferInst->payloadType[bufferInst->insertPosition] = RTPpacket->payloadType;
306 bufferInst->seqNumber[bufferInst->insertPosition] = RTPpacket->seqNumber;
307 bufferInst->timeStamp[bufferInst->insertPosition] = RTPpacket->timeStamp;
308 bufferInst->rcuPlCntr[bufferInst->insertPosition] = RTPpacket->rcuPlCntr;
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000309 bufferInst->waitingTime[bufferInst->insertPosition] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 /* Update buffer parameters */
311 bufferInst->numPacketsInBuffer++;
312 bufferInst->currentMemoryPos += (RTPpacket->payloadLen + 1) >> 1;
313
314#ifdef NETEQ_DELAY_LOGGING
315 /* special code for offline delay logging */
316 if (*flushed)
317 {
318 temp_var = NETEQ_DELAY_LOGGING_SIGNAL_FLUSH;
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000319 if (fwrite(&temp_var, sizeof(int), 1, delay_fid2) != 1) {
320 return -1;
321 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000322 }
323 temp_var = NETEQ_DELAY_LOGGING_SIGNAL_RECIN;
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000324 if ((fwrite(&temp_var, sizeof(int),
325 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000326 (fwrite(&RTPpacket->timeStamp, sizeof(uint32_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000327 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000328 (fwrite(&RTPpacket->seqNumber, sizeof(uint16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000329 1, delay_fid2) != 1) ||
330 (fwrite(&RTPpacket->payloadType, sizeof(int),
331 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000332 (fwrite(&RTPpacket->payloadLen, sizeof(int16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000333 1, delay_fid2) != 1)) {
334 return -1;
335 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000336 tot_received_packets++;
337#endif /* NETEQ_DELAY_LOGGING */
338
339 return (0);
340}
341
342
343int WebRtcNetEQ_PacketBufferExtract(PacketBuf_t *bufferInst, RTPPacket_t *RTPpacket,
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000344 int bufferPosition, int *waitingTime)
niklase@google.com470e71d2011-07-07 08:21:25 +0000345{
346
347 /* Sanity check */
348 if (bufferInst->startPayloadMemory == NULL)
349 {
350 /* packet buffer has not been initialized */
351 return (PBUFFER_NOT_INITIALIZED);
352 }
353
354 if (bufferPosition < 0 || bufferPosition >= bufferInst->maxInsertPositions)
355 {
356 /* buffer position is outside valid range */
357 return (NETEQ_OTHER_ERROR);
358 }
359
360 /* Check that there is a valid payload in the specified position */
361 if (bufferInst->payloadLengthBytes[bufferPosition] <= 0)
362 {
363 /* The position does not contain a valid payload */
364 RTPpacket->payloadLen = 0; /* Set zero length */
365 return (PBUFFER_NONEXISTING_PACKET); /* Return error */
366 }
367
368 /* Payload exists => extract payload data */
369
370 /* Copy the actual data payload to RTP packet struct */
371
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000372 WEBRTC_SPL_MEMCPY_W16((int16_t*) RTPpacket->payload,
niklase@google.com470e71d2011-07-07 08:21:25 +0000373 bufferInst->payloadLocation[bufferPosition],
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000374 (bufferInst->payloadLengthBytes[bufferPosition] + 1) >> 1); /*length in int16_t*/
niklase@google.com470e71d2011-07-07 08:21:25 +0000375
376 /* Copy payload parameters */
377 RTPpacket->payloadLen = bufferInst->payloadLengthBytes[bufferPosition];
378 RTPpacket->payloadType = bufferInst->payloadType[bufferPosition];
379 RTPpacket->seqNumber = bufferInst->seqNumber[bufferPosition];
380 RTPpacket->timeStamp = bufferInst->timeStamp[bufferPosition];
381 RTPpacket->rcuPlCntr = bufferInst->rcuPlCntr[bufferPosition];
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000382 *waitingTime = bufferInst->waitingTime[bufferPosition];
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 RTPpacket->starts_byte1 = 0; /* payload is 16-bit aligned */
384
385 /* Clear the position in the packet buffer */
386 bufferInst->payloadType[bufferPosition] = -1;
387 bufferInst->payloadLengthBytes[bufferPosition] = 0;
388 bufferInst->seqNumber[bufferPosition] = 0;
389 bufferInst->timeStamp[bufferPosition] = 0;
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000390 bufferInst->waitingTime[bufferPosition] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 bufferInst->payloadLocation[bufferPosition] = bufferInst->startPayloadMemory;
392
393 /* Reduce packet counter with one */
394 bufferInst->numPacketsInBuffer--;
395
396 return (0);
397}
398
kma@webrtc.org89a10002012-01-30 15:37:33 +0000399int WebRtcNetEQ_PacketBufferFindLowestTimestamp(PacketBuf_t* buffer_inst,
400 uint32_t current_time_stamp,
401 uint32_t* time_stamp,
402 int* buffer_position,
403 int erase_old_packets,
404 int16_t* payload_type) {
405 int32_t time_stamp_diff = WEBRTC_SPL_WORD32_MAX; /* Smallest diff found. */
406 int32_t new_diff;
407 int i;
408 int16_t rcu_payload_cntr;
niklase@google.com470e71d2011-07-07 08:21:25 +0000409
kma@webrtc.org89a10002012-01-30 15:37:33 +0000410 if (buffer_inst->startPayloadMemory == NULL) {
411 /* Packet buffer has not been initialized. */
412 return PBUFFER_NOT_INITIALIZED;
413 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000414
kma@webrtc.org89a10002012-01-30 15:37:33 +0000415 /* Initialize all return values. */
416 *time_stamp = 0;
417 *payload_type = -1; /* Indicates that no packet was found. */
418 *buffer_position = -1; /* Indicates that no packet was found. */
419 rcu_payload_cntr = WEBRTC_SPL_WORD16_MAX; /* Indicates no packet found. */
niklase@google.com470e71d2011-07-07 08:21:25 +0000420
kma@webrtc.org89a10002012-01-30 15:37:33 +0000421 /* Check if buffer is empty. */
422 if (buffer_inst->numPacketsInBuffer <= 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000423 return 0;
kma@webrtc.org89a10002012-01-30 15:37:33 +0000424 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000425
kma@webrtc.org89a10002012-01-30 15:37:33 +0000426 /* Loop through all slots in buffer. */
427 if (erase_old_packets) { /* If old payloads should be discarded. */
428 for (i = 0; i < buffer_inst->maxInsertPositions; ++i) {
429 /* Calculate difference between this slot and current_time_stamp. */
430 new_diff = (int32_t)(buffer_inst->timeStamp[i] - current_time_stamp);
431
432 /* Check if payload should be discarded. */
433 if ((new_diff < 0) /* Payload is too old */
434 && (new_diff > -30000) /* Account for TS wrap-around. */
435 && (buffer_inst->payloadLengthBytes[i] > 0)) { /* Payload exists. */
436 /* Throw away old packet. */
437
438 /* Clear the position in the buffer. */
439 buffer_inst->payloadType[i] = -1;
440 buffer_inst->payloadLengthBytes[i] = 0;
441
442 /* Reduce packet counter by one. */
443 buffer_inst->numPacketsInBuffer--;
444 /* Increase discard counter for in-call statistics. */
445 buffer_inst->discardedPackets++;
446 } else if (((new_diff < time_stamp_diff)
447 || ((new_diff == time_stamp_diff)
448 && (buffer_inst->rcuPlCntr[i] < rcu_payload_cntr)))
449 && (buffer_inst->payloadLengthBytes[i] > 0)) {
450 /* New diff is smaller than previous diffs or we have a candidate with a
451 * time stamp as previous candidate but better RCU-counter;
452 * and the payload exists.
453 */
454 /* Save this position as the best candidate. */
455 *buffer_position = i;
456 time_stamp_diff = new_diff;
457 *payload_type = buffer_inst->payloadType[i];
458 rcu_payload_cntr = buffer_inst->rcuPlCntr[i];
459 }
460 }
461 } else {
462 for (i = 0; i < buffer_inst->maxInsertPositions; ++i) {
463 /* Calculate difference between this slot and current_time_stamp. */
464 new_diff = (int32_t)(buffer_inst->timeStamp[i] - current_time_stamp);
465
466 /* Check if this is the oldest packet. */
467 if (((new_diff < time_stamp_diff)
468 || ((new_diff == time_stamp_diff)
469 && (buffer_inst->rcuPlCntr[i] < rcu_payload_cntr)))
470 && (buffer_inst->payloadLengthBytes[i] > 0)) {
471 /* New diff is smaller than previous diffs or we have a candidate with a
472 * time_stamp as previous candidate but better RCU-counter;
473 * and the payload exists.
474 */
475 /* Save this position as the best candidate. */
476 *buffer_position = i;
477 time_stamp_diff = new_diff;
478 *payload_type = buffer_inst->payloadType[i];
479 rcu_payload_cntr = buffer_inst->rcuPlCntr[i];
480 }
481 }
482 }
483
484 /* Check that we did find a real position. */
485 if (*buffer_position >= 0) {
486 /* Get the time_stamp for the best position. */
487 *time_stamp = buffer_inst->timeStamp[*buffer_position];
488 }
489
490 return 0;
491}
niklase@google.com470e71d2011-07-07 08:21:25 +0000492
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000493int WebRtcNetEQ_PacketBufferGetPacketSize(const PacketBuf_t* buffer_inst,
494 int buffer_pos,
495 const CodecDbInst_t* codec_database,
496 int codec_pos, int last_duration) {
497 if (codec_database->funcDurationEst[codec_pos] == NULL) {
498 return last_duration;
499 }
500 return (*codec_database->funcDurationEst[codec_pos])(
501 codec_database->codec_state[codec_pos],
502 (const uint8_t *)buffer_inst->payloadLocation[buffer_pos],
503 buffer_inst->payloadLengthBytes[buffer_pos]);
504}
niklase@google.com470e71d2011-07-07 08:21:25 +0000505
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000506int32_t WebRtcNetEQ_PacketBufferGetSize(const PacketBuf_t* buffer_inst,
507 const CodecDbInst_t* codec_database) {
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000508 int i, count;
509 int last_duration;
510 int last_codec_pos;
511 int last_payload_type;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000512 int32_t size_samples;
niklase@google.com470e71d2011-07-07 08:21:25 +0000513
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000514 count = 0;
515 last_duration = buffer_inst->packSizeSamples;
516 last_codec_pos = -1;
517 last_payload_type = -1;
518 size_samples = 0;
519
520 /* Loop through all slots in the buffer */
521 for (i = 0; i < buffer_inst->maxInsertPositions; i++) {
522 /* Only count the packets with non-zero size */
523 if (buffer_inst->payloadLengthBytes[i] != 0) {
524 int payload_type;
525 int codec_pos;
526 /* Figure out the codec database entry for this payload_type. */
527 payload_type = buffer_inst->payloadType[i];
528 /* Remember the last one, to avoid the database search. */
529 if(payload_type == last_payload_type) {
530 codec_pos = last_codec_pos;
531 }
532 else {
533 codec_pos = WebRtcNetEQ_DbGetCodec(codec_database,
534 payload_type);
535 if (codec_pos >= 0) {
536 codec_pos = codec_database->position[codec_pos];
niklase@google.com470e71d2011-07-07 08:21:25 +0000537 }
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000538 }
539 last_codec_pos = codec_pos;
540 last_payload_type = payload_type;
541 if (codec_pos >= 0) {
542 /*
543 * Right now WebRtcNetEQ_PacketBufferGetPacketSize either always
544 * returns last_duration or always computes the real duration without
545 * looking at last_duration. If an implementation really wanted to use
546 * last_duration to compute a changing duration, we would have to
547 * iterate through the packets in chronological order by timestamp.
548 */
549 last_duration = WebRtcNetEQ_PacketBufferGetPacketSize(
550 buffer_inst, i, codec_database, codec_pos,
551 last_duration);
552 }
553 /* Add in the size of this packet. */
554 size_samples += last_duration;
555 count++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 }
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000557 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000558
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000559 /* Sanity check; size cannot be negative */
560 if (size_samples < 0) {
561 size_samples = 0;
562 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000563
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000564 return size_samples;
niklase@google.com470e71d2011-07-07 08:21:25 +0000565}
566
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000567void WebRtcNetEQ_IncrementWaitingTimes(PacketBuf_t *buffer_inst) {
568 int i;
569 /* Loop through all slots in the buffer. */
570 for (i = 0; i < buffer_inst->maxInsertPositions; ++i) {
571 /* Only increment waiting time for the packets with non-zero size. */
572 if (buffer_inst->payloadLengthBytes[i] != 0) {
573 buffer_inst->waitingTime[i]++;
574 }
575 }
576}
niklase@google.com470e71d2011-07-07 08:21:25 +0000577
578int WebRtcNetEQ_GetDefaultCodecSettings(const enum WebRtcNetEQDecoder *codecID,
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +0000579 int noOfCodecs, int *maxBytes,
580 int *maxSlots,
581 int* per_slot_overhead_bytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000582{
583 int i;
584 int ok = 0;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000585 int16_t w16_tmp;
586 int16_t codecBytes;
587 int16_t codecBuffers;
niklase@google.com470e71d2011-07-07 08:21:25 +0000588
589 /* Initialize return variables to zero */
590 *maxBytes = 0;
591 *maxSlots = 0;
592
593 /* Loop through all codecs supplied to function */
594 for (i = 0; i < noOfCodecs; i++)
595 {
596 /* Find current codec and set parameters accordingly */
597
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000598 if ((codecID[i] == kDecoderPCMu) || (codecID[i] == kDecoderPCMu_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000599 {
600 codecBytes = 1680; /* Up to 210ms @ 64kbps */
601 codecBuffers = 30; /* Down to 5ms frames */
602 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000603 else if ((codecID[i] == kDecoderPCMa) ||
604 (codecID[i] == kDecoderPCMa_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000605 {
606 codecBytes = 1680; /* Up to 210ms @ 64kbps */
607 codecBuffers = 30; /* Down to 5ms frames */
608 }
609 else if (codecID[i] == kDecoderILBC)
610 {
611 codecBytes = 380; /* 200ms @ 15.2kbps (20ms frames) */
612 codecBuffers = 10;
613 }
614 else if (codecID[i] == kDecoderISAC)
615 {
616 codecBytes = 960; /* 240ms @ 32kbps (60ms frames) */
617 codecBuffers = 8;
618 }
turaj@webrtc.orgb0dff122012-12-03 17:43:52 +0000619 else if ((codecID[i] == kDecoderISACswb) ||
620 (codecID[i] == kDecoderISACfb))
niklase@google.com470e71d2011-07-07 08:21:25 +0000621 {
622 codecBytes = 1560; /* 240ms @ 52kbps (30ms frames) */
623 codecBuffers = 8;
624 }
tina.legrand@webrtc.orgc4590582012-11-28 12:23:29 +0000625 else if (codecID[i] == kDecoderOpus)
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000626 {
627 codecBytes = 15300; /* 240ms @ 510kbps (60ms frames) */
628 codecBuffers = 30; /* Replicating the value for PCMu/a */
629 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000630 else if ((codecID[i] == kDecoderPCM16B) ||
631 (codecID[i] == kDecoderPCM16B_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000632 {
633 codecBytes = 3360; /* 210ms */
634 codecBuffers = 15;
635 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000636 else if ((codecID[i] == kDecoderPCM16Bwb) ||
637 (codecID[i] == kDecoderPCM16Bwb_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000638 {
639 codecBytes = 6720; /* 210ms */
640 codecBuffers = 15;
641 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000642 else if ((codecID[i] == kDecoderPCM16Bswb32kHz) ||
643 (codecID[i] == kDecoderPCM16Bswb32kHz_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000644 {
645 codecBytes = 13440; /* 210ms */
646 codecBuffers = 15;
647 }
648 else if (codecID[i] == kDecoderPCM16Bswb48kHz)
649 {
650 codecBytes = 20160; /* 210ms */
651 codecBuffers = 15;
652 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000653 else if ((codecID[i] == kDecoderG722) ||
654 (codecID[i] == kDecoderG722_2ch))
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 {
656 codecBytes = 1680; /* 210ms @ 64kbps */
657 codecBuffers = 15;
658 }
659 else if (codecID[i] == kDecoderRED)
660 {
661 codecBytes = 0; /* Should not be max... */
662 codecBuffers = 0;
663 }
664 else if (codecID[i] == kDecoderAVT)
665 {
666 codecBytes = 0; /* Should not be max... */
667 codecBuffers = 0;
668 }
669 else if (codecID[i] == kDecoderCNG)
670 {
671 codecBytes = 0; /* Should not be max... */
672 codecBuffers = 0;
673 }
674 else if (codecID[i] == kDecoderG729)
675 {
676 codecBytes = 210; /* 210ms @ 8kbps */
677 codecBuffers = 20; /* max 200ms supported for 10ms frames */
678 }
679 else if (codecID[i] == kDecoderG729_1)
680 {
681 codecBytes = 840; /* 210ms @ 32kbps */
682 codecBuffers = 10; /* max 200ms supported for 20ms frames */
683 }
684 else if (codecID[i] == kDecoderG726_16)
685 {
686 codecBytes = 400; /* 200ms @ 16kbps */
687 codecBuffers = 10;
688 }
689 else if (codecID[i] == kDecoderG726_24)
690 {
691 codecBytes = 600; /* 200ms @ 24kbps */
692 codecBuffers = 10;
693 }
694 else if (codecID[i] == kDecoderG726_32)
695 {
696 codecBytes = 800; /* 200ms @ 32kbps */
697 codecBuffers = 10;
698 }
699 else if (codecID[i] == kDecoderG726_40)
700 {
701 codecBytes = 1000; /* 200ms @ 40kbps */
702 codecBuffers = 10;
703 }
704 else if (codecID[i] == kDecoderG722_1_16)
705 {
706 codecBytes = 420; /* 210ms @ 16kbps */
707 codecBuffers = 10;
708 }
709 else if (codecID[i] == kDecoderG722_1_24)
710 {
711 codecBytes = 630; /* 210ms @ 24kbps */
712 codecBuffers = 10;
713 }
714 else if (codecID[i] == kDecoderG722_1_32)
715 {
716 codecBytes = 840; /* 210ms @ 32kbps */
717 codecBuffers = 10;
718 }
719 else if (codecID[i] == kDecoderG722_1C_24)
720 {
721 codecBytes = 630; /* 210ms @ 24kbps */
722 codecBuffers = 10;
723 }
724 else if (codecID[i] == kDecoderG722_1C_32)
725 {
726 codecBytes = 840; /* 210ms @ 32kbps */
727 codecBuffers = 10;
728 }
729 else if (codecID[i] == kDecoderG722_1C_48)
730 {
731 codecBytes = 1260; /* 210ms @ 48kbps */
732 codecBuffers = 10;
733 }
734 else if (codecID[i] == kDecoderSPEEX_8)
735 {
736 codecBytes = 1250; /* 210ms @ 50kbps */
737 codecBuffers = 10;
738 }
739 else if (codecID[i] == kDecoderSPEEX_16)
740 {
741 codecBytes = 1250; /* 210ms @ 50kbps */
742 codecBuffers = 10;
743 }
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000744 else if ((codecID[i] == kDecoderCELT_32) ||
745 (codecID[i] == kDecoderCELT_32_2ch))
tina.legrand@webrtc.orgdf697752012-02-08 10:22:21 +0000746 {
747 codecBytes = 1250; /* 210ms @ 50kbps */
748 codecBuffers = 10;
749 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000750 else if (codecID[i] == kDecoderGSMFR)
751 {
752 codecBytes = 340; /* 200ms */
753 codecBuffers = 10;
754 }
755 else if (codecID[i] == kDecoderAMR)
756 {
757 codecBytes = 384; /* 240ms @ 12.2kbps+headers (60ms frames) */
758 codecBuffers = 10;
759 }
760 else if (codecID[i] == kDecoderAMRWB)
761 {
762 codecBytes = 744;
763 codecBuffers = 10;
764 }
765 else if (codecID[i] == kDecoderArbitrary)
766 {
767 codecBytes = 6720; /* Assume worst case uncompressed WB 210ms */
768 codecBuffers = 15;
769 }
770 else
771 {
772 /*Unknow codec */
773 codecBytes = 0;
774 codecBuffers = 0;
775 ok = CODEC_DB_UNKNOWN_CODEC;
776 }
777
778 /* Update max variables */
779 *maxBytes = WEBRTC_SPL_MAX((*maxBytes), codecBytes);
780 *maxSlots = WEBRTC_SPL_MAX((*maxSlots), codecBuffers);
781
782 } /* end of for loop */
783
784 /*
785 * Add size needed by the additional pointers for each slot inside struct,
786 * as indicated on each line below.
787 */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000788 w16_tmp = (sizeof(uint32_t) /* timeStamp */
789 + sizeof(int16_t*) /* payloadLocation */
790 + sizeof(uint16_t) /* seqNumber */
791 + sizeof(int16_t) /* payloadType */
792 + sizeof(int16_t) /* payloadLengthBytes */
793 + sizeof(int16_t) /* rcuPlCntr */
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000794 + sizeof(int)); /* waitingTime */
niklase@google.com470e71d2011-07-07 08:21:25 +0000795 /* Add the extra size per slot to the memory count */
796 *maxBytes += w16_tmp * (*maxSlots);
797
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +0000798 *per_slot_overhead_bytes = w16_tmp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 return ok;
800}