Let's also include aclocal.m4
[asterisk-bristuff.git] / main / fixedjitterbuf.c
blob1d7a5cc301f71f0d0a78c61b1fdb8d33eef6c18a
1 /*
2 * Copyright (C) 2005, Attractel OOD
4 * Contributors:
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
18 * this code.
21 /*! \file
23 * \brief Jitterbuffering algorithm.
25 * \author Slav Klenov <slav@securax.org>
28 #include "asterisk.h"
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <assert.h>
35 #include <string.h>
36 #include <unistd.h>
38 #include "asterisk/utils.h"
39 #include "fixedjitterbuf.h"
41 #undef FIXED_JB_DEBUG
43 #ifdef FIXED_JB_DEBUG
44 #define ASSERT(a)
45 #else
46 #define ASSERT(a) assert(a)
47 #endif
49 /*! \brief private fixed_jb structure */
50 struct fixed_jb
52 struct fixed_jb_frame *frames;
53 struct fixed_jb_frame *tail;
54 struct fixed_jb_conf conf;
55 long rxcore;
56 long delay;
57 long next_delivery;
58 int force_resynch;
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)
74 free(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 */
82 fr = jb->frames;
83 jb->frames = fr->next;
84 if (jb->frames) {
85 jb->frames->prev = NULL;
86 } else {
87 /* the jb is empty - update tail */
88 jb->tail = NULL;
91 /* update next */
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)
104 struct fixed_jb *jb;
106 if (!(jb = ast_calloc(1, sizeof(*jb))))
107 return NULL;
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 */
113 conf = &jb->conf;
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;
125 return jb;
129 void fixed_jb_destroy(struct fixed_jb *jb)
131 /* jitterbuf MUST be empty before it can be destroyed */
132 ASSERT(jb->frames == NULL);
134 free(jb);
138 static int resynch_jb(struct fixed_jb *jb, void *data, long ms, long ts, long now)
140 long diff, offset;
141 struct fixed_jb_frame *frame;
143 /* If jb is empty, just reinitialize the jb */
144 if (!jb->frames) {
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
158 offset */
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;
170 frame = jb->frames;
171 while (frame) {
172 frame->ts += offset;
173 frame = frame->next;
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;
195 /* put the frame */
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;
203 long delivery;
205 /* debug check the validity of the input params */
206 ASSERT(data != NULL);
207 /* do not allow frames shorter than 2 ms */
208 ASSERT(ms >= 2);
209 ASSERT(ts >= 0);
210 ASSERT(now >= 0);
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 */
230 frame = jb->tail;
231 while (frame && frame->delivery > delivery) {
232 frame = frame->prev;
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;
254 newframe->ts = ts;
255 newframe->ms = ms;
256 newframe->delivery = delivery;
258 /* and insert it right on place */
259 if (frame) {
260 next = frame->next;
261 frame->next = newframe;
262 if (next) {
263 newframe->next = next;
264 next->prev = newframe;
265 } else {
266 /* insert after the last frame - should update tail */
267 jb->tail = newframe;
268 newframe->next = NULL;
270 newframe->prev = frame;
272 return FIXED_JB_OK;
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;
281 return FIXED_JB_OK;
282 } else {
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;
289 return FIXED_JB_OK;
294 int fixed_jb_get(struct fixed_jb *jb, struct fixed_jb_frame *frame, long now, long interpl)
296 ASSERT(now >= 0);
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? */
305 if (!jb->frames) {
306 /* should interpolate a frame */
307 /* update next */
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 */
324 /* update next */
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);
333 return FIXED_JB_OK;
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)
345 if (!jb->frames)
346 return FIXED_JB_NOFRAME;
348 get_jb_head(jb, frameout);
350 return FIXED_JB_OK;