![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
abstract_jb.c
Go to the documentation of this file.
00001 /* 00002 * abstract_jb: common implementation-independent jitterbuffer stuff 00003 * 00004 * Copyright (C) 2005, Attractel OOD 00005 * 00006 * Contributors: 00007 * Slav Klenov <slav@securax.org> 00008 * 00009 * See http://www.asterisk.org for more information about 00010 * the Asterisk project. Please do not directly contact 00011 * any of the maintainers of this project for assistance; 00012 * the project provides a web site, mailing lists and IRC 00013 * channels for your use. 00014 * 00015 * This program is free software, distributed under the terms of 00016 * the GNU General Public License Version 2. See the LICENSE file 00017 * at the top of the source tree. 00018 * 00019 * A license has been granted to Digium (via disclaimer) for the use of 00020 * this code. 00021 */ 00022 00023 /*! \file 00024 * 00025 * \brief Common implementation-independent jitterbuffer stuff. 00026 * 00027 * \author Slav Klenov <slav@securax.org> 00028 */ 00029 00030 #include "asterisk.h" 00031 00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 51499 $") 00033 00034 #include <stdio.h> 00035 #include <stdlib.h> 00036 00037 #include "asterisk/frame.h" 00038 #include "asterisk/channel.h" 00039 #include "asterisk/logger.h" 00040 #include "asterisk/term.h" 00041 #include "asterisk/options.h" 00042 #include "asterisk/utils.h" 00043 00044 #include "asterisk/abstract_jb.h" 00045 #include "fixedjitterbuf.h" 00046 #include "jitterbuf.h" 00047 00048 /*! Internal jb flags */ 00049 enum { 00050 JB_USE = (1 << 0), 00051 JB_TIMEBASE_INITIALIZED = (1 << 1), 00052 JB_CREATED = (1 << 2) 00053 }; 00054 00055 /* Hooks for the abstract jb implementation */ 00056 00057 /*! \brief Create */ 00058 typedef void * (*jb_create_impl)(struct ast_jb_conf *general_config, long resynch_threshold); 00059 /*! \brief Destroy */ 00060 typedef void (*jb_destroy_impl)(void *jb); 00061 /*! \brief Put first frame */ 00062 typedef int (*jb_put_first_impl)(void *jb, struct ast_frame *fin, long now); 00063 /*! \brief Put frame */ 00064 typedef int (*jb_put_impl)(void *jb, struct ast_frame *fin, long now); 00065 /*! \brief Get frame for now */ 00066 typedef int (*jb_get_impl)(void *jb, struct ast_frame **fout, long now, long interpl); 00067 /*! \brief Get next */ 00068 typedef long (*jb_next_impl)(void *jb); 00069 /*! \brief Remove first frame */ 00070 typedef int (*jb_remove_impl)(void *jb, struct ast_frame **fout); 00071 /*! \brief Force resynch */ 00072 typedef void (*jb_force_resynch_impl)(void *jb); 00073 00074 00075 /*! 00076 * \brief Jitterbuffer implementation private struct. 00077 */ 00078 struct ast_jb_impl 00079 { 00080 char name[AST_JB_IMPL_NAME_SIZE]; 00081 jb_create_impl create; 00082 jb_destroy_impl destroy; 00083 jb_put_first_impl put_first; 00084 jb_put_impl put; 00085 jb_get_impl get; 00086 jb_next_impl next; 00087 jb_remove_impl remove; 00088 jb_force_resynch_impl force_resync; 00089 }; 00090 00091 /* Implementation functions */ 00092 /* fixed */ 00093 static void * jb_create_fixed(struct ast_jb_conf *general_config, long resynch_threshold); 00094 static void jb_destroy_fixed(void *jb); 00095 static int jb_put_first_fixed(void *jb, struct ast_frame *fin, long now); 00096 static int jb_put_fixed(void *jb, struct ast_frame *fin, long now); 00097 static int jb_get_fixed(void *jb, struct ast_frame **fout, long now, long interpl); 00098 static long jb_next_fixed(void *jb); 00099 static int jb_remove_fixed(void *jb, struct ast_frame **fout); 00100 static void jb_force_resynch_fixed(void *jb); 00101 /* adaptive */ 00102 static void * jb_create_adaptive(struct ast_jb_conf *general_config, long resynch_threshold); 00103 static void jb_destroy_adaptive(void *jb); 00104 static int jb_put_first_adaptive(void *jb, struct ast_frame *fin, long now); 00105 static int jb_put_adaptive(void *jb, struct ast_frame *fin, long now); 00106 static int jb_get_adaptive(void *jb, struct ast_frame **fout, long now, long interpl); 00107 static long jb_next_adaptive(void *jb); 00108 static int jb_remove_adaptive(void *jb, struct ast_frame **fout); 00109 static void jb_force_resynch_adaptive(void *jb); 00110 00111 /* Available jb implementations */ 00112 static struct ast_jb_impl avail_impl[] = 00113 { 00114 { 00115 .name = "fixed", 00116 .create = jb_create_fixed, 00117 .destroy = jb_destroy_fixed, 00118 .put_first = jb_put_first_fixed, 00119 .put = jb_put_fixed, 00120 .get = jb_get_fixed, 00121 .next = jb_next_fixed, 00122 .remove = jb_remove_fixed, 00123 .force_resync = jb_force_resynch_fixed 00124 }, 00125 { 00126 .name = "adaptive", 00127 .create = jb_create_adaptive, 00128 .destroy = jb_destroy_adaptive, 00129 .put_first = jb_put_first_adaptive, 00130 .put = jb_put_adaptive, 00131 .get = jb_get_adaptive, 00132 .next = jb_next_adaptive, 00133 .remove = jb_remove_adaptive, 00134 .force_resync = jb_force_resynch_adaptive 00135 } 00136 }; 00137 00138 static int default_impl = 0; 00139 00140 00141 /*! Abstract return codes */ 00142 enum { 00143 JB_IMPL_OK, 00144 JB_IMPL_DROP, 00145 JB_IMPL_INTERP, 00146 JB_IMPL_NOFRAME 00147 }; 00148 00149 /* Translations between impl and abstract return codes */ 00150 static int fixed_to_abstract_code[] = 00151 {JB_IMPL_OK, JB_IMPL_DROP, JB_IMPL_INTERP, JB_IMPL_NOFRAME}; 00152 static int adaptive_to_abstract_code[] = 00153 {JB_IMPL_OK, JB_IMPL_NOFRAME, JB_IMPL_NOFRAME, JB_IMPL_INTERP, JB_IMPL_DROP, JB_IMPL_OK}; 00154 00155 /* JB_GET actions (used only for the frames log) */ 00156 static char *jb_get_actions[] = {"Delivered", "Dropped", "Interpolated", "No"}; 00157 00158 /*! \brief Macros for the frame log files */ 00159 #define jb_framelog(...) do { \ 00160 if (jb->logfile) { \ 00161 fprintf(jb->logfile, __VA_ARGS__); \ 00162 fflush(jb->logfile); \ 00163 } \ 00164 } while (0) 00165 00166 00167 /* Internal utility functions */ 00168 static void jb_choose_impl(struct ast_channel *chan); 00169 static void jb_get_and_deliver(struct ast_channel *chan); 00170 static int create_jb(struct ast_channel *chan, struct ast_frame *first_frame); 00171 static long get_now(struct ast_jb *jb, struct timeval *tv); 00172 00173 00174 /* Interface ast jb functions impl */ 00175 00176 00177 static void jb_choose_impl(struct ast_channel *chan) 00178 { 00179 struct ast_jb *jb = &chan->jb; 00180 struct ast_jb_conf *jbconf = &jb->conf; 00181 struct ast_jb_impl *test_impl; 00182 int i, avail_impl_count = sizeof(avail_impl) / sizeof(avail_impl[0]); 00183 00184 jb->impl = &avail_impl[default_impl]; 00185 00186 if (ast_strlen_zero(jbconf->impl)) 00187 return; 00188 00189 for (i = 0; i < avail_impl_count; i++) { 00190 test_impl = &avail_impl[i]; 00191 if (!strcasecmp(jbconf->impl, test_impl->name)) { 00192 jb->impl = test_impl; 00193 return; 00194 } 00195 } 00196 } 00197 00198 int ast_jb_do_usecheck(struct ast_channel *c0, struct ast_channel *c1) 00199 { 00200 struct ast_jb *jb0 = &c0->jb; 00201 struct ast_jb *jb1 = &c1->jb; 00202 struct ast_jb_conf *conf0 = &jb0->conf; 00203 struct ast_jb_conf *conf1 = &jb1->conf; 00204 int c0_wants_jitter = c0->tech->properties & AST_CHAN_TP_WANTSJITTER; 00205 int c0_creates_jitter = c0->tech->properties & AST_CHAN_TP_CREATESJITTER; 00206 int c0_jb_enabled = ast_test_flag(conf0, AST_JB_ENABLED); 00207 int c0_force_jb = ast_test_flag(conf0, AST_JB_FORCED); 00208 int c0_jb_timebase_initialized = ast_test_flag(jb0, JB_TIMEBASE_INITIALIZED); 00209 int c0_jb_created = ast_test_flag(jb0, JB_CREATED); 00210 int c1_wants_jitter = c1->tech->properties & AST_CHAN_TP_WANTSJITTER; 00211 int c1_creates_jitter = c1->tech->properties & AST_CHAN_TP_CREATESJITTER; 00212 int c1_jb_enabled = ast_test_flag(conf1, AST_JB_ENABLED); 00213 int c1_force_jb = ast_test_flag(conf1, AST_JB_FORCED); 00214 int c1_jb_timebase_initialized = ast_test_flag(jb1, JB_TIMEBASE_INITIALIZED); 00215 int c1_jb_created = ast_test_flag(jb1, JB_CREATED); 00216 int inuse = 0; 00217 00218 /* Determine whether audio going to c0 needs a jitter buffer */ 00219 if (((!c0_wants_jitter && c1_creates_jitter) || (c0_force_jb && c1_creates_jitter)) && c0_jb_enabled) { 00220 ast_set_flag(jb0, JB_USE); 00221 if (!c0_jb_timebase_initialized) { 00222 if (c1_jb_timebase_initialized) { 00223 memcpy(&jb0->timebase, &jb1->timebase, sizeof(struct timeval)); 00224 } else { 00225 gettimeofday(&jb0->timebase, NULL); 00226 } 00227 ast_set_flag(jb0, JB_TIMEBASE_INITIALIZED); 00228 } 00229 00230 if (!c0_jb_created) { 00231 jb_choose_impl(c0); 00232 } 00233 00234 inuse = 1; 00235 } 00236 00237 /* Determine whether audio going to c1 needs a jitter buffer */ 00238 if (((!c1_wants_jitter && c0_creates_jitter) || (c1_force_jb && c0_creates_jitter)) && c1_jb_enabled) { 00239 ast_set_flag(jb1, JB_USE); 00240 if (!c1_jb_timebase_initialized) { 00241 if (c0_jb_timebase_initialized) { 00242 memcpy(&jb1->timebase, &jb0->timebase, sizeof(struct timeval)); 00243 } else { 00244 gettimeofday(&jb1->timebase, NULL); 00245 } 00246 ast_set_flag(jb1, JB_TIMEBASE_INITIALIZED); 00247 } 00248 00249 if (!c1_jb_created) { 00250 jb_choose_impl(c1); 00251 } 00252 00253 inuse = 1; 00254 } 00255 00256 return inuse; 00257 } 00258 00259 int ast_jb_get_when_to_wakeup(struct ast_channel *c0, struct ast_channel *c1, int time_left) 00260 { 00261 struct ast_jb *jb0 = &c0->jb; 00262 struct ast_jb *jb1 = &c1->jb; 00263 int c0_use_jb = ast_test_flag(jb0, JB_USE); 00264 int c0_jb_is_created = ast_test_flag(jb0, JB_CREATED); 00265 int c1_use_jb = ast_test_flag(jb1, JB_USE); 00266 int c1_jb_is_created = ast_test_flag(jb1, JB_CREATED); 00267 int wait, wait0, wait1; 00268 struct timeval tv_now; 00269 00270 if (time_left == 0) { 00271 /* No time left - the bridge will be retried */ 00272 /* TODO: Test disable this */ 00273 /*return 0;*/ 00274 } 00275 00276 if (time_left < 0) { 00277 time_left = INT_MAX; 00278 } 00279 00280 gettimeofday(&tv_now, NULL); 00281 00282 wait0 = (c0_use_jb && c0_jb_is_created) ? jb0->next - get_now(jb0, &tv_now) : time_left; 00283 wait1 = (c1_use_jb && c1_jb_is_created) ? jb1->next - get_now(jb1, &tv_now) : time_left; 00284 00285 wait = wait0 < wait1 ? wait0 : wait1; 00286 wait = wait < time_left ? wait : time_left; 00287 00288 if (wait == INT_MAX) { 00289 wait = -1; 00290 } else if (wait < 1) { 00291 /* don't let wait=0, because this can cause the pbx thread to loop without any sleeping at all */ 00292 wait = 1; 00293 } 00294 00295 return wait; 00296 } 00297 00298 00299 int ast_jb_put(struct ast_channel *chan, struct ast_frame *f) 00300 { 00301 struct ast_jb *jb = &chan->jb; 00302 struct ast_jb_impl *jbimpl = jb->impl; 00303 void *jbobj = jb->jbobj; 00304 struct ast_frame *frr; 00305 long now = 0; 00306 00307 if (!ast_test_flag(jb, JB_USE)) 00308 return -1; 00309 00310 if (f->frametype != AST_FRAME_VOICE) { 00311 if (f->frametype == AST_FRAME_DTMF && ast_test_flag(jb, JB_CREATED)) { 00312 jb_framelog("JB_PUT {now=%ld}: Received DTMF frame. Force resynching jb...\n", now); 00313 jbimpl->force_resync(jbobj); 00314 } 00315 00316 return -1; 00317 } 00318 00319 /* We consider an enabled jitterbuffer should receive frames with valid timing info. */ 00320 if (!f->has_timing_info || f->len < 2 || f->ts < 0) { 00321 ast_log(LOG_WARNING, "%s recieved frame with invalid timing info: " 00322 "has_timing_info=%d, len=%ld, ts=%ld, src=%s\n", 00323 chan->name, f->has_timing_info, f->len, f->ts, f->src); 00324 return -1; 00325 } 00326 00327 frr = ast_frdup(f); 00328 00329 if (!frr) { 00330 ast_log(LOG_ERROR, "Failed to isolate frame for the jitterbuffer on channel '%s'\n", chan->name); 00331 return -1; 00332 } 00333 00334 if (!ast_test_flag(jb, JB_CREATED)) { 00335 if (create_jb(chan, frr)) { 00336 ast_frfree(frr); 00337 /* Disable the jitterbuffer */ 00338 ast_clear_flag(jb, JB_USE); 00339 return -1; 00340 } 00341 00342 ast_set_flag(jb, JB_CREATED); 00343 return 0; 00344 } else { 00345 now = get_now(jb, NULL); 00346 if (jbimpl->put(jbobj, frr, now) != JB_IMPL_OK) { 00347 jb_framelog("JB_PUT {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len); 00348 ast_frfree(frr); 00349 /*return -1;*/ 00350 /* TODO: Check this fix - should return 0 here, because the dropped frame shouldn't 00351 be delivered at all */ 00352 return 0; 00353 } 00354 00355 jb->next = jbimpl->next(jbobj); 00356 00357 jb_framelog("JB_PUT {now=%ld}: Queued frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len); 00358 00359 return 0; 00360 } 00361 } 00362 00363 00364 void ast_jb_get_and_deliver(struct ast_channel *c0, struct ast_channel *c1) 00365 { 00366 struct ast_jb *jb0 = &c0->jb; 00367 struct ast_jb *jb1 = &c1->jb; 00368 int c0_use_jb = ast_test_flag(jb0, JB_USE); 00369 int c0_jb_is_created = ast_test_flag(jb0, JB_CREATED); 00370 int c1_use_jb = ast_test_flag(jb1, JB_USE); 00371 int c1_jb_is_created = ast_test_flag(jb1, JB_CREATED); 00372 00373 if (c0_use_jb && c0_jb_is_created) 00374 jb_get_and_deliver(c0); 00375 00376 if (c1_use_jb && c1_jb_is_created) 00377 jb_get_and_deliver(c1); 00378 } 00379 00380 00381 static void jb_get_and_deliver(struct ast_channel *chan) 00382 { 00383 struct ast_jb *jb = &chan->jb; 00384 struct ast_jb_impl *jbimpl = jb->impl; 00385 void *jbobj = jb->jbobj; 00386 struct ast_frame *f, finterp; 00387 long now; 00388 int interpolation_len, res; 00389 00390 now = get_now(jb, NULL); 00391 jb->next = jbimpl->next(jbobj); 00392 if (now < jb->next) { 00393 jb_framelog("\tJB_GET {now=%ld}: now < next=%ld\n", now, jb->next); 00394 return; 00395 } 00396 00397 while (now >= jb->next) { 00398 interpolation_len = ast_codec_interp_len(jb->last_format); 00399 00400 res = jbimpl->get(jbobj, &f, now, interpolation_len); 00401 00402 switch (res) { 00403 case JB_IMPL_OK: 00404 /* deliver the frame */ 00405 ast_write(chan, f); 00406 case JB_IMPL_DROP: 00407 jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n", 00408 now, jb_get_actions[res], f->ts, f->len); 00409 jb->last_format = f->subclass; 00410 ast_frfree(f); 00411 break; 00412 case JB_IMPL_INTERP: 00413 /* interpolate a frame */ 00414 f = &finterp; 00415 f->frametype = AST_FRAME_VOICE; 00416 f->subclass = jb->last_format; 00417 f->datalen = 0; 00418 f->samples = interpolation_len * 8; 00419 f->mallocd = 0; 00420 f->src = "JB interpolation"; 00421 f->data = NULL; 00422 f->delivery = ast_tvadd(jb->timebase, ast_samp2tv(jb->next, 1000)); 00423 f->offset = AST_FRIENDLY_OFFSET; 00424 /* deliver the interpolated frame */ 00425 ast_write(chan, f); 00426 jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now, interpolation_len); 00427 break; 00428 case JB_IMPL_NOFRAME: 00429 ast_log(LOG_WARNING, 00430 "JB_IMPL_NOFRAME is retuned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n", 00431 jbimpl->name, now, jb->next, jbimpl->next(jbobj)); 00432 jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now); 00433 return; 00434 default: 00435 ast_log(LOG_ERROR, "This should never happen!\n"); 00436 CRASH; 00437 break; 00438 } 00439 00440 jb->next = jbimpl->next(jbobj); 00441 } 00442 } 00443 00444 00445 static int create_jb(struct ast_channel *chan, struct ast_frame *frr) 00446 { 00447 struct ast_jb *jb = &chan->jb; 00448 struct ast_jb_conf *jbconf = &jb->conf; 00449 struct ast_jb_impl *jbimpl = jb->impl; 00450 void *jbobj; 00451 struct ast_channel *bridged; 00452 long now; 00453 char logfile_pathname[20 + AST_JB_IMPL_NAME_SIZE + 2*AST_CHANNEL_NAME + 1]; 00454 char name1[AST_CHANNEL_NAME], name2[AST_CHANNEL_NAME], *tmp; 00455 int res; 00456 00457 jbobj = jb->jbobj = jbimpl->create(jbconf, jbconf->resync_threshold); 00458 if (!jbobj) { 00459 ast_log(LOG_WARNING, "Failed to create jitterbuffer on channel '%s'\n", chan->name); 00460 return -1; 00461 } 00462 00463 now = get_now(jb, NULL); 00464 res = jbimpl->put_first(jbobj, frr, now); 00465 00466 /* The result of putting the first frame should not differ from OK. However, its possible 00467 some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */ 00468 if (res != JB_IMPL_OK) { 00469 ast_log(LOG_WARNING, "Failed to put first frame in the jitterbuffer on channel '%s'\n", chan->name); 00470 /* 00471 jbimpl->destroy(jbobj); 00472 return -1; 00473 */ 00474 } 00475 00476 /* Init next */ 00477 jb->next = jbimpl->next(jbobj); 00478 00479 /* Init last format for a first time. */ 00480 jb->last_format = frr->subclass; 00481 00482 /* Create a frame log file */ 00483 if (ast_test_flag(jbconf, AST_JB_LOG)) { 00484 snprintf(name2, sizeof(name2), "%s", chan->name); 00485 tmp = strchr(name2, '/'); 00486 if (tmp) 00487 *tmp = '#'; 00488 00489 bridged = ast_bridged_channel(chan); 00490 if (!bridged) { 00491 /* We should always have bridged chan if a jitterbuffer is in use */ 00492 CRASH; 00493 } 00494 snprintf(name1, sizeof(name1), "%s", bridged->name); 00495 tmp = strchr(name1, '/'); 00496 if (tmp) 00497 *tmp = '#'; 00498 00499 snprintf(logfile_pathname, sizeof(logfile_pathname), 00500 "/tmp/ast_%s_jb_%s--%s.log", jbimpl->name, name1, name2); 00501 jb->logfile = fopen(logfile_pathname, "w+b"); 00502 00503 if (!jb->logfile) 00504 ast_log(LOG_WARNING, "Failed to create frame log file with pathname '%s'\n", logfile_pathname); 00505 00506 if (res == JB_IMPL_OK) 00507 jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n", 00508 now, frr->ts, frr->len); 00509 else 00510 jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", 00511 now, frr->ts, frr->len); 00512 } 00513 00514 if (option_verbose > 2) 00515 ast_verbose(VERBOSE_PREFIX_3 "%s jitterbuffer created on channel %s\n", jbimpl->name, chan->name); 00516 00517 /* Free the frame if it has not been queued in the jb */ 00518 if (res != JB_IMPL_OK) 00519 ast_frfree(frr); 00520 00521 return 0; 00522 } 00523 00524 00525 void ast_jb_destroy(struct ast_channel *chan) 00526 { 00527 struct ast_jb *jb = &chan->jb; 00528 struct ast_jb_impl *jbimpl = jb->impl; 00529 void *jbobj = jb->jbobj; 00530 struct ast_frame *f; 00531 00532 if (jb->logfile) { 00533 fclose(jb->logfile); 00534 jb->logfile = NULL; 00535 } 00536 00537 if (ast_test_flag(jb, JB_CREATED)) { 00538 /* Remove and free all frames still queued in jb */ 00539 while (jbimpl->remove(jbobj, &f) == JB_IMPL_OK) { 00540 ast_frfree(f); 00541 } 00542 00543 jbimpl->destroy(jbobj); 00544 jb->jbobj = NULL; 00545 00546 ast_clear_flag(jb, JB_CREATED); 00547 00548 if (option_verbose > 2) 00549 ast_verbose(VERBOSE_PREFIX_3 "%s jitterbuffer destroyed on channel %s\n", jbimpl->name, chan->name); 00550 } 00551 } 00552 00553 00554 static long get_now(struct ast_jb *jb, struct timeval *tv) 00555 { 00556 struct timeval now; 00557 00558 if (!tv) { 00559 tv = &now; 00560 gettimeofday(tv, NULL); 00561 } 00562 00563 return ast_tvdiff_ms(*tv, jb->timebase); 00564 } 00565 00566 00567 int ast_jb_read_conf(struct ast_jb_conf *conf, char *varname, char *value) 00568 { 00569 int prefixlen = sizeof(AST_JB_CONF_PREFIX) - 1; 00570 char *name; 00571 int tmp; 00572 00573 if (strncasecmp(AST_JB_CONF_PREFIX, varname, prefixlen)) 00574 return -1; 00575 00576 name = varname + prefixlen; 00577 00578 if (!strcasecmp(name, AST_JB_CONF_ENABLE)) { 00579 ast_set2_flag(conf, ast_true(value), AST_JB_ENABLED); 00580 } else if (!strcasecmp(name, AST_JB_CONF_FORCE)) { 00581 ast_set2_flag(conf, ast_true(value), AST_JB_FORCED); 00582 } else if (!strcasecmp(name, AST_JB_CONF_MAX_SIZE)) { 00583 if ((tmp = atoi(value)) > 0) 00584 conf->max_size = tmp; 00585 } else if (!strcasecmp(name, AST_JB_CONF_RESYNCH_THRESHOLD)) { 00586 if ((tmp = atoi(value)) > 0) 00587 conf->resync_threshold = tmp; 00588 } else if (!strcasecmp(name, AST_JB_CONF_IMPL)) { 00589 if (!ast_strlen_zero(value)) 00590 snprintf(conf->impl, sizeof(conf->impl), "%s", value); 00591 } else if (!strcasecmp(name, AST_JB_CONF_LOG)) { 00592 ast_set2_flag(conf, ast_true(value), AST_JB_LOG); 00593 } else { 00594 return -1; 00595 } 00596 00597 return 0; 00598 } 00599 00600 00601 void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf) 00602 { 00603 memcpy(&chan->jb.conf, conf, sizeof(*conf)); 00604 } 00605 00606 00607 void ast_jb_get_config(const struct ast_channel *chan, struct ast_jb_conf *conf) 00608 { 00609 memcpy(conf, &chan->jb.conf, sizeof(*conf)); 00610 } 00611 00612 00613 /* Implementation functions */ 00614 00615 /* fixed */ 00616 00617 static void * jb_create_fixed(struct ast_jb_conf *general_config, long resynch_threshold) 00618 { 00619 struct fixed_jb_conf conf; 00620 00621 conf.jbsize = general_config->max_size; 00622 conf.resync_threshold = resynch_threshold; 00623 00624 return fixed_jb_new(&conf); 00625 } 00626 00627 00628 static void jb_destroy_fixed(void *jb) 00629 { 00630 struct fixed_jb *fixedjb = (struct fixed_jb *) jb; 00631 00632 /* destroy the jb */ 00633 fixed_jb_destroy(fixedjb); 00634 } 00635 00636 00637 static int jb_put_first_fixed(void *jb, struct ast_frame *fin, long now) 00638 { 00639 struct fixed_jb *fixedjb = (struct fixed_jb *) jb; 00640 int res; 00641 00642 res = fixed_jb_put_first(fixedjb, fin, fin->len, fin->ts, now); 00643 00644 return fixed_to_abstract_code[res]; 00645 } 00646 00647 00648 static int jb_put_fixed(void *jb, struct ast_frame *fin, long now) 00649 { 00650 struct fixed_jb *fixedjb = (struct fixed_jb *) jb; 00651 int res; 00652 00653 res = fixed_jb_put(fixedjb, fin, fin->len, fin->ts, now); 00654 00655 return fixed_to_abstract_code[res]; 00656 } 00657 00658 00659 static int jb_get_fixed(void *jb, struct ast_frame **fout, long now, long interpl) 00660 { 00661 struct fixed_jb *fixedjb = (struct fixed_jb *) jb; 00662 struct fixed_jb_frame frame; 00663 int res; 00664 00665 res = fixed_jb_get(fixedjb, &frame, now, interpl); 00666 *fout = frame.data; 00667 00668 return fixed_to_abstract_code[res]; 00669 } 00670 00671 00672 static long jb_next_fixed(void *jb) 00673 { 00674 struct fixed_jb *fixedjb = (struct fixed_jb *) jb; 00675 00676 return fixed_jb_next(fixedjb); 00677 } 00678 00679 00680 static int jb_remove_fixed(void *jb, struct ast_frame **fout) 00681 { 00682 struct fixed_jb *fixedjb = (struct fixed_jb *) jb; 00683 struct fixed_jb_frame frame; 00684 int res; 00685 00686 res = fixed_jb_remove(fixedjb, &frame); 00687 *fout = frame.data; 00688 00689 return fixed_to_abstract_code[res]; 00690 } 00691 00692 00693 static void jb_force_resynch_fixed(void *jb) 00694 { 00695 struct fixed_jb *fixedjb = (struct fixed_jb *) jb; 00696 00697 fixed_jb_set_force_resynch(fixedjb); 00698 } 00699 00700 00701 /* adaptive */ 00702 00703 static void *jb_create_adaptive(struct ast_jb_conf *general_config, long resynch_threshold) 00704 { 00705 jb_conf jbconf; 00706 jitterbuf *adaptivejb; 00707 00708 adaptivejb = jb_new(); 00709 if (adaptivejb) { 00710 jbconf.max_jitterbuf = general_config->max_size; 00711 jbconf.resync_threshold = general_config->resync_threshold; 00712 jbconf.max_contig_interp = 10; 00713 jb_setconf(adaptivejb, &jbconf); 00714 } 00715 00716 return adaptivejb; 00717 } 00718 00719 00720 static void jb_destroy_adaptive(void *jb) 00721 { 00722 jitterbuf *adaptivejb = (jitterbuf *) jb; 00723 00724 jb_destroy(adaptivejb); 00725 } 00726 00727 00728 static int jb_put_first_adaptive(void *jb, struct ast_frame *fin, long now) 00729 { 00730 return jb_put_adaptive(jb, fin, now); 00731 } 00732 00733 00734 static int jb_put_adaptive(void *jb, struct ast_frame *fin, long now) 00735 { 00736 jitterbuf *adaptivejb = (jitterbuf *) jb; 00737 int res; 00738 00739 res = jb_put(adaptivejb, fin, JB_TYPE_VOICE, fin->len, fin->ts, now); 00740 00741 return adaptive_to_abstract_code[res]; 00742 } 00743 00744 00745 static int jb_get_adaptive(void *jb, struct ast_frame **fout, long now, long interpl) 00746 { 00747 jitterbuf *adaptivejb = (jitterbuf *) jb; 00748 jb_frame frame; 00749 int res; 00750 00751 res = jb_get(adaptivejb, &frame, now, interpl); 00752 *fout = frame.data; 00753 00754 return adaptive_to_abstract_code[res]; 00755 } 00756 00757 00758 static long jb_next_adaptive(void *jb) 00759 { 00760 jitterbuf *adaptivejb = (jitterbuf *) jb; 00761 00762 return jb_next(adaptivejb); 00763 } 00764 00765 00766 static int jb_remove_adaptive(void *jb, struct ast_frame **fout) 00767 { 00768 jitterbuf *adaptivejb = (jitterbuf *) jb; 00769 jb_frame frame; 00770 int res; 00771 00772 res = jb_getall(adaptivejb, &frame); 00773 *fout = frame.data; 00774 00775 return adaptive_to_abstract_code[res]; 00776 } 00777 00778 00779 static void jb_force_resynch_adaptive(void *jb) 00780 { 00781 }