blob: 3d37e1732472f1a448bbb484beeac847d9051646 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11/*
12 * This file contains the function where the main decision logic for buffer level
13 * adaptation happens.
14 */
15
16#include "buffer_stats.h"
17
18#include <assert.h>
19
20#include "signal_processing_library.h"
21
22#include "automode.h"
23#include "neteq_defines.h"
24#include "neteq_error_codes.h"
25#include "webrtc_neteq.h"
26
27#define NETEQ_BUFSTAT_20MS_Q7 2560 /* = 20 ms in Q7 */
28
29WebRtc_UWord16 WebRtcNetEQ_BufstatsDecision(BufstatsInst_t *inst, WebRtc_Word16 frameSize,
30 WebRtc_Word32 cur_size, WebRtc_UWord32 targetTS,
31 WebRtc_UWord32 availableTS, int noPacket,
32 int cngPacket, int prevPlayMode,
33 enum WebRtcNetEQPlayoutMode playoutMode,
34 int timestampsPerCall, int NoOfExpandCalls,
35 WebRtc_Word16 fs_mult,
36 WebRtc_Word16 lastModeBGNonly, int playDtmf)
37{
38
39 int currentDelayMs;
40 WebRtc_Word32 currSizeSamples = cur_size;
niklas.enbom@webrtc.orgcd2f1352013-01-24 22:05:30 +000041 WebRtc_Word16 extraDelayPacketsQ8 = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000042
43 /* Avoid overflow if the buffer size should be really large (cur_size is limited 256ms) */
44 WebRtc_Word32 curr_sizeQ7 = WEBRTC_SPL_LSHIFT_W32(cur_size, 4);
niklas.enbom@webrtc.orgcd2f1352013-01-24 22:05:30 +000045 WebRtc_UWord16 level_limit_hi, level_limit_lo;
niklase@google.com470e71d2011-07-07 08:21:25 +000046
47 inst->Automode_inst.prevTimeScale &= (prevPlayMode == MODE_SUCCESS_ACCELERATE
48 || prevPlayMode == MODE_LOWEN_ACCELERATE || prevPlayMode == MODE_SUCCESS_PREEMPTIVE
49 || prevPlayMode == MODE_LOWEN_PREEMPTIVE);
50
51 if ((prevPlayMode != MODE_RFC3389CNG) && (prevPlayMode != MODE_CODEC_INTERNAL_CNG))
52 {
53 /*
54 * Do not update buffer history if currently playing CNG
55 * since it will bias the filtered buffer level.
56 */
57 WebRtcNetEQ_BufferLevelFilter(cur_size, &(inst->Automode_inst), timestampsPerCall,
58 fs_mult);
59 }
60 else
61 {
62 /* only update time counters */
63 inst->Automode_inst.packetIatCountSamp += timestampsPerCall; /* packet inter-arrival time */
64 inst->Automode_inst.peakIatCountSamp += timestampsPerCall; /* peak inter-arrival time */
65 inst->Automode_inst.timescaleHoldOff >>= 1; /* time-scaling limiter */
66 }
67 cur_size = WEBRTC_SPL_MIN(curr_sizeQ7, WEBRTC_SPL_WORD16_MAX);
68
69 /* Calculate VQmon related variables */
70 /* avgDelay = avgDelay*(511/512) + currentDelay*(1/512) (sample ms delay in Q8) */
71 inst->avgDelayMsQ8 = (WebRtc_Word16) (WEBRTC_SPL_MUL_16_16_RSFT(inst->avgDelayMsQ8,511,9)
72 + (cur_size >> 9));
73
74 /* Update maximum delay if needed */
75 currentDelayMs = (curr_sizeQ7 >> 7);
76 if (currentDelayMs > inst->maxDelayMs)
77 {
78 inst->maxDelayMs = currentDelayMs;
79 }
80
81 /* NetEQ is on with normal or steaming mode */
82 if (playoutMode == kPlayoutOn || playoutMode == kPlayoutStreaming)
83 {
84 /* Guard for errors, so that it should not get stuck in error mode */
85 if (prevPlayMode == MODE_ERROR)
86 {
87 if (noPacket)
88 {
89 return BUFSTATS_DO_EXPAND;
90 }
91 else
92 {
93 return BUFSTAT_REINIT;
94 }
95 }
96
97 if (prevPlayMode != MODE_EXPAND && prevPlayMode != MODE_FADE_TO_BGN)
98 {
99 inst->w16_noExpand = 1;
100 }
101 else
102 {
103 inst->w16_noExpand = 0;
104 }
105
106 if (cngPacket)
107 {
108 /* signed difference between wanted and available TS */
109 WebRtc_Word32 diffTS = (inst->uw32_CNGplayedTS + targetTS) - availableTS;
henrik.lundin@webrtc.org46796522012-01-25 16:37:41 +0000110 int32_t optimal_level_samp = (inst->Automode_inst.optBufLevel *
111 inst->Automode_inst.packetSpeechLenSamp) >> 8;
112 int32_t excess_waiting_time_samp = -diffTS - optimal_level_samp;
113
114 if (excess_waiting_time_samp > optimal_level_samp / 2)
115 {
116 /* The waiting time for this packet will be longer than 1.5
henrik.lundin@webrtc.orgdcf00642012-01-25 16:48:00 +0000117 * times the wanted buffer delay. Advance the clock to cut
henrik.lundin@webrtc.org46796522012-01-25 16:37:41 +0000118 * waiting time down to the optimal.
119 */
120 inst->uw32_CNGplayedTS += excess_waiting_time_samp;
121 diffTS += excess_waiting_time_samp;
122 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000123
124 if ((diffTS) < 0 && (prevPlayMode == MODE_RFC3389CNG))
125 {
126 /* Not time to play this packet yet. Wait another round before using this
127 * packet. Keep on playing CNG from previous CNG parameters. */
128 return BUFSTATS_DO_RFC3389CNG_NOPACKET;
129 }
130
131 /* otherwise, go for the CNG packet now */
132 return BUFSTATS_DO_RFC3389CNG_PACKET;
133 }
134
135 /*Check for expand/cng */
136 if (noPacket)
137 {
138 if (inst->w16_cngOn == CNG_RFC3389_ON)
139 {
140 /* keep on playing CNG */
141 return BUFSTATS_DO_RFC3389CNG_NOPACKET;
142 }
143 else if (inst->w16_cngOn == CNG_INTERNAL_ON)
144 {
145 /* keep on playing internal CNG */
146 return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
147 }
148 else if (playDtmf == 1)
149 {
150 /* we have not audio data, but can play DTMF */
151 return BUFSTATS_DO_DTMF_ONLY;
152 }
153 else
154 {
155 /* nothing to play => do Expand */
156 return BUFSTATS_DO_EXPAND;
157 }
158 }
159
160 /*
161 * If the expand period was very long, reset NetEQ since it is likely that the
162 * sender was restarted.
163 */
164 if (NoOfExpandCalls > REINIT_AFTER_EXPANDS) return BUFSTAT_REINIT_DECODER;
165
166 /* Calculate extra delay in Q8 packets */
167 if (inst->Automode_inst.extraDelayMs > 0 && inst->Automode_inst.packetSpeechLenSamp
168 > 0)
169 {
niklas.enbom@webrtc.orgcd2f1352013-01-24 22:05:30 +0000170 extraDelayPacketsQ8 = WebRtcSpl_DivW32W16ResW16(
171 (WEBRTC_SPL_MUL(inst->Automode_inst.extraDelayMs, 8 * fs_mult) << 8),
172 inst->Automode_inst.packetSpeechLenSamp);
niklase@google.com470e71d2011-07-07 08:21:25 +0000173 /* (extra delay in samples in Q8) */
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 }
175
176 /* Check if needed packet is available */
177 if (targetTS == availableTS)
178 {
179
180 /* If last mode was not expand, and there is no DTMF to play */
181 if (inst->w16_noExpand == 1 && playDtmf == 0)
182 {
183 /* If so check for accelerate */
184
185 level_limit_lo = ((inst->Automode_inst.optBufLevel) >> 1) /* 50 % */
186 + ((inst->Automode_inst.optBufLevel) >> 2); /* ... + 25% = 75% */
187
188 /* set upper limit to optBufLevel, but make sure that window is at least 20ms */
189 level_limit_hi = WEBRTC_SPL_MAX(inst->Automode_inst.optBufLevel,
190 level_limit_lo +
191 WebRtcSpl_DivW32W16ResW16((WEBRTC_SPL_MUL(20*8, fs_mult) << 8),
192 inst->Automode_inst.packetSpeechLenSamp));
193
194 /* if extra delay is non-zero, add it */
195 if (extraDelayPacketsQ8 > 0)
196 {
197 level_limit_hi += extraDelayPacketsQ8;
198 level_limit_lo += extraDelayPacketsQ8;
199 }
200
201 if (((inst->Automode_inst.buffLevelFilt >= level_limit_hi) &&
202 (inst->Automode_inst.timescaleHoldOff == 0)) ||
203 (inst->Automode_inst.buffLevelFilt >= level_limit_hi << 2))
204 {
205 /*
206 * Buffer level higher than limit and time-scaling allowed,
207 * OR buffer level _really_ high.
208 */
209 return BUFSTATS_DO_ACCELERATE;
210 }
211 else if ((inst->Automode_inst.buffLevelFilt < level_limit_lo)
212 && (inst->Automode_inst.timescaleHoldOff == 0))
213 {
214 return BUFSTATS_DO_PREEMPTIVE_EXPAND;
215 }
216 }
217 return BUFSTATS_DO_NORMAL;
218 }
219
220 /* Check for Merge */
221 else if (availableTS > targetTS)
222 {
223
224 /* Check that we do not play a packet "too early" */
225 if ((prevPlayMode == MODE_EXPAND)
226 && (availableTS - targetTS
227 < (WebRtc_UWord32) WEBRTC_SPL_MUL_16_16((WebRtc_Word16)timestampsPerCall,
228 (WebRtc_Word16)REINIT_AFTER_EXPANDS))
229 && (NoOfExpandCalls < MAX_WAIT_FOR_PACKET)
230 && (availableTS
231 > targetTS
232 + WEBRTC_SPL_MUL_16_16((WebRtc_Word16)timestampsPerCall,
233 (WebRtc_Word16)NoOfExpandCalls))
234 && (inst->Automode_inst.buffLevelFilt <= inst->Automode_inst.optBufLevel
235 + extraDelayPacketsQ8))
236 {
237 if (playDtmf == 1)
238 {
239 /* we still have DTMF to play, so do not perform expand */
240 return BUFSTATS_DO_DTMF_ONLY;
241 }
242 else
243 {
244 /* nothing to play */
245 return BUFSTATS_DO_EXPAND;
246 }
247 }
248
249 /* If previous was CNG period or BGNonly then no merge is needed */
250 if ((prevPlayMode == MODE_RFC3389CNG) || (prevPlayMode == MODE_CODEC_INTERNAL_CNG)
251 || lastModeBGNonly)
252 {
253 /*
254 * Keep the same delay as before the CNG (or maximum 70 ms in buffer as safety
255 * precaution), but make sure that the number of samples in buffer is no
256 * higher than 4 times the optimal level.
257 */
258 WebRtc_Word32 diffTS = (inst->uw32_CNGplayedTS + targetTS) - availableTS;
259 if (diffTS >= 0
260 || (WEBRTC_SPL_MUL_16_16_RSFT( inst->Automode_inst.optBufLevel
261 + extraDelayPacketsQ8,
262 inst->Automode_inst.packetSpeechLenSamp, 6) < currSizeSamples))
263 {
264 /* it is time to play this new packet */
265 return BUFSTATS_DO_NORMAL;
266 }
267 else
268 {
269 /* it is too early to play this new packet => keep on playing CNG */
270 if (prevPlayMode == MODE_RFC3389CNG)
271 {
272 return BUFSTATS_DO_RFC3389CNG_NOPACKET;
273 }
274 else if (prevPlayMode == MODE_CODEC_INTERNAL_CNG)
275 {
276 return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
277 }
278 else if (playDtmf == 1)
279 {
280 /* we have not audio data, but can play DTMF */
281 return BUFSTATS_DO_DTMF_ONLY;
282 }
283 else /* lastModeBGNonly */
284 {
285 /* signal expand, but this will result in BGN again */
286 return BUFSTATS_DO_EXPAND;
287 }
288 }
289 }
290
291 /* Do not merge unless we have done a Expand before (for complexity reasons) */
292 if ((inst->w16_noExpand == 0) || ((frameSize < timestampsPerCall) && (cur_size
293 > NETEQ_BUFSTAT_20MS_Q7)))
294 {
295 return BUFSTATS_DO_MERGE;
296 }
297 else if (playDtmf == 1)
298 {
299 /* play DTMF instead of expand */
300 return BUFSTATS_DO_DTMF_ONLY;
301 }
302 else
303 {
304 return BUFSTATS_DO_EXPAND;
305 }
306 }
307 }
308 else
309 { /* kPlayoutOff or kPlayoutFax */
310 if (cngPacket)
311 {
312 if (((WebRtc_Word32) ((inst->uw32_CNGplayedTS + targetTS) - availableTS)) >= 0)
313 {
314 /* time to play this packet now */
315 return BUFSTATS_DO_RFC3389CNG_PACKET;
316 }
317 else
318 {
319 /* wait before playing this packet */
320 return BUFSTATS_DO_RFC3389CNG_NOPACKET;
321 }
322 }
323 if (noPacket)
324 {
325 /*
326 * No packet =>
327 * 1. If in CNG mode play as usual
328 * 2. Otherwise use other method to generate data and hold TS value
329 */
330 if (inst->w16_cngOn == CNG_RFC3389_ON)
331 {
332 /* keep on playing CNG */
333 return BUFSTATS_DO_RFC3389CNG_NOPACKET;
334 }
335 else if (inst->w16_cngOn == CNG_INTERNAL_ON)
336 {
337 /* keep on playing internal CNG */
338 return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
339 }
340 else
341 {
342 /* nothing to play => invent some data to play out */
343 if (playoutMode == kPlayoutOff)
344 {
345 return BUFSTATS_DO_ALTERNATIVE_PLC;
346 }
347 else if (playoutMode == kPlayoutFax)
348 {
349 return BUFSTATS_DO_AUDIO_REPETITION;
350 }
351 else
352 {
353 /* UNDEFINED, should not get here... */
354 assert(0);
355 return BUFSTAT_REINIT;
356 }
357 }
358 }
359 else if (targetTS == availableTS)
360 {
361 return BUFSTATS_DO_NORMAL;
362 }
363 else
364 {
365 if (((WebRtc_Word32) ((inst->uw32_CNGplayedTS + targetTS) - availableTS)) >= 0)
366 {
367 return BUFSTATS_DO_NORMAL;
368 }
369 else if (playoutMode == kPlayoutOff)
370 {
371 /*
372 * If currently playing CNG, continue with that. Don't increase TS
373 * since uw32_CNGplayedTS will be increased.
374 */
375 if (inst->w16_cngOn == CNG_RFC3389_ON)
376 {
377 return BUFSTATS_DO_RFC3389CNG_NOPACKET;
378 }
379 else if (inst->w16_cngOn == CNG_INTERNAL_ON)
380 {
381 return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
382 }
383 else
384 {
385 /*
386 * Otherwise, do PLC and increase TS while waiting for the time to
387 * play this packet.
388 */
389 return BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS;
390 }
391 }
392 else if (playoutMode == kPlayoutFax)
393 {
394 /*
395 * If currently playing CNG, continue with that don't increase TS since
396 * uw32_CNGplayedTS will be increased.
397 */
398 if (inst->w16_cngOn == CNG_RFC3389_ON)
399 {
400 return BUFSTATS_DO_RFC3389CNG_NOPACKET;
401 }
402 else if (inst->w16_cngOn == CNG_INTERNAL_ON)
403 {
404 return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
405 }
406 else
407 {
408 /*
409 * Otherwise, do audio repetition and increase TS while waiting for the
410 * time to play this packet.
411 */
412 return BUFSTATS_DO_AUDIO_REPETITION_INC_TS;
413 }
414 }
415 else
416 {
417 /* UNDEFINED, should not get here... */
418 assert(0);
419 return BUFSTAT_REINIT;
420 }
421 }
422 }
423 /* We should not get here (but sometimes we do anyway...) */
424 return BUFSTAT_REINIT;
425}
426