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

Generated by: LCOV version 1.14