LCOV - code coverage report
Current view: top level - lib_dec - jbm_jb4_jmf.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 106 119 89.1 %
Date: 2025-05-03 01:55:50 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : /*====================================================================================
      34             :     EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0
      35             :   ====================================================================================*/
      36             : 
      37             : /** \file jbm_jb4_jmf.c jitter measure fifo - a fifo used for windowed measure of network status */
      38             : 
      39             : /* system includes */
      40             : #include <assert.h>
      41             : #include <stdlib.h>
      42             : #include <stdio.h>
      43             : #include <stdint.h>
      44             : #include "options.h"
      45             : #include "prot_fx.h"
      46             : #include "wmc_auto.h"
      47             : 
      48             : /* local includes */
      49             : #include "jbm_jb4_jmf.h"
      50             : #include "jbm_jb4_circularbuffer.h"
      51             : /* instrumentation */
      52             : 
      53             : #define INV_125_Q15 262 /*1/125 IN Q_15*/
      54             : 
      55             : /** jitter measure fifo - a fifo used for windowed measure of network status */
      56             : struct JB4_JMF
      57             : {
      58             :     /** scale of system time and RTP time stamps */
      59             :     Word16 timeScale;
      60             :     /** the window size of the fifo as time in sysTimeScale */
      61             :     UWord16 maxWindowDuration;
      62             :     /** considered fraction in 1/1000 units, e.g. 900 ignores 10% of the highest samples */
      63             :     UWord16 consideredFraction;
      64             : 
      65             :     /** fifo containing the delay entries (ordered by receive time) */
      66             :     JB4_CIRCULARBUFFER_HANDLE fifo;
      67             :     /** fifo containing the offset entries (ordered by receive time) */
      68             :     JB4_CIRCULARBUFFER_HANDLE offsetFifo;
      69             :     /** fifo containing the RTP times of the values in offsetFifo (ordered by receive time) */
      70             :     JB4_CIRCULARBUFFER_HANDLE timeStampFifo;
      71             :     /** flag if the first packet was already pushed */
      72             :     Word16 firstPacketPushed;
      73             :     /** last packets system time in microseconds */
      74             :     Word32 lastSysTime;
      75             :     /** RTP time stamp of the last pushed packet */
      76             :     Word32 lastRtpTimeStamp;
      77             :     /** last packets calculated delay value */
      78             :     Word32 lastDelay;
      79             :     /** number of elements to ignore for percentile calculation - value set within init */
      80             :     Word16 nElementsToIgnore;
      81             : };
      82             : 
      83             : 
      84             : /** helper function to add an entry at back of the buffer */
      85             : static void JB4_JMF_pushBack( JB4_JMF_HANDLE h, const Word32 delay, const Word32 offset, const UWord32 time );
      86             : 
      87             : /** helper function to remove an entry from the front of the buffer */
      88             : static void JB4_JMF_popFront( JB4_JMF_HANDLE h );
      89             : 
      90             : 
      91          54 : ivas_error JB4_JMF_Create(
      92             :     JB4_JMF_HANDLE *ph )
      93             : {
      94             :     JB4_JMF_HANDLE h;
      95             :     ivas_error error;
      96             : 
      97          54 :     IF( ( h = malloc( sizeof( struct JB4_JMF ) ) ) == NULL )
      98             :     {
      99           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM\n" ) );
     100             :     }
     101             : 
     102          54 :     IF( NE_32( ( error = JB4_CIRCULARBUFFER_Create( &h->fifo ) ), IVAS_ERR_OK ) )
     103             :     {
     104           0 :         return error;
     105             :     }
     106          54 :     IF( NE_32( ( JB4_CIRCULARBUFFER_Create( &h->offsetFifo ) ), IVAS_ERR_OK ) )
     107             :     {
     108           0 :         return error;
     109             :     }
     110          54 :     IF( NE_32( ( JB4_CIRCULARBUFFER_Create( &h->timeStampFifo ) ), IVAS_ERR_OK ) )
     111             :     {
     112           0 :         return error;
     113             :     }
     114             : 
     115          54 :     h->timeScale = 1000;
     116          54 :     move16();
     117          54 :     h->consideredFraction = 1000;
     118          54 :     move16();
     119          54 :     h->firstPacketPushed = 0;
     120          54 :     move16();
     121          54 :     h->lastSysTime = 0;
     122          54 :     move32();
     123          54 :     h->lastRtpTimeStamp = 0;
     124          54 :     move32();
     125          54 :     h->lastDelay = 0;
     126          54 :     move32();
     127          54 :     h->nElementsToIgnore = 0;
     128          54 :     move16();
     129             : 
     130          54 :     *ph = h;
     131             : 
     132          54 :     return IVAS_ERR_OK;
     133             : }
     134             : 
     135             : 
     136          54 : void JB4_JMF_Destroy(
     137             :     JB4_JMF_HANDLE *ph )
     138             : {
     139             :     JB4_JMF_HANDLE h;
     140             : 
     141          54 :     IF( !ph )
     142             :     {
     143           0 :         return;
     144             :     }
     145          54 :     h = *ph;
     146          54 :     IF( !h )
     147             :     {
     148           0 :         return;
     149             :     }
     150             : 
     151          54 :     JB4_CIRCULARBUFFER_Destroy( &h->fifo );
     152          54 :     JB4_CIRCULARBUFFER_Destroy( &h->offsetFifo );
     153          54 :     JB4_CIRCULARBUFFER_Destroy( &h->timeStampFifo );
     154             : 
     155          54 :     free( h );
     156          54 :     *ph = NULL;
     157             : 
     158          54 :     return;
     159             : }
     160             : 
     161             : 
     162             : /* function to set the window size of the fifo and the fraction which will be considered */
     163          54 : Word16 JB4_JMF_Init(
     164             :     JB4_JMF_HANDLE h,
     165             :     const Word16 timeScale,
     166             :     const UWord16 windowSize,
     167             :     const UWord16 windowDuration,
     168             :     const UWord16 consideredFraction )
     169             : {
     170             : 
     171             :     /* check parameters */
     172             :     Word32 temp;
     173          54 :     temp = Mult_32_16( W_extract_l( W_shr( W_mult0_32_32( consideredFraction, windowSize ), 3 ) ), INV_125_Q15 );
     174          54 :     test();
     175          54 :     IF( windowSize != 0U && LT_32( temp, 2 ) )
     176             :     {
     177           0 :         return -1;
     178             :     }
     179          54 :     IF( GT_32( consideredFraction, 1000 ) )
     180             :     {
     181           0 :         return -1;
     182             :     }
     183             : 
     184             :     /* store values */
     185          54 :     h->timeScale = timeScale;
     186          54 :     move16();
     187          54 :     h->maxWindowDuration = windowDuration;
     188          54 :     move16();
     189          54 :     h->consideredFraction = consideredFraction;
     190          54 :     move16();
     191             : 
     192          54 :     JB4_CIRCULARBUFFER_Init( h->fifo, windowSize );
     193          54 :     JB4_CIRCULARBUFFER_Init( h->offsetFifo, windowSize );
     194          54 :     JB4_CIRCULARBUFFER_Init( h->timeStampFifo, windowSize );
     195             : 
     196          54 :     h->nElementsToIgnore = (UWord16) round_fx( imult3216( W_extract_l( W_shr( W_mult0_32_32( windowSize, L_sub( 1000, consideredFraction ) ), 2 ) ), INV_125_Q15 ) );
     197          54 :     move16();
     198             : 
     199          54 :     return 0;
     200             : }
     201             : 
     202             : 
     203             : /* function to calculate delay for the current packet */
     204       35055 : Word16 JB4_JMF_PushPacket(
     205             :     JB4_JMF_HANDLE h,
     206             :     const UWord32 sysTime,
     207             :     const UWord32 rtpTimeStamp )
     208             : {
     209             :     Word32 rtpTimeDiff, sysTimeDiff;
     210             :     Word32 offset, delay;
     211             : 
     212             :     /* check if this is the first entry */
     213       35055 :     IF( h->firstPacketPushed == 0 )
     214             :     {
     215          54 :         h->firstPacketPushed = 1;
     216          54 :         move16();
     217          54 :         h->lastSysTime = sysTime;
     218          54 :         move32();
     219          54 :         h->lastRtpTimeStamp = rtpTimeStamp;
     220          54 :         move32();
     221          54 :         return 0;
     222             :     }
     223             : 
     224       35001 :     rtpTimeDiff = W_extract_l( W_sub( rtpTimeStamp, h->lastRtpTimeStamp ) );
     225       35001 :     sysTimeDiff = W_extract_l( W_sub( sysTime, h->lastSysTime ) );
     226       35001 :     offset = W_extract_l( W_sub( sysTime, rtpTimeStamp ) );
     227             : 
     228             :     /* get the delay (yes, signed!!!!) */
     229       35001 :     delay = L_add( L_sub( sysTimeDiff, rtpTimeDiff ), h->lastDelay );
     230             : 
     231             :     /* remember old values */
     232       35001 :     h->lastSysTime = sysTime;
     233       35001 :     move32();
     234       35001 :     h->lastRtpTimeStamp = rtpTimeStamp;
     235       35001 :     move32();
     236             :     /* reset delay if absolute value is greater than 60s
     237             :      * to avoid overflow caused by clockdrift */
     238       35001 :     test();
     239       35001 :     IF( GT_32( delay, L_mult0( 60, h->timeScale ) ) || LT_32( delay, L_mult0( -60, h->timeScale ) ) )
     240             :     {
     241           0 :         h->lastDelay = 0;
     242           0 :         move32();
     243             :     }
     244             :     ELSE
     245             :     {
     246       35001 :         h->lastDelay = delay;
     247       35001 :         move32();
     248             :     }
     249             : 
     250       35001 :     JB4_JMF_pushBack( h, delay, offset, rtpTimeStamp );
     251             : 
     252       35001 :     return 0;
     253             : }
     254             : 
     255             : 
     256             : /* function to get the current jitter */
     257       36980 : Word16 JB4_JMF_Jitter(
     258             :     const JB4_JMF_HANDLE h,
     259             :     UWord32 *jitter )
     260             : {
     261             :     JB4_CIRCULARBUFFER_ELEMENT min_ele, percentile;
     262             : 
     263             :     /* sanity check (must not be empty) and return invalid result if there is only one entry */
     264       36980 :     IF( LT_32( JB4_CIRCULARBUFFER_Size( h->fifo ), 2U ) )
     265             :     {
     266         108 :         return -1;
     267             :     }
     268             : 
     269       36872 :     JB4_CIRCULARBUFFER_MinAndPercentile( h->fifo, h->nElementsToIgnore, &min_ele, &percentile );
     270             : 
     271             :     /* return the difference between the highest considered and the smallest value */
     272       36872 :     *jitter = L_sub( percentile, min_ele );
     273       36872 :     move32();
     274       36872 :     assert( percentile >= min_ele );
     275             : 
     276       36872 :     return 0;
     277             : }
     278             : 
     279             : 
     280             : /* function to get the minimum offset between received time and time stamp of all entries in the fifo */
     281       72295 : Word16 JB4_JMF_MinOffset(
     282             :     const JB4_JMF_HANDLE h,
     283             :     Word32 *offset )
     284             : {
     285             :     JB4_CIRCULARBUFFER_ELEMENT min_ele;
     286             : 
     287       72295 :     IF( JB4_CIRCULARBUFFER_IsEmpty( h->offsetFifo ) )
     288             :     {
     289           0 :         return -1;
     290             :     }
     291             : 
     292       72295 :     JB4_CIRCULARBUFFER_Min( h->offsetFifo, &min_ele );
     293             : 
     294       72295 :     *offset = min_ele;
     295       72295 :     move32();
     296             : 
     297       72295 :     return 0;
     298             : }
     299             : 
     300             : 
     301             : /*****************************************************************************
     302             :  **************************** private functions ******************************
     303             :  *****************************************************************************/
     304             : 
     305             : /* helper function to add entry at back of the buffer */
     306       35001 : static void JB4_JMF_pushBack(
     307             :     JB4_JMF_HANDLE h,
     308             :     const Word32 delay,
     309             :     const Word32 offset,
     310             :     const UWord32 time )
     311             : {
     312             :     Word32 minTime, maxTime;
     313             :     UWord32 duration;
     314             : 
     315             :     /* check for size and discard first entry if too big */
     316       35001 :     IF( JB4_CIRCULARBUFFER_IsFull( h->fifo ) )
     317             :     {
     318        5934 :         JB4_JMF_popFront( h );
     319             :     }
     320             : 
     321             :     /* push back new entry */
     322       35001 :     JB4_CIRCULARBUFFER_Enque( h->fifo, delay );
     323       35001 :     JB4_CIRCULARBUFFER_Enque( h->offsetFifo, offset );
     324       35001 :     JB4_CIRCULARBUFFER_Enque( h->timeStampFifo, time );
     325             : 
     326             :     /* check for duration and discard first entries if too long */
     327       35001 :     minTime = JB4_CIRCULARBUFFER_Front( h->timeStampFifo );
     328       35001 :     maxTime = JB4_CIRCULARBUFFER_Back( h->timeStampFifo );
     329       35001 :     IF( GT_32( maxTime, minTime ) )
     330             :     {
     331       34947 :         duration = L_sub( maxTime, minTime );
     332       53562 :         WHILE( GT_64( duration, h->maxWindowDuration ) )
     333             :         {
     334       18615 :             JB4_JMF_popFront( h );
     335       18615 :             minTime = JB4_CIRCULARBUFFER_Front( h->timeStampFifo );
     336       18615 :             IF( LT_32( maxTime, minTime ) )
     337             :             {
     338           0 :                 BREAK;
     339             :             }
     340       18615 :             duration = (UWord32) ( W_sub( maxTime, minTime ) );
     341             :         }
     342             :     }
     343             : 
     344       35001 :     return;
     345             : }
     346             : 
     347             : 
     348             : /* helper function to remove an entry from the front of the buffer */
     349       24549 : static void JB4_JMF_popFront(
     350             :     JB4_JMF_HANDLE h )
     351             : {
     352             :     JB4_CIRCULARBUFFER_ELEMENT tmpElement;
     353             : 
     354             :     /* try to remove one element - fails if empty */
     355       24549 :     IF( JB4_CIRCULARBUFFER_Deque( h->fifo, &tmpElement ) != 0 )
     356             :     {
     357           0 :         return;
     358             :     }
     359             : 
     360             :     /* also remove offset entry */
     361       24549 :     JB4_CIRCULARBUFFER_Deque( h->offsetFifo, &tmpElement );
     362       24549 :     JB4_CIRCULARBUFFER_Deque( h->timeStampFifo, &tmpElement );
     363             : 
     364       24549 :     return;
     365             : }

Generated by: LCOV version 1.14