LCOV - code coverage report
Current view: top level - lib_dec - jbm_jb4sb.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 442 571 77.4 %
Date: 2025-05-23 08:37:30 Functions: 22 25 88.0 %

          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, &ltJitter ) == 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, &ltOffset );
    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

Generated by: LCOV version 1.14