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>
29 <support_level>core</support_level>
36 #include "asterisk/utils.h"
37 #include "fixedjitterbuf.h"
44 #define ASSERT(a) assert(a)
47 /*! \brief private fixed_jb structure */
50 struct fixed_jb_frame *frames;
51 struct fixed_jb_frame *tail;
52 struct fixed_jb_conf conf;
60 static struct fixed_jb_frame *alloc_jb_frame(struct fixed_jb *jb);
61 static void release_jb_frame(struct fixed_jb *jb, struct fixed_jb_frame *frame);
62 static void get_jb_head(struct fixed_jb *jb, struct fixed_jb_frame *frame);
63 static int resynch_jb(struct fixed_jb *jb, void *data, long ms, long ts, long now);
65 static inline struct fixed_jb_frame *alloc_jb_frame(struct fixed_jb *jb)
67 return ast_calloc(1, sizeof(*jb));
70 static inline void release_jb_frame(struct fixed_jb *jb, struct fixed_jb_frame *frame)
75 static void get_jb_head(struct fixed_jb *jb, struct fixed_jb_frame *frame)
77 struct fixed_jb_frame *fr;
79 /* unlink the frame */
81 jb->frames = fr->next;
83 jb->frames->prev = NULL;
85 /* the jb is empty - update tail */
90 jb->next_delivery = fr->delivery + fr->ms;
92 /* copy the destination */
93 memcpy(frame, fr, sizeof(struct fixed_jb_frame));
95 /* and release the frame */
96 release_jb_frame(jb, fr);
100 struct fixed_jb *fixed_jb_new(struct fixed_jb_conf *conf)
104 if (!(jb = ast_calloc(1, sizeof(*jb))))
107 /* First copy our config */
108 memcpy(&jb->conf, conf, sizeof(struct fixed_jb_conf));
110 /* we don't need the passed config anymore - continue working with the saved one */
113 /* validate the configuration */
114 if (conf->jbsize < 1)
115 conf->jbsize = FIXED_JB_SIZE_DEFAULT;
117 if (conf->resync_threshold < 1)
118 conf->resync_threshold = FIXED_JB_RESYNCH_THRESHOLD_DEFAULT;
120 /* Set the constant delay to the jitterbuf */
121 jb->delay = conf->jbsize;
127 void fixed_jb_destroy(struct fixed_jb *jb)
129 /* jitterbuf MUST be empty before it can be destroyed */
130 ASSERT(jb->frames == NULL);
136 static int resynch_jb(struct fixed_jb *jb, void *data, long ms, long ts, long now)
139 struct fixed_jb_frame *frame;
141 /* If jb is empty, just reinitialize the jb */
143 /* debug check: tail should also be NULL */
144 ASSERT(jb->tail == NULL);
146 return fixed_jb_put_first(jb, data, ms, ts, now);
149 /* Adjust all jb state just as the new frame is with delivery = the delivery of the last
150 frame (e.g. this one with max delivery) + the length of the last frame. */
152 /* Get the diff in timestamps */
153 diff = ts - jb->tail->ts;
155 /* Ideally this should be just the length of the last frame. The deviation is the desired
157 offset = diff - jb->tail->ms;
159 /* Do we really need to resynch, or this is just a frame for dropping? */
160 if (!jb->force_resynch && (offset < jb->conf.resync_threshold && offset > -jb->conf.resync_threshold))
161 return FIXED_JB_DROP;
163 /* Reset the force resynch flag */
164 jb->force_resynch = 0;
166 /* apply the offset to the jb state */
167 jb->rxcore -= offset;
174 /* now jb_put() should add the frame at a last position */
175 return fixed_jb_put(jb, data, ms, ts, now);
179 void fixed_jb_set_force_resynch(struct fixed_jb *jb)
181 jb->force_resynch = 1;
185 int fixed_jb_put_first(struct fixed_jb *jb, void *data, long ms, long ts, long now)
187 /* this is our first frame - set the base of the receivers time */
188 jb->rxcore = now - ts;
190 /* init next for a first time - it should be the time the first frame should be played */
191 jb->next_delivery = now + jb->delay;
194 return fixed_jb_put(jb, data, ms, ts, now);
198 int fixed_jb_put(struct fixed_jb *jb, void *data, long ms, long ts, long now)
200 struct fixed_jb_frame *frame, *next, *newframe;
203 /* debug check the validity of the input params */
204 ASSERT(data != NULL);
205 /* do not allow frames shorter than 2 ms */
210 delivery = jb->rxcore + jb->delay + ts;
212 /* check if the new frame is not too late */
213 if (delivery < jb->next_delivery) {
214 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
215 the force resynch flag was not set. */
216 return resynch_jb(jb, data, ms, ts, now);
219 /* what if the delivery time is bigger than next + delay? Seems like a frame for the future.
220 However, allow more resync_threshold ms in advance */
221 if (delivery > jb->next_delivery + jb->delay + jb->conf.resync_threshold) {
222 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
223 the force resynch flag was not set. */
224 return resynch_jb(jb, data, ms, ts, now);
227 /* find the right place in the frames list, sorted by delivery time */
229 while (frame && frame->delivery > delivery) {
233 /* Check if the new delivery time is not covered already by the chosen frame */
234 if (frame && (frame->delivery == delivery ||
235 delivery < frame->delivery + frame->ms ||
236 (frame->next && delivery + ms > frame->next->delivery)))
238 /* TODO: Should we check for resynch here? Be careful to do not allow threshold smaller than
239 the size of the jb */
241 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
242 the force resynch flag was not set. */
243 return resynch_jb(jb, data, ms, ts, now);
246 /* Reset the force resynch flag */
247 jb->force_resynch = 0;
249 /* Get a new frame */
250 newframe = alloc_jb_frame(jb);
251 newframe->data = data;
254 newframe->delivery = delivery;
256 /* and insert it right on place */
259 frame->next = newframe;
261 newframe->next = next;
262 next->prev = newframe;
264 /* insert after the last frame - should update tail */
266 newframe->next = NULL;
268 newframe->prev = frame;
271 } else if (!jb->frames) {
272 /* the frame list is empty or thats just the first frame ever */
273 /* tail should also be NULL is that case */
274 ASSERT(jb->tail == NULL);
275 jb->frames = jb->tail = newframe;
276 newframe->next = NULL;
277 newframe->prev = NULL;
281 /* insert on a first position - should update frames head */
282 newframe->next = jb->frames;
283 newframe->prev = NULL;
284 jb->frames->prev = newframe;
285 jb->frames = newframe;
292 int fixed_jb_get(struct fixed_jb *jb, struct fixed_jb_frame *frame, long now, long interpl)
295 ASSERT(interpl >= 2);
297 if (now < jb->next_delivery) {
298 /* too early for the next frame */
299 return FIXED_JB_NOFRAME;
302 /* Is the jb empty? */
304 /* should interpolate a frame */
306 jb->next_delivery += interpl;
308 return FIXED_JB_INTERP;
311 /* Isn't it too late for the first frame available in the jb? */
312 if (now > jb->frames->delivery + jb->frames->ms) {
313 /* yes - should drop this frame and update next to point the next frame (get_jb_head() does it) */
314 get_jb_head(jb, frame);
316 return FIXED_JB_DROP;
319 /* isn't it too early to play the first frame available? */
320 if (now < jb->frames->delivery) {
321 /* yes - should interpolate one frame */
323 jb->next_delivery += interpl;
325 return FIXED_JB_INTERP;
328 /* we have a frame for playing now (get_jb_head() updates next) */
329 get_jb_head(jb, frame);
335 long fixed_jb_next(struct fixed_jb *jb)
337 return jb->next_delivery;
341 int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout)
344 return FIXED_JB_NOFRAME;
346 get_jb_head(jb, frameout);