2 * Copyright (C) 2005, Attractel OOD
5 * Slav Klenov <slav@securax.org>
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
17 * A license has been granted to Digium (via disclaimer) for the use of
23 * \brief Jitterbuffering algorithm.
25 * \author Slav Klenov <slav@securax.org>
30 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
38 #include "asterisk/utils.h"
39 #include "fixedjitterbuf.h"
46 #define ASSERT(a) assert(a)
49 /*! \brief private fixed_jb structure */
52 struct fixed_jb_frame
*frames
;
53 struct fixed_jb_frame
*tail
;
54 struct fixed_jb_conf conf
;
62 static struct fixed_jb_frame
*alloc_jb_frame(struct fixed_jb
*jb
);
63 static void release_jb_frame(struct fixed_jb
*jb
, struct fixed_jb_frame
*frame
);
64 static void get_jb_head(struct fixed_jb
*jb
, struct fixed_jb_frame
*frame
);
65 static int resynch_jb(struct fixed_jb
*jb
, void *data
, long ms
, long ts
, long now
);
67 static inline struct fixed_jb_frame
*alloc_jb_frame(struct fixed_jb
*jb
)
69 return ast_calloc(1, sizeof(struct fixed_jb_frame
));
72 static inline void release_jb_frame(struct fixed_jb
*jb
, struct fixed_jb_frame
*frame
)
77 static void get_jb_head(struct fixed_jb
*jb
, struct fixed_jb_frame
*frame
)
79 struct fixed_jb_frame
*fr
;
81 /* unlink the frame */
83 jb
->frames
= fr
->next
;
85 jb
->frames
->prev
= NULL
;
87 /* the jb is empty - update tail */
92 jb
->next_delivery
= fr
->delivery
+ fr
->ms
;
94 /* copy the destination */
95 memcpy(frame
, fr
, sizeof(struct fixed_jb_frame
));
97 /* and release the frame */
98 release_jb_frame(jb
, fr
);
102 struct fixed_jb
*fixed_jb_new(struct fixed_jb_conf
*conf
)
106 if (!(jb
= ast_calloc(1, sizeof(*jb
))))
109 /* First copy our config */
110 memcpy(&jb
->conf
, conf
, sizeof(struct fixed_jb_conf
));
112 /* we dont need the passed config anymore - continue working with the saved one */
115 /* validate the configuration */
116 if (conf
->jbsize
< 1)
117 conf
->jbsize
= FIXED_JB_SIZE_DEFAULT
;
119 if (conf
->resync_threshold
< 1)
120 conf
->resync_threshold
= FIXED_JB_RESYNCH_THRESHOLD_DEFAULT
;
122 /* Set the constant delay to the jitterbuf */
123 jb
->delay
= conf
->jbsize
;
129 void fixed_jb_destroy(struct fixed_jb
*jb
)
131 /* jitterbuf MUST be empty before it can be destroyed */
132 ASSERT(jb
->frames
== NULL
);
138 static int resynch_jb(struct fixed_jb
*jb
, void *data
, long ms
, long ts
, long now
)
141 struct fixed_jb_frame
*frame
;
143 /* If jb is empty, just reinitialize the jb */
145 /* debug check: tail should also be NULL */
146 ASSERT(jb
->tail
== NULL
);
148 return fixed_jb_put_first(jb
, data
, ms
, ts
, now
);
151 /* Adjust all jb state just as the new frame is with delivery = the delivery of the last
152 frame (e.g. this one with max delivery) + the length of the last frame. */
154 /* Get the diff in timestamps */
155 diff
= ts
- jb
->tail
->ts
;
157 /* Ideally this should be just the length of the last frame. The deviation is the desired
159 offset
= diff
- jb
->tail
->ms
;
161 /* Do we really need to resynch, or this is just a frame for dropping? */
162 if (!jb
->force_resynch
&& (offset
< jb
->conf
.resync_threshold
&& offset
> -jb
->conf
.resync_threshold
))
163 return FIXED_JB_DROP
;
165 /* Reset the force resynch flag */
166 jb
->force_resynch
= 0;
168 /* apply the offset to the jb state */
169 jb
->rxcore
-= offset
;
176 /* now jb_put() should add the frame at a last position */
177 return fixed_jb_put(jb
, data
, ms
, ts
, now
);
181 void fixed_jb_set_force_resynch(struct fixed_jb
*jb
)
183 jb
->force_resynch
= 1;
187 int fixed_jb_put_first(struct fixed_jb
*jb
, void *data
, long ms
, long ts
, long now
)
189 /* this is our first frame - set the base of the receivers time */
190 jb
->rxcore
= now
- ts
;
192 /* init next for a first time - it should be the time the first frame should be played */
193 jb
->next_delivery
= now
+ jb
->delay
;
196 return fixed_jb_put(jb
, data
, ms
, ts
, now
);
200 int fixed_jb_put(struct fixed_jb
*jb
, void *data
, long ms
, long ts
, long now
)
202 struct fixed_jb_frame
*frame
, *next
, *newframe
;
205 /* debug check the validity of the input params */
206 ASSERT(data
!= NULL
);
207 /* do not allow frames shorter than 2 ms */
212 delivery
= jb
->rxcore
+ jb
->delay
+ ts
;
214 /* check if the new frame is not too late */
215 if (delivery
< jb
->next_delivery
) {
216 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
217 the force resynch flag was not set. */
218 return resynch_jb(jb
, data
, ms
, ts
, now
);
221 /* what if the delivery time is bigger than next + delay? Seems like a frame for the future.
222 However, allow more resync_threshold ms in advance */
223 if (delivery
> jb
->next_delivery
+ jb
->delay
+ jb
->conf
.resync_threshold
) {
224 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
225 the force resynch flag was not set. */
226 return resynch_jb(jb
, data
, ms
, ts
, now
);
229 /* find the right place in the frames list, sorted by delivery time */
231 while (frame
&& frame
->delivery
> delivery
) {
235 /* Check if the new delivery time is not covered already by the chosen frame */
236 if (frame
&& (frame
->delivery
== delivery
||
237 delivery
< frame
->delivery
+ frame
->ms
||
238 (frame
->next
&& delivery
+ ms
> frame
->next
->delivery
)))
240 /* TODO: Should we check for resynch here? Be careful to do not allow threshold smaller than
241 the size of the jb */
243 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
244 the force resynch flag was not set. */
245 return resynch_jb(jb
, data
, ms
, ts
, now
);
248 /* Reset the force resynch flag */
249 jb
->force_resynch
= 0;
251 /* Get a new frame */
252 newframe
= alloc_jb_frame(jb
);
253 newframe
->data
= data
;
256 newframe
->delivery
= delivery
;
258 /* and insert it right on place */
261 frame
->next
= newframe
;
263 newframe
->next
= next
;
264 next
->prev
= newframe
;
266 /* insert after the last frame - should update tail */
268 newframe
->next
= NULL
;
270 newframe
->prev
= frame
;
273 } else if (!jb
->frames
) {
274 /* the frame list is empty or thats just the first frame ever */
275 /* tail should also be NULL is that case */
276 ASSERT(jb
->tail
== NULL
);
277 jb
->frames
= jb
->tail
= newframe
;
278 newframe
->next
= NULL
;
279 newframe
->prev
= NULL
;
283 /* insert on a first position - should update frames head */
284 newframe
->next
= jb
->frames
;
285 newframe
->prev
= NULL
;
286 jb
->frames
->prev
= newframe
;
287 jb
->frames
= newframe
;
294 int fixed_jb_get(struct fixed_jb
*jb
, struct fixed_jb_frame
*frame
, long now
, long interpl
)
297 ASSERT(interpl
>= 2);
299 if (now
< jb
->next_delivery
) {
300 /* too early for the next frame */
301 return FIXED_JB_NOFRAME
;
304 /* Is the jb empty? */
306 /* should interpolate a frame */
308 jb
->next_delivery
+= interpl
;
310 return FIXED_JB_INTERP
;
313 /* Isn't it too late for the first frame available in the jb? */
314 if (now
> jb
->frames
->delivery
+ jb
->frames
->ms
) {
315 /* yes - should drop this frame and update next to point the next frame (get_jb_head() does it) */
316 get_jb_head(jb
, frame
);
318 return FIXED_JB_DROP
;
321 /* isn't it too early to play the first frame available? */
322 if (now
< jb
->frames
->delivery
) {
323 /* yes - should interpolate one frame */
325 jb
->next_delivery
+= interpl
;
327 return FIXED_JB_INTERP
;
330 /* we have a frame for playing now (get_jb_head() updates next) */
331 get_jb_head(jb
, frame
);
337 long fixed_jb_next(struct fixed_jb
*jb
)
339 return jb
->next_delivery
;
343 int fixed_jb_remove(struct fixed_jb
*jb
, struct fixed_jb_frame
*frameout
)
346 return FIXED_JB_NOFRAME
;
348 get_jb_head(jb
, frameout
);