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