#include "asterisk.h"
#include <assert.h>
#include "asterisk/utils.h"
#include "fixedjitterbuf.h"
Go to the source code of this file.
Data Structures | |
struct | fixed_jb |
private fixed_jb structure More... | |
Defines | |
#define | ASSERT(a) assert(a) |
Functions | |
static struct fixed_jb_frame * | alloc_jb_frame (struct fixed_jb *jb) |
void | fixed_jb_destroy (struct fixed_jb *jb) |
int | fixed_jb_get (struct fixed_jb *jb, struct fixed_jb_frame *frame, long now, long interpl) |
fixed_jb * | fixed_jb_new (struct fixed_jb_conf *conf) |
long | fixed_jb_next (struct fixed_jb *jb) |
int | fixed_jb_put (struct fixed_jb *jb, void *data, long ms, long ts, long now) |
int | fixed_jb_put_first (struct fixed_jb *jb, void *data, long ms, long ts, long now) |
int | fixed_jb_remove (struct fixed_jb *jb, struct fixed_jb_frame *frameout) |
void | fixed_jb_set_force_resynch (struct fixed_jb *jb) |
static void | get_jb_head (struct fixed_jb *jb, struct fixed_jb_frame *frame) |
static void | release_jb_frame (struct fixed_jb *jb, struct fixed_jb_frame *frame) |
static int | resynch_jb (struct fixed_jb *jb, void *data, long ms, long ts, long now) |
Definition in file fixedjitterbuf.c.
#define ASSERT | ( | a | ) | assert(a) |
Definition at line 42 of file fixedjitterbuf.c.
Referenced by fixed_jb_destroy(), fixed_jb_get(), fixed_jb_put(), and resynch_jb().
static struct fixed_jb_frame * alloc_jb_frame | ( | struct fixed_jb * | jb | ) | [inline, static] |
Definition at line 63 of file fixedjitterbuf.c.
References ast_calloc.
Referenced by fixed_jb_put().
00064 { 00065 return ast_calloc(1, sizeof(*jb)); 00066 }
void fixed_jb_destroy | ( | struct fixed_jb * | jb | ) |
Definition at line 125 of file fixedjitterbuf.c.
References ASSERT, ast_free, and fixed_jb::frames.
Referenced by jb_destroy_fixed().
00126 { 00127 /* jitterbuf MUST be empty before it can be destroyed */ 00128 ASSERT(jb->frames == NULL); 00129 00130 ast_free(jb); 00131 }
int fixed_jb_get | ( | struct fixed_jb * | jb, | |
struct fixed_jb_frame * | frame, | |||
long | now, | |||
long | interpl | |||
) |
Definition at line 290 of file fixedjitterbuf.c.
References ASSERT, fixed_jb_frame::delivery, FIXED_JB_DROP, FIXED_JB_INTERP, FIXED_JB_NOFRAME, FIXED_JB_OK, fixed_jb::frames, frames, get_jb_head(), fixed_jb_frame::ms, and fixed_jb::next_delivery.
Referenced by jb_get_fixed().
00291 { 00292 ASSERT(now >= 0); 00293 ASSERT(interpl >= 2); 00294 00295 if (now < jb->next_delivery) { 00296 /* too early for the next frame */ 00297 return FIXED_JB_NOFRAME; 00298 } 00299 00300 /* Is the jb empty? */ 00301 if (!jb->frames) { 00302 /* should interpolate a frame */ 00303 /* update next */ 00304 jb->next_delivery += interpl; 00305 00306 return FIXED_JB_INTERP; 00307 } 00308 00309 /* Isn't it too late for the first frame available in the jb? */ 00310 if (now > jb->frames->delivery + jb->frames->ms) { 00311 /* yes - should drop this frame and update next to point the next frame (get_jb_head() does it) */ 00312 get_jb_head(jb, frame); 00313 00314 return FIXED_JB_DROP; 00315 } 00316 00317 /* isn't it too early to play the first frame available? */ 00318 if (now < jb->frames->delivery) { 00319 /* yes - should interpolate one frame */ 00320 /* update next */ 00321 jb->next_delivery += interpl; 00322 00323 return FIXED_JB_INTERP; 00324 } 00325 00326 /* we have a frame for playing now (get_jb_head() updates next) */ 00327 get_jb_head(jb, frame); 00328 00329 return FIXED_JB_OK; 00330 }
struct fixed_jb* fixed_jb_new | ( | struct fixed_jb_conf * | conf | ) |
Definition at line 98 of file fixedjitterbuf.c.
References ast_calloc, fixed_jb::conf, FIXED_JB_RESYNCH_THRESHOLD_DEFAULT, FIXED_JB_SIZE_DEFAULT, fixed_jb_conf::jbsize, and fixed_jb_conf::resync_threshold.
Referenced by jb_create_fixed().
00099 { 00100 struct fixed_jb *jb; 00101 00102 if (!(jb = ast_calloc(1, sizeof(*jb)))) 00103 return NULL; 00104 00105 /* First copy our config */ 00106 memcpy(&jb->conf, conf, sizeof(struct fixed_jb_conf)); 00107 00108 /* we don't need the passed config anymore - continue working with the saved one */ 00109 conf = &jb->conf; 00110 00111 /* validate the configuration */ 00112 if (conf->jbsize < 1) 00113 conf->jbsize = FIXED_JB_SIZE_DEFAULT; 00114 00115 if (conf->resync_threshold < 1) 00116 conf->resync_threshold = FIXED_JB_RESYNCH_THRESHOLD_DEFAULT; 00117 00118 /* Set the constant delay to the jitterbuf */ 00119 jb->delay = conf->jbsize; 00120 00121 return jb; 00122 }
long fixed_jb_next | ( | struct fixed_jb * | jb | ) |
Definition at line 333 of file fixedjitterbuf.c.
References fixed_jb::next_delivery.
Referenced by jb_next_fixed().
00334 { 00335 return jb->next_delivery; 00336 }
int fixed_jb_put | ( | struct fixed_jb * | jb, | |
void * | data, | |||
long | ms, | |||
long | ts, | |||
long | now | |||
) |
Definition at line 196 of file fixedjitterbuf.c.
References alloc_jb_frame(), ASSERT, fixed_jb::conf, fixed_jb_frame::data, fixed_jb::delay, fixed_jb_frame::delivery, FIXED_JB_OK, fixed_jb::force_resynch, fixed_jb::frames, fixed_jb_frame::ms, fixed_jb_frame::next, fixed_jb::next_delivery, fixed_jb_frame::prev, fixed_jb_conf::resync_threshold, resynch_jb(), fixed_jb::rxcore, fixed_jb::tail, and fixed_jb_frame::ts.
Referenced by fixed_jb_put_first(), jb_put_fixed(), and resynch_jb().
00197 { 00198 struct fixed_jb_frame *frame, *next, *newframe; 00199 long delivery; 00200 00201 /* debug check the validity of the input params */ 00202 ASSERT(data != NULL); 00203 /* do not allow frames shorter than 2 ms */ 00204 ASSERT(ms >= 2); 00205 ASSERT(ts >= 0); 00206 ASSERT(now >= 0); 00207 00208 delivery = jb->rxcore + jb->delay + ts; 00209 00210 /* check if the new frame is not too late */ 00211 if (delivery < jb->next_delivery) { 00212 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or 00213 the force resynch flag was not set. */ 00214 return resynch_jb(jb, data, ms, ts, now); 00215 } 00216 00217 /* what if the delivery time is bigger than next + delay? Seems like a frame for the future. 00218 However, allow more resync_threshold ms in advance */ 00219 if (delivery > jb->next_delivery + jb->delay + jb->conf.resync_threshold) { 00220 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or 00221 the force resynch flag was not set. */ 00222 return resynch_jb(jb, data, ms, ts, now); 00223 } 00224 00225 /* find the right place in the frames list, sorted by delivery time */ 00226 frame = jb->tail; 00227 while (frame && frame->delivery > delivery) { 00228 frame = frame->prev; 00229 } 00230 00231 /* Check if the new delivery time is not covered already by the chosen frame */ 00232 if (frame && (frame->delivery == delivery || 00233 delivery < frame->delivery + frame->ms || 00234 (frame->next && delivery + ms > frame->next->delivery))) 00235 { 00236 /* TODO: Should we check for resynch here? Be careful to do not allow threshold smaller than 00237 the size of the jb */ 00238 00239 /* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or 00240 the force resynch flag was not set. */ 00241 return resynch_jb(jb, data, ms, ts, now); 00242 } 00243 00244 /* Reset the force resynch flag */ 00245 jb->force_resynch = 0; 00246 00247 /* Get a new frame */ 00248 newframe = alloc_jb_frame(jb); 00249 newframe->data = data; 00250 newframe->ts = ts; 00251 newframe->ms = ms; 00252 newframe->delivery = delivery; 00253 00254 /* and insert it right on place */ 00255 if (frame) { 00256 next = frame->next; 00257 frame->next = newframe; 00258 if (next) { 00259 newframe->next = next; 00260 next->prev = newframe; 00261 } else { 00262 /* insert after the last frame - should update tail */ 00263 jb->tail = newframe; 00264 newframe->next = NULL; 00265 } 00266 newframe->prev = frame; 00267 00268 return FIXED_JB_OK; 00269 } else if (!jb->frames) { 00270 /* the frame list is empty or thats just the first frame ever */ 00271 /* tail should also be NULL is that case */ 00272 ASSERT(jb->tail == NULL); 00273 jb->frames = jb->tail = newframe; 00274 newframe->next = NULL; 00275 newframe->prev = NULL; 00276 00277 return FIXED_JB_OK; 00278 } else { 00279 /* insert on a first position - should update frames head */ 00280 newframe->next = jb->frames; 00281 newframe->prev = NULL; 00282 jb->frames->prev = newframe; 00283 jb->frames = newframe; 00284 00285 return FIXED_JB_OK; 00286 } 00287 }
int fixed_jb_put_first | ( | struct fixed_jb * | jb, | |
void * | data, | |||
long | ms, | |||
long | ts, | |||
long | now | |||
) |
Definition at line 183 of file fixedjitterbuf.c.
References fixed_jb::delay, fixed_jb_put(), fixed_jb::next_delivery, and fixed_jb::rxcore.
Referenced by jb_put_first_fixed(), and resynch_jb().
00184 { 00185 /* this is our first frame - set the base of the receivers time */ 00186 jb->rxcore = now - ts; 00187 00188 /* init next for a first time - it should be the time the first frame should be played */ 00189 jb->next_delivery = now + jb->delay; 00190 00191 /* put the frame */ 00192 return fixed_jb_put(jb, data, ms, ts, now); 00193 }
int fixed_jb_remove | ( | struct fixed_jb * | jb, | |
struct fixed_jb_frame * | frameout | |||
) |
Definition at line 339 of file fixedjitterbuf.c.
References FIXED_JB_NOFRAME, FIXED_JB_OK, fixed_jb::frames, and get_jb_head().
Referenced by jb_empty_and_reset_fixed(), and jb_remove_fixed().
00340 { 00341 if (!jb->frames) 00342 return FIXED_JB_NOFRAME; 00343 00344 get_jb_head(jb, frameout); 00345 00346 return FIXED_JB_OK; 00347 }
void fixed_jb_set_force_resynch | ( | struct fixed_jb * | jb | ) |
Definition at line 177 of file fixedjitterbuf.c.
References fixed_jb::force_resynch.
Referenced by jb_force_resynch_fixed().
00178 { 00179 jb->force_resynch = 1; 00180 }
static void get_jb_head | ( | struct fixed_jb * | jb, | |
struct fixed_jb_frame * | frame | |||
) | [static] |
Definition at line 73 of file fixedjitterbuf.c.
References fixed_jb_frame::delivery, fixed_jb::frames, fixed_jb_frame::ms, fixed_jb_frame::next, fixed_jb::next_delivery, fixed_jb_frame::prev, release_jb_frame(), and fixed_jb::tail.
Referenced by fixed_jb_get(), and fixed_jb_remove().
00074 { 00075 struct fixed_jb_frame *fr; 00076 00077 /* unlink the frame */ 00078 fr = jb->frames; 00079 jb->frames = fr->next; 00080 if (jb->frames) { 00081 jb->frames->prev = NULL; 00082 } else { 00083 /* the jb is empty - update tail */ 00084 jb->tail = NULL; 00085 } 00086 00087 /* update next */ 00088 jb->next_delivery = fr->delivery + fr->ms; 00089 00090 /* copy the destination */ 00091 memcpy(frame, fr, sizeof(struct fixed_jb_frame)); 00092 00093 /* and release the frame */ 00094 release_jb_frame(jb, fr); 00095 }
static void release_jb_frame | ( | struct fixed_jb * | jb, | |
struct fixed_jb_frame * | frame | |||
) | [inline, static] |
Definition at line 68 of file fixedjitterbuf.c.
References ast_free.
Referenced by get_jb_head().
00069 { 00070 ast_free(frame); 00071 }
static int resynch_jb | ( | struct fixed_jb * | jb, | |
void * | data, | |||
long | ms, | |||
long | ts, | |||
long | now | |||
) | [static] |
Definition at line 134 of file fixedjitterbuf.c.
References ASSERT, fixed_jb::conf, FIXED_JB_DROP, fixed_jb_put(), fixed_jb_put_first(), fixed_jb::force_resynch, fixed_jb::frames, fixed_jb_frame::ms, fixed_jb_frame::next, fixed_jb_conf::resync_threshold, fixed_jb::rxcore, fixed_jb::tail, and fixed_jb_frame::ts.
Referenced by fixed_jb_put().
00135 { 00136 long diff, offset; 00137 struct fixed_jb_frame *frame; 00138 00139 /* If jb is empty, just reinitialize the jb */ 00140 if (!jb->frames) { 00141 /* debug check: tail should also be NULL */ 00142 ASSERT(jb->tail == NULL); 00143 00144 return fixed_jb_put_first(jb, data, ms, ts, now); 00145 } 00146 00147 /* Adjust all jb state just as the new frame is with delivery = the delivery of the last 00148 frame (e.g. this one with max delivery) + the length of the last frame. */ 00149 00150 /* Get the diff in timestamps */ 00151 diff = ts - jb->tail->ts; 00152 00153 /* Ideally this should be just the length of the last frame. The deviation is the desired 00154 offset */ 00155 offset = diff - jb->tail->ms; 00156 00157 /* Do we really need to resynch, or this is just a frame for dropping? */ 00158 if (!jb->force_resynch && (offset < jb->conf.resync_threshold && offset > -jb->conf.resync_threshold)) 00159 return FIXED_JB_DROP; 00160 00161 /* Reset the force resynch flag */ 00162 jb->force_resynch = 0; 00163 00164 /* apply the offset to the jb state */ 00165 jb->rxcore -= offset; 00166 frame = jb->frames; 00167 while (frame) { 00168 frame->ts += offset; 00169 frame = frame->next; 00170 } 00171 00172 /* now jb_put() should add the frame at a last position */ 00173 return fixed_jb_put(jb, data, ms, ts, now); 00174 }