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

Generated by: LCOV version 1.14