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