LCOV - code coverage report
Current view: top level - lib_dec - jbm_jb4_jmf.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 84 96 87.5 %
Date: 2025-05-23 08:37:30 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.h"
      46             : #ifdef DEBUGGING
      47             : #include "debug.h"
      48             : #endif
      49             : #include "wmc_auto.h"
      50             : 
      51             : /* local includes */
      52             : #include "jbm_jb4_jmf.h"
      53             : #include "jbm_jb4_circularbuffer.h"
      54             : /* instrumentation */
      55             : 
      56             : 
      57             : /** jitter measure fifo - a fifo used for windowed measure of network status */
      58             : struct JB4_JMF
      59             : {
      60             :     /** scale of system time and RTP time stamps */
      61             :     int16_t timeScale;
      62             :     /** the window size of the fifo as time in sysTimeScale */
      63             :     uint16_t maxWindowDuration;
      64             :     /** considered fraction in 1/1000 units, e.g. 900 ignores 10% of the highest samples */
      65             :     uint16_t consideredFraction;
      66             : 
      67             :     /** fifo containing the delay entries (ordered by receive time) */
      68             :     JB4_CIRCULARBUFFER_HANDLE fifo;
      69             :     /** fifo containing the offset entries (ordered by receive time) */
      70             :     JB4_CIRCULARBUFFER_HANDLE offsetFifo;
      71             :     /** fifo containing the RTP times of the values in offsetFifo (ordered by receive time) */
      72             :     JB4_CIRCULARBUFFER_HANDLE timeStampFifo;
      73             :     /** flag if the first packet was already pushed */
      74             :     int16_t firstPacketPushed;
      75             :     /** last packets system time in microseconds */
      76             :     int32_t lastSysTime;
      77             :     /** RTP time stamp of the last pushed packet */
      78             :     int32_t lastRtpTimeStamp;
      79             :     /** last packets calculated delay value */
      80             :     int32_t lastDelay;
      81             :     /** number of elements to ignore for percentile calculation - value set within init */
      82             :     int16_t nElementsToIgnore;
      83             : };
      84             : 
      85             : 
      86             : /** helper function to add an entry at back of the buffer */
      87             : static void JB4_JMF_pushBack( JB4_JMF_HANDLE h, const int32_t delay, const int32_t offset, const uint32_t time );
      88             : 
      89             : /** helper function to remove an entry from the front of the buffer */
      90             : static void JB4_JMF_popFront( JB4_JMF_HANDLE h );
      91             : 
      92             : 
      93         210 : ivas_error JB4_JMF_Create(
      94             :     JB4_JMF_HANDLE *ph )
      95             : {
      96             :     JB4_JMF_HANDLE h;
      97             :     ivas_error error;
      98             : 
      99         210 :     if ( ( h = malloc( sizeof( struct JB4_JMF ) ) ) == NULL )
     100             :     {
     101           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM\n" ) );
     102             :     }
     103             : 
     104         210 :     if ( ( error = JB4_CIRCULARBUFFER_Create( &h->fifo ) ) != IVAS_ERR_OK )
     105             :     {
     106           0 :         return error;
     107             :     }
     108         210 :     if ( ( JB4_CIRCULARBUFFER_Create( &h->offsetFifo ) ) != IVAS_ERR_OK )
     109             :     {
     110           0 :         return error;
     111             :     }
     112         210 :     if ( ( JB4_CIRCULARBUFFER_Create( &h->timeStampFifo ) ) != IVAS_ERR_OK )
     113             :     {
     114           0 :         return error;
     115             :     }
     116             : 
     117         210 :     h->timeScale = 1000;
     118         210 :     h->consideredFraction = 1000;
     119         210 :     h->firstPacketPushed = 0;
     120         210 :     h->lastSysTime = 0;
     121         210 :     h->lastRtpTimeStamp = 0;
     122         210 :     h->lastDelay = 0;
     123         210 :     h->nElementsToIgnore = 0;
     124             : 
     125         210 :     *ph = h;
     126             : 
     127         210 :     return IVAS_ERR_OK;
     128             : }
     129             : 
     130             : 
     131         210 : void JB4_JMF_Destroy(
     132             :     JB4_JMF_HANDLE *ph )
     133             : {
     134             :     JB4_JMF_HANDLE h;
     135             : 
     136         210 :     if ( !ph )
     137             :     {
     138           0 :         return;
     139             :     }
     140         210 :     h = *ph;
     141         210 :     if ( !h )
     142             :     {
     143           0 :         return;
     144             :     }
     145             : 
     146         210 :     JB4_CIRCULARBUFFER_Destroy( &h->fifo );
     147         210 :     JB4_CIRCULARBUFFER_Destroy( &h->offsetFifo );
     148         210 :     JB4_CIRCULARBUFFER_Destroy( &h->timeStampFifo );
     149             : 
     150         210 :     free( h );
     151         210 :     *ph = NULL;
     152             : 
     153         210 :     return;
     154             : }
     155             : 
     156             : 
     157             : /* function to set the window size of the fifo and the fraction which will be considered */
     158         210 : int16_t JB4_JMF_Init(
     159             :     JB4_JMF_HANDLE h,
     160             :     const int16_t timeScale,
     161             :     const uint16_t windowSize,
     162             :     const uint16_t windowDuration,
     163             :     const uint16_t consideredFraction )
     164             : {
     165             : 
     166             :     /* check parameters */
     167         210 :     if ( windowSize != 0U && consideredFraction * windowSize / 1000 < 2 )
     168             :     {
     169           0 :         return -1;
     170             :     }
     171         210 :     if ( consideredFraction > 1000 )
     172             :     {
     173           0 :         return -1;
     174             :     }
     175             : 
     176             :     /* store values */
     177         210 :     h->timeScale = timeScale;
     178         210 :     h->maxWindowDuration = windowDuration;
     179         210 :     h->consideredFraction = consideredFraction;
     180             : 
     181         210 :     JB4_CIRCULARBUFFER_Init( h->fifo, windowSize );
     182         210 :     JB4_CIRCULARBUFFER_Init( h->offsetFifo, windowSize );
     183         210 :     JB4_CIRCULARBUFFER_Init( h->timeStampFifo, windowSize );
     184             : 
     185         210 :     h->nElementsToIgnore = (uint16_t) ( windowSize * ( 1000 - consideredFraction ) / 1000 );
     186             : 
     187         210 :     return 0;
     188             : }
     189             : 
     190             : 
     191             : /* function to calculate delay for the current packet */
     192      139842 : int16_t JB4_JMF_PushPacket(
     193             :     JB4_JMF_HANDLE h,
     194             :     const uint32_t sysTime,
     195             :     const uint32_t rtpTimeStamp )
     196             : {
     197             :     int32_t rtpTimeDiff, sysTimeDiff;
     198             :     int32_t offset, delay;
     199             : 
     200             :     /* check if this is the first entry */
     201      139842 :     if ( h->firstPacketPushed == 0 )
     202             :     {
     203         210 :         h->firstPacketPushed = 1;
     204         210 :         h->lastSysTime = sysTime;
     205         210 :         h->lastRtpTimeStamp = rtpTimeStamp;
     206         210 :         return 0;
     207             :     }
     208             : 
     209      139632 :     rtpTimeDiff = (int32_t) ( rtpTimeStamp - h->lastRtpTimeStamp );
     210      139632 :     sysTimeDiff = sysTime - h->lastSysTime;
     211      139632 :     offset = (int32_t) sysTime - (int32_t) rtpTimeStamp;
     212             : 
     213             :     /* get the delay (yes, signed!!!!) */
     214      139632 :     delay = sysTimeDiff - rtpTimeDiff + h->lastDelay;
     215             : 
     216             :     /* remember old values */
     217      139632 :     h->lastSysTime = sysTime;
     218      139632 :     h->lastRtpTimeStamp = rtpTimeStamp;
     219             :     /* reset delay if absolute value is greater than 60s
     220             :      * to avoid overflow caused by clockdrift */
     221      139632 :     if ( delay > 60 * h->timeScale || delay < -60 * h->timeScale )
     222             :     {
     223           0 :         h->lastDelay = 0;
     224             :     }
     225             :     else
     226             :     {
     227      139632 :         h->lastDelay = delay;
     228             :     }
     229             : 
     230      139632 :     JB4_JMF_pushBack( h, delay, offset, rtpTimeStamp );
     231             : 
     232      139632 :     return 0;
     233             : }
     234             : 
     235             : 
     236             : /* function to get the current jitter */
     237      146727 : int16_t JB4_JMF_Jitter(
     238             :     const JB4_JMF_HANDLE h,
     239             :     uint32_t *jitter )
     240             : {
     241             :     JB4_CIRCULARBUFFER_ELEMENT min_ele, percentile;
     242             : 
     243             :     /* sanity check (must not be empty) and return invalid result if there is only one entry */
     244      146727 :     if ( JB4_CIRCULARBUFFER_Size( h->fifo ) < 2U )
     245             :     {
     246         420 :         return -1;
     247             :     }
     248             : 
     249      146307 :     JB4_CIRCULARBUFFER_MinAndPercentile( h->fifo, h->nElementsToIgnore, &min_ele, &percentile );
     250             : 
     251             :     /* return the difference between the highest considered and the smallest value */
     252      146307 :     *jitter = percentile - min_ele;
     253      146307 :     assert( percentile >= min_ele );
     254             : 
     255      146307 :     return 0;
     256             : }
     257             : 
     258             : 
     259             : /* function to get the minimum offset between received time and time stamp of all entries in the fifo */
     260      287109 : int16_t JB4_JMF_MinOffset(
     261             :     const JB4_JMF_HANDLE h,
     262             :     int32_t *offset )
     263             : {
     264             :     JB4_CIRCULARBUFFER_ELEMENT min_ele;
     265             : 
     266      287109 :     if ( JB4_CIRCULARBUFFER_IsEmpty( h->offsetFifo ) )
     267             :     {
     268           0 :         return -1;
     269             :     }
     270             : 
     271      287109 :     JB4_CIRCULARBUFFER_Min( h->offsetFifo, &min_ele );
     272             : 
     273      287109 :     *offset = min_ele;
     274             : 
     275      287109 :     return 0;
     276             : }
     277             : 
     278             : 
     279             : /*****************************************************************************
     280             :  **************************** private functions ******************************
     281             :  *****************************************************************************/
     282             : 
     283             : /* helper function to add entry at back of the buffer */
     284      139632 : static void JB4_JMF_pushBack(
     285             :     JB4_JMF_HANDLE h,
     286             :     const int32_t delay,
     287             :     const int32_t offset,
     288             :     const uint32_t time )
     289             : {
     290             :     int32_t minTime, maxTime;
     291             :     uint32_t duration;
     292             : 
     293             :     /* check for size and discard first entry if too big */
     294      139632 :     if ( JB4_CIRCULARBUFFER_IsFull( h->fifo ) )
     295             :     {
     296       21573 :         JB4_JMF_popFront( h );
     297             :     }
     298             : 
     299             :     /* push back new entry */
     300      139632 :     JB4_CIRCULARBUFFER_Enque( h->fifo, delay );
     301      139632 :     JB4_CIRCULARBUFFER_Enque( h->offsetFifo, offset );
     302      139632 :     JB4_CIRCULARBUFFER_Enque( h->timeStampFifo, time );
     303             : 
     304             :     /* check for duration and discard first entries if too long */
     305      139632 :     minTime = JB4_CIRCULARBUFFER_Front( h->timeStampFifo );
     306      139632 :     maxTime = JB4_CIRCULARBUFFER_Back( h->timeStampFifo );
     307      139632 :     if ( maxTime > minTime )
     308             :     {
     309      139422 :         duration = maxTime - minTime;
     310      217521 :         while ( duration > h->maxWindowDuration )
     311             :         {
     312       78099 :             JB4_JMF_popFront( h );
     313       78099 :             minTime = JB4_CIRCULARBUFFER_Front( h->timeStampFifo );
     314       78099 :             if ( maxTime <= minTime )
     315             :             {
     316           0 :                 break;
     317             :             }
     318       78099 :             duration = maxTime - minTime;
     319             :         }
     320             :     }
     321             : 
     322      139632 :     return;
     323             : }
     324             : 
     325             : 
     326             : /* helper function to remove an entry from the front of the buffer */
     327       99672 : static void JB4_JMF_popFront(
     328             :     JB4_JMF_HANDLE h )
     329             : {
     330             :     JB4_CIRCULARBUFFER_ELEMENT tmpElement;
     331             : 
     332             :     /* try to remove one element - fails if empty */
     333       99672 :     if ( JB4_CIRCULARBUFFER_Deque( h->fifo, &tmpElement ) != 0 )
     334             :     {
     335           0 :         return;
     336             :     }
     337             : 
     338             :     /* also remove offset entry */
     339       99672 :     JB4_CIRCULARBUFFER_Deque( h->offsetFifo, &tmpElement );
     340       99672 :     JB4_CIRCULARBUFFER_Deque( h->timeStampFifo, &tmpElement );
     341             : 
     342       99672 :     return;
     343             : }

Generated by: LCOV version 1.14