LCOV - code coverage report
Current view: top level - lib_dec - jbm_jb4sb_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 607 788 77.0 %
Date: 2025-08-23 01:22:27 Functions: 22 24 91.7 %

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

Generated by: LCOV version 1.14