Merged revisions 116463 via svnmerge from
[asterisk-bristuff.git] / main / fixedjitterbuf.c
blob8a885b8e6d2fa88b9450299283f8119c9c4c685c
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 <assert.h>
34 #include "asterisk/utils.h"
35 #include "fixedjitterbuf.h"
37 #undef FIXED_JB_DEBUG
39 #ifdef FIXED_JB_DEBUG
40 #define ASSERT(a)
41 #else
42 #define ASSERT(a) assert(a)
43 #endif
45 /*! \brief private fixed_jb structure */
46 struct fixed_jb
48 struct fixed_jb_frame *frames;
49 struct fixed_jb_frame *tail;
50 struct fixed_jb_conf conf;
51 long rxcore;
52 long delay;
53 long next_delivery;
54 int force_resynch;
58 static struct fixed_jb_frame *alloc_jb_frame(struct fixed_jb *jb);
59 static void release_jb_frame(struct fixed_jb *jb, struct fixed_jb_frame *frame);
60 static void get_jb_head(struct fixed_jb *jb, struct fixed_jb_frame *frame);
61 static int resynch_jb(struct fixed_jb *jb, void *data, long ms, long ts, long now);
63 static inline struct fixed_jb_frame *alloc_jb_frame(struct fixed_jb *jb)
65 return ast_calloc(1, sizeof(*jb));
68 static inline void release_jb_frame(struct fixed_jb *jb, struct fixed_jb_frame *frame)
70 ast_free(frame);
73 static void get_jb_head(struct fixed_jb *jb, struct fixed_jb_frame *frame)
75 struct fixed_jb_frame *fr;
77 /* unlink the frame */
78 fr = jb->frames;
79 jb->frames = fr->next;
80 if (jb->frames) {
81 jb->frames->prev = NULL;
82 } else {
83 /* the jb is empty - update tail */
84 jb->tail = NULL;
87 /* update next */
88 jb->next_delivery = fr->delivery + fr->ms;
90 /* copy the destination */
91 memcpy(frame, fr, sizeof(struct fixed_jb_frame));
93 /* and release the frame */
94 release_jb_frame(jb, fr);
98 struct fixed_jb *fixed_jb_new(struct fixed_jb_conf *conf)
100 struct fixed_jb *jb;
102 if (!(jb = ast_calloc(1, sizeof(*jb))))
103 return NULL;
105 /* First copy our config */
106 memcpy(&jb->conf, conf, sizeof(struct fixed_jb_conf));
108 /* we dont need the passed config anymore - continue working with the saved one */
109 conf = &jb->conf;
111 /* validate the configuration */
112 if (conf->jbsize < 1)
113 conf->jbsize = FIXED_JB_SIZE_DEFAULT;
115 if (conf->resync_threshold < 1)
116 conf->resync_threshold = FIXED_JB_RESYNCH_THRESHOLD_DEFAULT;
118 /* Set the constant delay to the jitterbuf */
119 jb->delay = conf->jbsize;
121 return jb;
125 void fixed_jb_destroy(struct fixed_jb *jb)
127 /* jitterbuf MUST be empty before it can be destroyed */
128 ASSERT(jb->frames == NULL);
130 ast_free(jb);
134 static int resynch_jb(struct fixed_jb *jb, void *data, long ms, long ts, long now)
136 long diff, offset;
137 struct fixed_jb_frame *frame;
139 /* If jb is empty, just reinitialize the jb */
140 if (!jb->frames) {
141 /* debug check: tail should also be NULL */
142 ASSERT(jb->tail == NULL);
144 return fixed_jb_put_first(jb, data, ms, ts, now);
147 /* Adjust all jb state just as the new frame is with delivery = the delivery of the last
148 frame (e.g. this one with max delivery) + the length of the last frame. */
150 /* Get the diff in timestamps */
151 diff = ts - jb->tail->ts;
153 /* Ideally this should be just the length of the last frame. The deviation is the desired
154 offset */
155 offset = diff - jb->tail->ms;
157 /* Do we really need to resynch, or this is just a frame for dropping? */
158 if (!jb->force_resynch && (offset < jb->conf.resync_threshold && offset > -jb->conf.resync_threshold))
159 return FIXED_JB_DROP;
161 /* Reset the force resynch flag */
162 jb->force_resynch = 0;
164 /* apply the offset to the jb state */
165 jb->rxcore -= offset;
166 frame = jb->frames;
167 while (frame) {
168 frame->ts += offset;
169 frame = frame->next;
172 /* now jb_put() should add the frame at a last position */
173 return fixed_jb_put(jb, data, ms, ts, now);
177 void fixed_jb_set_force_resynch(struct fixed_jb *jb)
179 jb->force_resynch = 1;
183 int fixed_jb_put_first(struct fixed_jb *jb, void *data, long ms, long ts, long now)
185 /* this is our first frame - set the base of the receivers time */
186 jb->rxcore = now - ts;
188 /* init next for a first time - it should be the time the first frame should be played */
189 jb->next_delivery = now + jb->delay;
191 /* put the frame */
192 return fixed_jb_put(jb, data, ms, ts, now);
196 int fixed_jb_put(struct fixed_jb *jb, void *data, long ms, long ts, long now)
198 struct fixed_jb_frame *frame, *next, *newframe;
199 long delivery;
201 /* debug check the validity of the input params */
202 ASSERT(data != NULL);
203 /* do not allow frames shorter than 2 ms */
204 ASSERT(ms >= 2);
205 ASSERT(ts >= 0);
206 ASSERT(now >= 0);
208 delivery = jb->rxcore + jb->delay + ts;
210 /* check if the new frame is not too late */
211 if (delivery < jb->next_delivery) {
212 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
213 the force resynch flag was not set. */
214 return resynch_jb(jb, data, ms, ts, now);
217 /* what if the delivery time is bigger than next + delay? Seems like a frame for the future.
218 However, allow more resync_threshold ms in advance */
219 if (delivery > jb->next_delivery + jb->delay + jb->conf.resync_threshold) {
220 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
221 the force resynch flag was not set. */
222 return resynch_jb(jb, data, ms, ts, now);
225 /* find the right place in the frames list, sorted by delivery time */
226 frame = jb->tail;
227 while (frame && frame->delivery > delivery) {
228 frame = frame->prev;
231 /* Check if the new delivery time is not covered already by the chosen frame */
232 if (frame && (frame->delivery == delivery ||
233 delivery < frame->delivery + frame->ms ||
234 (frame->next && delivery + ms > frame->next->delivery)))
236 /* TODO: Should we check for resynch here? Be careful to do not allow threshold smaller than
237 the size of the jb */
239 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
240 the force resynch flag was not set. */
241 return resynch_jb(jb, data, ms, ts, now);
244 /* Reset the force resynch flag */
245 jb->force_resynch = 0;
247 /* Get a new frame */
248 newframe = alloc_jb_frame(jb);
249 newframe->data = data;
250 newframe->ts = ts;
251 newframe->ms = ms;
252 newframe->delivery = delivery;
254 /* and insert it right on place */
255 if (frame) {
256 next = frame->next;
257 frame->next = newframe;
258 if (next) {
259 newframe->next = next;
260 next->prev = newframe;
261 } else {
262 /* insert after the last frame - should update tail */
263 jb->tail = newframe;
264 newframe->next = NULL;
266 newframe->prev = frame;
268 return FIXED_JB_OK;
269 } else if (!jb->frames) {
270 /* the frame list is empty or thats just the first frame ever */
271 /* tail should also be NULL is that case */
272 ASSERT(jb->tail == NULL);
273 jb->frames = jb->tail = newframe;
274 newframe->next = NULL;
275 newframe->prev = NULL;
277 return FIXED_JB_OK;
278 } else {
279 /* insert on a first position - should update frames head */
280 newframe->next = jb->frames;
281 newframe->prev = NULL;
282 jb->frames->prev = newframe;
283 jb->frames = newframe;
285 return FIXED_JB_OK;
290 int fixed_jb_get(struct fixed_jb *jb, struct fixed_jb_frame *frame, long now, long interpl)
292 ASSERT(now >= 0);
293 ASSERT(interpl >= 2);
295 if (now < jb->next_delivery) {
296 /* too early for the next frame */
297 return FIXED_JB_NOFRAME;
300 /* Is the jb empty? */
301 if (!jb->frames) {
302 /* should interpolate a frame */
303 /* update next */
304 jb->next_delivery += interpl;
306 return FIXED_JB_INTERP;
309 /* Isn't it too late for the first frame available in the jb? */
310 if (now > jb->frames->delivery + jb->frames->ms) {
311 /* yes - should drop this frame and update next to point the next frame (get_jb_head() does it) */
312 get_jb_head(jb, frame);
314 return FIXED_JB_DROP;
317 /* isn't it too early to play the first frame available? */
318 if (now < jb->frames->delivery) {
319 /* yes - should interpolate one frame */
320 /* update next */
321 jb->next_delivery += interpl;
323 return FIXED_JB_INTERP;
326 /* we have a frame for playing now (get_jb_head() updates next) */
327 get_jb_head(jb, frame);
329 return FIXED_JB_OK;
333 long fixed_jb_next(struct fixed_jb *jb)
335 return jb->next_delivery;
339 int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout)
341 if (!jb->frames)
342 return FIXED_JB_NOFRAME;
344 get_jb_head(jb, frameout);
346 return FIXED_JB_OK;