Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/webrtc/modules/audio_coding/neteq/bufstats_decision.c @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 15.5 KB
Line 
1/*
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
29uint16_t WebRtcNetEQ_BufstatsDecision(BufstatsInst_t *inst, int16_t frameSize,
30                                      int32_t cur_size, uint32_t targetTS,
31                                      uint32_t availableTS, int noPacket,
32                                      int cngPacket, int prevPlayMode,
33                                      enum WebRtcNetEQPlayoutMode playoutMode,
34                                      int timestampsPerCall, int NoOfExpandCalls,
35                                      int16_t fs_mult,
36                                      int16_t lastModeBGNonly, int playDtmf)
37{
38
39    int currentDelayMs;
40    int32_t currSizeSamples = cur_size;
41    int extraDelayPacketsQ8 = 0;
42
43    /* Avoid overflow if the buffer size should be really large (cur_size is limited 256ms) */
44    int32_t curr_sizeQ7 = WEBRTC_SPL_LSHIFT_W32(cur_size, 4);
45    int level_limit_hi, level_limit_lo;
46
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 = (int16_t) (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            int32_t diffTS = (inst->uw32_CNGplayedTS + targetTS) - availableTS;
110            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
117                 * times the wanted buffer delay. Advance the clock to cut
118                 * waiting time down to the optimal.
119                 */
120                inst->uw32_CNGplayedTS += excess_waiting_time_samp;
121                diffTS += excess_waiting_time_samp;
122            }
123
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        {
170
171            /* (extra delay in samples in Q8) */
172            extraDelayPacketsQ8 =
173                ((inst->Automode_inst.extraDelayMs * 8 * fs_mult) << 8) /
174                inst->Automode_inst.packetSpeechLenSamp;
175        }
176
177        /* Check if needed packet is available */
178        if (targetTS == availableTS)
179        {
180
181            /* If last mode was not expand, and there is no DTMF to play */
182            if (inst->w16_noExpand == 1 && playDtmf == 0)
183            {
184                /* If so check for accelerate */
185
186                level_limit_lo = ((inst->Automode_inst.optBufLevel) >> 1) /* 50 % */
187                    + ((inst->Automode_inst.optBufLevel) >> 2); /* ... + 25% = 75% */
188
189                /* set upper limit to optBufLevel, but make sure that window is at least 20ms */
190                level_limit_hi = WEBRTC_SPL_MAX(inst->Automode_inst.optBufLevel,
191                    level_limit_lo +
192                    WebRtcSpl_DivW32W16ResW16((WEBRTC_SPL_MUL(20*8, fs_mult) << 8),
193                        inst->Automode_inst.packetSpeechLenSamp));
194
195                /* if extra delay is non-zero, add it */
196                if (extraDelayPacketsQ8 > 0)
197                {
198                    level_limit_hi += extraDelayPacketsQ8;
199                    level_limit_lo += extraDelayPacketsQ8;
200                }
201
202                if (((inst->Automode_inst.buffLevelFilt >= level_limit_hi) &&
203                    (inst->Automode_inst.timescaleHoldOff == 0)) ||
204                    (inst->Automode_inst.buffLevelFilt >= level_limit_hi << 2))
205                {
206                    /*
207                     * Buffer level higher than limit and time-scaling allowed,
208                     * OR buffer level _really_ high.
209                     */
210                    return BUFSTATS_DO_ACCELERATE;
211                }
212                else if ((inst->Automode_inst.buffLevelFilt < level_limit_lo)
213                    && (inst->Automode_inst.timescaleHoldOff == 0))
214                {
215                    return BUFSTATS_DO_PREEMPTIVE_EXPAND;
216                }
217            }
218            return BUFSTATS_DO_NORMAL;
219        }
220
221        /* Check for Merge */
222        else if (availableTS > targetTS)
223        {
224
225            /* Check that we do not play a packet "too early" */
226            if ((prevPlayMode == MODE_EXPAND)
227                && (availableTS - targetTS
228                    < (uint32_t) WEBRTC_SPL_MUL_16_16((int16_t)timestampsPerCall,
229                        (int16_t)REINIT_AFTER_EXPANDS))
230                && (NoOfExpandCalls < MAX_WAIT_FOR_PACKET)
231                && (availableTS
232                    > targetTS
233                        + WEBRTC_SPL_MUL_16_16((int16_t)timestampsPerCall,
234                            (int16_t)NoOfExpandCalls))
235                && (inst->Automode_inst.buffLevelFilt <= inst->Automode_inst.optBufLevel
236                    + extraDelayPacketsQ8))
237            {
238                if (playDtmf == 1)
239                {
240                    /* we still have DTMF to play, so do not perform expand */
241                    return BUFSTATS_DO_DTMF_ONLY;
242                }
243                else
244                {
245                    /* nothing to play */
246                    return BUFSTATS_DO_EXPAND;
247                }
248            }
249
250            /* If previous was CNG period or BGNonly then no merge is needed */
251            if ((prevPlayMode == MODE_RFC3389CNG) || (prevPlayMode == MODE_CODEC_INTERNAL_CNG)
252                || lastModeBGNonly)
253            {
254                /*
255                 * Keep the same delay as before the CNG (or maximum 70 ms in buffer as safety
256                 * precaution), but make sure that the number of samples in buffer is no
257                 * higher than 4 times the optimal level.
258                 */
259                int32_t diffTS = (inst->uw32_CNGplayedTS + targetTS) - availableTS;
260                int val = ((inst->Automode_inst.optBufLevel +
261                    extraDelayPacketsQ8) *
262                    inst->Automode_inst.packetSpeechLenSamp) >> 6;
263                if (diffTS >= 0 || val < currSizeSamples)
264                {
265                    /* it is time to play this new packet */
266                    return BUFSTATS_DO_NORMAL;
267                }
268                else
269                {
270                    /* it is too early to play this new packet => keep on playing CNG */
271                    if (prevPlayMode == MODE_RFC3389CNG)
272                    {
273                        return BUFSTATS_DO_RFC3389CNG_NOPACKET;
274                    }
275                    else if (prevPlayMode == MODE_CODEC_INTERNAL_CNG)
276                    {
277                        return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
278                    }
279                    else if (playDtmf == 1)
280                    {
281                        /* we have not audio data, but can play DTMF */
282                        return BUFSTATS_DO_DTMF_ONLY;
283                    }
284                    else /* lastModeBGNonly */
285                    {
286                        /* signal expand, but this will result in BGN again */
287                        return BUFSTATS_DO_EXPAND;
288                    }
289                }
290            }
291
292            /* Do not merge unless we have done a Expand before (for complexity reasons) */
293            if ((inst->w16_noExpand == 0) || ((frameSize < timestampsPerCall) && (cur_size
294                > NETEQ_BUFSTAT_20MS_Q7)))
295            {
296                return BUFSTATS_DO_MERGE;
297            }
298            else if (playDtmf == 1)
299            {
300                /* play DTMF instead of expand */
301                return BUFSTATS_DO_DTMF_ONLY;
302            }
303            else
304            {
305                return BUFSTATS_DO_EXPAND;
306            }
307        }
308    }
309    else
310    { /* kPlayoutOff or kPlayoutFax */
311        if (cngPacket)
312        {
313            if (((int32_t) ((inst->uw32_CNGplayedTS + targetTS) - availableTS)) >= 0)
314            {
315                /* time to play this packet now */
316                return BUFSTATS_DO_RFC3389CNG_PACKET;
317            }
318            else
319            {
320                /* wait before playing this packet */
321                return BUFSTATS_DO_RFC3389CNG_NOPACKET;
322            }
323        }
324        if (noPacket)
325        {
326            /*
327             * No packet =>
328             * 1. If in CNG mode play as usual
329             * 2. Otherwise use other method to generate data and hold TS value
330             */
331            if (inst->w16_cngOn == CNG_RFC3389_ON)
332            {
333                /* keep on playing CNG */
334                return BUFSTATS_DO_RFC3389CNG_NOPACKET;
335            }
336            else if (inst->w16_cngOn == CNG_INTERNAL_ON)
337            {
338                /* keep on playing internal CNG */
339                return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
340            }
341            else
342            {
343                /* nothing to play => invent some data to play out */
344                if (playoutMode == kPlayoutOff)
345                {
346                    return BUFSTATS_DO_ALTERNATIVE_PLC;
347                }
348                else if (playoutMode == kPlayoutFax)
349                {
350                    return BUFSTATS_DO_AUDIO_REPETITION;
351                }
352                else
353                {
354                    /* UNDEFINED, should not get here... */
355                    assert(0);
356                    return BUFSTAT_REINIT;
357                }
358            }
359        }
360        else if (targetTS == availableTS)
361        {
362            return BUFSTATS_DO_NORMAL;
363        }
364        else
365        {
366            if (((int32_t) ((inst->uw32_CNGplayedTS + targetTS) - availableTS)) >= 0)
367            {
368                return BUFSTATS_DO_NORMAL;
369            }
370            else if (playoutMode == kPlayoutOff)
371            {
372                /*
373                 * If currently playing CNG, continue with that. Don't increase TS
374                 * since uw32_CNGplayedTS will be increased.
375                 */
376                if (inst->w16_cngOn == CNG_RFC3389_ON)
377                {
378                    return BUFSTATS_DO_RFC3389CNG_NOPACKET;
379                }
380                else if (inst->w16_cngOn == CNG_INTERNAL_ON)
381                {
382                    return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
383                }
384                else
385                {
386                    /*
387                     * Otherwise, do PLC and increase TS while waiting for the time to
388                     * play this packet.
389                     */
390                    return BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS;
391                }
392            }
393            else if (playoutMode == kPlayoutFax)
394            {
395                /*
396                 * If currently playing CNG, continue with that don't increase TS since
397                 * uw32_CNGplayedTS will be increased.
398                 */
399                if (inst->w16_cngOn == CNG_RFC3389_ON)
400                {
401                    return BUFSTATS_DO_RFC3389CNG_NOPACKET;
402                }
403                else if (inst->w16_cngOn == CNG_INTERNAL_ON)
404                {
405                    return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
406                }
407                else
408                {
409                    /*
410                     * Otherwise, do audio repetition and increase TS while waiting for the
411                     * time to play this packet.
412                     */
413                    return BUFSTATS_DO_AUDIO_REPETITION_INC_TS;
414                }
415            }
416            else
417            {
418                /* UNDEFINED, should not get here... */
419                assert(0);
420                return BUFSTAT_REINIT;
421            }
422        }
423    }
424    /* We should not get here (but sometimes we do anyway...) */
425    return BUFSTAT_REINIT;
426}
427
Note: See TracBrowser for help on using the repository browser.