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 : }
|