Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : /*====================================================================================
34 : EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
35 : ====================================================================================*/
36 :
37 : /*! \file jbm_jb4sb.c EVS Jitter Buffer Management Interface */
38 :
39 : /* system headers */
40 : #include <assert.h>
41 : #include <stdlib.h>
42 : #include <math.h>
43 : #include <stdint.h>
44 : #include "options.h"
45 : #include "wmc_auto.h"
46 : /* local headers */
47 : #include "jbm_jb4_circularbuffer.h"
48 : #include "jbm_jb4_inputbuffer.h"
49 : #include "jbm_jb4_jmf.h"
50 : #include "jbm_jb4sb.h"
51 : #include "prot_fx.h"
52 : #define WMC_TOOL_SKIP
53 :
54 : #define INV_500_Q31 4294967 /*1/500 IN Q_31*/
55 : #define DIV_600_1000_Q31 1288490189 /*600/1000 IN Q_31*/
56 : #define INV_20_Q31 107374183 /*1/20 in Q31*/
57 : #define JB4_MIN( a, b ) ( ( a ) > ( b ) ? ( b ) : ( a ) )
58 : #define JB4_MAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
59 :
60 : #define MAXOFFSET 10
61 :
62 : /*! Calculates the difference between two RTP timestamps - the diff is positive, if B 'later', negative otherwise */
63 : static Word32 JB4_rtpTimeStampDiff( const UWord32 tsA, const UWord32 tsB );
64 : /* function to calculate different options for the target playout delay */
65 : static void JB4_targetPlayoutDelay( const JB4_HANDLE h, UWord32 *targetMin, UWord32 *targetMax, UWord32 *targetDtx, UWord32 *targetStartUp );
66 : /*! function to do playout adaptation before playing the next data unit */
67 : /*! In case of time shrinking, data units will be dropped before the next data unit to play is returned and
68 : * in case of time stretching a empty data unit is returned and the frame should be concealed.
69 : * @param[in] now current system time
70 : * @param[out] dataUnit the next data unit to play
71 : * @param[out] scale the scale in percent used as target for time scaling of the returned data unit
72 : * @param[out] maxScaling the maximum allowed external time scaling */
73 : static Word16 JB4_adaptPlayout( JB4_HANDLE h, UWord32 sysTime, UWord32 extBufferedTime, JB4_DATAUNIT_HANDLE *pDataUnit, UWord32 *scale, UWord32 *maxScaling );
74 : /*! function to do playout adaptation before playing the first data unit */
75 : /*! @param[in] now current system time
76 : * @param[out] prebuffer true, if the data unit should be prebuffered */
77 : static void JB4_adaptFirstPlayout( JB4_HANDLE h, UWord32 sysTime, bool *prebuffer );
78 : /*! function for playout adaptation while active (no DTX) */
79 : static void JB4_adaptActivePlayout( JB4_HANDLE h, UWord32 extBufferedTime, UWord32 *scale, UWord32 *maxScaling );
80 : /*! function for playout adaptation while DTX */
81 : static void JB4_adaptDtxPlayout( JB4_HANDLE h, UWord32 sysTime, bool *stretchTime );
82 : /*! function to look into the buffer and check if it makes sense to drop a data unit */
83 : /*! @param[out] dropEarly true, if a data unit could be dropped early
84 : * @param[out] buffered the buffered time span in timeScale units
85 : * @return true, if a data unit could be dropped */
86 : static Word16 JB4_inspectBufferForDropping( const JB4_HANDLE h, bool *dropEarly, UWord32 *buffered );
87 : /* function to look into the buffer and check if it makes sense to drop a data unit during DTX */
88 : static Word16 JB4_checkDtxDropping( const JB4_HANDLE h );
89 : /*! function to estimate the short term jitter */
90 : static void JB4_estimateShortTermJitter( JB4_HANDLE h, const UWord32 rcvTime, const UWord32 rtpTimeStamp );
91 : /*! function to pop a data unit from the buffer */
92 : static void JB4_popFromBuffer( JB4_HANDLE h, const UWord32 sysTime, JB4_DATAUNIT_HANDLE *pDataUnit );
93 : /*! function to drop a data unit from the buffer - updates nShrinked */
94 : static void JB4_dropFromBuffer( JB4_HANDLE h );
95 : /*! function to calculate the playout delay based on the current jitter */
96 : /*! @param[in] playTime the system time when the data unit will be played
97 : * @param[in] timeStamp the time stamp of the data unit to played
98 : * @param[out] delay the calculated playout delay */
99 : static Word16 JB4_playoutDelay( const JB4_HANDLE h, const UWord32 playTime, const UWord32 rtpTimeStamp, UWord32 *delay );
100 : /*! function to update lastPlayoutDelay and lastTargetTime after popFromBuffer() */
101 : static void JB4_updateLastTimingMembers( JB4_HANDLE h, const UWord32 playTime, const UWord32 rtpTimeStamp );
102 : /*! function to compare the RTP time stamps of two data units: newElement==arrayElement ? 0 : (newElement>arrayElement ? +1 : -1) */
103 : static Word16 JB4_inputBufferCompareFunction( const JB4_INPUTBUFFER_ELEMENT newElement, const JB4_INPUTBUFFER_ELEMENT arrayElement, bool *replaceWithNewElementIfEqual );
104 :
105 :
106 : /*! Jitter Buffer Management Interface */
107 : struct JB4
108 : {
109 : /*! @name statistics for user */
110 : /*@{ */
111 : /*! the number of late lost data units */
112 : UWord32 nLateLost;
113 : /*! the number of data units that were available (not NULL) at playout time */
114 : UWord32 nAvailablePopped;
115 : /*! the number of data units that were not available (NULL) at playout time */
116 : UWord32 nUnavailablePopped;
117 : /*! the number of unavailable pops since the last available one - used as temp value for nLost and nStretched */
118 : UWord32 nLostOrStretched;
119 : /*! the number of data units that were lost at playout time */
120 : UWord32 nLost;
121 : /*! the number of empty data units inserted for playout adaptation */
122 : UWord32 nStretched;
123 : /*! the number of data units dropped for playout adaptation */
124 : /*! This function counts all time shrinking events, no matter if a dropped data unit was actually available. */
125 : UWord32 nShrinked;
126 : /*! the number of data units that were returned to create comfort noice (including NULL) */
127 : UWord32 nComfortNoice;
128 : /*! the number of jitter induced concealment operations (as defined in 3GPP TS 26.114) */
129 : UWord32 jitterInducedConcealments;
130 : /*! the target playout delay of the last returned data unit */
131 : UWord32 targetPlayoutDelay;
132 : /*! the target playout time of the last returned data unit */
133 : UWord32 lastTargetTime;
134 : /*@} */
135 : /*! @name internal configuration values - do not change!!! */
136 : /*@{ */
137 : /*! internal time scale for all calculations */
138 : Word16 timeScale;
139 : /*! internal frame duration in timeScale units */
140 : UWord32 frameDuration;
141 : /*@} */
142 : /*! @name jitter buffer configuration values */
143 : /*@{ */
144 : /*! the allowed delay reserve in addition to network jitter to reduce late-loss [milliseconds] */
145 : Word16 safetyMargin;
146 : /*@} */
147 : /*! @name data for short term jitter estimation */
148 : /*@{ */
149 : /*! short term jitter measure FIFO */
150 : JB4_JMF_HANDLE stJmf;
151 : /*! FIFO of short term jitter values */
152 : JB4_CIRCULARBUFFER_HANDLE stJitterFifo;
153 : /*! FIFO of RTP time stamps for the values stored in stJitterFifo */
154 : JB4_CIRCULARBUFFER_HANDLE stTimeStampFifo;
155 : /*! short term jitter */
156 : UWord32 stJitter;
157 : /*@} */
158 : /*! @name jitter buffer data */
159 : /*@{ */
160 : /*! true, if a data unit was already popped from the buffer */
161 : bool firstDataUnitPopped;
162 : /*! system time of the previous JB4_PopDataUnit() call */
163 : UWord32 prevPopSysTime;
164 : /*! RTP timestamp of the last played/dropped data unit that was actually available */
165 : UWord32 lastReturnedTs;
166 : /*! true, if the last popped data unit contained no active signal, i.e. silence -> hint for DTX */
167 : bool lastPoppedWasSilence;
168 : /*! the playout time minus the minimum offset of the last played data unit in microseconds */
169 : Word32 lastPlayoutOffset;
170 : /*! RTP time stamp of the next data unit that is expected to be fetched from the buffer */
171 : UWord32 nextExpectedTs;
172 : Word16 rfOffset2Active;
173 : Word16 rfOffset3Active;
174 : Word16 rfOffset5Active;
175 : Word16 rfOffset7Active;
176 : Word32 rfDelay;
177 : /*! long term jitter measure FIFO */
178 : JB4_JMF_HANDLE ltJmf;
179 :
180 : UWord32 FecOffWinLen;
181 : UWord32 FecOffWin[10];
182 : UWord32 optimum_offset;
183 :
184 : Word32 netLossRate_fx; // Q15
185 : Word32 nPartialCopiesUsed;
186 : Word32 last_nLost;
187 : Word32 last_ntot;
188 :
189 : UWord32 totWin;
190 : bool pre_partial_frame;
191 : /*@} */
192 :
193 : /*! @name members to store the data units */
194 : /*@{ */
195 : /*! the data unit buffer */
196 : JB4_INPUTBUFFER_HANDLE inputBuffer;
197 : struct JB4_DATAUNIT memorySlots[MAX_JBM_SLOTS];
198 : JB4_DATAUNIT_HANDLE freeMemorySlots[MAX_JBM_SLOTS];
199 : UWord16 nFreeMemorySlots;
200 : /*@} */
201 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
202 : bool evsMode;
203 : #endif
204 : }; /* JB4 */
205 :
206 :
207 28 : ivas_error JB4_Create(
208 : JB4_HANDLE *ph )
209 : {
210 : Word16 iter;
211 : JB4_HANDLE h;
212 : ivas_error error;
213 :
214 28 : IF( ( h = malloc( sizeof( struct JB4 ) ) ) == NULL )
215 : {
216 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JB4 structure\n" ) );
217 : }
218 :
219 : /* statistics for user */
220 28 : h->nLateLost = 0;
221 28 : move32();
222 28 : h->nAvailablePopped = 0;
223 28 : move32();
224 28 : h->nUnavailablePopped = 0;
225 28 : move32();
226 28 : h->nLostOrStretched = 0;
227 28 : move32();
228 28 : h->nLost = 0;
229 28 : move32();
230 28 : h->nStretched = 0;
231 28 : move32();
232 28 : h->nShrinked = 0;
233 28 : move32();
234 28 : h->nComfortNoice = 0;
235 28 : move32();
236 28 : h->jitterInducedConcealments = 0;
237 28 : move32();
238 28 : h->targetPlayoutDelay = 0;
239 28 : move32();
240 28 : h->lastTargetTime = 0;
241 28 : move32();
242 : /* internal configuration values - do not change!!! */
243 28 : h->timeScale = 0;
244 28 : move16();
245 28 : h->frameDuration = 0;
246 28 : move32();
247 :
248 : /* jitter buffer configuration values: done in JB4_Init() */
249 : /* short term jitter evaluation */
250 28 : IF( NE_32( ( error = JB4_JMF_Create( &h->stJmf ) ), IVAS_ERR_OK ) )
251 : {
252 0 : return error;
253 : }
254 28 : IF( NE_32( ( error = JB4_CIRCULARBUFFER_Create( &h->stJitterFifo ) ), IVAS_ERR_OK ) )
255 : {
256 0 : return error;
257 : }
258 28 : IF( NE_32( ( error = JB4_CIRCULARBUFFER_Create( &h->stTimeStampFifo ) ), IVAS_ERR_OK ) )
259 : {
260 0 : return error;
261 : }
262 28 : h->stJitter = 0;
263 28 : move32();
264 :
265 : /* jitter buffer data */
266 28 : h->firstDataUnitPopped = false;
267 28 : move16();
268 28 : h->prevPopSysTime = 0;
269 28 : move32();
270 28 : h->lastReturnedTs = 0;
271 28 : move32();
272 28 : h->lastPoppedWasSilence = false;
273 28 : move16();
274 28 : h->lastPlayoutOffset = 0;
275 28 : move32();
276 28 : h->nextExpectedTs = 0;
277 28 : move32();
278 28 : h->rfOffset2Active = 0;
279 28 : move16();
280 28 : h->rfOffset3Active = 0;
281 28 : move16();
282 28 : h->rfOffset5Active = 0;
283 28 : move16();
284 28 : h->rfOffset7Active = 0;
285 28 : move16();
286 28 : h->rfDelay = 0;
287 28 : move32();
288 28 : JB4_JMF_Create( &h->ltJmf );
289 28 : h->pre_partial_frame = 0;
290 28 : move16();
291 :
292 28 : h->FecOffWinLen = 0;
293 28 : move32();
294 308 : FOR( iter = 0; iter < 10; iter++ )
295 : {
296 280 : h->FecOffWin[iter] = 0;
297 280 : move32();
298 : }
299 28 : h->optimum_offset = 3;
300 28 : move32();
301 28 : h->totWin = 0;
302 28 : move32();
303 28 : h->netLossRate_fx = 0;
304 28 : move32();
305 28 : h->nPartialCopiesUsed = 0;
306 28 : move32();
307 28 : h->last_nLost = 0;
308 28 : move32();
309 28 : h->last_ntot = 0;
310 28 : move32();
311 :
312 : /* members to store the data units */
313 28 : IF( NE_32( ( error = JB4_INPUTBUFFER_Create( &h->inputBuffer ) ), IVAS_ERR_OK ) )
314 : {
315 0 : return error;
316 : }
317 :
318 : /* allocate memory for data units */
319 2828 : FOR( iter = 0; iter < MAX_JBM_SLOTS; ++iter )
320 : {
321 2800 : IF( ( h->memorySlots[iter].data = malloc( MAX_AU_SIZE ) ) == NULL )
322 : {
323 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JB4 structure\n" ) );
324 : }
325 2800 : h->freeMemorySlots[iter] = &h->memorySlots[iter];
326 : }
327 28 : h->nFreeMemorySlots = MAX_JBM_SLOTS;
328 28 : move16();
329 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
330 28 : h->evsMode = false;
331 28 : move16();
332 : #endif
333 28 : *ph = h;
334 :
335 28 : return IVAS_ERR_OK;
336 : }
337 :
338 :
339 28 : void JB4_Destroy(
340 : JB4_HANDLE *ph )
341 : {
342 : JB4_HANDLE h;
343 : UWord16 i;
344 :
345 28 : IF( !ph )
346 : {
347 0 : return;
348 : }
349 28 : h = *ph;
350 28 : IF( !h )
351 : {
352 0 : return;
353 : }
354 :
355 28 : JB4_JMF_Destroy( &h->stJmf );
356 28 : JB4_CIRCULARBUFFER_Destroy( &h->stJitterFifo );
357 28 : JB4_CIRCULARBUFFER_Destroy( &h->stTimeStampFifo );
358 28 : JB4_JMF_Destroy( &h->ltJmf );
359 28 : JB4_INPUTBUFFER_Destroy( &h->inputBuffer );
360 :
361 2828 : FOR( i = 0; i < MAX_JBM_SLOTS; ++i )
362 : {
363 2800 : free( h->memorySlots[i].data );
364 : }
365 :
366 28 : free( h );
367 28 : *ph = NULL;
368 :
369 28 : return;
370 : }
371 :
372 :
373 28 : ivas_error JB4_Init(
374 : JB4_HANDLE h,
375 : const Word16 safetyMargin )
376 : {
377 : UWord16 ltJmfSize, stFifoSize, stJmfSize, stJmfAllowedLateLoss;
378 : UWord16 inputBufferCapacity;
379 : ivas_error error;
380 :
381 : /* internal timescale is 1000, frame duration is 20ms */
382 28 : h->timeScale = 1000; /* ms */
383 28 : move16();
384 28 : h->frameDuration = 20; /* ms */
385 28 : move32();
386 :
387 : /* jitter buffer configuration values */
388 28 : h->safetyMargin = safetyMargin;
389 28 : move16();
390 :
391 : /* long term jitter measure FIFO: 500 frames and 10s */
392 28 : ltJmfSize = 10000;
393 28 : move16();
394 28 : JB4_JMF_Init( h->ltJmf, h->timeScale, 500 /*ltJmfSize / 20*/, ltJmfSize, 1000 );
395 : /* short term jitter evaluation */
396 28 : stFifoSize = 200;
397 28 : move16();
398 28 : stJmfSize = 50;
399 28 : move16();
400 28 : stJmfAllowedLateLoss = 60; /* 6%, e.g. ignore three packets out of 50 */
401 28 : move16();
402 28 : JB4_CIRCULARBUFFER_Init( h->stJitterFifo, stFifoSize );
403 28 : JB4_CIRCULARBUFFER_Init( h->stTimeStampFifo, stFifoSize );
404 28 : JB4_JMF_Init( h->stJmf, h->timeScale, stJmfSize, h->timeScale /* 1s */, (UWord16) L_sub( 1000, stJmfAllowedLateLoss ) );
405 :
406 28 : inputBufferCapacity = MAX_JBM_SLOTS - 2;
407 28 : move16();
408 :
409 28 : IF( NE_32( ( error = JB4_INPUTBUFFER_Init( h->inputBuffer, inputBufferCapacity, JB4_inputBufferCompareFunction ) ), IVAS_ERR_OK ) )
410 : {
411 0 : return error;
412 : }
413 :
414 28 : return IVAS_ERR_OK;
415 : }
416 :
417 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
418 0 : void JB4_TMP_SetEvsCompatFlag( JB4_HANDLE h )
419 : {
420 0 : h->evsMode = true;
421 0 : move16();
422 0 : }
423 : #endif
424 :
425 : /* Returns a memory slot to store a new data unit */
426 17683 : JB4_DATAUNIT_HANDLE JB4_AllocDataUnit(
427 : JB4_HANDLE h )
428 : {
429 : JB4_DATAUNIT_HANDLE dataUnit;
430 17683 : WHILE( h->nFreeMemorySlots == 0 )
431 : {
432 0 : assert( JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) == 0 );
433 0 : JB4_dropFromBuffer( h );
434 : }
435 :
436 : /* LOCK JBM MEMORY SLOT BEGIN */
437 17683 : h->nFreeMemorySlots = (UWord16) L_sub( h->nFreeMemorySlots, 1 );
438 17683 : move16();
439 17683 : dataUnit = h->freeMemorySlots[h->nFreeMemorySlots];
440 17683 : h->freeMemorySlots[h->nFreeMemorySlots] = NULL;
441 : /* LOCK JBM MEMORY SLOT END */
442 17683 : assert( dataUnit != NULL );
443 :
444 17683 : return dataUnit;
445 : }
446 :
447 :
448 : /* Notifies the JBM that a data unit is no longer used and the memory can be reused */
449 17683 : void JB4_FreeDataUnit(
450 : JB4_HANDLE h,
451 : JB4_DATAUNIT_HANDLE dataUnit )
452 : {
453 17683 : assert( dataUnit != NULL );
454 17683 : assert( h->nFreeMemorySlots < MAX_JBM_SLOTS );
455 : /* LOCK JBM MEMORY SLOT BEGIN */
456 17683 : h->freeMemorySlots[h->nFreeMemorySlots] = dataUnit;
457 17683 : h->nFreeMemorySlots = (UWord16) L_add( h->nFreeMemorySlots, 1 );
458 : /* LOCK JBM MEMORY SLOT END */
459 17683 : move16();
460 :
461 17683 : return;
462 : }
463 :
464 :
465 17683 : Word16 JB4_PushDataUnit(
466 : JB4_HANDLE h,
467 : JB4_DATAUNIT_HANDLE dataUnit,
468 : const UWord32 rcvTime )
469 : {
470 17683 : JB4_DATAUNIT_HANDLE droppedDataUnit = NULL;
471 :
472 17683 : assert( dataUnit->duration == h->frameDuration );
473 17683 : assert( dataUnit->timeScale == (UWord16) h->timeScale );
474 :
475 : /* ignore frames from too far in future (3 seconds) */
476 17683 : test();
477 17683 : IF( h->firstDataUnitPopped && GE_32( JB4_rtpTimeStampDiff( h->lastReturnedTs, dataUnit->timeStamp ),
478 : imult3216( (Word32) dataUnit->duration, 50 * 3 ) ) )
479 : {
480 0 : JB4_FreeDataUnit( h, dataUnit );
481 0 : return 0;
482 : }
483 :
484 : /* reserve space for one element to add: drop oldest if buffer is full */
485 17683 : WHILE( JB4_INPUTBUFFER_IsFull( h->inputBuffer ) )
486 : {
487 0 : JB4_dropFromBuffer( h );
488 : }
489 17683 : assert( JB4_INPUTBUFFER_IsFull( h->inputBuffer ) == 0 );
490 :
491 : /* do statistics on partial copy offset using active primary copies to
492 : * avoid unexpected resets because RF_NO_DATA partial copies are dropped before JBM */
493 17683 : test();
494 17683 : IF( dataUnit->silenceIndicator == 0 && dataUnit->partial_frame == 0 )
495 : {
496 17420 : IF( dataUnit->partialCopyOffset == 0 )
497 : {
498 17420 : IF( h->rfOffset2Active > 0 )
499 : {
500 0 : h->rfOffset2Active = sub( h->rfOffset2Active, 1 );
501 0 : move16();
502 : }
503 17420 : IF( h->rfOffset3Active > 0 )
504 : {
505 0 : h->rfOffset3Active = sub( h->rfOffset3Active, 1 );
506 0 : move16();
507 : }
508 17420 : IF( h->rfOffset5Active > 0 )
509 : {
510 0 : h->rfOffset5Active = sub( h->rfOffset5Active, 1 );
511 0 : move16();
512 : }
513 17420 : IF( h->rfOffset7Active > 0 )
514 : {
515 0 : h->rfOffset7Active = sub( h->rfOffset7Active, 1 );
516 0 : move16();
517 : }
518 : }
519 0 : ELSE IF( EQ_16( dataUnit->partialCopyOffset, 2 ) )
520 : {
521 0 : h->rfOffset2Active = 100;
522 0 : move16();
523 0 : h->rfOffset3Active = 0;
524 0 : move16();
525 0 : h->rfOffset5Active = 0;
526 0 : move16();
527 0 : h->rfOffset7Active = 0;
528 0 : move16();
529 : }
530 0 : ELSE IF( EQ_16( dataUnit->partialCopyOffset, 3 ) )
531 : {
532 0 : h->rfOffset2Active = 0;
533 0 : move16();
534 0 : h->rfOffset3Active = 100;
535 0 : move16();
536 0 : h->rfOffset5Active = 0;
537 0 : move16();
538 0 : h->rfOffset7Active = 0;
539 0 : move16();
540 : }
541 0 : ELSE IF( EQ_16( dataUnit->partialCopyOffset, 5 ) )
542 : {
543 0 : h->rfOffset2Active = 0;
544 0 : move16();
545 0 : h->rfOffset3Active = 0;
546 0 : move16();
547 0 : h->rfOffset5Active = 100;
548 0 : move16();
549 0 : h->rfOffset7Active = 0;
550 0 : move16();
551 : }
552 0 : ELSE IF( EQ_16( dataUnit->partialCopyOffset, 7 ) )
553 : {
554 0 : h->rfOffset2Active = 0;
555 0 : move16();
556 0 : h->rfOffset3Active = 0;
557 0 : move16();
558 0 : h->rfOffset5Active = 0;
559 0 : move16();
560 0 : h->rfOffset7Active = 100;
561 0 : move16();
562 : }
563 : }
564 :
565 17683 : IF( dataUnit->partial_frame != 0 )
566 : {
567 : /* check for "real" late loss: a frame with higher/same timestamp was already returned to be fed into decoder */
568 0 : test();
569 0 : IF( h->firstDataUnitPopped && JB4_rtpTimeStampDiff( h->lastReturnedTs, dataUnit->timeStamp ) <= 0 )
570 : {
571 0 : JB4_FreeDataUnit( h, dataUnit );
572 0 : return 0;
573 : }
574 :
575 : /* drop partial copy if the missing frame was already concealed */
576 0 : IF( h->firstDataUnitPopped )
577 : {
578 0 : test();
579 0 : test();
580 0 : test();
581 0 : IF( LE_16( dataUnit->partialCopyOffset, 3 ) && JB4_rtpTimeStampDiff( h->nextExpectedTs, dataUnit->timeStamp ) < 0 )
582 : {
583 0 : JB4_FreeDataUnit( h, dataUnit );
584 0 : return 0;
585 : }
586 0 : ELSE IF( EQ_16( dataUnit->partialCopyOffset, 5 ) && LT_32( JB4_rtpTimeStampDiff( h->nextExpectedTs, dataUnit->timeStamp ), -40 ) )
587 : {
588 0 : JB4_FreeDataUnit( h, dataUnit );
589 0 : return 0;
590 : }
591 0 : ELSE IF( EQ_16( dataUnit->partialCopyOffset, 7 ) && LT_32( JB4_rtpTimeStampDiff( h->nextExpectedTs, dataUnit->timeStamp ), -80 ) )
592 : {
593 0 : JB4_FreeDataUnit( h, dataUnit );
594 0 : return 0;
595 : }
596 : }
597 :
598 : /* try to store partial copy - will be dropped if primary copy already available */
599 0 : IF( JB4_INPUTBUFFER_Enque( h->inputBuffer, dataUnit, (void **) &droppedDataUnit ) == 0 )
600 : {
601 : /* partial copy is useful, consider it in long-term jitter estimation */
602 0 : IF( LE_16( dataUnit->partialCopyOffset, 3 ) )
603 : {
604 0 : JB4_JMF_PushPacket( h->ltJmf, rcvTime, dataUnit->timeStamp );
605 : }
606 : }
607 : ELSE
608 : {
609 0 : JB4_FreeDataUnit( h, dataUnit );
610 : }
611 0 : IF( droppedDataUnit != NULL )
612 : {
613 0 : JB4_FreeDataUnit( h, droppedDataUnit );
614 : }
615 : }
616 : ELSE
617 : {
618 : /* calculate jitter */
619 17683 : JB4_JMF_PushPacket( h->ltJmf, rcvTime, dataUnit->timeStamp );
620 17683 : JB4_estimateShortTermJitter( h, rcvTime, dataUnit->timeStamp );
621 : /* check for "real" late loss: a frame with higher/same timestamp was already returned to be fed into decoder */
622 17683 : test();
623 17683 : IF( h->firstDataUnitPopped && JB4_rtpTimeStampDiff( h->lastReturnedTs, dataUnit->timeStamp ) <= 0 )
624 : {
625 0 : IF( !dataUnit->silenceIndicator )
626 : {
627 0 : h->nLateLost = (UWord32) W_add( h->nLateLost, 1 );
628 0 : move32();
629 : /* deletion of a speech frame because it arrived at the JBM too late */
630 0 : h->jitterInducedConcealments = (UWord32) W_add( h->jitterInducedConcealments, 1 );
631 0 : move32();
632 : }
633 0 : JB4_FreeDataUnit( h, dataUnit );
634 0 : return 0;
635 : }
636 : /* store data unit */
637 17683 : IF( JB4_INPUTBUFFER_Enque( h->inputBuffer, dataUnit, (void **) &droppedDataUnit ) != 0 )
638 : {
639 0 : JB4_FreeDataUnit( h, dataUnit );
640 : }
641 17683 : IF( droppedDataUnit != NULL )
642 : {
643 0 : JB4_FreeDataUnit( h, droppedDataUnit );
644 : }
645 : }
646 17683 : return 0;
647 : }
648 :
649 :
650 0 : Word16 JB4_getFECoffset(
651 : JB4_HANDLE h )
652 : {
653 0 : return (Word16) h->optimum_offset;
654 : }
655 :
656 :
657 0 : Word16 JB4_FECoffset(
658 : JB4_HANDLE h )
659 : {
660 0 : IF( LT_32( h->netLossRate_fx, 1634 /*.05f in Q15*/ ) )
661 : {
662 0 : return 0;
663 : }
664 : ELSE
665 : {
666 0 : return 1;
667 : }
668 : }
669 :
670 :
671 19751 : Word16 JB4_PopDataUnit(
672 : JB4_HANDLE h,
673 : const UWord32 sysTime,
674 : const UWord32 extBufferedTime,
675 : JB4_DATAUNIT_HANDLE *pDataUnit,
676 : UWord32 *scale,
677 : UWord32 *maxScaling )
678 : {
679 : Word16 ret;
680 :
681 19751 : assert( sysTime >= h->prevPopSysTime );
682 19751 : IF( GT_64( sysTime, W_add( h->prevPopSysTime, 20 ) ) )
683 : {
684 0 : h->lastPlayoutOffset = L_add( h->lastPlayoutOffset, 20 );
685 0 : move32();
686 : }
687 19751 : h->prevPopSysTime = sysTime;
688 19751 : move32();
689 :
690 19751 : ret = JB4_adaptPlayout( h, sysTime, extBufferedTime, pDataUnit, scale, maxScaling );
691 :
692 19751 : return ret;
693 : }
694 :
695 :
696 : /* Calculates the difference between two RTP timestamps - the diff is positive, if B 'later', negative otherwise */
697 94050 : static Word32 JB4_rtpTimeStampDiff(
698 : const UWord32 tsA,
699 : const UWord32 tsB )
700 : {
701 : Word32 ret;
702 : /* do not dare to inline this function, casting to Word32 is important here! */
703 94050 : ret = W_extract_l( W_sub( tsB, tsA ) );
704 94050 : return ret;
705 : }
706 :
707 :
708 : /* function to get the number of data units contained in the buffer */
709 211 : UWord16 JB4_bufferedDataUnits(
710 : const JB4_HANDLE h )
711 :
712 : {
713 211 : return JB4_INPUTBUFFER_Size( h->inputBuffer );
714 : }
715 :
716 :
717 : /*****************************************************************************
718 : **************************** private functions ******************************
719 : *****************************************************************************/
720 :
721 :
722 : /* function to calculate different options for the target playout delay */
723 19607 : static void JB4_targetPlayoutDelay(
724 : const JB4_HANDLE h,
725 : UWord32 *targetMin,
726 : UWord32 *targetMax,
727 : UWord32 *targetDtx,
728 : UWord32 *targetStartUp )
729 : {
730 : UWord32 ltJitter, extraDelayReserve;
731 :
732 : /* adapt target delay to partial copy offset */
733 19607 : extraDelayReserve = 0;
734 19607 : move32();
735 19607 : h->rfDelay = 0;
736 19607 : move32();
737 19607 : test();
738 19607 : IF( h->rfOffset7Active != 0 )
739 : {
740 0 : h->rfDelay = 140;
741 0 : move32();
742 : }
743 19607 : ELSE IF( h->rfOffset5Active != 0 )
744 : {
745 0 : h->rfDelay = 100;
746 0 : move32();
747 : }
748 19607 : ELSE IF( h->rfOffset2Active == 0 && h->rfOffset3Active == 0 )
749 : {
750 : /* keep some delay reserve for RF-off */
751 19607 : extraDelayReserve = 15;
752 19607 : move32();
753 : }
754 :
755 : /* get estimated long term jitter */
756 19607 : IF( JB4_JMF_Jitter( h->ltJmf, <Jitter ) == 0 )
757 : {
758 : /* combine long term and short term jitter to calculate target delay values */
759 19551 : *targetMax = (UWord32) W_add( h->stJitter, W_add( h->safetyMargin, h->rfDelay ) );
760 19551 : *targetMin = JB4_MIN( (UWord32) W_add( W_add( ltJitter, 20 ), W_add( h->rfDelay, extraDelayReserve ) ), *targetMax );
761 19551 : *targetDtx = JB4_MIN( (UWord32) W_add( ltJitter, extraDelayReserve ), h->stJitter );
762 19551 : *targetStartUp = (UWord32) W_shr( W_add( W_add( *targetMin, *targetMax ), W_shr( extraDelayReserve, 2 ) /*extraDelayReserve / 4*/ ), 1 );
763 : }
764 : ELSE
765 : {
766 : /* combine long term and short term jitter to calculate target delay values */
767 56 : *targetMax = h->safetyMargin;
768 56 : *targetMin = JB4_MIN( 20, *targetMax );
769 56 : *targetDtx = 0;
770 56 : *targetStartUp = (UWord32) W_shr( W_add( *targetMin, *targetMax ), 1 );
771 : }
772 19607 : move32();
773 19607 : move32();
774 19607 : move32();
775 19607 : move32();
776 :
777 : #ifdef NONBE_1122_JBM_FIX_PLAYOUT_DELAY_IN_DTX
778 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
779 19607 : IF( !h->evsMode )
780 : {
781 : #endif
782 19607 : *targetDtx = JB4_MAX( *targetDtx, (UWord32) h->safetyMargin );
783 19607 : move32();
784 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
785 : }
786 : #endif
787 19607 : *targetStartUp = JB4_MAX( *targetStartUp, (UWord32) h->safetyMargin );
788 19607 : move32();
789 : #else
790 : if ( LT_64( *targetStartUp, 60 ) )
791 : {
792 : *targetStartUp = 60;
793 : move32();
794 : }
795 : #endif
796 :
797 19607 : return;
798 : }
799 :
800 :
801 : /* function to do playout adaptation before playing the next data unit */
802 19751 : static Word16 JB4_adaptPlayout(
803 : JB4_HANDLE h,
804 : UWord32 sysTime,
805 : UWord32 extBufferedTime,
806 : JB4_DATAUNIT_HANDLE *pDataUnit,
807 : UWord32 *scale,
808 : UWord32 *maxScaling )
809 : {
810 : bool stretchTime;
811 :
812 : /* reset scale */
813 19751 : test();
814 19751 : IF( scale == NULL || maxScaling == NULL )
815 : {
816 0 : return -1;
817 : }
818 19751 : *scale = 100;
819 19751 : move32();
820 19751 : *maxScaling = 0;
821 19751 : move32();
822 19751 : stretchTime = false;
823 19751 : move16();
824 : /* switch type of current playout (first one, active, DTX) */
825 19751 : IF( !h->firstDataUnitPopped )
826 : {
827 228 : JB4_adaptFirstPlayout( h, sysTime, &stretchTime );
828 : }
829 19523 : ELSE IF( h->lastPoppedWasSilence )
830 : {
831 1263 : JB4_adaptDtxPlayout( h, sysTime, &stretchTime );
832 : }
833 : ELSE
834 : {
835 18260 : JB4_adaptActivePlayout( h, extBufferedTime, scale, maxScaling );
836 : }
837 :
838 : /* time shrinking done IF needed, now do time stretching or pop data unit to play */
839 19751 : IF( stretchTime )
840 : {
841 : /* return empty data unit */
842 335 : *pDataUnit = NULL;
843 335 : IF( h->firstDataUnitPopped )
844 : {
845 135 : h->nUnavailablePopped = (UWord32) W_add( h->nUnavailablePopped, 1 );
846 135 : move32();
847 135 : IF( !h->lastPoppedWasSilence )
848 : {
849 0 : h->nStretched = (UWord32) W_add( h->nStretched, 1 );
850 0 : move32();
851 : /* jitter-induced insertion (e.g. buffer underflow) */
852 0 : h->jitterInducedConcealments = (UWord32) W_add( h->jitterInducedConcealments, 1 );
853 0 : move32();
854 : }
855 : }
856 : /* add one frame to last playout delay */
857 335 : h->lastPlayoutOffset = L_add( h->lastPlayoutOffset, (Word32) h->frameDuration );
858 335 : move32();
859 : }
860 : ELSE
861 : {
862 : /* return next data unit from buffer */
863 19416 : JB4_popFromBuffer( h, sysTime, pDataUnit );
864 : }
865 :
866 19751 : return 0;
867 : }
868 :
869 :
870 : /* function for playout adaptation while active (no DTX) */
871 18260 : static void JB4_adaptActivePlayout(
872 : JB4_HANDLE h,
873 : UWord32 extBufferedTime,
874 : UWord32 *scale,
875 : UWord32 *maxScaling )
876 : {
877 : JB4_DATAUNIT_HANDLE nextDataUnit;
878 : bool convertToLateLoss, dropEarly;
879 : UWord32 targetMin, targetMax, targetDtx, targetStartUp, targetMaxStretch;
880 : UWord32 currPlayoutDelay, gap, buffered;
881 : UWord32 dropGapMax, dropRateMin, dropRateMax, rate;
882 : Word32 minOffTicks, tsDiffToNextDataUnit;
883 :
884 18260 : JB4_targetPlayoutDelay( h, &targetMin, &targetMax, &targetDtx, &targetStartUp );
885 18260 : IF( JB4_JMF_MinOffset( h->ltJmf, &minOffTicks ) != 0 )
886 : {
887 0 : return;
888 : }
889 18260 : h->targetPlayoutDelay = (UWord32) W_shr( W_add( targetMin, targetMax ), 1 );
890 18260 : move32();
891 :
892 18260 : convertToLateLoss = false;
893 18260 : dropEarly = false;
894 18260 : move16();
895 18260 : move16();
896 18260 : dropGapMax = 200;
897 18260 : move32();
898 18260 : dropRateMin = 5;
899 18260 : move32();
900 18260 : dropRateMax = 200; /* 20% */
901 18260 : move32();
902 :
903 : /* calculate current playout delay */
904 18260 : currPlayoutDelay = (UWord32) W_add( W_sub( h->lastPlayoutOffset, minOffTicks ), extBufferedTime );
905 18260 : IF( !JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
906 : {
907 18133 : nextDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
908 18133 : tsDiffToNextDataUnit = JB4_rtpTimeStampDiff( h->nextExpectedTs, nextDataUnit->timeStamp );
909 18133 : IF( tsDiffToNextDataUnit < 0 )
910 : {
911 87 : convertToLateLoss = true;
912 87 : move16();
913 : /* time stretching is expected -> increase playout delay to allow dropping the late frame */
914 87 : currPlayoutDelay = (UWord32) W_sub( currPlayoutDelay, tsDiffToNextDataUnit );
915 87 : currPlayoutDelay = (UWord32) ( W_add( currPlayoutDelay, 1 ) );
916 : }
917 : }
918 :
919 : /* decided between shrinking/stretching */
920 18260 : IF( GT_64( currPlayoutDelay, targetMax ) ) /* time shrinking */
921 : {
922 241 : gap = (UWord32) W_sub( currPlayoutDelay, h->targetPlayoutDelay );
923 : /* check if gap is positive and dropping is allowed
924 : * and buffer contains enough time (ignoring one frame) */
925 241 : test();
926 241 : test();
927 241 : test();
928 241 : IF( gap > 0 &&
929 : JB4_inspectBufferForDropping( h, &dropEarly, &buffered ) == 0 &&
930 : ( convertToLateLoss ||
931 : GT_64( W_add( buffered, W_add( h->frameDuration, extBufferedTime ) ), targetMax ) ) )
932 : {
933 170 : IF( convertToLateLoss )
934 : {
935 26 : JB4_dropFromBuffer( h );
936 26 : h->nLostOrStretched = L_add( h->nLostOrStretched, 1 );
937 26 : move32();
938 : }
939 144 : ELSE IF( dropEarly )
940 : {
941 3 : JB4_dropFromBuffer( h );
942 : }
943 : ELSE
944 : {
945 : Word16 exp;
946 141 : Word32 temp = BASOP_Util_Divide3232_Scale_newton( W_extract_l( W_sub( dropRateMax, dropRateMin ) ), W_extract_l( dropGapMax ), &exp );
947 : /* limit gap to [gapMin,gapMax] and calculate current drop rate from gap */
948 141 : Word64 temp2 = W_mult0_32_32( W_extract_l( JB4_MIN( gap, dropGapMax ) ), temp );
949 141 : Word64 temp3 = W_shr( temp2, sub( 31, exp ) );
950 141 : Word64 diff = W_sub( W_shl( W_add( temp3, 1 ), sub( 31, exp ) ), temp2 );
951 141 : if ( LE_64( diff, 21 ) )
952 : {
953 0 : temp3 = W_add( temp3, 1 );
954 : }
955 141 : rate = (UWord32) W_add( temp3, dropRateMin );
956 141 : *scale = idiv1616( sub( 1000, (Word16) rate ), 10 );
957 : /* Limit max scaling to the duration of one frame. APA will not exceed this limit
958 : * anyway due to the 50% limitation of APA_MIN_SCALE and APA_MAX_SCALE. Limiting
959 : * the value to a sensible range here avoids integer overflows at later stages when
960 : * converting maxScaling from milliseconds to samples. */
961 141 : *maxScaling = (UWord32) JB4_MIN( W_sub( currPlayoutDelay, targetMax ), 1000 / IVAS_NUM_FRAMES_PER_SEC );
962 141 : move32();
963 141 : move32();
964 : }
965 : }
966 : }
967 : ELSE /* time stretching */
968 : {
969 : UWord32 delayWithClearedExternalBuffer;
970 : /* Stretching only makes sense if we win one additional frame in the input buffer.
971 : * If too much additional delay would be required to do so, then do not scale.
972 : * Also make sure that the delay doesn't increase too much. */
973 18019 : delayWithClearedExternalBuffer = (UWord32) W_add( W_sub( currPlayoutDelay, extBufferedTime ), h->frameDuration );
974 18019 : targetMaxStretch = (UWord32) W_sub( targetMax, h->frameDuration );
975 18019 : test();
976 18019 : test();
977 18019 : IF( LE_64( W_add( delayWithClearedExternalBuffer, h->frameDuration ), targetMaxStretch ) &&
978 : LT_64( currPlayoutDelay, targetMaxStretch ) && LT_64( currPlayoutDelay, L_add( 110, L_shr( h->rfDelay, 2 ) ) ) )
979 : {
980 436 : *scale = 120;
981 436 : move32();
982 : /* Limit max scaling to the duration of one frame. APA will not exceed this limit
983 : * anyway due to the 50% limitation of APA_MIN_SCALE and APA_MAX_SCALE. Limiting
984 : * the value to a sensible range here avoids integer overflows at later stages when
985 : * converting maxScaling from milliseconds to samples. */
986 436 : *maxScaling = (UWord32) JB4_MIN( W_sub( targetMaxStretch, currPlayoutDelay ), 1000 / IVAS_NUM_FRAMES_PER_SEC );
987 436 : move32();
988 : }
989 : }
990 :
991 18260 : return;
992 : }
993 :
994 :
995 : /* function for playout adaptation while DTX */
996 1263 : static void JB4_adaptDtxPlayout(
997 : JB4_HANDLE h,
998 : UWord32 sysTime,
999 : bool *stretchTime )
1000 : {
1001 : JB4_DATAUNIT_HANDLE firstDu;
1002 : UWord32 firstTs;
1003 : UWord32 targetMin, targetMax, targetDtx, targetStartUp;
1004 : UWord32 currPlayoutDelay, headRoom;
1005 : Word32 minOffTicks, tsDiffToNextDataUnit;
1006 :
1007 1263 : JB4_targetPlayoutDelay( h, &targetMin, &targetMax, &targetDtx, &targetStartUp );
1008 1263 : IF( JB4_JMF_MinOffset( h->ltJmf, &minOffTicks ) != 0 )
1009 : {
1010 0 : return;
1011 : }
1012 :
1013 : /* calculate current playout delay */
1014 1263 : currPlayoutDelay = L_sub( h->lastPlayoutOffset, minOffTicks );
1015 :
1016 : /* check for startup after DTX */
1017 1263 : IF( !JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
1018 : {
1019 740 : firstDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1020 740 : firstTs = firstDu->timeStamp;
1021 740 : move32();
1022 :
1023 740 : tsDiffToNextDataUnit = JB4_rtpTimeStampDiff( h->nextExpectedTs, firstTs );
1024 : /* check if the next available data unit should already be used (time stamp order) */
1025 740 : IF( tsDiffToNextDataUnit > 0 )
1026 : {
1027 : /* time stretching is expected -> increase playout delay */
1028 374 : currPlayoutDelay = (UWord32) W_add( currPlayoutDelay, tsDiffToNextDataUnit );
1029 : }
1030 740 : IF( !firstDu->silenceIndicator )
1031 : {
1032 : /* recalculate playout delay based on first buffered data unit */
1033 348 : JB4_playoutDelay( h, sysTime, firstTs, &currPlayoutDelay );
1034 : /* check if the next available data unit should already be used (time stamp order) */
1035 348 : IF( tsDiffToNextDataUnit > 0 )
1036 : {
1037 : /* time stretching is expected -> increase playout delay */
1038 196 : currPlayoutDelay = (UWord32) W_add( currPlayoutDelay, tsDiffToNextDataUnit );
1039 : }
1040 348 : h->targetPlayoutDelay = targetStartUp;
1041 348 : move32();
1042 348 : headRoom = (UWord32) W_shr( W_mult0_32_32( DIV_600_1000_Q31, h->frameDuration ), 31 );
1043 : /* decided between shrinking/stretching */
1044 348 : IF( GT_64( currPlayoutDelay, W_add( targetStartUp, headRoom ) ) ) /* time shrinking */
1045 : {
1046 0 : IF( JB4_checkDtxDropping( h ) )
1047 : {
1048 0 : JB4_dropFromBuffer( h );
1049 : }
1050 : }
1051 348 : ELSE IF( LT_64( W_add( currPlayoutDelay, headRoom ), targetStartUp ) ) /* time stretching */
1052 : {
1053 15 : *stretchTime = true;
1054 15 : move16();
1055 : }
1056 348 : return;
1057 : }
1058 : }
1059 :
1060 : /* adapt while DTX */
1061 915 : h->targetPlayoutDelay = targetDtx;
1062 915 : move32();
1063 :
1064 : /* decided between shrinking/stretching */
1065 915 : IF( GE_64( currPlayoutDelay, W_add( targetDtx, h->frameDuration ) ) ) /* time shrinking */
1066 : {
1067 144 : IF( JB4_checkDtxDropping( h ) )
1068 : {
1069 144 : JB4_dropFromBuffer( h );
1070 : }
1071 : }
1072 771 : ELSE IF( LT_64( W_add( currPlayoutDelay, W_shr( h->frameDuration, 1 ) ), targetDtx ) ) /* time stretching */
1073 : {
1074 120 : *stretchTime = true;
1075 120 : move16();
1076 : }
1077 :
1078 915 : return;
1079 : }
1080 :
1081 :
1082 : /* function to do playout adaptation before playing the first data unit */
1083 228 : static void JB4_adaptFirstPlayout(
1084 : JB4_HANDLE h,
1085 : UWord32 sysTime,
1086 : bool *prebuffer )
1087 : {
1088 : UWord32 currPlayoutDelay;
1089 : JB4_DATAUNIT_HANDLE firstDu;
1090 : UWord32 targetMin, targetMax, targetDtx, targetStartUp;
1091 228 : IF( JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
1092 : {
1093 144 : *prebuffer = true;
1094 144 : move16();
1095 144 : return;
1096 : }
1097 84 : JB4_targetPlayoutDelay( h, &targetMin, &targetMax, &targetDtx, &targetStartUp );
1098 84 : IF( LT_64( targetStartUp, h->frameDuration ) )
1099 : {
1100 0 : return;
1101 : }
1102 : /* calculate delay if first data unit would be played now */
1103 84 : firstDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1104 84 : IF( JB4_playoutDelay( h, sysTime, firstDu->timeStamp, &currPlayoutDelay ) != 0 )
1105 : {
1106 0 : *prebuffer = true;
1107 0 : move16();
1108 0 : return;
1109 : }
1110 84 : IF( LT_64( W_add( currPlayoutDelay, W_shr( h->frameDuration, 1 ) ), targetStartUp ) ) /* time stretching */
1111 : {
1112 56 : *prebuffer = true;
1113 56 : move16();
1114 : }
1115 : ELSE /* no adaptation, start playout */
1116 : {
1117 28 : *prebuffer = false;
1118 28 : move16();
1119 : }
1120 :
1121 84 : return;
1122 : }
1123 :
1124 :
1125 : /* function to look into the buffer and check if it makes sense to drop a data unit */
1126 241 : static Word16 JB4_inspectBufferForDropping(
1127 : const JB4_HANDLE h,
1128 : bool *dropEarly,
1129 : UWord32 *buffered )
1130 : {
1131 : UWord16 inputBufferSize;
1132 : Word32 seqNrDiff;
1133 : Word32 bufferedTs;
1134 : UWord32 firstTs;
1135 : UWord64 beginTs, endTs;
1136 : JB4_DATAUNIT_HANDLE firstDu, secondDu, lastDu;
1137 :
1138 241 : assert( !h->lastPoppedWasSilence );
1139 241 : *dropEarly = false;
1140 241 : move16();
1141 241 : *buffered = 0;
1142 241 : move16();
1143 241 : inputBufferSize = JB4_INPUTBUFFER_Size( h->inputBuffer );
1144 241 : IF( inputBufferSize == 0U )
1145 : {
1146 0 : return -1;
1147 : }
1148 :
1149 241 : firstDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1150 241 : firstTs = firstDu->timeStamp;
1151 241 : move32();
1152 : /* check for loss: sequence number diff is exactly 0 in the valid case */
1153 241 : IF( h->firstDataUnitPopped )
1154 : {
1155 : Word16 temp, exp;
1156 241 : temp = BASOP_Util_Divide3232_Scale( JB4_rtpTimeStampDiff( h->nextExpectedTs, firstTs ), (Word32) ( h->frameDuration ), &exp );
1157 241 : seqNrDiff = L_shl( temp, sub( exp, 15 ) ); // Q0
1158 : }
1159 : ELSE
1160 : {
1161 0 : seqNrDiff = 0;
1162 0 : move32();
1163 : }
1164 241 : IF( seqNrDiff <= 0 )
1165 : {
1166 : /* preview data unit to play after dropping */
1167 231 : IF( LE_32( inputBufferSize, 1U ) )
1168 : {
1169 : /* data unit to play missing, avoid drop followed by concealment */
1170 1 : return -1;
1171 : }
1172 230 : secondDu = JB4_INPUTBUFFER_Element( h->inputBuffer, 1 );
1173 230 : IF( NE_64( W_add( firstTs, h->frameDuration ), secondDu->timeStamp ) )
1174 : {
1175 : /* data unit to play is not available, avoid drop followed by concealment */
1176 8 : return -1;
1177 : }
1178 : /* calculate buffered time span */
1179 222 : bufferedTs = 0;
1180 222 : move32();
1181 : }
1182 10 : ELSE IF( EQ_32( seqNrDiff, 2 ) )
1183 : {
1184 : /* data unit to play is not available, avoid dropping followed by concealment */
1185 5 : return -1;
1186 : }
1187 : ELSE /* seqNoDiff == 1 || seqNoDiff > 2 */
1188 : {
1189 : /* first data unit is not available -> drop it early to avoid concealment
1190 : * This is very aggressive: ignores the maximum drop rate (50% drop and 50% concealment for adjacent lost),
1191 : * but on the other hand, dropping sounds better than concealment. */
1192 5 : *dropEarly = true;
1193 5 : move16();
1194 : /* data unit to drop (first one) is lost */
1195 5 : bufferedTs = 0;
1196 5 : move32();
1197 : }
1198 :
1199 : /* add time stamp difference of last and first actually buffered data unit */
1200 227 : IF( EQ_32( inputBufferSize, 1U ) )
1201 : {
1202 0 : bufferedTs = L_add( bufferedTs, (Word32) h->frameDuration );
1203 : }
1204 : ELSE
1205 : {
1206 227 : lastDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Back( h->inputBuffer );
1207 227 : beginTs = firstTs;
1208 227 : move64();
1209 227 : endTs = W_add( lastDu->timeStamp, h->frameDuration );
1210 : /* check for RTP time stamp wrap around */
1211 227 : if ( LT_64( endTs, beginTs ) )
1212 : {
1213 0 : endTs = W_add( endTs, 0xFFFFFFFF );
1214 : }
1215 227 : bufferedTs = L_add( bufferedTs, W_extract_l( W_sub( endTs, beginTs ) ) );
1216 : }
1217 :
1218 : /* the result should not be negative */
1219 227 : IF( bufferedTs < 0 )
1220 : {
1221 0 : return -1;
1222 : }
1223 227 : *buffered = bufferedTs;
1224 227 : move32();
1225 :
1226 227 : return 0;
1227 : }
1228 :
1229 :
1230 : /* function to look into the buffer and check if it makes sense to drop a data unit */
1231 144 : static Word16 JB4_checkDtxDropping(
1232 : const JB4_HANDLE h )
1233 : {
1234 : UWord16 inputBufferSize;
1235 : Word32 seqNrDiff;
1236 : JB4_DATAUNIT_HANDLE firstDu;
1237 : Word16 droppingAllowed;
1238 :
1239 144 : assert( h->firstDataUnitPopped );
1240 144 : assert( h->lastPoppedWasSilence );
1241 :
1242 144 : droppingAllowed = 1;
1243 144 : move16();
1244 144 : inputBufferSize = JB4_INPUTBUFFER_Size( h->inputBuffer );
1245 144 : IF( inputBufferSize > 0U )
1246 : {
1247 131 : firstDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1248 : /* check for loss: sequence number diff is exactly 0 in the valid case */
1249 : Word16 temp, exp;
1250 131 : temp = BASOP_Util_Divide3232_Scale( JB4_rtpTimeStampDiff( h->nextExpectedTs, firstDu->timeStamp ),
1251 131 : (Word32) ( h->frameDuration ), &exp );
1252 131 : seqNrDiff = L_shl( temp, sub( exp, 15 ) ); // Q0
1253 131 : if ( seqNrDiff <= 0 )
1254 : {
1255 : /* no not drop first active frame */
1256 0 : droppingAllowed = 0;
1257 0 : move16();
1258 : }
1259 : }
1260 : /* else: buffer empty, allow dropping FRAME_NO_DATA */
1261 :
1262 144 : return droppingAllowed;
1263 : }
1264 :
1265 :
1266 : /* function to estimate the short term jitter */
1267 17683 : static void JB4_estimateShortTermJitter(
1268 : JB4_HANDLE h,
1269 : const UWord32 rcvTime,
1270 : const UWord32 rtpTimeStamp )
1271 : {
1272 : UWord32 jitter, duration, maxDuration;
1273 : Word32 minTime, maxTime;
1274 : JB4_CIRCULARBUFFER_ELEMENT maxElement, dequedElement;
1275 :
1276 17683 : jitter = 0;
1277 17683 : move32();
1278 17683 : JB4_JMF_PushPacket( h->stJmf, rcvTime, rtpTimeStamp );
1279 : /* save delta delay */
1280 17683 : IF( JB4_JMF_Jitter( h->stJmf, &jitter ) == 0 )
1281 : {
1282 : /* compensate difference between both offsets */
1283 : Word32 stOffset, ltOffset;
1284 17627 : JB4_JMF_MinOffset( h->stJmf, &stOffset );
1285 17627 : JB4_JMF_MinOffset( h->ltJmf, <Offset );
1286 17627 : jitter = (UWord32) W_add( jitter, W_sub( stOffset, ltOffset ) );
1287 17627 : assert( (Word16) jitter >= 0 );
1288 17627 : IF( JB4_CIRCULARBUFFER_IsFull( h->stJitterFifo ) )
1289 : {
1290 802 : JB4_CIRCULARBUFFER_Deque( h->stJitterFifo, &dequedElement );
1291 802 : JB4_CIRCULARBUFFER_Deque( h->stTimeStampFifo, &dequedElement );
1292 : }
1293 17627 : JB4_CIRCULARBUFFER_Enque( h->stJitterFifo, jitter );
1294 17627 : JB4_CIRCULARBUFFER_Enque( h->stTimeStampFifo, rtpTimeStamp );
1295 :
1296 : /* check for duration and discard first entries if too long */
1297 17627 : minTime = JB4_CIRCULARBUFFER_Front( h->stTimeStampFifo );
1298 17627 : maxTime = JB4_CIRCULARBUFFER_Back( h->stTimeStampFifo );
1299 17627 : IF( GT_32( maxTime, minTime ) )
1300 : {
1301 17599 : duration = (UWord32) W_sub( maxTime, minTime );
1302 17599 : maxDuration = (UWord32) W_shl( h->timeScale, 2 );
1303 29672 : WHILE( duration > maxDuration )
1304 : {
1305 12073 : JB4_CIRCULARBUFFER_Deque( h->stJitterFifo, &dequedElement );
1306 12073 : JB4_CIRCULARBUFFER_Deque( h->stTimeStampFifo, &dequedElement );
1307 12073 : minTime = JB4_CIRCULARBUFFER_Front( h->stTimeStampFifo );
1308 12073 : IF( LE_32( maxTime, minTime ) )
1309 : {
1310 0 : BREAK;
1311 : }
1312 12073 : duration = (UWord32) W_sub( maxTime, minTime );
1313 : }
1314 : }
1315 : }
1316 :
1317 : /* update h->stJitter */
1318 17683 : IF( !JB4_CIRCULARBUFFER_IsEmpty( h->stJitterFifo ) )
1319 : {
1320 17627 : JB4_CIRCULARBUFFER_Max( h->stJitterFifo, &maxElement );
1321 : /* round up to full frame duration */
1322 : Word16 exp;
1323 : Word32 temp;
1324 17627 : temp = BASOP_Util_Divide3232_Scale( maxElement, (Word32) h->frameDuration, &exp );
1325 17627 : IF( exp < 0 )
1326 : {
1327 0 : temp = L_shl( temp, exp ); // Q31
1328 0 : exp = 0;
1329 0 : move16();
1330 : }
1331 17627 : IF( temp != 0 )
1332 : {
1333 17459 : temp = L_shr( ceil_fixed( temp, sub( 15, exp ) ), sub( 15, exp ) ); // Q31
1334 : }
1335 17627 : h->stJitter = (UWord32) W_mult0_32_32( temp, h->frameDuration );
1336 17627 : move32();
1337 : }
1338 :
1339 17683 : return;
1340 : }
1341 :
1342 :
1343 : /* function to pop a data unit from the buffer */
1344 19416 : static void JB4_popFromBuffer(
1345 : JB4_HANDLE h,
1346 : const UWord32 sysTime,
1347 : JB4_DATAUNIT_HANDLE *pDataUnit )
1348 : {
1349 : JB4_DATAUNIT_HANDLE nextDataUnit;
1350 : UWord32 nStretched;
1351 : Word32 tsDiff;
1352 : JB4_DATAUNIT_HANDLE tempDataUnit;
1353 : UWord16 readlen;
1354 : UWord16 i;
1355 : Word16 frameoffset;
1356 : UWord32 maxval;
1357 : Word32 lost, total_rec;
1358 : JB4_DATAUNIT_HANDLE partialCopyDu;
1359 : UWord16 searchpos, endpos;
1360 :
1361 : /* check if a data unit is available */
1362 19416 : IF( JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
1363 : {
1364 : /* no data unit available */
1365 646 : *pDataUnit = NULL;
1366 646 : h->nextExpectedTs = (UWord32) W_add( h->nextExpectedTs, h->frameDuration );
1367 646 : move32();
1368 646 : IF( h->lastPoppedWasSilence )
1369 : {
1370 519 : h->nComfortNoice = (UWord32) W_add( h->nComfortNoice, 1 );
1371 519 : move32();
1372 : }
1373 : ELSE
1374 : {
1375 127 : h->nUnavailablePopped = (UWord32) W_add( h->nUnavailablePopped, 1 );
1376 127 : h->nLostOrStretched = (UWord32) W_add( h->nLostOrStretched, 1 );
1377 127 : move32();
1378 127 : move32();
1379 : }
1380 :
1381 646 : return;
1382 : }
1383 :
1384 : /* preview next data unit in sequence order */
1385 18770 : nextDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1386 :
1387 : /* check if this is the first data unit */
1388 18770 : IF( !h->firstDataUnitPopped )
1389 : {
1390 28 : h->firstDataUnitPopped = true;
1391 : /* adjust sequence numbers to avoid handling first packet as loss */
1392 28 : h->nextExpectedTs = nextDataUnit->timeStamp;
1393 28 : move16();
1394 28 : move32();
1395 : }
1396 :
1397 : /* check if the next available data unit should already be used (time stamp order) */
1398 18770 : tsDiff = JB4_rtpTimeStampDiff( nextDataUnit->timeStamp, h->nextExpectedTs );
1399 :
1400 18770 : h->totWin = (UWord32) W_add( h->totWin, 1 );
1401 18770 : move32();
1402 18770 : test();
1403 18770 : IF( GT_64( h->totWin, 3000 ) || GT_64( h->FecOffWinLen, 100 ) )
1404 : {
1405 2 : maxval = h->FecOffWin[1];
1406 2 : move16();
1407 2 : h->optimum_offset = 1;
1408 2 : move16();
1409 18 : FOR( i = 2; i < MAXOFFSET; i++ )
1410 : {
1411 16 : IF( GT_64( h->FecOffWin[i], maxval ) )
1412 : {
1413 1 : maxval = h->FecOffWin[i];
1414 1 : move16();
1415 1 : h->optimum_offset = i;
1416 1 : move32();
1417 : }
1418 16 : h->FecOffWin[i] = 0;
1419 16 : move32();
1420 : }
1421 2 : h->FecOffWin[0] = 0;
1422 2 : move32();
1423 2 : h->FecOffWin[1] = 0;
1424 2 : move32();
1425 2 : h->totWin = 0;
1426 2 : move32();
1427 2 : h->FecOffWinLen = 0;
1428 2 : move32();
1429 :
1430 :
1431 2 : lost = W_extract_l( W_add( h->nLost, W_sub( h->nPartialCopiesUsed, h->last_nLost ) ) );
1432 2 : total_rec = W_extract_l( W_add( h->nAvailablePopped, W_sub( h->nUnavailablePopped, h->last_ntot ) ) );
1433 :
1434 2 : test();
1435 2 : IF( lost != 0 && total_rec != 0 )
1436 : {
1437 1 : h->netLossRate_fx = divide3232( lost, total_rec ); // Q15
1438 : }
1439 : ELSE
1440 : {
1441 1 : h->netLossRate_fx = 0;
1442 : }
1443 2 : move32();
1444 2 : h->last_nLost = L_add( h->nLost, h->nPartialCopiesUsed );
1445 2 : h->last_ntot = L_add( h->nAvailablePopped, h->nUnavailablePopped );
1446 2 : move32();
1447 2 : move32();
1448 : }
1449 :
1450 18770 : IF( tsDiff < 0 )
1451 : {
1452 1113 : readlen = JB4_INPUTBUFFER_Size( h->inputBuffer );
1453 5275 : FOR( i = 0; i < readlen; i++ )
1454 : {
1455 4162 : tempDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Element( h->inputBuffer, i );
1456 4162 : test();
1457 4162 : IF( !tempDataUnit->partial_frame && !h->lastPoppedWasSilence )
1458 : {
1459 3608 : frameoffset = extract_l( Mult_32_32( JB4_rtpTimeStampDiff( h->nextExpectedTs, tempDataUnit->timeStamp ), INV_20_Q31 ) );
1460 3608 : test();
1461 3608 : IF( frameoffset > 0 && LT_16( frameoffset, MAXOFFSET ) )
1462 : {
1463 3608 : h->FecOffWin[frameoffset] = (UWord32) ( W_add( h->FecOffWin[frameoffset], 1 ) );
1464 3608 : move32();
1465 : }
1466 : }
1467 : }
1468 1113 : h->FecOffWinLen = (UWord32) W_add( h->FecOffWinLen, 1 );
1469 1113 : move32();
1470 :
1471 : /* next expected data unit is missing
1472 : * -> conceal network loss, do time stretching or create comfort noise */
1473 1113 : *pDataUnit = NULL;
1474 :
1475 : /* update statistics */
1476 1113 : h->nextExpectedTs = (UWord32) W_add( h->nextExpectedTs, h->frameDuration );
1477 1113 : move32();
1478 1113 : IF( h->lastPoppedWasSilence )
1479 : {
1480 350 : h->nComfortNoice = (UWord32) W_add( h->nComfortNoice, 1 );
1481 350 : move32();
1482 : }
1483 : ELSE
1484 : {
1485 763 : h->nUnavailablePopped = (UWord32) W_add( h->nUnavailablePopped, 1 );
1486 763 : h->nLostOrStretched = (UWord32) W_add( h->nLostOrStretched, 1 );
1487 763 : move32();
1488 763 : move32();
1489 : }
1490 1113 : return;
1491 : }
1492 :
1493 : /* fetch the next data unit from buffer */
1494 17657 : *pDataUnit = nextDataUnit;
1495 17657 : nextDataUnit->nextCoderType = INACTIVE;
1496 17657 : move16();
1497 17657 : test();
1498 17657 : IF( h->pre_partial_frame || nextDataUnit->partial_frame )
1499 : {
1500 0 : IF( nextDataUnit->partial_frame )
1501 : {
1502 0 : h->pre_partial_frame = 1;
1503 0 : move16();
1504 : }
1505 0 : ELSE IF( h->pre_partial_frame )
1506 : {
1507 0 : h->pre_partial_frame = 0;
1508 0 : move16();
1509 : }
1510 :
1511 0 : endpos = JB4_INPUTBUFFER_Size( h->inputBuffer );
1512 0 : FOR( searchpos = 0; searchpos < endpos; searchpos++ )
1513 : {
1514 0 : partialCopyDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Element( h->inputBuffer, searchpos );
1515 0 : IF( EQ_64( partialCopyDu->timeStamp, W_add( nextDataUnit->timeStamp, partialCopyDu->duration ) ) )
1516 : {
1517 0 : get_NextCoderType_fx( partialCopyDu->data, &nextDataUnit->nextCoderType );
1518 0 : BREAK;
1519 : }
1520 : }
1521 : }
1522 17657 : JB4_INPUTBUFFER_Deque( h->inputBuffer, (void **) pDataUnit );
1523 :
1524 17657 : IF( nextDataUnit->partial_frame )
1525 : {
1526 0 : h->nPartialCopiesUsed = L_add( h->nPartialCopiesUsed, 1 );
1527 0 : move32();
1528 :
1529 0 : readlen = JB4_INPUTBUFFER_Size( h->inputBuffer );
1530 0 : FOR( i = 0; i < readlen; i++ )
1531 : {
1532 0 : tempDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Element( h->inputBuffer, i );
1533 0 : test();
1534 0 : IF( !tempDataUnit->partial_frame && !h->lastPoppedWasSilence )
1535 : {
1536 0 : frameoffset = extract_l( Mult_32_32( JB4_rtpTimeStampDiff( h->nextExpectedTs, tempDataUnit->timeStamp ), INV_20_Q31 ) ); // Q0
1537 0 : test();
1538 0 : IF( ( frameoffset > 0 ) && LT_16( frameoffset, MAXOFFSET ) )
1539 : {
1540 0 : h->FecOffWin[frameoffset] = (UWord32) W_add( h->FecOffWin[frameoffset], 1 );
1541 0 : move32();
1542 : }
1543 : }
1544 : }
1545 0 : h->FecOffWinLen = (UWord32) W_add( h->FecOffWinLen, 1 );
1546 0 : move32();
1547 : }
1548 :
1549 : /* update statistics */
1550 17657 : IF( h->nLostOrStretched != 0U )
1551 : {
1552 464 : assert( h->lastPoppedWasSilence == false );
1553 : /* separate concealments since last available pop in lost and stretched */
1554 : Word16 exp;
1555 464 : nStretched = BASOP_Util_Divide3232_Scale( tsDiff, h->frameDuration, &exp );
1556 464 : nStretched = (UWord32) W_shr( nStretched, sub( 15, exp ) ); // Q0
1557 464 : assert( h->nLostOrStretched >= nStretched );
1558 464 : h->nLost = (UWord32) W_add( h->nLost, W_sub( h->nLostOrStretched, nStretched ) );
1559 : /* jitter-induced insertion (e.g. buffer underflow) */
1560 464 : h->jitterInducedConcealments = (UWord32) W_add( h->jitterInducedConcealments, nStretched );
1561 464 : h->nStretched = (UWord32) W_add( h->nStretched, nStretched );
1562 464 : h->nLostOrStretched = 0;
1563 464 : move32();
1564 464 : move32();
1565 464 : move32();
1566 464 : move32();
1567 : }
1568 17657 : h->lastReturnedTs = nextDataUnit->timeStamp;
1569 17657 : move32();
1570 17657 : JB4_updateLastTimingMembers( h, sysTime, nextDataUnit->timeStamp );
1571 17657 : h->nextExpectedTs = (UWord32) W_add( nextDataUnit->timeStamp, h->frameDuration );
1572 17657 : move32();
1573 17657 : IF( nextDataUnit->silenceIndicator )
1574 : {
1575 263 : h->lastPoppedWasSilence = true;
1576 263 : move16();
1577 263 : h->nComfortNoice = (UWord32) W_add( h->nComfortNoice, 1 );
1578 263 : move32();
1579 : }
1580 : ELSE
1581 : {
1582 17394 : h->lastPoppedWasSilence = false;
1583 17394 : move16();
1584 17394 : h->nAvailablePopped = (UWord32) W_add( h->nAvailablePopped, 1 );
1585 17394 : move32();
1586 : }
1587 :
1588 17657 : return;
1589 : }
1590 :
1591 : /* function to drop a data unit from the buffer - updates nShrinked */
1592 173 : static void JB4_dropFromBuffer(
1593 : JB4_HANDLE h )
1594 : {
1595 : JB4_DATAUNIT_HANDLE nextDataUnit, dataUnit;
1596 : Word32 tsDiff;
1597 : UWord32 nStretched;
1598 :
1599 : /* check if a data unit is available */
1600 173 : IF( JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
1601 : {
1602 13 : return;
1603 : }
1604 : /* preview next data unit in sequence order */
1605 160 : nextDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1606 :
1607 : /* check if this is the first data unit */
1608 160 : IF( !h->firstDataUnitPopped )
1609 : {
1610 0 : h->firstDataUnitPopped = true;
1611 0 : move16();
1612 : /* adjust sequence numbers to avoid handling first packet as loss */
1613 0 : h->nextExpectedTs = nextDataUnit->timeStamp;
1614 0 : move32();
1615 : }
1616 :
1617 : /* check if the next available data unit should already be used (time stamp order) */
1618 160 : tsDiff = JB4_rtpTimeStampDiff( nextDataUnit->timeStamp, h->nextExpectedTs );
1619 160 : IF( tsDiff < 0 )
1620 : {
1621 : /* next expected data unit is missing, remember this data unit as popped,
1622 : * but do not count it as lost, because it will not be concealed */
1623 134 : h->nextExpectedTs = (UWord32) W_add( h->nextExpectedTs, h->frameDuration );
1624 134 : move32();
1625 : /* substract one frame from last playout delay */
1626 134 : h->lastPlayoutOffset = (UWord32) W_sub( h->lastPlayoutOffset, h->frameDuration );
1627 134 : move32();
1628 134 : IF( !h->lastPoppedWasSilence )
1629 : {
1630 3 : h->nShrinked = (UWord32) W_add( h->nShrinked, 1 );
1631 : /* modification of the output timeline due to link loss */
1632 3 : h->nUnavailablePopped = (UWord32) W_add( h->nUnavailablePopped, 1 );
1633 3 : h->nLostOrStretched = (UWord32) W_add( h->nLostOrStretched, 1 );
1634 3 : move32();
1635 3 : move32();
1636 3 : move32();
1637 : }
1638 134 : IF( h->lastTargetTime != 0U )
1639 : {
1640 134 : h->lastTargetTime = (UWord32) W_add( h->lastTargetTime, h->frameDuration );
1641 134 : move32();
1642 : }
1643 134 : return;
1644 : }
1645 :
1646 : /* fetch the next data unit from buffer */
1647 26 : JB4_INPUTBUFFER_Deque( h->inputBuffer, (void *) &dataUnit );
1648 : /* update statistics */
1649 26 : IF( h->nLostOrStretched != 0U )
1650 : {
1651 26 : assert( h->lastPoppedWasSilence == false );
1652 : /* separate concealments since last available pop in lost and stretched */
1653 : Word16 exp;
1654 26 : nStretched = BASOP_Util_Divide3232_Scale( tsDiff, (Word32) h->frameDuration, &exp );
1655 26 : nStretched = (UWord32) W_shr( nStretched, sub( 15, exp ) ); // Q0
1656 26 : assert( h->nLostOrStretched >= nStretched );
1657 :
1658 : /* convert stretching followed by shrinking to late-loss */
1659 26 : IF( nStretched > 0U )
1660 : {
1661 26 : nStretched = (UWord32) W_sub( nStretched, 1 );
1662 26 : h->nLateLost = (UWord32) W_add( h->nLateLost, 1 );
1663 26 : h->nLost = (UWord32) W_add( h->nLost, W_sub( h->nLostOrStretched, nStretched ) );
1664 : /* jitter-induced insertion (e.g. buffer underflow) */
1665 26 : h->jitterInducedConcealments = (UWord32) W_add( h->jitterInducedConcealments, nStretched );
1666 26 : move32();
1667 26 : move32();
1668 26 : move32();
1669 26 : IF( !dataUnit->silenceIndicator )
1670 : {
1671 : /* JBM induced removal of a speech frame (intentional frame dropping) */
1672 26 : h->jitterInducedConcealments = (UWord32) W_add( h->jitterInducedConcealments, 1 );
1673 26 : move32();
1674 : }
1675 26 : h->nStretched = (UWord32) W_add( h->nStretched, nStretched );
1676 26 : move32();
1677 : }
1678 : ELSE
1679 : {
1680 0 : h->nLost = (UWord32) W_add( h->nLost, h->nLostOrStretched );
1681 0 : h->nShrinked = (UWord32) W_add( h->nShrinked, 1 );
1682 0 : move32();
1683 0 : move32();
1684 0 : IF( !dataUnit->silenceIndicator )
1685 : {
1686 : /* JBM induced removal of a speech frame (intentional frame dropping) */
1687 0 : h->jitterInducedConcealments = (UWord32) W_add( h->jitterInducedConcealments, 1 );
1688 0 : move32();
1689 : }
1690 : }
1691 26 : h->nLostOrStretched = 0;
1692 26 : move32();
1693 : }
1694 : ELSE
1695 : {
1696 0 : IF( !dataUnit->silenceIndicator )
1697 : {
1698 0 : h->nShrinked = (UWord32) W_add( h->nShrinked, 1 );
1699 : /* JBM induced removal of a speech frame (intentional frame dropping) */
1700 0 : h->jitterInducedConcealments = (UWord32) W_add( h->jitterInducedConcealments, 1 );
1701 0 : move32();
1702 0 : move32();
1703 : }
1704 : }
1705 :
1706 26 : h->lastReturnedTs = dataUnit->timeStamp;
1707 26 : move32();
1708 26 : h->lastPoppedWasSilence = dataUnit->silenceIndicator;
1709 26 : move16();
1710 26 : h->nextExpectedTs = (UWord32) W_add( dataUnit->timeStamp, h->frameDuration );
1711 26 : move32();
1712 :
1713 : /* substract one frame from last playout delay */
1714 26 : h->lastPlayoutOffset = L_sub( h->lastPlayoutOffset, (Word32) h->frameDuration );
1715 26 : move32();
1716 26 : IF( h->lastTargetTime != 0U )
1717 : {
1718 26 : h->lastTargetTime = (UWord32) W_add( h->lastTargetTime, h->frameDuration );
1719 26 : move32();
1720 : }
1721 :
1722 26 : JB4_FreeDataUnit( h, dataUnit );
1723 :
1724 26 : return;
1725 : }
1726 :
1727 :
1728 : /* function to calculate the playout delay based on the current jitter */
1729 432 : static Word16 JB4_playoutDelay(
1730 : const JB4_HANDLE h,
1731 : const UWord32 playTime,
1732 : const UWord32 rtpTimeStamp,
1733 : UWord32 *delay )
1734 : {
1735 : Word32 minOffTicks;
1736 :
1737 432 : IF( JB4_JMF_MinOffset( h->ltJmf, &minOffTicks ) != 0 )
1738 : {
1739 0 : return -1;
1740 : }
1741 :
1742 432 : *delay = (UWord32) W_sub( W_sub( playTime, minOffTicks ), rtpTimeStamp );
1743 432 : move32();
1744 :
1745 432 : return 0;
1746 : }
1747 :
1748 :
1749 : /* function to update lastPlayoutDelay and lastTargetTime after popFromBuffer() */
1750 17657 : static void JB4_updateLastTimingMembers(
1751 : JB4_HANDLE h,
1752 : const UWord32 playTime,
1753 : const UWord32 rtpTimeStamp )
1754 : {
1755 : Word32 minOffTicks;
1756 :
1757 17657 : IF( JB4_JMF_MinOffset( h->ltJmf, &minOffTicks ) != 0 )
1758 : {
1759 0 : return;
1760 : }
1761 :
1762 : /* playoutDelay = playTime - minOffset - timeStamp */
1763 17657 : h->lastPlayoutOffset = (UWord32) W_sub( playTime, rtpTimeStamp );
1764 17657 : move32();
1765 : /* targetTime = minOffset + timeStamp + targetDelay */
1766 17657 : h->lastTargetTime = (UWord32) ( W_add( minOffTicks, W_add( rtpTimeStamp, h->targetPlayoutDelay ) ) );
1767 17657 : move32();
1768 :
1769 17657 : return;
1770 : }
1771 :
1772 :
1773 : /* function to compare the RTP time stamps of two data units: newElement==arrayElement ? 0 : (newElement>arrayElement ? +1 : -1) */
1774 17125 : static Word16 JB4_inputBufferCompareFunction(
1775 : const JB4_INPUTBUFFER_ELEMENT newElement,
1776 : const JB4_INPUTBUFFER_ELEMENT arrayElement,
1777 : bool *replaceWithNewElementIfEqual )
1778 : {
1779 : JB4_DATAUNIT_HANDLE newDataUnit, arrayDataUnit;
1780 : Word32 diff;
1781 : Word16 result;
1782 :
1783 17125 : *replaceWithNewElementIfEqual = 0;
1784 17125 : move16();
1785 17125 : newDataUnit = (JB4_DATAUNIT_HANDLE) newElement;
1786 17125 : arrayDataUnit = (JB4_DATAUNIT_HANDLE) arrayElement;
1787 17125 : diff = JB4_rtpTimeStampDiff( arrayDataUnit->timeStamp, newDataUnit->timeStamp );
1788 17125 : IF( diff > 0 )
1789 : {
1790 17125 : result = 1;
1791 17125 : move16();
1792 : }
1793 0 : ELSE IF( diff < 0 )
1794 : {
1795 0 : result = -1;
1796 0 : move16();
1797 : }
1798 : ELSE /* equal timestamps */
1799 : {
1800 0 : result = 0;
1801 0 : move16();
1802 0 : test();
1803 0 : test();
1804 0 : IF( newDataUnit->partial_frame == 0 && EQ_16( arrayDataUnit->partial_frame, 1 ) )
1805 : {
1806 : /* replace partial copy with primary copy */
1807 0 : *replaceWithNewElementIfEqual = 1;
1808 0 : move16();
1809 : }
1810 0 : ELSE IF( EQ_16( newDataUnit->partial_frame, arrayDataUnit->partial_frame ) && GT_32( newDataUnit->dataSize, arrayDataUnit->dataSize ) )
1811 : {
1812 : /* if both are primary or partial: take the one with higher size (e.g. higher bitrate) */
1813 0 : *replaceWithNewElementIfEqual = 1;
1814 0 : move16();
1815 : }
1816 : }
1817 :
1818 17125 : return result;
1819 : }
1820 :
1821 : #undef WMC_TOOL_SKIP
|