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