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 : #ifdef DEBUGGING
46 : #include "debug.h"
47 : #endif
48 : #include "wmc_auto.h"
49 : /* local headers */
50 : #include "jbm_jb4_circularbuffer.h"
51 : #include "jbm_jb4_inputbuffer.h"
52 : #include "jbm_jb4_jmf.h"
53 : #include "jbm_jb4sb.h"
54 : #include "prot.h"
55 :
56 : #define WMC_TOOL_SKIP
57 :
58 : #define JB4_MIN( a, b ) ( ( a ) > ( b ) ? ( b ) : ( a ) )
59 : #define JB4_MAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
60 :
61 : #define MAXOFFSET 10
62 :
63 : /*! Calculates the difference between two RTP timestamps - the diff is positive, if B 'later', negative otherwise */
64 : static int32_t JB4_rtpTimeStampDiff( const uint32_t tsA, const uint32_t tsB );
65 : /* function to calculate different options for the target playout delay */
66 : static void JB4_targetPlayoutDelay( const JB4_HANDLE h, uint32_t *targetMin, uint32_t *targetMax, uint32_t *targetDtx, uint32_t *targetStartUp );
67 : /*! function to do playout adaptation before playing the next data unit */
68 : /*! In case of time shrinking, data units will be dropped before the next data unit to play is returned and
69 : * in case of time stretching a empty data unit is returned and the frame should be concealed.
70 : * @param[in] now current system time
71 : * @param[out] dataUnit the next data unit to play
72 : * @param[out] scale the scale in percent used as target for time scaling of the returned data unit
73 : * @param[out] maxScaling the maximum allowed external time scaling */
74 : static int16_t JB4_adaptPlayout( JB4_HANDLE h, uint32_t sysTime, uint32_t extBufferedTime, JB4_DATAUNIT_HANDLE *pDataUnit, uint32_t *scale, uint32_t *maxScaling );
75 : /*! function to do playout adaptation before playing the first data unit */
76 : /*! @param[in] now current system time
77 : * @param[out] prebuffer true, if the data unit should be prebuffered */
78 : static void JB4_adaptFirstPlayout( JB4_HANDLE h, uint32_t sysTime, bool *prebuffer );
79 : /*! function for playout adaptation while active (no DTX) */
80 : static void JB4_adaptActivePlayout( JB4_HANDLE h, uint32_t extBufferedTime, uint32_t *scale, uint32_t *maxScaling );
81 : /*! function for playout adaptation while DTX */
82 : static void JB4_adaptDtxPlayout( JB4_HANDLE h, uint32_t sysTime, bool *stretchTime );
83 : /*! function to look into the buffer and check if it makes sense to drop a data unit */
84 : /*! @param[out] dropEarly true, if a data unit could be dropped early
85 : * @param[out] buffered the buffered time span in timeScale units
86 : * @return true, if a data unit could be dropped */
87 : static int16_t JB4_inspectBufferForDropping( const JB4_HANDLE h, bool *dropEarly, uint32_t *buffered );
88 : /* function to look into the buffer and check if it makes sense to drop a data unit during DTX */
89 : static int16_t JB4_checkDtxDropping( const JB4_HANDLE h );
90 : /*! function to estimate the short term jitter */
91 : static void JB4_estimateShortTermJitter( JB4_HANDLE h, const uint32_t rcvTime, const uint32_t rtpTimeStamp );
92 : /*! function to pop a data unit from the buffer */
93 : static void JB4_popFromBuffer( JB4_HANDLE h, const uint32_t sysTime, JB4_DATAUNIT_HANDLE *pDataUnit );
94 : /*! function to drop a data unit from the buffer - updates nShrinked */
95 : static void JB4_dropFromBuffer( JB4_HANDLE h );
96 : /*! function to calculate the playout delay based on the current jitter */
97 : /*! @param[in] playTime the system time when the data unit will be played
98 : * @param[in] timeStamp the time stamp of the data unit to played
99 : * @param[out] delay the calculated playout delay */
100 : static int16_t JB4_playoutDelay( const JB4_HANDLE h, const uint32_t playTime, const uint32_t rtpTimeStamp, uint32_t *delay );
101 : /*! function to update lastPlayoutDelay and lastTargetTime after popFromBuffer() */
102 : static void JB4_updateLastTimingMembers( JB4_HANDLE h, const uint32_t playTime, const uint32_t rtpTimeStamp );
103 : /*! function to compare the RTP time stamps of two data units: newElement==arrayElement ? 0 : (newElement>arrayElement ? +1 : -1) */
104 : static int16_t JB4_inputBufferCompareFunction( const JB4_INPUTBUFFER_ELEMENT newElement, const JB4_INPUTBUFFER_ELEMENT arrayElement, bool *replaceWithNewElementIfEqual );
105 :
106 :
107 : /*! Jitter Buffer Management Interface */
108 : struct JB4
109 : {
110 : /*! @name statistics for user */
111 : /*@{ */
112 : /*! the number of late lost data units */
113 : uint32_t nLateLost;
114 : /*! the number of data units that were available (not NULL) at playout time */
115 : uint32_t nAvailablePopped;
116 : /*! the number of data units that were not available (NULL) at playout time */
117 : uint32_t nUnavailablePopped;
118 : /*! the number of unavailable pops since the last available one - used as temp value for nLost and nStretched */
119 : uint32_t nLostOrStretched;
120 : /*! the number of data units that were lost at playout time */
121 : uint32_t nLost;
122 : /*! the number of empty data units inserted for playout adaptation */
123 : uint32_t nStretched;
124 : /*! the number of data units dropped for playout adaptation */
125 : /*! This function counts all time shrinking events, no matter if a dropped data unit was actually available. */
126 : uint32_t nShrinked;
127 : /*! the number of data units that were returned to create comfort noice (including NULL) */
128 : uint32_t nComfortNoice;
129 : /*! the number of jitter induced concealment operations (as defined in 3GPP TS 26.114) */
130 : uint32_t jitterInducedConcealments;
131 : /*! the target playout delay of the last returned data unit */
132 : uint32_t targetPlayoutDelay;
133 : /*! the target playout time of the last returned data unit */
134 : uint32_t lastTargetTime;
135 : /*@} */
136 : /*! @name internal configuration values - do not change!!! */
137 : /*@{ */
138 : /*! internal time scale for all calculations */
139 : int16_t timeScale;
140 : /*! internal frame duration in timeScale units */
141 : uint32_t frameDuration;
142 : /*@} */
143 : /*! @name jitter buffer configuration values */
144 : /*@{ */
145 : /*! the allowed delay reserve in addition to network jitter to reduce late-loss [milliseconds] */
146 : int16_t safetyMargin;
147 : /*@} */
148 : /*! @name data for short term jitter estimation */
149 : /*@{ */
150 : /*! short term jitter measure FIFO */
151 : JB4_JMF_HANDLE stJmf;
152 : /*! FIFO of short term jitter values */
153 : JB4_CIRCULARBUFFER_HANDLE stJitterFifo;
154 : /*! FIFO of RTP time stamps for the values stored in stJitterFifo */
155 : JB4_CIRCULARBUFFER_HANDLE stTimeStampFifo;
156 : /*! short term jitter */
157 : uint32_t stJitter;
158 : /*@} */
159 : /*! @name jitter buffer data */
160 : /*@{ */
161 : /*! true, if a data unit was already popped from the buffer */
162 : bool firstDataUnitPopped;
163 : /*! system time of the previous JB4_PopDataUnit() call */
164 : uint32_t prevPopSysTime;
165 : /*! RTP timestamp of the last played/dropped data unit that was actually available */
166 : uint32_t lastReturnedTs;
167 : /*! true, if the last popped data unit contained no active signal, i.e. silence -> hint for DTX */
168 : bool lastPoppedWasSilence;
169 : /*! the playout time minus the minimum offset of the last played data unit in microseconds */
170 : int32_t lastPlayoutOffset;
171 : /*! RTP time stamp of the next data unit that is expected to be fetched from the buffer */
172 : uint32_t nextExpectedTs;
173 : Word16 rfOffset2Active;
174 : Word16 rfOffset3Active;
175 : Word16 rfOffset5Active;
176 : Word16 rfOffset7Active;
177 : Word32 rfDelay;
178 : /*! long term jitter measure FIFO */
179 : JB4_JMF_HANDLE ltJmf;
180 :
181 : uint32_t FecOffWinLen;
182 : uint32_t FecOffWin[10];
183 : uint32_t optimum_offset;
184 :
185 : float netLossRate;
186 : Word32 nPartialCopiesUsed;
187 : Word32 last_nLost;
188 : Word32 last_ntot;
189 :
190 : uint32_t totWin;
191 : bool pre_partial_frame;
192 : /*@} */
193 :
194 : /*! @name members to store the data units */
195 : /*@{ */
196 : /*! the data unit buffer */
197 : JB4_INPUTBUFFER_HANDLE inputBuffer;
198 : struct JB4_DATAUNIT memorySlots[MAX_JBM_SLOTS];
199 : JB4_DATAUNIT_HANDLE freeMemorySlots[MAX_JBM_SLOTS];
200 : uint16_t nFreeMemorySlots;
201 : /*@} */
202 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
203 : bool evsMode;
204 : #endif
205 : }; /* JB4 */
206 :
207 :
208 105 : ivas_error JB4_Create(
209 : JB4_HANDLE *ph )
210 : {
211 : int16_t iter;
212 : JB4_HANDLE h;
213 : ivas_error error;
214 :
215 105 : if ( ( h = malloc( sizeof( struct JB4 ) ) ) == NULL )
216 : {
217 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JB4 structure\n" ) );
218 : }
219 :
220 : /* statistics for user */
221 105 : h->nLateLost = 0;
222 105 : h->nAvailablePopped = 0;
223 105 : h->nUnavailablePopped = 0;
224 105 : h->nLostOrStretched = 0;
225 105 : h->nLost = 0;
226 105 : h->nStretched = 0;
227 105 : h->nShrinked = 0;
228 105 : h->nComfortNoice = 0;
229 105 : h->jitterInducedConcealments = 0;
230 105 : h->targetPlayoutDelay = 0;
231 105 : h->lastTargetTime = 0;
232 : /* internal configuration values - do not change!!! */
233 105 : h->timeScale = 0;
234 105 : h->frameDuration = 0;
235 :
236 : /* jitter buffer configuration values: done in JB4_Init() */
237 : /* short term jitter evaluation */
238 105 : if ( ( error = JB4_JMF_Create( &h->stJmf ) ) != IVAS_ERR_OK )
239 : {
240 0 : return error;
241 : }
242 105 : if ( ( error = JB4_CIRCULARBUFFER_Create( &h->stJitterFifo ) ) != IVAS_ERR_OK )
243 : {
244 0 : return error;
245 : }
246 105 : if ( ( error = JB4_CIRCULARBUFFER_Create( &h->stTimeStampFifo ) ) != IVAS_ERR_OK )
247 : {
248 0 : return error;
249 : }
250 105 : h->stJitter = 0;
251 :
252 : /* jitter buffer data */
253 105 : h->firstDataUnitPopped = false;
254 105 : h->prevPopSysTime = 0;
255 105 : h->lastReturnedTs = 0;
256 105 : h->lastPoppedWasSilence = false;
257 105 : h->lastPlayoutOffset = 0;
258 105 : h->nextExpectedTs = 0;
259 105 : h->rfOffset2Active = 0;
260 105 : h->rfOffset3Active = 0;
261 105 : h->rfOffset5Active = 0;
262 105 : h->rfOffset7Active = 0;
263 105 : h->rfDelay = 0;
264 105 : JB4_JMF_Create( &h->ltJmf );
265 105 : h->pre_partial_frame = 0;
266 :
267 105 : h->FecOffWinLen = 0;
268 1155 : for ( iter = 0; iter < 10; iter++ )
269 : {
270 1050 : h->FecOffWin[iter] = 0;
271 : }
272 105 : h->optimum_offset = 3;
273 105 : h->totWin = 0;
274 105 : h->netLossRate = 0.0f;
275 105 : move32();
276 105 : h->nPartialCopiesUsed = 0;
277 105 : move32();
278 105 : h->last_nLost = 0;
279 105 : move32();
280 105 : h->last_ntot = 0;
281 105 : move32();
282 :
283 : /* members to store the data units */
284 105 : if ( ( error = JB4_INPUTBUFFER_Create( &h->inputBuffer ) ) != IVAS_ERR_OK )
285 : {
286 0 : return error;
287 : }
288 :
289 : /* allocate memory for data units */
290 10605 : for ( iter = 0; iter < MAX_JBM_SLOTS; ++iter )
291 : {
292 10500 : if ( ( h->memorySlots[iter].data = malloc( MAX_AU_SIZE ) ) == NULL )
293 : {
294 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JB4 structure\n" ) );
295 : }
296 10500 : h->freeMemorySlots[iter] = &h->memorySlots[iter];
297 : }
298 105 : h->nFreeMemorySlots = MAX_JBM_SLOTS;
299 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
300 105 : h->evsMode = false;
301 : #endif
302 105 : *ph = h;
303 :
304 105 : return IVAS_ERR_OK;
305 : }
306 :
307 :
308 105 : void JB4_Destroy(
309 : JB4_HANDLE *ph )
310 : {
311 : JB4_HANDLE h;
312 : uint16_t i;
313 :
314 105 : if ( !ph )
315 : {
316 0 : return;
317 : }
318 105 : h = *ph;
319 105 : if ( !h )
320 : {
321 0 : return;
322 : }
323 :
324 105 : JB4_JMF_Destroy( &h->stJmf );
325 105 : JB4_CIRCULARBUFFER_Destroy( &h->stJitterFifo );
326 105 : JB4_CIRCULARBUFFER_Destroy( &h->stTimeStampFifo );
327 105 : JB4_JMF_Destroy( &h->ltJmf );
328 105 : JB4_INPUTBUFFER_Destroy( &h->inputBuffer );
329 :
330 10605 : for ( i = 0; i < MAX_JBM_SLOTS; ++i )
331 : {
332 10500 : free( h->memorySlots[i].data );
333 : }
334 :
335 105 : free( h );
336 105 : *ph = NULL;
337 :
338 105 : return;
339 : }
340 :
341 :
342 105 : ivas_error JB4_Init(
343 : JB4_HANDLE h,
344 : const int16_t safetyMargin )
345 : {
346 : uint16_t ltJmfSize, stFifoSize, stJmfSize, stJmfAllowedLateLoss;
347 : uint16_t inputBufferCapacity;
348 : ivas_error error;
349 :
350 : /* internal timescale is 1000, frame duration is 20ms */
351 105 : h->timeScale = 1000; /* ms */
352 105 : h->frameDuration = 20; /* ms */
353 :
354 : /* jitter buffer configuration values */
355 105 : h->safetyMargin = safetyMargin;
356 :
357 : /* long term jitter measure FIFO: 500 frames and 10s */
358 105 : ltJmfSize = 10000;
359 105 : JB4_JMF_Init( h->ltJmf, h->timeScale, ltJmfSize / 20, ltJmfSize, 1000 );
360 : /* short term jitter evaluation */
361 105 : stFifoSize = 200;
362 105 : stJmfSize = 50;
363 105 : stJmfAllowedLateLoss = 60; /* 6%, e.g. ignore three packets out of 50 */
364 105 : JB4_CIRCULARBUFFER_Init( h->stJitterFifo, stFifoSize );
365 105 : JB4_CIRCULARBUFFER_Init( h->stTimeStampFifo, stFifoSize );
366 105 : JB4_JMF_Init( h->stJmf, h->timeScale, stJmfSize, h->timeScale /* 1s */, (uint16_t) ( 1000 - stJmfAllowedLateLoss ) );
367 :
368 105 : inputBufferCapacity = MAX_JBM_SLOTS - 2;
369 :
370 105 : if ( ( error = JB4_INPUTBUFFER_Init( h->inputBuffer, inputBufferCapacity, JB4_inputBufferCompareFunction ) ) != IVAS_ERR_OK )
371 : {
372 0 : return error;
373 : }
374 :
375 105 : return IVAS_ERR_OK;
376 : }
377 :
378 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
379 0 : void JB4_TMP_SetEvsCompatFlag( JB4_HANDLE h )
380 : {
381 0 : h->evsMode = true;
382 0 : }
383 : #endif
384 :
385 : /* Returns a memory slot to store a new data unit */
386 69921 : JB4_DATAUNIT_HANDLE JB4_AllocDataUnit(
387 : JB4_HANDLE h )
388 : {
389 : JB4_DATAUNIT_HANDLE dataUnit;
390 69921 : while ( h->nFreeMemorySlots == 0 )
391 : {
392 0 : assert( JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) == 0 );
393 0 : JB4_dropFromBuffer( h );
394 : }
395 :
396 : /* LOCK JBM MEMORY SLOT BEGIN */
397 69921 : --h->nFreeMemorySlots;
398 69921 : dataUnit = h->freeMemorySlots[h->nFreeMemorySlots];
399 69921 : h->freeMemorySlots[h->nFreeMemorySlots] = NULL;
400 : /* LOCK JBM MEMORY SLOT END */
401 69921 : assert( dataUnit != NULL );
402 :
403 69921 : return dataUnit;
404 : }
405 :
406 :
407 : /* Notifies the JBM that a data unit is no longer used and the memory can be reused */
408 69921 : void JB4_FreeDataUnit(
409 : JB4_HANDLE h,
410 : JB4_DATAUNIT_HANDLE dataUnit )
411 : {
412 69921 : assert( dataUnit != NULL );
413 69921 : assert( h->nFreeMemorySlots < MAX_JBM_SLOTS );
414 : /* LOCK JBM MEMORY SLOT BEGIN */
415 69921 : h->freeMemorySlots[h->nFreeMemorySlots] = dataUnit;
416 69921 : h->nFreeMemorySlots++;
417 : /* LOCK JBM MEMORY SLOT END */
418 :
419 69921 : return;
420 : }
421 :
422 :
423 69921 : int16_t JB4_PushDataUnit(
424 : JB4_HANDLE h,
425 : JB4_DATAUNIT_HANDLE dataUnit,
426 : const uint32_t rcvTime )
427 : {
428 69921 : JB4_DATAUNIT_HANDLE droppedDataUnit = NULL;
429 :
430 69921 : assert( dataUnit->duration == h->frameDuration );
431 69921 : assert( dataUnit->timeScale == (uint16_t) h->timeScale );
432 :
433 : /* ignore frames from too far in future (3 seconds) */
434 69921 : if ( h->firstDataUnitPopped && JB4_rtpTimeStampDiff( h->lastReturnedTs, dataUnit->timeStamp ) >=
435 69501 : (int32_t) ( 50 * 3 * dataUnit->duration ) )
436 : {
437 0 : JB4_FreeDataUnit( h, dataUnit );
438 0 : return 0;
439 : }
440 :
441 : /* reserve space for one element to add: drop oldest if buffer is full */
442 69921 : while ( JB4_INPUTBUFFER_IsFull( h->inputBuffer ) )
443 : {
444 0 : JB4_dropFromBuffer( h );
445 : }
446 69921 : assert( JB4_INPUTBUFFER_IsFull( h->inputBuffer ) == 0 );
447 :
448 : /* do statistics on partial copy offset using active primary copies to
449 : * avoid unexpected resets because RF_NO_DATA partial copies are dropped before JBM */
450 69921 : if ( dataUnit->silenceIndicator == 0 && dataUnit->partial_frame == 0 )
451 : {
452 69117 : if ( dataUnit->partialCopyOffset == 0 )
453 : {
454 69117 : if ( h->rfOffset2Active > 0 )
455 0 : --h->rfOffset2Active;
456 69117 : if ( h->rfOffset3Active > 0 )
457 0 : --h->rfOffset3Active;
458 69117 : if ( h->rfOffset5Active > 0 )
459 0 : --h->rfOffset5Active;
460 69117 : if ( h->rfOffset7Active > 0 )
461 0 : --h->rfOffset7Active;
462 : }
463 0 : else if ( dataUnit->partialCopyOffset == 2 )
464 : {
465 0 : h->rfOffset2Active = 100;
466 0 : h->rfOffset3Active = 0;
467 0 : h->rfOffset5Active = 0;
468 0 : h->rfOffset7Active = 0;
469 : }
470 0 : else if ( dataUnit->partialCopyOffset == 3 )
471 : {
472 0 : h->rfOffset2Active = 0;
473 0 : h->rfOffset3Active = 100;
474 0 : h->rfOffset5Active = 0;
475 0 : h->rfOffset7Active = 0;
476 : }
477 0 : else if ( dataUnit->partialCopyOffset == 5 )
478 : {
479 0 : h->rfOffset2Active = 0;
480 0 : h->rfOffset3Active = 0;
481 0 : h->rfOffset5Active = 100;
482 0 : h->rfOffset7Active = 0;
483 : }
484 0 : else if ( dataUnit->partialCopyOffset == 7 )
485 : {
486 0 : h->rfOffset2Active = 0;
487 0 : h->rfOffset3Active = 0;
488 0 : h->rfOffset5Active = 0;
489 0 : h->rfOffset7Active = 100;
490 : }
491 : }
492 :
493 69921 : if ( dataUnit->partial_frame != 0 )
494 : {
495 : /* check for "real" late loss: a frame with higher/same timestamp was already returned to be fed into decoder */
496 0 : if ( h->firstDataUnitPopped && JB4_rtpTimeStampDiff( h->lastReturnedTs, dataUnit->timeStamp ) <= 0 )
497 : {
498 0 : JB4_FreeDataUnit( h, dataUnit );
499 0 : return 0;
500 : }
501 :
502 : /* drop partial copy if the missing frame was already concealed */
503 0 : if ( h->firstDataUnitPopped )
504 : {
505 0 : if ( dataUnit->partialCopyOffset <= 3 && JB4_rtpTimeStampDiff( h->nextExpectedTs, dataUnit->timeStamp ) < 0 )
506 : {
507 0 : JB4_FreeDataUnit( h, dataUnit );
508 0 : return 0;
509 : }
510 0 : else if ( dataUnit->partialCopyOffset == 5 && JB4_rtpTimeStampDiff( h->nextExpectedTs, dataUnit->timeStamp ) < -40 )
511 : {
512 0 : JB4_FreeDataUnit( h, dataUnit );
513 0 : return 0;
514 : }
515 0 : else if ( dataUnit->partialCopyOffset == 7 && JB4_rtpTimeStampDiff( h->nextExpectedTs, dataUnit->timeStamp ) < -80 )
516 : {
517 0 : JB4_FreeDataUnit( h, dataUnit );
518 0 : return 0;
519 : }
520 : }
521 :
522 : /* try to store partial copy - will be dropped if primary copy already available */
523 0 : if ( JB4_INPUTBUFFER_Enque( h->inputBuffer, dataUnit, (void **) &droppedDataUnit ) == 0 )
524 : {
525 : /* partial copy is useful, consider it in long-term jitter estimation */
526 0 : if ( dataUnit->partialCopyOffset <= 3 )
527 : {
528 0 : JB4_JMF_PushPacket( h->ltJmf, rcvTime, dataUnit->timeStamp );
529 : }
530 : }
531 : else
532 : {
533 0 : JB4_FreeDataUnit( h, dataUnit );
534 : }
535 0 : if ( droppedDataUnit != NULL )
536 : {
537 0 : JB4_FreeDataUnit( h, droppedDataUnit );
538 : }
539 : }
540 : else
541 : {
542 : /* calculate jitter */
543 69921 : JB4_JMF_PushPacket( h->ltJmf, rcvTime, dataUnit->timeStamp );
544 69921 : JB4_estimateShortTermJitter( h, rcvTime, dataUnit->timeStamp );
545 : /* check for "real" late loss: a frame with higher/same timestamp was already returned to be fed into decoder */
546 69921 : if ( h->firstDataUnitPopped && JB4_rtpTimeStampDiff( h->lastReturnedTs, dataUnit->timeStamp ) <= 0 )
547 : {
548 0 : if ( !dataUnit->silenceIndicator )
549 : {
550 0 : ++h->nLateLost;
551 : /* deletion of a speech frame because it arrived at the JBM too late */
552 0 : ++h->jitterInducedConcealments;
553 : }
554 0 : JB4_FreeDataUnit( h, dataUnit );
555 0 : return 0;
556 : }
557 : /* store data unit */
558 69921 : if ( JB4_INPUTBUFFER_Enque( h->inputBuffer, dataUnit, (void **) &droppedDataUnit ) != 0 )
559 : {
560 0 : JB4_FreeDataUnit( h, dataUnit );
561 : }
562 69921 : if ( droppedDataUnit != NULL )
563 : {
564 0 : JB4_FreeDataUnit( h, droppedDataUnit );
565 : }
566 : }
567 69921 : return 0;
568 : }
569 :
570 :
571 0 : int16_t JB4_getFECoffset(
572 : JB4_HANDLE h )
573 : {
574 0 : return (int16_t) h->optimum_offset;
575 : }
576 :
577 :
578 0 : int16_t JB4_FECoffset(
579 : JB4_HANDLE h )
580 : {
581 0 : if ( h->netLossRate < 0.05 )
582 : {
583 0 : return 0;
584 : }
585 : else
586 : {
587 0 : return 1;
588 : }
589 : }
590 :
591 :
592 77364 : int16_t JB4_PopDataUnit(
593 : JB4_HANDLE h,
594 : const uint32_t sysTime,
595 : const uint32_t extBufferedTime,
596 : JB4_DATAUNIT_HANDLE *pDataUnit,
597 : uint32_t *scale,
598 : uint32_t *maxScaling )
599 : {
600 : int16_t ret;
601 :
602 77364 : assert( sysTime >= h->prevPopSysTime );
603 77364 : if ( sysTime > h->prevPopSysTime + 20 )
604 : {
605 6 : h->lastPlayoutOffset += 20;
606 : }
607 77364 : h->prevPopSysTime = sysTime;
608 :
609 77364 : ret = JB4_adaptPlayout( h, sysTime, extBufferedTime, pDataUnit, scale, maxScaling );
610 :
611 77364 : return ret;
612 : }
613 :
614 :
615 : /* Calculates the difference between two RTP timestamps - the diff is positive, if B 'later', negative otherwise */
616 373182 : static int32_t JB4_rtpTimeStampDiff(
617 : const uint32_t tsA,
618 : const uint32_t tsB )
619 : {
620 : int32_t ret;
621 : /* do not dare to inline this function, casting to int32_t is important here! */
622 373182 : ret = (int32_t) ( tsB - tsA );
623 373182 : return ret;
624 : }
625 :
626 :
627 : /* function to get the number of data units contained in the buffer */
628 1745 : uint16_t JB4_bufferedDataUnits(
629 : const JB4_HANDLE h )
630 :
631 : {
632 1745 : return JB4_INPUTBUFFER_Size( h->inputBuffer );
633 : }
634 :
635 :
636 : /*****************************************************************************
637 : **************************** private functions ******************************
638 : *****************************************************************************/
639 :
640 :
641 : /* function to calculate different options for the target playout delay */
642 76806 : static void JB4_targetPlayoutDelay(
643 : const JB4_HANDLE h,
644 : uint32_t *targetMin,
645 : uint32_t *targetMax,
646 : uint32_t *targetDtx,
647 : uint32_t *targetStartUp )
648 : {
649 : uint32_t ltJitter, extraDelayReserve;
650 :
651 : /* adapt target delay to partial copy offset */
652 76806 : extraDelayReserve = 0;
653 76806 : h->rfDelay = 0;
654 76806 : if ( h->rfOffset7Active != 0 )
655 : {
656 0 : h->rfDelay = 140;
657 : }
658 76806 : else if ( h->rfOffset5Active != 0 )
659 : {
660 0 : h->rfDelay = 100;
661 : }
662 76806 : else if ( h->rfOffset2Active == 0 && h->rfOffset3Active == 0 )
663 : {
664 : /* keep some delay reserve for RF-off */
665 76806 : extraDelayReserve = 15;
666 : }
667 :
668 : /* get estimated long term jitter */
669 76806 : if ( JB4_JMF_Jitter( h->ltJmf, <Jitter ) == 0 )
670 : {
671 : /* combine long term and short term jitter to calculate target delay values */
672 76596 : *targetMax = h->stJitter + h->safetyMargin + h->rfDelay;
673 76596 : *targetMin = JB4_MIN( ltJitter + 20 + h->rfDelay + extraDelayReserve, *targetMax );
674 76596 : *targetDtx = JB4_MIN( ltJitter + extraDelayReserve, h->stJitter );
675 76596 : *targetStartUp = ( *targetMin + *targetMax + extraDelayReserve / 4 ) / 2;
676 : }
677 : else
678 : {
679 : /* combine long term and short term jitter to calculate target delay values */
680 210 : *targetMax = h->safetyMargin;
681 210 : *targetMin = JB4_MIN( 20, *targetMax );
682 210 : *targetDtx = 0;
683 210 : *targetStartUp = ( *targetMin + *targetMax ) / 2;
684 : }
685 :
686 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
687 76806 : if ( !h->evsMode )
688 : {
689 : #endif
690 76806 : *targetDtx = JB4_MAX( *targetDtx, (uint32_t) h->safetyMargin );
691 : #ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED
692 : }
693 : #endif
694 76806 : *targetStartUp = JB4_MAX( *targetStartUp, (uint32_t) h->safetyMargin );
695 :
696 76806 : return;
697 : }
698 :
699 :
700 : /* function to do playout adaptation before playing the next data unit */
701 77364 : static int16_t JB4_adaptPlayout(
702 : JB4_HANDLE h,
703 : uint32_t sysTime,
704 : uint32_t extBufferedTime,
705 : JB4_DATAUNIT_HANDLE *pDataUnit,
706 : uint32_t *scale,
707 : uint32_t *maxScaling )
708 : {
709 : bool stretchTime;
710 :
711 : /* reset scale */
712 77364 : if ( scale == NULL || maxScaling == NULL )
713 : {
714 0 : return -1;
715 : }
716 77364 : *scale = 100;
717 77364 : *maxScaling = 0;
718 77364 : stretchTime = false;
719 :
720 : /* switch type of current playout (first one, active, DTX) */
721 77364 : if ( !h->firstDataUnitPopped )
722 : {
723 873 : JB4_adaptFirstPlayout( h, sysTime, &stretchTime );
724 : }
725 76491 : else if ( h->lastPoppedWasSilence )
726 : {
727 3855 : JB4_adaptDtxPlayout( h, sysTime, &stretchTime );
728 : }
729 : else
730 : {
731 72636 : JB4_adaptActivePlayout( h, extBufferedTime, scale, maxScaling );
732 : }
733 :
734 : /* time shrinking done if needed, now do time stretching or pop data unit to play */
735 77364 : if ( stretchTime )
736 : {
737 : /* return empty data unit */
738 1191 : *pDataUnit = NULL;
739 1191 : if ( h->firstDataUnitPopped )
740 : {
741 423 : ++h->nUnavailablePopped;
742 423 : if ( !h->lastPoppedWasSilence )
743 : {
744 0 : ++h->nStretched;
745 : /* jitter-induced insertion (e.g. buffer underflow) */
746 0 : ++h->jitterInducedConcealments;
747 : }
748 : }
749 : /* add one frame to last playout delay */
750 1191 : h->lastPlayoutOffset += h->frameDuration;
751 : }
752 : else
753 : {
754 : /* return next data unit from buffer */
755 76173 : JB4_popFromBuffer( h, sysTime, pDataUnit );
756 : }
757 :
758 77364 : return 0;
759 : }
760 :
761 :
762 : /* function for playout adaptation while active (no DTX) */
763 72636 : static void JB4_adaptActivePlayout(
764 : JB4_HANDLE h,
765 : uint32_t extBufferedTime,
766 : uint32_t *scale,
767 : uint32_t *maxScaling )
768 : {
769 : JB4_DATAUNIT_HANDLE nextDataUnit;
770 : bool convertToLateLoss, dropEarly;
771 : uint32_t targetMin, targetMax, targetDtx, targetStartUp, targetMaxStretch;
772 : uint32_t currPlayoutDelay, gap, buffered;
773 : uint32_t dropGapMax, dropRateMin, dropRateMax, rate;
774 : int32_t minOffTicks, tsDiffToNextDataUnit;
775 :
776 72636 : JB4_targetPlayoutDelay( h, &targetMin, &targetMax, &targetDtx, &targetStartUp );
777 72636 : if ( JB4_JMF_MinOffset( h->ltJmf, &minOffTicks ) != 0 )
778 : {
779 0 : return;
780 : }
781 72636 : h->targetPlayoutDelay = ( targetMin + targetMax ) / 2;
782 :
783 72636 : convertToLateLoss = false;
784 72636 : dropEarly = false;
785 72636 : dropGapMax = 200;
786 72636 : dropRateMin = 5;
787 72636 : dropRateMax = 200; /* 20% */
788 :
789 : /* calculate current playout delay */
790 72636 : currPlayoutDelay = h->lastPlayoutOffset - minOffTicks + extBufferedTime;
791 72636 : if ( !JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
792 : {
793 72129 : nextDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
794 72129 : tsDiffToNextDataUnit = JB4_rtpTimeStampDiff( h->nextExpectedTs, nextDataUnit->timeStamp );
795 72129 : if ( tsDiffToNextDataUnit < 0 )
796 : {
797 339 : convertToLateLoss = true;
798 : /* time stretching is expected -> increase playout delay to allow dropping the late frame */
799 339 : currPlayoutDelay -= tsDiffToNextDataUnit;
800 339 : currPlayoutDelay += 1;
801 : }
802 : }
803 :
804 : /* decided between shrinking/stretching */
805 72636 : if ( currPlayoutDelay > targetMax ) /* time shrinking */
806 : {
807 1203 : gap = currPlayoutDelay - h->targetPlayoutDelay;
808 : /* check if gap is positive and dropping is allowed
809 : * and buffer contains enough time (ignoring one frame) */
810 2406 : if ( gap > 0 &&
811 2355 : JB4_inspectBufferForDropping( h, &dropEarly, &buffered ) == 0 &&
812 1044 : ( convertToLateLoss ||
813 1044 : ( buffered + h->frameDuration + extBufferedTime ) > targetMax ) )
814 : {
815 930 : if ( convertToLateLoss )
816 : {
817 108 : JB4_dropFromBuffer( h );
818 : }
819 822 : else if ( dropEarly )
820 : {
821 18 : JB4_dropFromBuffer( h );
822 18 : ++h->nLostOrStretched;
823 : }
824 : else
825 : {
826 : /* limit gap to [gapMin,gapMax] and calculate current drop rate from gap */
827 804 : rate = JB4_MIN( (uint32_t) ( gap ), dropGapMax ) *
828 804 : ( dropRateMax - dropRateMin ) / dropGapMax +
829 : dropRateMin;
830 804 : *scale = ( 1000 - rate ) / 10;
831 : /* Limit max scaling to the duration of one frame. APA will not exceed this limit
832 : * anyway due to the 50% limitation of APA_MIN_SCALE and APA_MAX_SCALE. Limiting
833 : * the value to a sensible range here avoids integer overflows at later stages when
834 : * converting maxScaling from milliseconds to samples. */
835 804 : *maxScaling = JB4_MIN( currPlayoutDelay - targetMax, 1000 / IVAS_NUM_FRAMES_PER_SEC );
836 : }
837 : }
838 : }
839 : else /* time stretching */
840 : {
841 : uint32_t delayWithClearedExternalBuffer;
842 : /* Stretching only makes sense if we win one additional frame in the input buffer.
843 : * If too much additional delay would be required to do so, then do not scale.
844 : * Also make sure that the delay doesn't increase too much. */
845 71433 : delayWithClearedExternalBuffer = currPlayoutDelay - extBufferedTime + h->frameDuration;
846 71433 : targetMaxStretch = targetMax - h->frameDuration;
847 71433 : if ( delayWithClearedExternalBuffer + h->frameDuration <= targetMaxStretch &&
848 6051 : currPlayoutDelay < targetMaxStretch && currPlayoutDelay < (uint32_t) ( 110 + h->rfDelay / 4 ) )
849 : {
850 1407 : *scale = 120;
851 : /* Limit max scaling to the duration of one frame. APA will not exceed this limit
852 : * anyway due to the 50% limitation of APA_MIN_SCALE and APA_MAX_SCALE. Limiting
853 : * the value to a sensible range here avoids integer overflows at later stages when
854 : * converting maxScaling from milliseconds to samples. */
855 1407 : *maxScaling = JB4_MIN( targetMaxStretch - currPlayoutDelay, 1000 / IVAS_NUM_FRAMES_PER_SEC );
856 : }
857 : }
858 :
859 72636 : return;
860 : }
861 :
862 :
863 : /* function for playout adaptation while DTX */
864 3855 : static void JB4_adaptDtxPlayout(
865 : JB4_HANDLE h,
866 : uint32_t sysTime,
867 : bool *stretchTime )
868 : {
869 : JB4_DATAUNIT_HANDLE firstDu;
870 : uint32_t firstTs;
871 : uint32_t targetMin, targetMax, targetDtx, targetStartUp;
872 : uint32_t currPlayoutDelay, headRoom;
873 : int32_t minOffTicks, tsDiffToNextDataUnit;
874 :
875 3855 : JB4_targetPlayoutDelay( h, &targetMin, &targetMax, &targetDtx, &targetStartUp );
876 3855 : if ( JB4_JMF_MinOffset( h->ltJmf, &minOffTicks ) != 0 )
877 : {
878 0 : return;
879 : }
880 :
881 : /* calculate current playout delay */
882 3855 : currPlayoutDelay = h->lastPlayoutOffset - minOffTicks;
883 :
884 : /* check for startup after DTX */
885 3855 : if ( !JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
886 : {
887 2322 : firstDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
888 2322 : firstTs = firstDu->timeStamp;
889 :
890 2322 : tsDiffToNextDataUnit = JB4_rtpTimeStampDiff( h->nextExpectedTs, firstTs );
891 : /* check if the next available data unit should already be used (time stamp order) */
892 2322 : if ( tsDiffToNextDataUnit > 0 )
893 : {
894 : /* time stretching is expected -> increase playout delay */
895 1212 : currPlayoutDelay += tsDiffToNextDataUnit;
896 : }
897 2322 : if ( !firstDu->silenceIndicator )
898 : {
899 : /* recalculate playout delay based on first buffered data unit */
900 1068 : JB4_playoutDelay( h, sysTime, firstTs, &currPlayoutDelay );
901 : /* check if the next available data unit should already be used (time stamp order) */
902 1068 : if ( tsDiffToNextDataUnit > 0 )
903 : {
904 : /* time stretching is expected -> increase playout delay */
905 603 : currPlayoutDelay += tsDiffToNextDataUnit;
906 : }
907 1068 : h->targetPlayoutDelay = targetStartUp;
908 1068 : headRoom = 600 * h->frameDuration / 1000;
909 : /* decided between shrinking/stretching */
910 1068 : if ( currPlayoutDelay > targetStartUp + headRoom ) /* time shrinking */
911 : {
912 0 : if ( JB4_checkDtxDropping( h ) )
913 : {
914 0 : JB4_dropFromBuffer( h );
915 : }
916 : }
917 1068 : else if ( currPlayoutDelay + headRoom < targetStartUp ) /* time stretching */
918 : {
919 45 : *stretchTime = true;
920 : }
921 1068 : return;
922 : }
923 : }
924 :
925 : /* adapt while DTX */
926 2787 : h->targetPlayoutDelay = targetDtx;
927 :
928 : /* decided between shrinking/stretching */
929 2787 : if ( currPlayoutDelay >= targetDtx + h->frameDuration ) /* time shrinking */
930 : {
931 426 : if ( JB4_checkDtxDropping( h ) )
932 : {
933 426 : JB4_dropFromBuffer( h );
934 : }
935 : }
936 2361 : else if ( currPlayoutDelay + 500 * h->frameDuration / 1000 < targetDtx ) /* time stretching */
937 : {
938 378 : *stretchTime = true;
939 : }
940 :
941 2787 : return;
942 : }
943 :
944 :
945 : /* function to do playout adaptation before playing the first data unit */
946 873 : static void JB4_adaptFirstPlayout(
947 : JB4_HANDLE h,
948 : uint32_t sysTime,
949 : bool *prebuffer )
950 : {
951 : uint32_t currPlayoutDelay;
952 : JB4_DATAUNIT_HANDLE firstDu;
953 : uint32_t targetMin, targetMax, targetDtx, targetStartUp;
954 873 : if ( JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
955 : {
956 558 : *prebuffer = true;
957 558 : return;
958 : }
959 315 : JB4_targetPlayoutDelay( h, &targetMin, &targetMax, &targetDtx, &targetStartUp );
960 315 : if ( targetStartUp < h->frameDuration )
961 : {
962 0 : return;
963 : }
964 : /* calculate delay if first data unit would be played now */
965 315 : firstDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
966 315 : if ( JB4_playoutDelay( h, sysTime, firstDu->timeStamp, &currPlayoutDelay ) != 0 )
967 : {
968 0 : *prebuffer = true;
969 0 : return;
970 : }
971 315 : if ( currPlayoutDelay + h->frameDuration / 2 < targetStartUp ) /* time stretching */
972 : {
973 210 : *prebuffer = true;
974 : }
975 : else /* no adaptation, start playout */
976 : {
977 105 : *prebuffer = false;
978 : }
979 :
980 315 : return;
981 : }
982 :
983 :
984 : /* function to look into the buffer and check if it makes sense to drop a data unit */
985 1203 : static int16_t JB4_inspectBufferForDropping(
986 : const JB4_HANDLE h,
987 : bool *dropEarly,
988 : uint32_t *buffered )
989 : {
990 : uint16_t inputBufferSize;
991 : int32_t seqNrDiff;
992 : int32_t bufferedTs;
993 : uint32_t firstTs;
994 : uint64_t beginTs, endTs;
995 : JB4_DATAUNIT_HANDLE firstDu, secondDu, lastDu;
996 :
997 1203 : assert( !h->lastPoppedWasSilence );
998 1203 : *dropEarly = false;
999 1203 : *buffered = 0;
1000 1203 : inputBufferSize = JB4_INPUTBUFFER_Size( h->inputBuffer );
1001 1203 : if ( inputBufferSize == 0U )
1002 : {
1003 0 : return -1;
1004 : }
1005 :
1006 1203 : firstDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1007 1203 : firstTs = firstDu->timeStamp;
1008 : /* check for loss: sequence number diff is exactly 0 in the valid case */
1009 1203 : if ( h->firstDataUnitPopped )
1010 : {
1011 1203 : seqNrDiff = JB4_rtpTimeStampDiff( h->nextExpectedTs, firstTs ) /
1012 1203 : (int32_t) ( h->frameDuration );
1013 : }
1014 : else
1015 : {
1016 0 : seqNrDiff = 0;
1017 : }
1018 1203 : if ( seqNrDiff <= 0 )
1019 : {
1020 : /* preview data unit to play after dropping */
1021 1161 : if ( inputBufferSize <= 1U )
1022 : {
1023 : /* data unit to play missing, avoid drop followed by concealment */
1024 3 : return -1;
1025 : }
1026 1158 : secondDu = JB4_INPUTBUFFER_Element( h->inputBuffer, 1 );
1027 1158 : if ( firstTs + h->frameDuration != secondDu->timeStamp )
1028 : {
1029 : /* data unit to play is not available, avoid drop followed by concealment */
1030 27 : return -1;
1031 : }
1032 : /* calculate buffered time span */
1033 1131 : bufferedTs = 0;
1034 : }
1035 42 : else if ( seqNrDiff == 2 )
1036 : {
1037 : /* data unit to play is not available, avoid dropping followed by concealment */
1038 21 : return -1;
1039 : }
1040 : else /* seqNoDiff == 1 || seqNoDiff > 2 */
1041 : {
1042 : /* first data unit is not available -> drop it early to avoid concealment
1043 : * This is very aggressive: ignores the maximum drop rate (50% drop and 50% concealment for adjacent lost),
1044 : * but on the other hand, dropping sounds better than concealment. */
1045 21 : *dropEarly = true;
1046 : /* data unit to drop (first one) is lost */
1047 21 : bufferedTs = 0;
1048 : }
1049 :
1050 : /* add time stamp difference of last and first actually buffered data unit */
1051 1152 : if ( inputBufferSize == 1U )
1052 : {
1053 0 : bufferedTs += h->frameDuration;
1054 : }
1055 : else
1056 : {
1057 1152 : lastDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Back( h->inputBuffer );
1058 1152 : beginTs = firstTs;
1059 1152 : endTs = lastDu->timeStamp + h->frameDuration;
1060 : /* check for RTP time stamp wrap around */
1061 1152 : if ( endTs < beginTs )
1062 : {
1063 0 : endTs = endTs + 0xFFFFFFFF;
1064 : }
1065 1152 : bufferedTs += (int32_t) ( endTs - beginTs );
1066 : }
1067 :
1068 : /* the result should not be negative */
1069 1152 : if ( bufferedTs < 0 )
1070 : {
1071 0 : return -1;
1072 : }
1073 1152 : *buffered = bufferedTs;
1074 :
1075 1152 : return 0;
1076 : }
1077 :
1078 :
1079 : /* function to look into the buffer and check if it makes sense to drop a data unit */
1080 426 : static int16_t JB4_checkDtxDropping(
1081 : const JB4_HANDLE h )
1082 : {
1083 : uint16_t inputBufferSize;
1084 : int32_t seqNrDiff;
1085 : JB4_DATAUNIT_HANDLE firstDu;
1086 : int16_t droppingAllowed;
1087 :
1088 426 : assert( h->firstDataUnitPopped );
1089 426 : assert( h->lastPoppedWasSilence );
1090 :
1091 426 : droppingAllowed = 1;
1092 426 : inputBufferSize = JB4_INPUTBUFFER_Size( h->inputBuffer );
1093 426 : if ( inputBufferSize > 0U )
1094 : {
1095 408 : firstDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1096 : /* check for loss: sequence number diff is exactly 0 in the valid case */
1097 408 : seqNrDiff = JB4_rtpTimeStampDiff( h->nextExpectedTs, firstDu->timeStamp ) /
1098 408 : (int32_t) ( h->frameDuration );
1099 408 : if ( seqNrDiff <= 0 )
1100 : {
1101 : /* no not drop first active frame */
1102 0 : droppingAllowed = 0;
1103 : }
1104 : }
1105 : /* else: buffer empty, allow dropping FRAME_NO_DATA */
1106 :
1107 426 : return droppingAllowed;
1108 : }
1109 :
1110 :
1111 : /* function to estimate the short term jitter */
1112 69921 : static void JB4_estimateShortTermJitter(
1113 : JB4_HANDLE h,
1114 : const uint32_t rcvTime,
1115 : const uint32_t rtpTimeStamp )
1116 : {
1117 : uint32_t jitter, duration, maxDuration;
1118 : int32_t minTime, maxTime;
1119 : JB4_CIRCULARBUFFER_ELEMENT maxElement, dequedElement;
1120 :
1121 69921 : jitter = 0;
1122 69921 : JB4_JMF_PushPacket( h->stJmf, rcvTime, rtpTimeStamp );
1123 : /* save delta delay */
1124 69921 : if ( JB4_JMF_Jitter( h->stJmf, &jitter ) == 0 )
1125 : {
1126 : /* compensate difference between both offsets */
1127 : int32_t stOffset, ltOffset;
1128 69711 : JB4_JMF_MinOffset( h->stJmf, &stOffset );
1129 69711 : JB4_JMF_MinOffset( h->ltJmf, <Offset );
1130 69711 : jitter += stOffset - ltOffset;
1131 69711 : assert( (int16_t) jitter >= 0 );
1132 69711 : if ( JB4_CIRCULARBUFFER_IsFull( h->stJitterFifo ) )
1133 : {
1134 2406 : JB4_CIRCULARBUFFER_Deque( h->stJitterFifo, &dequedElement );
1135 2406 : JB4_CIRCULARBUFFER_Deque( h->stTimeStampFifo, &dequedElement );
1136 : }
1137 69711 : JB4_CIRCULARBUFFER_Enque( h->stJitterFifo, jitter );
1138 69711 : JB4_CIRCULARBUFFER_Enque( h->stTimeStampFifo, rtpTimeStamp );
1139 :
1140 : /* check for duration and discard first entries if too long */
1141 69711 : minTime = JB4_CIRCULARBUFFER_Front( h->stTimeStampFifo );
1142 69711 : maxTime = JB4_CIRCULARBUFFER_Back( h->stTimeStampFifo );
1143 69711 : if ( maxTime > minTime )
1144 : {
1145 69606 : duration = maxTime - minTime;
1146 69606 : maxDuration = 4 * h->timeScale;
1147 119079 : while ( duration > maxDuration )
1148 : {
1149 49473 : JB4_CIRCULARBUFFER_Deque( h->stJitterFifo, &dequedElement );
1150 49473 : JB4_CIRCULARBUFFER_Deque( h->stTimeStampFifo, &dequedElement );
1151 49473 : minTime = JB4_CIRCULARBUFFER_Front( h->stTimeStampFifo );
1152 49473 : if ( maxTime <= minTime )
1153 : {
1154 0 : break;
1155 : }
1156 49473 : duration = maxTime - minTime;
1157 : }
1158 : }
1159 : }
1160 :
1161 : /* update h->stJitter */
1162 69921 : if ( !JB4_CIRCULARBUFFER_IsEmpty( h->stJitterFifo ) )
1163 : {
1164 69711 : JB4_CIRCULARBUFFER_Max( h->stJitterFifo, &maxElement );
1165 : /* round up to full frame duration */
1166 69711 : h->stJitter = (uint32_t) ceil( (double) ( maxElement ) / h->frameDuration ) *
1167 69711 : h->frameDuration;
1168 : }
1169 :
1170 69921 : return;
1171 : }
1172 :
1173 :
1174 : /* function to pop a data unit from the buffer */
1175 76173 : static void JB4_popFromBuffer(
1176 : JB4_HANDLE h,
1177 : const uint32_t sysTime,
1178 : JB4_DATAUNIT_HANDLE *pDataUnit )
1179 : {
1180 : JB4_DATAUNIT_HANDLE nextDataUnit;
1181 : uint32_t nStretched;
1182 : int32_t tsDiff;
1183 : JB4_DATAUNIT_HANDLE tempDataUnit;
1184 : uint16_t readlen;
1185 : uint16_t i;
1186 : int16_t frameoffset;
1187 : uint32_t maxval;
1188 : Word32 lost, total_rec;
1189 : JB4_DATAUNIT_HANDLE partialCopyDu;
1190 : uint16_t searchpos, endpos;
1191 :
1192 : /* check if a data unit is available */
1193 76173 : if ( JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
1194 : {
1195 : /* no data unit available */
1196 2025 : *pDataUnit = NULL;
1197 2025 : h->nextExpectedTs += h->frameDuration;
1198 2025 : if ( h->lastPoppedWasSilence )
1199 : {
1200 1518 : ++h->nComfortNoice;
1201 : }
1202 : else
1203 : {
1204 507 : ++h->nUnavailablePopped;
1205 507 : ++h->nLostOrStretched;
1206 : }
1207 :
1208 2025 : return;
1209 : }
1210 :
1211 : /* preview next data unit in sequence order */
1212 74148 : nextDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1213 :
1214 : /* check if this is the first data unit */
1215 74148 : if ( !h->firstDataUnitPopped )
1216 : {
1217 105 : h->firstDataUnitPopped = true;
1218 : /* adjust sequence numbers to avoid handling first packet as loss */
1219 105 : h->nextExpectedTs = nextDataUnit->timeStamp;
1220 : }
1221 :
1222 : /* check if the next available data unit should already be used (time stamp order) */
1223 74148 : tsDiff = JB4_rtpTimeStampDiff( nextDataUnit->timeStamp, h->nextExpectedTs );
1224 :
1225 74148 : h->totWin += 1;
1226 74148 : if ( ( h->totWin > 3000 ) || ( h->FecOffWinLen > 100 ) )
1227 : {
1228 6 : maxval = h->FecOffWin[1];
1229 6 : h->optimum_offset = 1;
1230 54 : for ( i = 2; i < MAXOFFSET; i++ )
1231 : {
1232 48 : if ( h->FecOffWin[i] > maxval )
1233 : {
1234 3 : maxval = h->FecOffWin[i];
1235 3 : h->optimum_offset = i;
1236 : }
1237 48 : h->FecOffWin[i] = 0;
1238 : }
1239 6 : h->FecOffWin[0] = 0;
1240 6 : h->FecOffWin[1] = 0;
1241 6 : h->totWin = 0;
1242 6 : h->FecOffWinLen = 0;
1243 :
1244 :
1245 6 : lost = h->nLost + h->nPartialCopiesUsed - h->last_nLost;
1246 6 : total_rec = h->nAvailablePopped + h->nUnavailablePopped - h->last_ntot;
1247 :
1248 6 : if ( lost != 0 && total_rec != 0 )
1249 : {
1250 3 : h->netLossRate = (float) lost / (float) total_rec;
1251 : }
1252 : else
1253 : {
1254 3 : h->netLossRate = 0.0f;
1255 : }
1256 6 : h->last_nLost = L_add( h->nLost, h->nPartialCopiesUsed );
1257 6 : h->last_ntot = L_add( h->nAvailablePopped, h->nUnavailablePopped );
1258 : }
1259 :
1260 74148 : if ( tsDiff < 0 )
1261 : {
1262 4335 : readlen = JB4_INPUTBUFFER_Size( h->inputBuffer );
1263 21639 : for ( i = 0; i < readlen; i++ )
1264 : {
1265 17304 : tempDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Element( h->inputBuffer, i );
1266 17304 : if ( !tempDataUnit->partial_frame && !h->lastPoppedWasSilence )
1267 : {
1268 15540 : frameoffset = (int16_t) ( JB4_rtpTimeStampDiff( h->nextExpectedTs, tempDataUnit->timeStamp ) / 20 );
1269 :
1270 15540 : if ( frameoffset > 0 && frameoffset < MAXOFFSET )
1271 : {
1272 15540 : h->FecOffWin[frameoffset] += 1;
1273 : }
1274 : }
1275 : }
1276 4335 : h->FecOffWinLen += 1;
1277 :
1278 : /* next expected data unit is missing
1279 : * -> conceal network loss, do time stretching or create comfort noise */
1280 4335 : *pDataUnit = NULL;
1281 :
1282 : /* update statistics */
1283 4335 : h->nextExpectedTs += h->frameDuration;
1284 4335 : if ( h->lastPoppedWasSilence )
1285 : {
1286 1122 : ++h->nComfortNoice;
1287 : }
1288 : else
1289 : {
1290 3213 : ++h->nUnavailablePopped;
1291 3213 : ++h->nLostOrStretched;
1292 : }
1293 4335 : return;
1294 : }
1295 :
1296 : /* fetch the next data unit from buffer */
1297 69813 : *pDataUnit = nextDataUnit;
1298 69813 : nextDataUnit->nextCoderType = INACTIVE;
1299 69813 : if ( h->pre_partial_frame || nextDataUnit->partial_frame )
1300 : {
1301 0 : if ( nextDataUnit->partial_frame )
1302 : {
1303 0 : h->pre_partial_frame = 1;
1304 : }
1305 0 : else if ( h->pre_partial_frame )
1306 : {
1307 0 : h->pre_partial_frame = 0;
1308 : }
1309 :
1310 0 : endpos = JB4_INPUTBUFFER_Size( h->inputBuffer );
1311 0 : for ( searchpos = 0; searchpos < endpos; searchpos++ )
1312 : {
1313 0 : partialCopyDu = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Element( h->inputBuffer, searchpos );
1314 0 : if ( partialCopyDu->timeStamp == nextDataUnit->timeStamp + partialCopyDu->duration )
1315 : {
1316 0 : get_NextCoderType( partialCopyDu->data, &nextDataUnit->nextCoderType );
1317 0 : break;
1318 : }
1319 : }
1320 : }
1321 69813 : JB4_INPUTBUFFER_Deque( h->inputBuffer, (void **) pDataUnit );
1322 :
1323 69813 : if ( nextDataUnit->partial_frame )
1324 : {
1325 0 : h->nPartialCopiesUsed += 1;
1326 :
1327 0 : readlen = JB4_INPUTBUFFER_Size( h->inputBuffer );
1328 0 : for ( i = 0; i < readlen; i++ )
1329 : {
1330 0 : tempDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Element( h->inputBuffer, i );
1331 0 : if ( !tempDataUnit->partial_frame && !h->lastPoppedWasSilence )
1332 : {
1333 0 : frameoffset = (int16_t) ( JB4_rtpTimeStampDiff( h->nextExpectedTs, tempDataUnit->timeStamp ) / 20 );
1334 :
1335 0 : if ( frameoffset > 0 && frameoffset < MAXOFFSET )
1336 : {
1337 0 : h->FecOffWin[frameoffset] += 1;
1338 : }
1339 : }
1340 : }
1341 0 : h->FecOffWinLen += 1;
1342 : }
1343 :
1344 : /* update statistics */
1345 69813 : if ( h->nLostOrStretched != 0U )
1346 : {
1347 1821 : assert( h->lastPoppedWasSilence == false );
1348 : /* separate concealments since last available pop in lost and stretched */
1349 1821 : nStretched = tsDiff / h->frameDuration;
1350 1821 : assert( h->nLostOrStretched >= nStretched );
1351 1821 : h->nLost += h->nLostOrStretched - nStretched;
1352 : /* jitter-induced insertion (e.g. buffer underflow) */
1353 1821 : h->jitterInducedConcealments += nStretched;
1354 1821 : h->nStretched += nStretched;
1355 1821 : h->nLostOrStretched = 0;
1356 : }
1357 69813 : h->lastReturnedTs = nextDataUnit->timeStamp;
1358 69813 : JB4_updateLastTimingMembers( h, sysTime, nextDataUnit->timeStamp );
1359 69813 : h->nextExpectedTs = nextDataUnit->timeStamp + h->frameDuration;
1360 69813 : if ( nextDataUnit->silenceIndicator )
1361 : {
1362 804 : h->lastPoppedWasSilence = true;
1363 804 : ++h->nComfortNoice;
1364 : }
1365 : else
1366 : {
1367 69009 : h->lastPoppedWasSilence = false;
1368 69009 : ++h->nAvailablePopped;
1369 : }
1370 :
1371 69813 : return;
1372 : }
1373 :
1374 : /* function to drop a data unit from the buffer - updates nShrinked */
1375 552 : static void JB4_dropFromBuffer(
1376 : JB4_HANDLE h )
1377 : {
1378 : JB4_DATAUNIT_HANDLE nextDataUnit, dataUnit;
1379 : int32_t tsDiff;
1380 : uint32_t nStretched;
1381 :
1382 : /* check if a data unit is available */
1383 552 : if ( JB4_INPUTBUFFER_IsEmpty( h->inputBuffer ) )
1384 : {
1385 18 : return;
1386 : }
1387 : /* preview next data unit in sequence order */
1388 534 : nextDataUnit = (JB4_DATAUNIT_HANDLE) JB4_INPUTBUFFER_Front( h->inputBuffer );
1389 :
1390 : /* check if this is the first data unit */
1391 534 : if ( !h->firstDataUnitPopped )
1392 : {
1393 0 : h->firstDataUnitPopped = true;
1394 : /* adjust sequence numbers to avoid handling first packet as loss */
1395 0 : h->nextExpectedTs = nextDataUnit->timeStamp;
1396 : }
1397 :
1398 : /* check if the next available data unit should already be used (time stamp order) */
1399 534 : tsDiff = JB4_rtpTimeStampDiff( nextDataUnit->timeStamp, h->nextExpectedTs );
1400 534 : if ( tsDiff < 0 )
1401 : {
1402 : /* next expected data unit is missing, remember this data unit as popped,
1403 : * but do not count it as lost, because it will not be concealed */
1404 426 : h->nextExpectedTs += h->frameDuration;
1405 : /* substract one frame from last playout delay */
1406 426 : h->lastPlayoutOffset -= h->frameDuration;
1407 426 : if ( !h->lastPoppedWasSilence )
1408 : {
1409 18 : ++h->nShrinked;
1410 : /* modification of the output timeline due to link loss */
1411 18 : ++h->nUnavailablePopped;
1412 18 : ++h->nLostOrStretched;
1413 : }
1414 426 : if ( h->lastTargetTime != 0U )
1415 : {
1416 426 : h->lastTargetTime += h->frameDuration;
1417 : }
1418 426 : return;
1419 : }
1420 :
1421 : /* fetch the next data unit from buffer */
1422 108 : JB4_INPUTBUFFER_Deque( h->inputBuffer, (void *) &dataUnit );
1423 : /* update statistics */
1424 108 : if ( h->nLostOrStretched != 0U )
1425 : {
1426 108 : assert( h->lastPoppedWasSilence == false );
1427 : /* separate concealments since last available pop in lost and stretched */
1428 108 : nStretched = tsDiff / h->frameDuration;
1429 108 : assert( h->nLostOrStretched >= nStretched );
1430 :
1431 : /* convert stretching followed by shrinking to late-loss */
1432 108 : if ( nStretched > 0U )
1433 : {
1434 108 : --nStretched;
1435 108 : ++h->nLateLost;
1436 108 : h->nLost += h->nLostOrStretched - nStretched;
1437 : /* jitter-induced insertion (e.g. buffer underflow) */
1438 108 : h->jitterInducedConcealments += nStretched;
1439 108 : if ( !dataUnit->silenceIndicator )
1440 : {
1441 : /* JBM induced removal of a speech frame (intentional frame dropping) */
1442 108 : ++h->jitterInducedConcealments;
1443 : }
1444 108 : h->nStretched += nStretched;
1445 : }
1446 : else
1447 : {
1448 0 : h->nLost += h->nLostOrStretched;
1449 0 : ++h->nShrinked;
1450 0 : if ( !dataUnit->silenceIndicator )
1451 : {
1452 : /* JBM induced removal of a speech frame (intentional frame dropping) */
1453 0 : ++h->jitterInducedConcealments;
1454 : }
1455 : }
1456 108 : h->nLostOrStretched = 0;
1457 : }
1458 : else
1459 : {
1460 0 : if ( !dataUnit->silenceIndicator )
1461 : {
1462 0 : ++h->nShrinked;
1463 : /* JBM induced removal of a speech frame (intentional frame dropping) */
1464 0 : ++h->jitterInducedConcealments;
1465 : }
1466 : }
1467 :
1468 108 : h->lastReturnedTs = dataUnit->timeStamp;
1469 108 : h->lastPoppedWasSilence = dataUnit->silenceIndicator;
1470 108 : h->nextExpectedTs = dataUnit->timeStamp + h->frameDuration;
1471 :
1472 : /* substract one frame from last playout delay */
1473 108 : h->lastPlayoutOffset -= h->frameDuration;
1474 108 : if ( h->lastTargetTime != 0U )
1475 108 : h->lastTargetTime += h->frameDuration;
1476 :
1477 108 : JB4_FreeDataUnit( h, dataUnit );
1478 :
1479 108 : return;
1480 : }
1481 :
1482 :
1483 : /* function to calculate the playout delay based on the current jitter */
1484 1383 : static int16_t JB4_playoutDelay(
1485 : const JB4_HANDLE h,
1486 : const uint32_t playTime,
1487 : const uint32_t rtpTimeStamp,
1488 : uint32_t *delay )
1489 : {
1490 : int32_t minOffTicks;
1491 :
1492 1383 : if ( JB4_JMF_MinOffset( h->ltJmf, &minOffTicks ) != 0 )
1493 : {
1494 0 : return -1;
1495 : }
1496 :
1497 1383 : *delay = playTime - minOffTicks - rtpTimeStamp;
1498 :
1499 1383 : return 0;
1500 : }
1501 :
1502 :
1503 : /* function to update lastPlayoutDelay and lastTargetTime after popFromBuffer() */
1504 69813 : static void JB4_updateLastTimingMembers(
1505 : JB4_HANDLE h,
1506 : const uint32_t playTime,
1507 : const uint32_t rtpTimeStamp )
1508 : {
1509 : int32_t minOffTicks;
1510 :
1511 69813 : if ( JB4_JMF_MinOffset( h->ltJmf, &minOffTicks ) != 0 )
1512 : {
1513 0 : return;
1514 : }
1515 :
1516 : /* playoutDelay = playTime - minOffset - timeStamp */
1517 69813 : h->lastPlayoutOffset = playTime - rtpTimeStamp;
1518 : /* targetTime = minOffset + timeStamp + targetDelay */
1519 69813 : h->lastTargetTime = (uint32_t) ( minOffTicks + rtpTimeStamp + h->targetPlayoutDelay );
1520 :
1521 69813 : return;
1522 : }
1523 :
1524 :
1525 : /* function to compare the RTP time stamps of two data units: newElement==arrayElement ? 0 : (newElement>arrayElement ? +1 : -1) */
1526 67896 : static int16_t JB4_inputBufferCompareFunction(
1527 : const JB4_INPUTBUFFER_ELEMENT newElement,
1528 : const JB4_INPUTBUFFER_ELEMENT arrayElement,
1529 : bool *replaceWithNewElementIfEqual )
1530 : {
1531 : JB4_DATAUNIT_HANDLE newDataUnit, arrayDataUnit;
1532 : int32_t diff;
1533 : int16_t result;
1534 :
1535 67896 : *replaceWithNewElementIfEqual = 0;
1536 67896 : newDataUnit = (JB4_DATAUNIT_HANDLE) newElement;
1537 67896 : arrayDataUnit = (JB4_DATAUNIT_HANDLE) arrayElement;
1538 67896 : diff = JB4_rtpTimeStampDiff( arrayDataUnit->timeStamp, newDataUnit->timeStamp );
1539 67896 : if ( diff > 0 )
1540 : {
1541 67896 : result = 1;
1542 : }
1543 0 : else if ( diff < 0 )
1544 : {
1545 0 : result = -1;
1546 : }
1547 : else /* equal timestamps */
1548 : {
1549 0 : result = 0;
1550 0 : if ( newDataUnit->partial_frame == 0 && arrayDataUnit->partial_frame == 1 )
1551 : {
1552 : /* replace partial copy with primary copy */
1553 0 : *replaceWithNewElementIfEqual = 1;
1554 : }
1555 0 : else if ( newDataUnit->partial_frame == arrayDataUnit->partial_frame && newDataUnit->dataSize > arrayDataUnit->dataSize )
1556 : {
1557 : /* if both are primary or partial: take the one with higher size (e.g. higher bitrate) */
1558 0 : *replaceWithNewElementIfEqual = 1;
1559 : }
1560 : }
1561 :
1562 67896 : return result;
1563 : }
1564 :
1565 : #undef WMC_TOOL_SKIP
|