blob: ebe035dcb6cd4409c4682c8dec3c13d354ef04aa [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
tina.legrand@webrtc.orgfaa0ab82012-04-18 17:59:53 +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 * Signal the MCU that data is available and ask for a RecOut decision.
13 */
14
15#include "mcu.h"
16
17#include <string.h>
18
19#include "signal_processing_library.h"
20
21#include "automode.h"
22#include "dtmf_buffer.h"
23#include "mcu_dsp_common.h"
24#include "neteq_error_codes.h"
25
26#ifdef NETEQ_DELAY_LOGGING
27#include "delay_logging.h"
28#include <stdio.h>
29
30extern FILE *delay_fid2; /* file pointer to delay log file */
31#endif
32
33
34/*
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +000035 * Update the frame size, if we can.
36 */
37static int WebRtcNetEQ_UpdatePackSizeSamples(MCUInst_t* inst, int buffer_pos,
38 int payload_type,
39 int pack_size_samples) {
40 if (buffer_pos >= 0) {
41 int codec_pos;
42 codec_pos = WebRtcNetEQ_DbGetCodec(&inst->codec_DB_inst, payload_type);
43 if (codec_pos >= 0) {
44 codec_pos = inst->codec_DB_inst.position[codec_pos];
45 if (codec_pos >= 0) {
46 return WebRtcNetEQ_PacketBufferGetPacketSize(
47 &inst->PacketBuffer_inst, buffer_pos,
48 &inst->codec_DB_inst, codec_pos, pack_size_samples);
49 }
50 }
51 }
52 return pack_size_samples;
53}
54
55/*
niklase@google.com470e71d2011-07-07 08:21:25 +000056 * Signals the MCU that DSP status data is available.
57 */
58int WebRtcNetEQ_SignalMcu(MCUInst_t *inst)
59{
60
61 int i_bufferpos, i_res;
pbos@webrtc.org0946a562013-04-09 00:28:06 +000062 uint16_t uw16_instr;
niklase@google.com470e71d2011-07-07 08:21:25 +000063 DSP2MCU_info_t dspInfo;
pbos@webrtc.org0946a562013-04-09 00:28:06 +000064 int16_t *blockPtr, blockLen;
65 uint32_t uw32_availableTS;
niklase@google.com470e71d2011-07-07 08:21:25 +000066 RTPPacket_t temp_pkt;
pbos@webrtc.org0946a562013-04-09 00:28:06 +000067 int32_t w32_bufsize, w32_tmp;
68 int16_t payloadType = -1;
69 int16_t wantedNoOfTimeStamps;
70 int32_t totalTS;
71 int16_t oldPT, latePacketExist = 0;
72 uint32_t oldTS, prevTS, uw32_tmp;
73 uint16_t prevSeqNo;
74 int16_t nextSeqNoAvail;
75 int16_t fs_mult, w16_tmp;
76 int16_t lastModeBGNonly = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000077#ifdef NETEQ_DELAY_LOGGING
78 int temp_var;
79#endif
80 int playDtmf = 0;
81
82 fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000);
83
84 /* Increment counter since last statistics report */
85 inst->lastReportTS += inst->timestampsPerCall;
86
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +000087 /* Increment waiting time for all packets. */
88 WebRtcNetEQ_IncrementWaitingTimes(&inst->PacketBuffer_inst);
89
niklase@google.com470e71d2011-07-07 08:21:25 +000090 /* Read info from DSP so we now current status */
91
92 WEBRTC_SPL_MEMCPY_W8(&dspInfo,inst->pw16_readAddress,sizeof(DSP2MCU_info_t));
93
94 /* Set blockPtr to first payload block */
95 blockPtr = &inst->pw16_writeAddress[3];
96
pbos@webrtc.org0946a562013-04-09 00:28:06 +000097 /* Clear instruction word and number of lost samples (2*int16_t) */
niklase@google.com470e71d2011-07-07 08:21:25 +000098 inst->pw16_writeAddress[0] = 0;
99 inst->pw16_writeAddress[1] = 0;
100 inst->pw16_writeAddress[2] = 0;
101
102 if ((dspInfo.lastMode & MODE_AWAITING_CODEC_PTR) != 0)
103 {
104 /*
105 * Make sure state is adjusted so that a codec update is
106 * performed when first packet arrives.
107 */
108 if (inst->new_codec != 1)
109 {
110 inst->current_Codec = -1;
111 }
112 dspInfo.lastMode = (dspInfo.lastMode ^ MODE_AWAITING_CODEC_PTR);
113 }
114
115#ifdef NETEQ_STEREO
116 if ((dspInfo.lastMode & MODE_MASTER_DTMF_SIGNAL) != 0)
117 {
118 playDtmf = 1; /* force DTMF decision */
119 dspInfo.lastMode = (dspInfo.lastMode ^ MODE_MASTER_DTMF_SIGNAL);
120 }
121
122 if ((dspInfo.lastMode & MODE_USING_STEREO) != 0)
123 {
124 if (inst->usingStereo == 0)
125 {
126 /* stereo mode changed; reset automode instance to re-synchronize statistics */
127 WebRtcNetEQ_ResetAutomode(&(inst->BufferStat_inst.Automode_inst),
128 inst->PacketBuffer_inst.maxInsertPositions);
129 }
130 inst->usingStereo = 1;
131 dspInfo.lastMode = (dspInfo.lastMode ^ MODE_USING_STEREO);
132 }
133 else
134 {
135 inst->usingStereo = 0;
136 }
137#endif
138
139 /* detect if BGN_ONLY flag is set in lastMode */
140 if ((dspInfo.lastMode & MODE_BGN_ONLY) != 0)
141 {
142 lastModeBGNonly = 1; /* remember flag */
143 dspInfo.lastMode ^= MODE_BGN_ONLY; /* clear the flag */
144 }
145
146 if ((dspInfo.lastMode == MODE_RFC3389CNG) || (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG)
147 || (dspInfo.lastMode == MODE_EXPAND))
148 {
149 /*
150 * If last mode was CNG (or Expand, since this could be covering up for a lost CNG
151 * packet), increase the CNGplayedTS counter.
152 */
153 inst->BufferStat_inst.uw32_CNGplayedTS += inst->timestampsPerCall;
154
155 if (dspInfo.lastMode == MODE_RFC3389CNG)
156 {
157 /* remember that RFC3389CNG is on (needed if CNG is interrupted by DTMF) */
158 inst->BufferStat_inst.w16_cngOn = CNG_RFC3389_ON;
159 }
160 else if (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG)
161 {
162 /* remember that internal CNG is on (needed if CNG is interrupted by DTMF) */
163 inst->BufferStat_inst.w16_cngOn = CNG_INTERNAL_ON;
164 }
165
166 }
167
168 /* Update packet size from previously decoded packet */
169 if (dspInfo.frameLen > 0)
170 {
171 inst->PacketBuffer_inst.packSizeSamples = dspInfo.frameLen;
172 }
173
174 /* Look for late packet (unless codec has changed) */
175 if (inst->new_codec != 1)
176 {
177 if (WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) inst->current_Codec))
178 {
179 WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst,
180 inst->timeStamp, &uw32_availableTS, &i_bufferpos, 1, &payloadType);
181 if ((inst->new_codec != 1) && (inst->timeStamp == uw32_availableTS)
182 && (inst->timeStamp < dspInfo.playedOutTS) && (i_bufferpos != -1)
183 && (WebRtcNetEQ_DbGetPayload(&(inst->codec_DB_inst),
184 (enum WebRtcNetEQDecoder) inst->current_Codec) == payloadType))
185 {
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000186 int waitingTime;
niklase@google.com470e71d2011-07-07 08:21:25 +0000187 temp_pkt.payload = blockPtr + 1;
188 i_res = WebRtcNetEQ_PacketBufferExtract(&inst->PacketBuffer_inst, &temp_pkt,
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000189 i_bufferpos, &waitingTime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000190 if (i_res < 0)
191 { /* error returned */
192 return i_res;
193 }
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000194 WebRtcNetEQ_StoreWaitingTime(inst, waitingTime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 *blockPtr = temp_pkt.payloadLen;
196 /* set the flag if this is a redundant payload */
197 if (temp_pkt.rcuPlCntr > 0)
198 {
199 *blockPtr = (*blockPtr) | (DSP_CODEC_RED_FLAG);
200 }
201 blockPtr += ((temp_pkt.payloadLen + 1) >> 1) + 1;
202
203 /*
204 * Close the data with a zero size block, in case we will not write any
205 * more data.
206 */
207 *blockPtr = 0;
208 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff)
209 | DSP_CODEC_ADD_LATE_PKT;
210 latePacketExist = 1;
211 }
212 }
213 }
214
215 i_res = WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst,
216 dspInfo.playedOutTS, &uw32_availableTS, &i_bufferpos, (inst->new_codec == 0),
217 &payloadType);
218 if (i_res < 0)
219 { /* error returned */
220 return i_res;
221 }
222
223 if (inst->BufferStat_inst.w16_cngOn == CNG_RFC3389_ON)
224 {
225 /*
226 * Because of timestamp peculiarities, we have to "manually" disallow using a CNG
227 * packet with the same timestamp as the one that was last played. This can happen
228 * when using redundancy and will cause the timing to shift.
229 */
230 while (i_bufferpos != -1 && WebRtcNetEQ_DbIsCNGPayload(&inst->codec_DB_inst,
231 payloadType) && dspInfo.playedOutTS >= uw32_availableTS)
232 {
233
234 /* Don't use this packet, discard it */
235 inst->PacketBuffer_inst.payloadType[i_bufferpos] = -1;
236 inst->PacketBuffer_inst.payloadLengthBytes[i_bufferpos] = 0;
237 inst->PacketBuffer_inst.numPacketsInBuffer--;
238
239 /* Check buffer again */
240 WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst,
241 dspInfo.playedOutTS, &uw32_availableTS, &i_bufferpos, (inst->new_codec == 0),
242 &payloadType);
243 }
244 }
245
246 /* Check packet buffer */
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000247 w32_bufsize = WebRtcNetEQ_PacketBufferGetSize(&inst->PacketBuffer_inst,
248 &inst->codec_DB_inst);
niklase@google.com470e71d2011-07-07 08:21:25 +0000249
250 if (dspInfo.lastMode == MODE_SUCCESS_ACCELERATE || dspInfo.lastMode
251 == MODE_LOWEN_ACCELERATE || dspInfo.lastMode == MODE_SUCCESS_PREEMPTIVE
252 || dspInfo.lastMode == MODE_LOWEN_PREEMPTIVE)
253 {
254 /* Subtract (dspInfo.samplesLeft + inst->timestampsPerCall) from sampleMemory */
255 inst->BufferStat_inst.Automode_inst.sampleMemory -= dspInfo.samplesLeft
256 + inst->timestampsPerCall;
niklase@google.com470e71d2011-07-07 08:21:25 +0000257 }
258
259 /* calculate total current buffer size (in ms*8), including sync buffer */
260 w32_bufsize = WebRtcSpl_DivW32W16((w32_bufsize + dspInfo.samplesLeft), fs_mult);
261
niklase@google.com470e71d2011-07-07 08:21:25 +0000262#ifdef NETEQ_ATEVENT_DECODE
263 /* DTMF data will affect the decision */
264 if (WebRtcNetEQ_DtmfDecode(&inst->DTMF_inst, blockPtr + 1, blockPtr + 2,
265 dspInfo.playedOutTS + inst->BufferStat_inst.uw32_CNGplayedTS) > 0)
266 {
267 playDtmf = 1;
268
269 /* Flag DTMF payload */
270 inst->pw16_writeAddress[0] = inst->pw16_writeAddress[0] | DSP_DTMF_PAYLOAD;
271
272 /* Block Length in bytes */
273 blockPtr[0] = 4;
274 /* Advance to next payload position */
275 blockPtr += 3;
276 }
277#endif
278
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000279 /* Update the frame size, if we can. */
280 inst->PacketBuffer_inst.packSizeSamples =
281 WebRtcNetEQ_UpdatePackSizeSamples(inst, i_bufferpos, payloadType,
282 inst->PacketBuffer_inst.packSizeSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000283 /* Update statistics and make decision */
284 uw16_instr = WebRtcNetEQ_BufstatsDecision(&inst->BufferStat_inst,
285 inst->PacketBuffer_inst.packSizeSamples, w32_bufsize, dspInfo.playedOutTS,
286 uw32_availableTS, i_bufferpos == -1,
287 WebRtcNetEQ_DbIsCNGPayload(&inst->codec_DB_inst, payloadType), dspInfo.lastMode,
288 inst->NetEqPlayoutMode, inst->timestampsPerCall, inst->NoOfExpandCalls, fs_mult,
289 lastModeBGNonly, playDtmf);
290
291 /* Check if time to reset loss counter */
292 if (inst->lastReportTS > WEBRTC_SPL_UMUL(inst->fs, MAX_LOSS_REPORT_PERIOD))
293 {
294 /* reset loss counter */
295 WebRtcNetEQ_ResetMcuInCallStats(inst);
296 }
297
298 /* Check sync buffer size */
299 if ((dspInfo.samplesLeft >= inst->timestampsPerCall) && (uw16_instr
300 != BUFSTATS_DO_ACCELERATE) && (uw16_instr != BUFSTATS_DO_MERGE) && (uw16_instr
301 != BUFSTATS_DO_PREEMPTIVE_EXPAND))
302 {
303 *blockPtr = 0;
304 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_NORMAL;
305 return 0;
306 }
307
308 if (uw16_instr == BUFSTATS_DO_EXPAND)
309 {
310 inst->NoOfExpandCalls++;
311 }
312 else
313 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000314 /* reset counter */
315 inst->NoOfExpandCalls = 0;
316 }
317
318 /* New codec or big change in packet number? */
tina.legrand@webrtc.orgfaa0ab82012-04-18 17:59:53 +0000319 if ((inst->new_codec) || (uw16_instr == BUFSTAT_REINIT))
niklase@google.com470e71d2011-07-07 08:21:25 +0000320 {
321 CodecFuncInst_t cinst;
322
323 /* Clear other instructions */
324 blockPtr = &inst->pw16_writeAddress[3];
325 /* Clear instruction word */
326 inst->pw16_writeAddress[0] = 0;
327
328 inst->timeStamp = uw32_availableTS;
329 dspInfo.playedOutTS = uw32_availableTS;
330 if (inst->current_Codec != -1)
331 {
332 i_res = WebRtcNetEQ_DbGetPtrs(&inst->codec_DB_inst,
333 (enum WebRtcNetEQDecoder) inst->current_Codec, &cinst);
334 if (i_res < 0)
335 { /* error returned */
336 return i_res;
337 }
338 }
339 else
340 {
341 /* The main codec has not been initialized yet (first packets are DTMF or CNG). */
342 if (WebRtcNetEQ_DbIsCNGPayload(&inst->codec_DB_inst, payloadType))
343 {
344 /* The currently extracted packet is CNG; get CNG fs */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000345 uint16_t tempFs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000346
347 tempFs = WebRtcNetEQ_DbGetSampleRate(&inst->codec_DB_inst, payloadType);
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000348 /* TODO(tlegrand): Remove this limitation once ACM has full
349 * 48 kHz support. */
350 if (tempFs > 32000)
351 {
352 inst->fs = 32000;
353 }
354 else if (tempFs > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000355 {
356 inst->fs = tempFs;
357 }
358 }
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000359 WebRtcSpl_MemSetW16((int16_t*) &cinst, 0,
360 sizeof(CodecFuncInst_t) / sizeof(int16_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000361 cinst.codec_fs = inst->fs;
362 }
363 cinst.timeStamp = inst->timeStamp;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000364 blockLen = (sizeof(CodecFuncInst_t)) >> (sizeof(int16_t) - 1); /* in Word16 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 *blockPtr = blockLen * 2;
366 blockPtr++;
367 WEBRTC_SPL_MEMCPY_W8(blockPtr,&cinst,sizeof(CodecFuncInst_t));
368 blockPtr += blockLen;
369 inst->new_codec = 0;
370
371 /* Reinitialize the MCU fs */
372 i_res = WebRtcNetEQ_McuSetFs(inst, cinst.codec_fs);
373 if (i_res < 0)
374 { /* error returned */
375 return i_res;
376 }
377
378 /* Set the packet size by guessing */
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000379 inst->PacketBuffer_inst.packSizeSamples =
380 WebRtcNetEQ_UpdatePackSizeSamples(inst, i_bufferpos, payloadType,
381 inst->timestampsPerCall * 3);
niklase@google.com470e71d2011-07-07 08:21:25 +0000382
383 WebRtcNetEQ_ResetAutomode(&(inst->BufferStat_inst.Automode_inst),
384 inst->PacketBuffer_inst.maxInsertPositions);
385
386#ifdef NETEQ_CNG_CODEC
387 /* Also insert CNG state as this might be needed by DSP */
388 i_res = WebRtcNetEQ_DbGetPtrs(&inst->codec_DB_inst, kDecoderCNG, &cinst);
389 if ((i_res < 0) && (i_res != CODEC_DB_NOT_EXIST1))
390 {
391 /* other error returned */
392 /* (CODEC_DB_NOT_EXIST1 simply indicates that CNG is not used */
393 return i_res;
394 }
395 else
396 {
397 /* CNG exists */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000398 blockLen = (sizeof(cinst.codec_state)) >> (sizeof(int16_t) - 1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 *blockPtr = blockLen * 2;
400 blockPtr++;
401 WEBRTC_SPL_MEMCPY_W8(blockPtr,&cinst.codec_state,sizeof(cinst.codec_state));
402 blockPtr += blockLen;
403 }
404#endif
405
406 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff)
407 | DSP_CODEC_NEW_CODEC;
408
409 if (uw16_instr == BUFSTATS_DO_RFC3389CNG_NOPACKET)
410 {
411 /*
412 * Change decision to CNG packet, since we do have a CNG packet, but it was
413 * considered too early to use. Now, use it anyway.
414 */
415 uw16_instr = BUFSTATS_DO_RFC3389CNG_PACKET;
416 }
417 else if (uw16_instr != BUFSTATS_DO_RFC3389CNG_PACKET)
418 {
419 uw16_instr = BUFSTATS_DO_NORMAL;
420 }
421
422 /* reset loss counter */
423 WebRtcNetEQ_ResetMcuInCallStats(inst);
424 }
425
426 /* Should we just reset the decoder? */
427 if (uw16_instr == BUFSTAT_REINIT_DECODER)
428 {
429 /* Change decision to normal and flag decoder reset */
430 uw16_instr = BUFSTATS_DO_NORMAL;
431 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff) | DSP_CODEC_RESET;
432 }
433
434 /* Expand requires no new packet */
435 if (uw16_instr == BUFSTATS_DO_EXPAND)
436 {
437
438 inst->timeStamp = dspInfo.playedOutTS;
439
440 /* Have we got one descriptor left? */
441 if (WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) inst->current_Codec)
442 && (dspInfo.MD || latePacketExist))
443 {
444
445 if (dspInfo.lastMode != MODE_ONE_DESCRIPTOR)
446 {
447 /* this is the first "consecutive" one-descriptor decoding; reset counter */
448 inst->one_desc = 0;
449 }
450 if (inst->one_desc < MAX_ONE_DESC)
451 {
452 /* use that one descriptor */
453 inst->one_desc++; /* increase counter */
454 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
455 | DSP_INSTR_NORMAL_ONE_DESC;
456
457 /* decrease counter since we did no Expand */
458 inst->NoOfExpandCalls = WEBRTC_SPL_MAX(inst->NoOfExpandCalls - 1, 0);
459 return 0;
460 }
461 else
462 {
463 /* too many consecutive one-descriptor decodings; do expand instead */
464 inst->one_desc = 0; /* reset counter */
465 }
466
467 }
468
469 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_EXPAND;
470 return 0;
471 }
472
473 /* Merge is not needed if we still have a descriptor */
474 if ((uw16_instr == BUFSTATS_DO_MERGE) && (dspInfo.MD != 0))
475 {
476 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
477 | DSP_INSTR_NORMAL_ONE_DESC;
478 *blockPtr = 0;
479 return 0;
480 }
481
482 /* Do CNG without trying to extract any packets from buffer */
483 if (uw16_instr == BUFSTATS_DO_RFC3389CNG_NOPACKET)
484 {
485 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
486 | DSP_INSTR_DO_RFC3389CNG;
487 *blockPtr = 0;
488 return 0;
489 }
490
491 /* Do built-in CNG without extracting any new packets from buffer */
492 if (uw16_instr == BUFSTATS_DO_INTERNAL_CNG_NOPACKET)
493 {
494 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
495 | DSP_INSTR_DO_CODEC_INTERNAL_CNG;
496 *blockPtr = 0;
497 return 0;
498 }
499
500 /* Do DTMF without extracting any new packets from buffer */
501 if (uw16_instr == BUFSTATS_DO_DTMF_ONLY)
502 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000503 uint32_t timeStampJump = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000504
505 /* Update timestamp */
506 if ((inst->BufferStat_inst.uw32_CNGplayedTS > 0) && (dspInfo.lastMode != MODE_DTMF))
507 {
508 /* Jump in timestamps if needed */
509 timeStampJump = inst->BufferStat_inst.uw32_CNGplayedTS;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000510 inst->pw16_writeAddress[1] = (uint16_t) (timeStampJump >> 16);
511 inst->pw16_writeAddress[2] = (uint16_t) (timeStampJump & 0xFFFF);
niklase@google.com470e71d2011-07-07 08:21:25 +0000512 }
513
514 inst->timeStamp = dspInfo.playedOutTS + timeStampJump;
515
niklase@google.com470e71d2011-07-07 08:21:25 +0000516 inst->BufferStat_inst.uw32_CNGplayedTS = 0;
517 inst->NoOfExpandCalls = 0;
518
519 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
520 | DSP_INSTR_DTMF_GENERATE;
521 *blockPtr = 0;
522 return 0;
523 }
524
525 if (uw16_instr == BUFSTATS_DO_ACCELERATE)
526 {
527 /* In order to do a Accelerate we need at least 30 ms of data */
528 if (dspInfo.samplesLeft >= (3 * 80 * fs_mult))
529 {
530 /* Already have enough data, so we do not need to extract any more */
531 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
532 | DSP_INSTR_ACCELERATE;
533 *blockPtr = 0;
534 inst->BufferStat_inst.Automode_inst.sampleMemory
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000535 = (int32_t) dspInfo.samplesLeft;
niklase@google.com470e71d2011-07-07 08:21:25 +0000536 inst->BufferStat_inst.Automode_inst.prevTimeScale = 1;
537 return 0;
538 }
539 else if ((dspInfo.samplesLeft >= (1 * 80 * fs_mult))
540 && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult)))
541 {
542 /* Avoid decoding more data as it might overflow playout buffer */
543 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
544 | DSP_INSTR_NORMAL;
545 *blockPtr = 0;
546 return 0;
547 }
548 else if ((dspInfo.samplesLeft < (1 * 80 * fs_mult))
549 && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult)))
550 {
551 /* For >= 30ms allow Accelerate with a decoding to avoid overflow in playout buffer */
552 wantedNoOfTimeStamps = inst->timestampsPerCall;
553 }
554 else if (dspInfo.samplesLeft >= (2 * 80 * fs_mult))
555 {
556 /* We need to decode another 10 ms in order to do an Accelerate */
557 wantedNoOfTimeStamps = inst->timestampsPerCall;
558 }
559 else
560 {
561 /*
562 * Build up decoded data by decoding at least 20 ms of data.
563 * Do not perform Accelerate yet, but wait until we only need to do one decoding.
564 */
565 wantedNoOfTimeStamps = 2 * inst->timestampsPerCall;
566 uw16_instr = BUFSTATS_DO_NORMAL;
567 }
568 }
569 else if (uw16_instr == BUFSTATS_DO_PREEMPTIVE_EXPAND)
570 {
571 /* In order to do a Preemptive Expand we need at least 30 ms of data */
572 if (dspInfo.samplesLeft >= (3 * 80 * fs_mult))
573 {
574 /* Already have enough data, so we do not need to extract any more */
575 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
576 | DSP_INSTR_PREEMPTIVE_EXPAND;
577 *blockPtr = 0;
578 inst->BufferStat_inst.Automode_inst.sampleMemory
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000579 = (int32_t) dspInfo.samplesLeft;
niklase@google.com470e71d2011-07-07 08:21:25 +0000580 inst->BufferStat_inst.Automode_inst.prevTimeScale = 1;
581 return 0;
582 }
583 else if ((dspInfo.samplesLeft >= (1 * 80 * fs_mult))
584 && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult)))
585 {
586 /*
587 * Avoid decoding more data as it might overflow playout buffer;
588 * still try Preemptive Expand though.
589 */
590 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
591 | DSP_INSTR_PREEMPTIVE_EXPAND;
592 *blockPtr = 0;
593 inst->BufferStat_inst.Automode_inst.sampleMemory
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000594 = (int32_t) dspInfo.samplesLeft;
niklase@google.com470e71d2011-07-07 08:21:25 +0000595 inst->BufferStat_inst.Automode_inst.prevTimeScale = 1;
596 return 0;
597 }
598 else if ((dspInfo.samplesLeft < (1 * 80 * fs_mult))
599 && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult)))
600 {
601 /*
602 * For >= 30ms allow Preemptive Expand with a decoding to avoid overflow in
603 * playout buffer
604 */
605 wantedNoOfTimeStamps = inst->timestampsPerCall;
606 }
607 else if (dspInfo.samplesLeft >= (2 * 80 * fs_mult))
608 {
609 /* We need to decode another 10 ms in order to do an Preemptive Expand */
610 wantedNoOfTimeStamps = inst->timestampsPerCall;
611 }
612 else
613 {
614 /*
615 * Build up decoded data by decoding at least 20 ms of data,
616 * Still try to perform Preemptive Expand.
617 */
618 wantedNoOfTimeStamps = 2 * inst->timestampsPerCall;
619 }
620 }
621 else
622 {
623 wantedNoOfTimeStamps = inst->timestampsPerCall;
624 }
625
626 /* Otherwise get data from buffer, try to get at least 10ms */
627 totalTS = 0;
628 oldTS = uw32_availableTS;
629 if ((i_bufferpos > -1) && (uw16_instr != BUFSTATS_DO_ALTERNATIVE_PLC) && (uw16_instr
630 != BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS) && (uw16_instr != BUFSTATS_DO_AUDIO_REPETITION)
631 && (uw16_instr != BUFSTATS_DO_AUDIO_REPETITION_INC_TS))
632 {
633 uw32_tmp = (uw32_availableTS - dspInfo.playedOutTS);
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000634 inst->pw16_writeAddress[1] = (uint16_t) (uw32_tmp >> 16);
635 inst->pw16_writeAddress[2] = (uint16_t) (uw32_tmp & 0xFFFF);
niklase@google.com470e71d2011-07-07 08:21:25 +0000636 if (inst->BufferStat_inst.w16_cngOn == CNG_OFF)
637 {
638 /*
639 * Adjustment of TS only corresponds to an actual packet loss
640 * if comfort noise is not played. If comfort noise was just played,
641 * this adjustment of TS is only done to get back in sync with the
642 * stream TS; no loss to report.
643 */
644 inst->lostTS += uw32_tmp;
645 }
646
647 if (uw16_instr != BUFSTATS_DO_RFC3389CNG_PACKET)
648 {
649 /* We are about to decode and use a non-CNG packet => CNG period is ended */
650 inst->BufferStat_inst.w16_cngOn = CNG_OFF;
651 }
652
niklase@google.com470e71d2011-07-07 08:21:25 +0000653 /*
654 * Reset CNG timestamp as a new packet will be delivered.
655 * (Also if CNG packet, since playedOutTS is updated.)
656 */
657 inst->BufferStat_inst.uw32_CNGplayedTS = 0;
658
659 prevSeqNo = inst->PacketBuffer_inst.seqNumber[i_bufferpos];
660 prevTS = inst->PacketBuffer_inst.timeStamp[i_bufferpos];
661 oldPT = inst->PacketBuffer_inst.payloadType[i_bufferpos];
662
663 /* clear flag bits */
664 inst->pw16_writeAddress[0] = inst->pw16_writeAddress[0] & 0xFF3F;
665 do
666 {
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000667 int waitingTime;
niklase@google.com470e71d2011-07-07 08:21:25 +0000668 inst->timeStamp = uw32_availableTS;
669 /* Write directly to shared memory */
670 temp_pkt.payload = blockPtr + 1;
671 i_res = WebRtcNetEQ_PacketBufferExtract(&inst->PacketBuffer_inst, &temp_pkt,
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000672 i_bufferpos, &waitingTime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000673
674 if (i_res < 0)
675 {
676 /* error returned */
677 return i_res;
678 }
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000679 WebRtcNetEQ_StoreWaitingTime(inst, waitingTime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000680
681#ifdef NETEQ_DELAY_LOGGING
682 temp_var = NETEQ_DELAY_LOGGING_SIGNAL_DECODE;
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000683 if ((fwrite(&temp_var, sizeof(int),
684 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000685 (fwrite(&temp_pkt.timeStamp, sizeof(uint32_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000686 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000687 (fwrite(&dspInfo.samplesLeft, sizeof(uint16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000688 1, delay_fid2) != 1)) {
689 return -1;
690 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000691#endif
692
693 *blockPtr = temp_pkt.payloadLen;
694 /* set the flag if this is a redundant payload */
695 if (temp_pkt.rcuPlCntr > 0)
696 {
697 *blockPtr = (*blockPtr) | (DSP_CODEC_RED_FLAG);
698 }
699 blockPtr += ((temp_pkt.payloadLen + 1) >> 1) + 1;
700
701 if (i_bufferpos > -1)
702 {
703 /*
704 * Store number of TS extracted (last extracted is assumed to be of
705 * packSizeSamples).
706 */
707 totalTS = uw32_availableTS - oldTS + inst->PacketBuffer_inst.packSizeSamples;
708 }
709 /* Check what next packet is available */
710 WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst,
711 inst->timeStamp, &uw32_availableTS, &i_bufferpos, 0, &payloadType);
712
713 nextSeqNoAvail = 0;
714 if ((i_bufferpos > -1) && (oldPT
715 == inst->PacketBuffer_inst.payloadType[i_bufferpos]))
716 {
717 w16_tmp = inst->PacketBuffer_inst.seqNumber[i_bufferpos] - prevSeqNo;
718 w32_tmp = inst->PacketBuffer_inst.timeStamp[i_bufferpos] - prevTS;
719 if ((w16_tmp == 1) || /* Next packet */
720 ((w16_tmp == 0) && (w32_tmp == inst->PacketBuffer_inst.packSizeSamples)))
721 { /* or packet split into frames */
722 nextSeqNoAvail = 1;
723 }
724 prevSeqNo = inst->PacketBuffer_inst.seqNumber[i_bufferpos];
725 }
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000726 /* Update the frame size, if we can. */
727 inst->PacketBuffer_inst.packSizeSamples =
728 WebRtcNetEQ_UpdatePackSizeSamples(inst, i_bufferpos,
729 payloadType, inst->PacketBuffer_inst.packSizeSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 }
731 while ((totalTS < wantedNoOfTimeStamps) && (nextSeqNoAvail == 1));
732 }
733
734 if ((uw16_instr == BUFSTATS_DO_ACCELERATE)
735 || (uw16_instr == BUFSTATS_DO_PREEMPTIVE_EXPAND))
736 {
737 /* Check that we have enough data (30ms) to do the Accelearate */
738 if ((totalTS + dspInfo.samplesLeft) < WEBRTC_SPL_MUL(3,inst->timestampsPerCall)
739 && (uw16_instr == BUFSTATS_DO_ACCELERATE))
740 {
741 /* Not enough, do normal operation instead */
742 uw16_instr = BUFSTATS_DO_NORMAL;
743 }
744 else
745 {
746 inst->BufferStat_inst.Automode_inst.sampleMemory
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000747 = (int32_t) dspInfo.samplesLeft + totalTS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 inst->BufferStat_inst.Automode_inst.prevTimeScale = 1;
749 }
750 }
751
752 /* Close the data with a zero size block */
753 *blockPtr = 0;
754
755 /* Write data to DSP */
756 switch (uw16_instr)
757 {
758 case BUFSTATS_DO_NORMAL:
759 /* Normal with decoding included */
760 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
761 | DSP_INSTR_NORMAL;
762 break;
763 case BUFSTATS_DO_ACCELERATE:
764 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
765 | DSP_INSTR_ACCELERATE;
766 break;
767 case BUFSTATS_DO_MERGE:
768 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
769 | DSP_INSTR_MERGE;
770 break;
771 case BUFSTATS_DO_RFC3389CNG_PACKET:
772 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
773 | DSP_INSTR_DO_RFC3389CNG;
774 break;
775 case BUFSTATS_DO_ALTERNATIVE_PLC:
776 inst->pw16_writeAddress[1] = 0;
777 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
778 | DSP_INSTR_DO_ALTERNATIVE_PLC;
779 break;
780 case BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS:
781 inst->pw16_writeAddress[1] = 0;
782 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
783 | DSP_INSTR_DO_ALTERNATIVE_PLC_INC_TS;
784 break;
785 case BUFSTATS_DO_AUDIO_REPETITION:
786 inst->pw16_writeAddress[1] = 0;
787 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
788 | DSP_INSTR_DO_AUDIO_REPETITION;
789 break;
790 case BUFSTATS_DO_AUDIO_REPETITION_INC_TS:
791 inst->pw16_writeAddress[1] = 0;
792 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
793 | DSP_INSTR_DO_AUDIO_REPETITION_INC_TS;
794 break;
795 case BUFSTATS_DO_PREEMPTIVE_EXPAND:
796 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
797 | DSP_INSTR_PREEMPTIVE_EXPAND;
798 break;
799 default:
800 return UNKNOWN_BUFSTAT_DECISION;
801 }
802
803 inst->timeStamp = dspInfo.playedOutTS;
804 return 0;
805
806}