blob: b795ec30e3826fc48ba33d85c6e8f55aef584075 [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) {
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +000046 int temp_packet_size_samples = WebRtcNetEQ_PacketBufferGetPacketSize(
47 &inst->PacketBuffer_inst, buffer_pos, &inst->codec_DB_inst,
48 codec_pos, pack_size_samples, inst->av_sync);
49 if (temp_packet_size_samples > 0)
50 return temp_packet_size_samples;
51 return pack_size_samples;
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +000052 }
53 }
54 }
55 return pack_size_samples;
56}
57
58/*
niklase@google.com470e71d2011-07-07 08:21:25 +000059 * Signals the MCU that DSP status data is available.
60 */
61int WebRtcNetEQ_SignalMcu(MCUInst_t *inst)
62{
63
64 int i_bufferpos, i_res;
pbos@webrtc.org0946a562013-04-09 00:28:06 +000065 uint16_t uw16_instr;
niklase@google.com470e71d2011-07-07 08:21:25 +000066 DSP2MCU_info_t dspInfo;
pbos@webrtc.org0946a562013-04-09 00:28:06 +000067 int16_t *blockPtr, blockLen;
68 uint32_t uw32_availableTS;
niklase@google.com470e71d2011-07-07 08:21:25 +000069 RTPPacket_t temp_pkt;
pbos@webrtc.org0946a562013-04-09 00:28:06 +000070 int32_t w32_bufsize, w32_tmp;
71 int16_t payloadType = -1;
72 int16_t wantedNoOfTimeStamps;
73 int32_t totalTS;
74 int16_t oldPT, latePacketExist = 0;
75 uint32_t oldTS, prevTS, uw32_tmp;
76 uint16_t prevSeqNo;
77 int16_t nextSeqNoAvail;
78 int16_t fs_mult, w16_tmp;
79 int16_t lastModeBGNonly = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000080#ifdef NETEQ_DELAY_LOGGING
81 int temp_var;
82#endif
83 int playDtmf = 0;
84
85 fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000);
86
87 /* Increment counter since last statistics report */
88 inst->lastReportTS += inst->timestampsPerCall;
89
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +000090 /* Increment waiting time for all packets. */
91 WebRtcNetEQ_IncrementWaitingTimes(&inst->PacketBuffer_inst);
92
niklase@google.com470e71d2011-07-07 08:21:25 +000093 /* Read info from DSP so we now current status */
94
95 WEBRTC_SPL_MEMCPY_W8(&dspInfo,inst->pw16_readAddress,sizeof(DSP2MCU_info_t));
96
97 /* Set blockPtr to first payload block */
98 blockPtr = &inst->pw16_writeAddress[3];
99
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000100 /* Clear instruction word and number of lost samples (2*int16_t) */
niklase@google.com470e71d2011-07-07 08:21:25 +0000101 inst->pw16_writeAddress[0] = 0;
102 inst->pw16_writeAddress[1] = 0;
103 inst->pw16_writeAddress[2] = 0;
104
105 if ((dspInfo.lastMode & MODE_AWAITING_CODEC_PTR) != 0)
106 {
107 /*
108 * Make sure state is adjusted so that a codec update is
109 * performed when first packet arrives.
110 */
111 if (inst->new_codec != 1)
112 {
113 inst->current_Codec = -1;
114 }
115 dspInfo.lastMode = (dspInfo.lastMode ^ MODE_AWAITING_CODEC_PTR);
116 }
117
118#ifdef NETEQ_STEREO
119 if ((dspInfo.lastMode & MODE_MASTER_DTMF_SIGNAL) != 0)
120 {
121 playDtmf = 1; /* force DTMF decision */
122 dspInfo.lastMode = (dspInfo.lastMode ^ MODE_MASTER_DTMF_SIGNAL);
123 }
124
125 if ((dspInfo.lastMode & MODE_USING_STEREO) != 0)
126 {
127 if (inst->usingStereo == 0)
128 {
129 /* stereo mode changed; reset automode instance to re-synchronize statistics */
130 WebRtcNetEQ_ResetAutomode(&(inst->BufferStat_inst.Automode_inst),
131 inst->PacketBuffer_inst.maxInsertPositions);
132 }
133 inst->usingStereo = 1;
134 dspInfo.lastMode = (dspInfo.lastMode ^ MODE_USING_STEREO);
135 }
136 else
137 {
138 inst->usingStereo = 0;
139 }
140#endif
141
142 /* detect if BGN_ONLY flag is set in lastMode */
143 if ((dspInfo.lastMode & MODE_BGN_ONLY) != 0)
144 {
145 lastModeBGNonly = 1; /* remember flag */
146 dspInfo.lastMode ^= MODE_BGN_ONLY; /* clear the flag */
147 }
148
149 if ((dspInfo.lastMode == MODE_RFC3389CNG) || (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG)
150 || (dspInfo.lastMode == MODE_EXPAND))
151 {
152 /*
153 * If last mode was CNG (or Expand, since this could be covering up for a lost CNG
154 * packet), increase the CNGplayedTS counter.
155 */
156 inst->BufferStat_inst.uw32_CNGplayedTS += inst->timestampsPerCall;
157
158 if (dspInfo.lastMode == MODE_RFC3389CNG)
159 {
160 /* remember that RFC3389CNG is on (needed if CNG is interrupted by DTMF) */
161 inst->BufferStat_inst.w16_cngOn = CNG_RFC3389_ON;
162 }
163 else if (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG)
164 {
165 /* remember that internal CNG is on (needed if CNG is interrupted by DTMF) */
166 inst->BufferStat_inst.w16_cngOn = CNG_INTERNAL_ON;
167 }
168
169 }
170
171 /* Update packet size from previously decoded packet */
172 if (dspInfo.frameLen > 0)
173 {
174 inst->PacketBuffer_inst.packSizeSamples = dspInfo.frameLen;
175 }
176
177 /* Look for late packet (unless codec has changed) */
178 if (inst->new_codec != 1)
179 {
180 if (WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) inst->current_Codec))
181 {
182 WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst,
183 inst->timeStamp, &uw32_availableTS, &i_bufferpos, 1, &payloadType);
184 if ((inst->new_codec != 1) && (inst->timeStamp == uw32_availableTS)
185 && (inst->timeStamp < dspInfo.playedOutTS) && (i_bufferpos != -1)
186 && (WebRtcNetEQ_DbGetPayload(&(inst->codec_DB_inst),
187 (enum WebRtcNetEQDecoder) inst->current_Codec) == payloadType))
188 {
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000189 int waitingTime;
niklase@google.com470e71d2011-07-07 08:21:25 +0000190 temp_pkt.payload = blockPtr + 1;
191 i_res = WebRtcNetEQ_PacketBufferExtract(&inst->PacketBuffer_inst, &temp_pkt,
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000192 i_bufferpos, &waitingTime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 if (i_res < 0)
194 { /* error returned */
195 return i_res;
196 }
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000197 WebRtcNetEQ_StoreWaitingTime(inst, waitingTime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 *blockPtr = temp_pkt.payloadLen;
199 /* set the flag if this is a redundant payload */
200 if (temp_pkt.rcuPlCntr > 0)
201 {
202 *blockPtr = (*blockPtr) | (DSP_CODEC_RED_FLAG);
203 }
204 blockPtr += ((temp_pkt.payloadLen + 1) >> 1) + 1;
205
206 /*
207 * Close the data with a zero size block, in case we will not write any
208 * more data.
209 */
210 *blockPtr = 0;
211 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff)
212 | DSP_CODEC_ADD_LATE_PKT;
213 latePacketExist = 1;
214 }
215 }
216 }
217
218 i_res = WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst,
219 dspInfo.playedOutTS, &uw32_availableTS, &i_bufferpos, (inst->new_codec == 0),
220 &payloadType);
221 if (i_res < 0)
222 { /* error returned */
223 return i_res;
224 }
225
226 if (inst->BufferStat_inst.w16_cngOn == CNG_RFC3389_ON)
227 {
228 /*
229 * Because of timestamp peculiarities, we have to "manually" disallow using a CNG
230 * packet with the same timestamp as the one that was last played. This can happen
231 * when using redundancy and will cause the timing to shift.
232 */
233 while (i_bufferpos != -1 && WebRtcNetEQ_DbIsCNGPayload(&inst->codec_DB_inst,
234 payloadType) && dspInfo.playedOutTS >= uw32_availableTS)
235 {
236
237 /* Don't use this packet, discard it */
238 inst->PacketBuffer_inst.payloadType[i_bufferpos] = -1;
239 inst->PacketBuffer_inst.payloadLengthBytes[i_bufferpos] = 0;
240 inst->PacketBuffer_inst.numPacketsInBuffer--;
241
242 /* Check buffer again */
243 WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst,
244 dspInfo.playedOutTS, &uw32_availableTS, &i_bufferpos, (inst->new_codec == 0),
245 &payloadType);
246 }
247 }
248
249 /* Check packet buffer */
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000250 w32_bufsize = WebRtcNetEQ_PacketBufferGetSize(&inst->PacketBuffer_inst,
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000251 &inst->codec_DB_inst, inst->av_sync);
niklase@google.com470e71d2011-07-07 08:21:25 +0000252
253 if (dspInfo.lastMode == MODE_SUCCESS_ACCELERATE || dspInfo.lastMode
254 == MODE_LOWEN_ACCELERATE || dspInfo.lastMode == MODE_SUCCESS_PREEMPTIVE
255 || dspInfo.lastMode == MODE_LOWEN_PREEMPTIVE)
256 {
257 /* Subtract (dspInfo.samplesLeft + inst->timestampsPerCall) from sampleMemory */
258 inst->BufferStat_inst.Automode_inst.sampleMemory -= dspInfo.samplesLeft
259 + inst->timestampsPerCall;
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 }
261
262 /* calculate total current buffer size (in ms*8), including sync buffer */
263 w32_bufsize = WebRtcSpl_DivW32W16((w32_bufsize + dspInfo.samplesLeft), fs_mult);
264
niklase@google.com470e71d2011-07-07 08:21:25 +0000265#ifdef NETEQ_ATEVENT_DECODE
266 /* DTMF data will affect the decision */
267 if (WebRtcNetEQ_DtmfDecode(&inst->DTMF_inst, blockPtr + 1, blockPtr + 2,
268 dspInfo.playedOutTS + inst->BufferStat_inst.uw32_CNGplayedTS) > 0)
269 {
270 playDtmf = 1;
271
272 /* Flag DTMF payload */
273 inst->pw16_writeAddress[0] = inst->pw16_writeAddress[0] | DSP_DTMF_PAYLOAD;
274
275 /* Block Length in bytes */
276 blockPtr[0] = 4;
277 /* Advance to next payload position */
278 blockPtr += 3;
279 }
280#endif
281
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000282 /* Update the frame size, if we can. */
283 inst->PacketBuffer_inst.packSizeSamples =
284 WebRtcNetEQ_UpdatePackSizeSamples(inst, i_bufferpos, payloadType,
285 inst->PacketBuffer_inst.packSizeSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000286 /* Update statistics and make decision */
287 uw16_instr = WebRtcNetEQ_BufstatsDecision(&inst->BufferStat_inst,
288 inst->PacketBuffer_inst.packSizeSamples, w32_bufsize, dspInfo.playedOutTS,
289 uw32_availableTS, i_bufferpos == -1,
290 WebRtcNetEQ_DbIsCNGPayload(&inst->codec_DB_inst, payloadType), dspInfo.lastMode,
291 inst->NetEqPlayoutMode, inst->timestampsPerCall, inst->NoOfExpandCalls, fs_mult,
292 lastModeBGNonly, playDtmf);
293
294 /* Check if time to reset loss counter */
295 if (inst->lastReportTS > WEBRTC_SPL_UMUL(inst->fs, MAX_LOSS_REPORT_PERIOD))
296 {
297 /* reset loss counter */
298 WebRtcNetEQ_ResetMcuInCallStats(inst);
299 }
300
301 /* Check sync buffer size */
302 if ((dspInfo.samplesLeft >= inst->timestampsPerCall) && (uw16_instr
303 != BUFSTATS_DO_ACCELERATE) && (uw16_instr != BUFSTATS_DO_MERGE) && (uw16_instr
304 != BUFSTATS_DO_PREEMPTIVE_EXPAND))
305 {
306 *blockPtr = 0;
307 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_NORMAL;
308 return 0;
309 }
310
311 if (uw16_instr == BUFSTATS_DO_EXPAND)
312 {
313 inst->NoOfExpandCalls++;
314 }
315 else
316 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000317 /* reset counter */
318 inst->NoOfExpandCalls = 0;
319 }
320
321 /* New codec or big change in packet number? */
tina.legrand@webrtc.orgfaa0ab82012-04-18 17:59:53 +0000322 if ((inst->new_codec) || (uw16_instr == BUFSTAT_REINIT))
niklase@google.com470e71d2011-07-07 08:21:25 +0000323 {
324 CodecFuncInst_t cinst;
325
326 /* Clear other instructions */
327 blockPtr = &inst->pw16_writeAddress[3];
328 /* Clear instruction word */
329 inst->pw16_writeAddress[0] = 0;
330
331 inst->timeStamp = uw32_availableTS;
332 dspInfo.playedOutTS = uw32_availableTS;
333 if (inst->current_Codec != -1)
334 {
335 i_res = WebRtcNetEQ_DbGetPtrs(&inst->codec_DB_inst,
336 (enum WebRtcNetEQDecoder) inst->current_Codec, &cinst);
337 if (i_res < 0)
338 { /* error returned */
339 return i_res;
340 }
341 }
342 else
343 {
344 /* The main codec has not been initialized yet (first packets are DTMF or CNG). */
345 if (WebRtcNetEQ_DbIsCNGPayload(&inst->codec_DB_inst, payloadType))
346 {
347 /* The currently extracted packet is CNG; get CNG fs */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000348 uint16_t tempFs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000349
350 tempFs = WebRtcNetEQ_DbGetSampleRate(&inst->codec_DB_inst, payloadType);
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000351 /* TODO(tlegrand): Remove this limitation once ACM has full
352 * 48 kHz support. */
353 if (tempFs > 32000)
354 {
355 inst->fs = 32000;
356 }
357 else if (tempFs > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000358 {
359 inst->fs = tempFs;
360 }
361 }
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000362 WebRtcSpl_MemSetW16((int16_t*) &cinst, 0,
363 sizeof(CodecFuncInst_t) / sizeof(int16_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000364 cinst.codec_fs = inst->fs;
365 }
366 cinst.timeStamp = inst->timeStamp;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000367 blockLen = (sizeof(CodecFuncInst_t)) >> (sizeof(int16_t) - 1); /* in Word16 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000368 *blockPtr = blockLen * 2;
369 blockPtr++;
370 WEBRTC_SPL_MEMCPY_W8(blockPtr,&cinst,sizeof(CodecFuncInst_t));
371 blockPtr += blockLen;
372 inst->new_codec = 0;
373
374 /* Reinitialize the MCU fs */
375 i_res = WebRtcNetEQ_McuSetFs(inst, cinst.codec_fs);
376 if (i_res < 0)
377 { /* error returned */
378 return i_res;
379 }
380
381 /* Set the packet size by guessing */
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000382 inst->PacketBuffer_inst.packSizeSamples =
383 WebRtcNetEQ_UpdatePackSizeSamples(inst, i_bufferpos, payloadType,
384 inst->timestampsPerCall * 3);
niklase@google.com470e71d2011-07-07 08:21:25 +0000385
386 WebRtcNetEQ_ResetAutomode(&(inst->BufferStat_inst.Automode_inst),
387 inst->PacketBuffer_inst.maxInsertPositions);
388
389#ifdef NETEQ_CNG_CODEC
390 /* Also insert CNG state as this might be needed by DSP */
391 i_res = WebRtcNetEQ_DbGetPtrs(&inst->codec_DB_inst, kDecoderCNG, &cinst);
392 if ((i_res < 0) && (i_res != CODEC_DB_NOT_EXIST1))
393 {
394 /* other error returned */
395 /* (CODEC_DB_NOT_EXIST1 simply indicates that CNG is not used */
396 return i_res;
397 }
398 else
399 {
400 /* CNG exists */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000401 blockLen = (sizeof(cinst.codec_state)) >> (sizeof(int16_t) - 1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 *blockPtr = blockLen * 2;
403 blockPtr++;
404 WEBRTC_SPL_MEMCPY_W8(blockPtr,&cinst.codec_state,sizeof(cinst.codec_state));
405 blockPtr += blockLen;
406 }
407#endif
408
409 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff)
410 | DSP_CODEC_NEW_CODEC;
411
412 if (uw16_instr == BUFSTATS_DO_RFC3389CNG_NOPACKET)
413 {
414 /*
415 * Change decision to CNG packet, since we do have a CNG packet, but it was
416 * considered too early to use. Now, use it anyway.
417 */
418 uw16_instr = BUFSTATS_DO_RFC3389CNG_PACKET;
419 }
420 else if (uw16_instr != BUFSTATS_DO_RFC3389CNG_PACKET)
421 {
422 uw16_instr = BUFSTATS_DO_NORMAL;
423 }
424
425 /* reset loss counter */
426 WebRtcNetEQ_ResetMcuInCallStats(inst);
427 }
428
429 /* Should we just reset the decoder? */
430 if (uw16_instr == BUFSTAT_REINIT_DECODER)
431 {
432 /* Change decision to normal and flag decoder reset */
433 uw16_instr = BUFSTATS_DO_NORMAL;
434 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff) | DSP_CODEC_RESET;
435 }
436
437 /* Expand requires no new packet */
438 if (uw16_instr == BUFSTATS_DO_EXPAND)
439 {
440
441 inst->timeStamp = dspInfo.playedOutTS;
442
443 /* Have we got one descriptor left? */
444 if (WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) inst->current_Codec)
445 && (dspInfo.MD || latePacketExist))
446 {
447
448 if (dspInfo.lastMode != MODE_ONE_DESCRIPTOR)
449 {
450 /* this is the first "consecutive" one-descriptor decoding; reset counter */
451 inst->one_desc = 0;
452 }
453 if (inst->one_desc < MAX_ONE_DESC)
454 {
455 /* use that one descriptor */
456 inst->one_desc++; /* increase counter */
457 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
458 | DSP_INSTR_NORMAL_ONE_DESC;
459
460 /* decrease counter since we did no Expand */
461 inst->NoOfExpandCalls = WEBRTC_SPL_MAX(inst->NoOfExpandCalls - 1, 0);
462 return 0;
463 }
464 else
465 {
466 /* too many consecutive one-descriptor decodings; do expand instead */
467 inst->one_desc = 0; /* reset counter */
468 }
469
470 }
471
472 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_EXPAND;
473 return 0;
474 }
475
476 /* Merge is not needed if we still have a descriptor */
477 if ((uw16_instr == BUFSTATS_DO_MERGE) && (dspInfo.MD != 0))
478 {
479 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
480 | DSP_INSTR_NORMAL_ONE_DESC;
481 *blockPtr = 0;
482 return 0;
483 }
484
485 /* Do CNG without trying to extract any packets from buffer */
486 if (uw16_instr == BUFSTATS_DO_RFC3389CNG_NOPACKET)
487 {
488 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
489 | DSP_INSTR_DO_RFC3389CNG;
490 *blockPtr = 0;
491 return 0;
492 }
493
494 /* Do built-in CNG without extracting any new packets from buffer */
495 if (uw16_instr == BUFSTATS_DO_INTERNAL_CNG_NOPACKET)
496 {
497 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
498 | DSP_INSTR_DO_CODEC_INTERNAL_CNG;
499 *blockPtr = 0;
500 return 0;
501 }
502
503 /* Do DTMF without extracting any new packets from buffer */
504 if (uw16_instr == BUFSTATS_DO_DTMF_ONLY)
505 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000506 uint32_t timeStampJump = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000507
508 /* Update timestamp */
509 if ((inst->BufferStat_inst.uw32_CNGplayedTS > 0) && (dspInfo.lastMode != MODE_DTMF))
510 {
511 /* Jump in timestamps if needed */
512 timeStampJump = inst->BufferStat_inst.uw32_CNGplayedTS;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000513 inst->pw16_writeAddress[1] = (uint16_t) (timeStampJump >> 16);
514 inst->pw16_writeAddress[2] = (uint16_t) (timeStampJump & 0xFFFF);
niklase@google.com470e71d2011-07-07 08:21:25 +0000515 }
516
517 inst->timeStamp = dspInfo.playedOutTS + timeStampJump;
518
niklase@google.com470e71d2011-07-07 08:21:25 +0000519 inst->BufferStat_inst.uw32_CNGplayedTS = 0;
520 inst->NoOfExpandCalls = 0;
521
522 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
523 | DSP_INSTR_DTMF_GENERATE;
524 *blockPtr = 0;
525 return 0;
526 }
527
528 if (uw16_instr == BUFSTATS_DO_ACCELERATE)
529 {
530 /* In order to do a Accelerate we need at least 30 ms of data */
531 if (dspInfo.samplesLeft >= (3 * 80 * fs_mult))
532 {
533 /* Already have enough data, so we do not need to extract any more */
534 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
535 | DSP_INSTR_ACCELERATE;
536 *blockPtr = 0;
537 inst->BufferStat_inst.Automode_inst.sampleMemory
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000538 = (int32_t) dspInfo.samplesLeft;
niklase@google.com470e71d2011-07-07 08:21:25 +0000539 inst->BufferStat_inst.Automode_inst.prevTimeScale = 1;
540 return 0;
541 }
542 else if ((dspInfo.samplesLeft >= (1 * 80 * fs_mult))
543 && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult)))
544 {
545 /* Avoid decoding more data as it might overflow playout buffer */
546 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
547 | DSP_INSTR_NORMAL;
548 *blockPtr = 0;
549 return 0;
550 }
551 else if ((dspInfo.samplesLeft < (1 * 80 * fs_mult))
552 && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult)))
553 {
554 /* For >= 30ms allow Accelerate with a decoding to avoid overflow in playout buffer */
555 wantedNoOfTimeStamps = inst->timestampsPerCall;
556 }
557 else if (dspInfo.samplesLeft >= (2 * 80 * fs_mult))
558 {
559 /* We need to decode another 10 ms in order to do an Accelerate */
560 wantedNoOfTimeStamps = inst->timestampsPerCall;
561 }
562 else
563 {
564 /*
565 * Build up decoded data by decoding at least 20 ms of data.
566 * Do not perform Accelerate yet, but wait until we only need to do one decoding.
567 */
568 wantedNoOfTimeStamps = 2 * inst->timestampsPerCall;
569 uw16_instr = BUFSTATS_DO_NORMAL;
570 }
571 }
572 else if (uw16_instr == BUFSTATS_DO_PREEMPTIVE_EXPAND)
573 {
574 /* In order to do a Preemptive Expand we need at least 30 ms of data */
575 if (dspInfo.samplesLeft >= (3 * 80 * fs_mult))
576 {
577 /* Already have enough data, so we do not need to extract any more */
578 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
579 | DSP_INSTR_PREEMPTIVE_EXPAND;
580 *blockPtr = 0;
581 inst->BufferStat_inst.Automode_inst.sampleMemory
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000582 = (int32_t) dspInfo.samplesLeft;
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 inst->BufferStat_inst.Automode_inst.prevTimeScale = 1;
584 return 0;
585 }
586 else if ((dspInfo.samplesLeft >= (1 * 80 * fs_mult))
587 && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult)))
588 {
589 /*
590 * Avoid decoding more data as it might overflow playout buffer;
591 * still try Preemptive Expand though.
592 */
593 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
594 | DSP_INSTR_PREEMPTIVE_EXPAND;
595 *blockPtr = 0;
596 inst->BufferStat_inst.Automode_inst.sampleMemory
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000597 = (int32_t) dspInfo.samplesLeft;
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 inst->BufferStat_inst.Automode_inst.prevTimeScale = 1;
599 return 0;
600 }
601 else if ((dspInfo.samplesLeft < (1 * 80 * fs_mult))
602 && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult)))
603 {
604 /*
605 * For >= 30ms allow Preemptive Expand with a decoding to avoid overflow in
606 * playout buffer
607 */
608 wantedNoOfTimeStamps = inst->timestampsPerCall;
609 }
610 else if (dspInfo.samplesLeft >= (2 * 80 * fs_mult))
611 {
612 /* We need to decode another 10 ms in order to do an Preemptive Expand */
613 wantedNoOfTimeStamps = inst->timestampsPerCall;
614 }
615 else
616 {
617 /*
618 * Build up decoded data by decoding at least 20 ms of data,
619 * Still try to perform Preemptive Expand.
620 */
621 wantedNoOfTimeStamps = 2 * inst->timestampsPerCall;
622 }
623 }
624 else
625 {
626 wantedNoOfTimeStamps = inst->timestampsPerCall;
627 }
628
629 /* Otherwise get data from buffer, try to get at least 10ms */
630 totalTS = 0;
631 oldTS = uw32_availableTS;
632 if ((i_bufferpos > -1) && (uw16_instr != BUFSTATS_DO_ALTERNATIVE_PLC) && (uw16_instr
633 != BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS) && (uw16_instr != BUFSTATS_DO_AUDIO_REPETITION)
634 && (uw16_instr != BUFSTATS_DO_AUDIO_REPETITION_INC_TS))
635 {
636 uw32_tmp = (uw32_availableTS - dspInfo.playedOutTS);
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000637 inst->pw16_writeAddress[1] = (uint16_t) (uw32_tmp >> 16);
638 inst->pw16_writeAddress[2] = (uint16_t) (uw32_tmp & 0xFFFF);
niklase@google.com470e71d2011-07-07 08:21:25 +0000639 if (inst->BufferStat_inst.w16_cngOn == CNG_OFF)
640 {
641 /*
642 * Adjustment of TS only corresponds to an actual packet loss
643 * if comfort noise is not played. If comfort noise was just played,
644 * this adjustment of TS is only done to get back in sync with the
645 * stream TS; no loss to report.
646 */
647 inst->lostTS += uw32_tmp;
648 }
649
650 if (uw16_instr != BUFSTATS_DO_RFC3389CNG_PACKET)
651 {
652 /* We are about to decode and use a non-CNG packet => CNG period is ended */
653 inst->BufferStat_inst.w16_cngOn = CNG_OFF;
654 }
655
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 /*
657 * Reset CNG timestamp as a new packet will be delivered.
658 * (Also if CNG packet, since playedOutTS is updated.)
659 */
660 inst->BufferStat_inst.uw32_CNGplayedTS = 0;
661
662 prevSeqNo = inst->PacketBuffer_inst.seqNumber[i_bufferpos];
663 prevTS = inst->PacketBuffer_inst.timeStamp[i_bufferpos];
664 oldPT = inst->PacketBuffer_inst.payloadType[i_bufferpos];
665
turaj@webrtc.orga305e962013-06-06 19:00:09 +0000666 /* These values are used by NACK module to estimate time-to-play of
667 * a missing packet. Occasionally, NetEq might decide to decode more
668 * than one packet. Therefore, these values store sequence number and
669 * timestamp of the first packet pulled from the packet buffer. In
670 * such cases, these values do not exactly represent the sequence number
671 * or timestamp associated with a 10ms audio pulled from NetEq. NACK
672 * module is designed to compensate for this.
673 */
674 inst->decoded_packet_sequence_number = prevSeqNo;
675 inst->decoded_packet_timestamp = prevTS;
676
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 /* clear flag bits */
678 inst->pw16_writeAddress[0] = inst->pw16_writeAddress[0] & 0xFF3F;
679 do
680 {
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000681 int waitingTime;
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 inst->timeStamp = uw32_availableTS;
683 /* Write directly to shared memory */
684 temp_pkt.payload = blockPtr + 1;
685 i_res = WebRtcNetEQ_PacketBufferExtract(&inst->PacketBuffer_inst, &temp_pkt,
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000686 i_bufferpos, &waitingTime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000687
688 if (i_res < 0)
689 {
690 /* error returned */
691 return i_res;
692 }
henrik.lundin@webrtc.orgdbba1f92011-12-20 15:45:05 +0000693 WebRtcNetEQ_StoreWaitingTime(inst, waitingTime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000694
695#ifdef NETEQ_DELAY_LOGGING
696 temp_var = NETEQ_DELAY_LOGGING_SIGNAL_DECODE;
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000697 if ((fwrite(&temp_var, sizeof(int),
698 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000699 (fwrite(&temp_pkt.timeStamp, sizeof(uint32_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000700 1, delay_fid2) != 1) ||
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000701 (fwrite(&dspInfo.samplesLeft, sizeof(uint16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000702 1, delay_fid2) != 1)) {
703 return -1;
704 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000705#endif
706
707 *blockPtr = temp_pkt.payloadLen;
708 /* set the flag if this is a redundant payload */
709 if (temp_pkt.rcuPlCntr > 0)
710 {
711 *blockPtr = (*blockPtr) | (DSP_CODEC_RED_FLAG);
712 }
713 blockPtr += ((temp_pkt.payloadLen + 1) >> 1) + 1;
714
715 if (i_bufferpos > -1)
716 {
717 /*
718 * Store number of TS extracted (last extracted is assumed to be of
719 * packSizeSamples).
720 */
721 totalTS = uw32_availableTS - oldTS + inst->PacketBuffer_inst.packSizeSamples;
722 }
723 /* Check what next packet is available */
724 WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst,
725 inst->timeStamp, &uw32_availableTS, &i_bufferpos, 0, &payloadType);
726
727 nextSeqNoAvail = 0;
728 if ((i_bufferpos > -1) && (oldPT
729 == inst->PacketBuffer_inst.payloadType[i_bufferpos]))
730 {
731 w16_tmp = inst->PacketBuffer_inst.seqNumber[i_bufferpos] - prevSeqNo;
732 w32_tmp = inst->PacketBuffer_inst.timeStamp[i_bufferpos] - prevTS;
733 if ((w16_tmp == 1) || /* Next packet */
734 ((w16_tmp == 0) && (w32_tmp == inst->PacketBuffer_inst.packSizeSamples)))
735 { /* or packet split into frames */
736 nextSeqNoAvail = 1;
737 }
738 prevSeqNo = inst->PacketBuffer_inst.seqNumber[i_bufferpos];
739 }
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000740 /* Update the frame size, if we can. */
741 inst->PacketBuffer_inst.packSizeSamples =
742 WebRtcNetEQ_UpdatePackSizeSamples(inst, i_bufferpos,
743 payloadType, inst->PacketBuffer_inst.packSizeSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000744 }
745 while ((totalTS < wantedNoOfTimeStamps) && (nextSeqNoAvail == 1));
746 }
747
748 if ((uw16_instr == BUFSTATS_DO_ACCELERATE)
749 || (uw16_instr == BUFSTATS_DO_PREEMPTIVE_EXPAND))
750 {
751 /* Check that we have enough data (30ms) to do the Accelearate */
752 if ((totalTS + dspInfo.samplesLeft) < WEBRTC_SPL_MUL(3,inst->timestampsPerCall)
753 && (uw16_instr == BUFSTATS_DO_ACCELERATE))
754 {
755 /* Not enough, do normal operation instead */
756 uw16_instr = BUFSTATS_DO_NORMAL;
757 }
758 else
759 {
760 inst->BufferStat_inst.Automode_inst.sampleMemory
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000761 = (int32_t) dspInfo.samplesLeft + totalTS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000762 inst->BufferStat_inst.Automode_inst.prevTimeScale = 1;
763 }
764 }
765
766 /* Close the data with a zero size block */
767 *blockPtr = 0;
768
769 /* Write data to DSP */
770 switch (uw16_instr)
771 {
772 case BUFSTATS_DO_NORMAL:
773 /* Normal with decoding included */
774 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
775 | DSP_INSTR_NORMAL;
776 break;
777 case BUFSTATS_DO_ACCELERATE:
778 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
779 | DSP_INSTR_ACCELERATE;
780 break;
781 case BUFSTATS_DO_MERGE:
782 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
783 | DSP_INSTR_MERGE;
784 break;
785 case BUFSTATS_DO_RFC3389CNG_PACKET:
786 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
787 | DSP_INSTR_DO_RFC3389CNG;
788 break;
789 case BUFSTATS_DO_ALTERNATIVE_PLC:
790 inst->pw16_writeAddress[1] = 0;
791 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
792 | DSP_INSTR_DO_ALTERNATIVE_PLC;
793 break;
794 case BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS:
795 inst->pw16_writeAddress[1] = 0;
796 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
797 | DSP_INSTR_DO_ALTERNATIVE_PLC_INC_TS;
798 break;
799 case BUFSTATS_DO_AUDIO_REPETITION:
800 inst->pw16_writeAddress[1] = 0;
801 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
802 | DSP_INSTR_DO_AUDIO_REPETITION;
803 break;
804 case BUFSTATS_DO_AUDIO_REPETITION_INC_TS:
805 inst->pw16_writeAddress[1] = 0;
806 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
807 | DSP_INSTR_DO_AUDIO_REPETITION_INC_TS;
808 break;
809 case BUFSTATS_DO_PREEMPTIVE_EXPAND:
810 inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff)
811 | DSP_INSTR_PREEMPTIVE_EXPAND;
812 break;
813 default:
814 return UNKNOWN_BUFSTAT_DECISION;
815 }
816
817 inst->timeStamp = dspInfo.playedOutTS;
818 return 0;
819
820}