Fix the actual place that was pointed out, for previous commit.
[asterisk/asterisk.git] / main / fixedjitterbuf.c
1 /*
2  * Copyright (C) 2005, Attractel OOD
3  *
4  * Contributors:
5  * Slav Klenov <slav@securax.org>
6  *
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.
12  *
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.
16  *
17  * A license has been granted to Digium (via disclaimer) for the use of
18  * this code.
19  */
20
21 /*! \file 
22  * 
23  * \brief Jitterbuffering algorithm.
24  * 
25  * \author Slav Klenov <slav@securax.org>
26  */
27
28 #include "asterisk.h"
29
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31
32 #include <assert.h>
33
34 #include "asterisk/utils.h"
35 #include "fixedjitterbuf.h"
36
37 #undef FIXED_JB_DEBUG
38
39 #ifdef FIXED_JB_DEBUG
40 #define ASSERT(a)
41 #else
42 #define ASSERT(a) assert(a)
43 #endif
44
45 /*! \brief private fixed_jb structure */
46 struct fixed_jb
47 {
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;
55 };
56
57
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);
62
63 static inline struct fixed_jb_frame *alloc_jb_frame(struct fixed_jb *jb)
64 {
65         return ast_calloc(1, sizeof(*jb));
66 }
67
68 static inline void release_jb_frame(struct fixed_jb *jb, struct fixed_jb_frame *frame)
69 {
70         ast_free(frame);
71 }
72
73 static void get_jb_head(struct fixed_jb *jb, struct fixed_jb_frame *frame)
74 {
75         struct fixed_jb_frame *fr;
76         
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;
85         }
86         
87         /* update next */
88         jb->next_delivery = fr->delivery + fr->ms;
89         
90         /* copy the destination */
91         memcpy(frame, fr, sizeof(struct fixed_jb_frame));
92         
93         /* and release the frame */
94         release_jb_frame(jb, fr);
95 }
96
97
98 struct fixed_jb *fixed_jb_new(struct fixed_jb_conf *conf)
99 {
100         struct fixed_jb *jb;
101         
102         if (!(jb = ast_calloc(1, sizeof(*jb))))
103                 return NULL;
104         
105         /* First copy our config */
106         memcpy(&jb->conf, conf, sizeof(struct fixed_jb_conf));
107
108         /* we dont need the passed config anymore - continue working with the saved one */
109         conf = &jb->conf;
110         
111         /* validate the configuration */
112         if (conf->jbsize < 1)
113                 conf->jbsize = FIXED_JB_SIZE_DEFAULT;
114
115         if (conf->resync_threshold < 1)
116                 conf->resync_threshold = FIXED_JB_RESYNCH_THRESHOLD_DEFAULT;
117         
118         /* Set the constant delay to the jitterbuf */
119         jb->delay = conf->jbsize;
120         
121         return jb;
122 }
123
124
125 void fixed_jb_destroy(struct fixed_jb *jb)
126 {
127         /* jitterbuf MUST be empty before it can be destroyed */
128         ASSERT(jb->frames == NULL);
129         
130         ast_free(jb);
131 }
132
133
134 static int resynch_jb(struct fixed_jb *jb, void *data, long ms, long ts, long now)
135 {
136         long diff, offset;
137         struct fixed_jb_frame *frame;
138         
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);
143                 
144                 return fixed_jb_put_first(jb, data, ms, ts, now);
145         }
146         
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. */
149         
150         /* Get the diff in timestamps */
151         diff = ts - jb->tail->ts;
152         
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;
156         
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;
160         
161         /* Reset the force resynch flag */
162         jb->force_resynch = 0;
163         
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;
170         }
171         
172         /* now jb_put() should add the frame at a last position */
173         return fixed_jb_put(jb, data, ms, ts, now);
174 }
175
176
177 void fixed_jb_set_force_resynch(struct fixed_jb *jb)
178 {
179         jb->force_resynch = 1;
180 }
181
182
183 int fixed_jb_put_first(struct fixed_jb *jb, void *data, long ms, long ts, long now)
184 {
185         /* this is our first frame - set the base of the receivers time */
186         jb->rxcore = now - ts;
187         
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;
190         
191         /* put the frame */
192         return fixed_jb_put(jb, data, ms, ts, now);
193 }
194
195
196 int fixed_jb_put(struct fixed_jb *jb, void *data, long ms, long ts, long now)
197 {
198         struct fixed_jb_frame *frame, *next, *newframe;
199         long delivery;
200         
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);
207         
208         delivery = jb->rxcore + jb->delay + ts;
209         
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);
215         }
216         
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);
223         }
224
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;
229         }
230         
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)))
235         {
236                 /* TODO: Should we check for resynch here? Be careful to do not allow threshold smaller than
237                    the size of the jb */
238                 
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);
242         }
243         
244         /* Reset the force resynch flag */
245         jb->force_resynch = 0;
246         
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;
253         
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;
265                 }
266                 newframe->prev = frame;
267                 
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;
276                 
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;
284                 
285                 return FIXED_JB_OK;
286         }
287 }
288
289
290 int fixed_jb_get(struct fixed_jb *jb, struct fixed_jb_frame *frame, long now, long interpl)
291 {
292         ASSERT(now >= 0);
293         ASSERT(interpl >= 2);
294         
295         if (now < jb->next_delivery) {
296                 /* too early for the next frame */
297                 return FIXED_JB_NOFRAME;
298         }
299         
300         /* Is the jb empty? */
301         if (!jb->frames) {
302                 /* should interpolate a frame */
303                 /* update next */
304                 jb->next_delivery += interpl;
305                 
306                 return FIXED_JB_INTERP;
307         }
308         
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);
313                 
314                 return FIXED_JB_DROP;
315         }
316         
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;
322                 
323                 return FIXED_JB_INTERP;
324         }
325         
326         /* we have a frame for playing now (get_jb_head() updates next) */
327         get_jb_head(jb, frame);
328         
329         return FIXED_JB_OK;
330 }
331
332
333 long fixed_jb_next(struct fixed_jb *jb)
334 {
335         return jb->next_delivery;
336 }
337
338
339 int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout)
340 {
341         if (!jb->frames)
342                 return FIXED_JB_NOFRAME;
343         
344         get_jb_head(jb, frameout);
345         
346         return FIXED_JB_OK;
347 }