Sat Feb 11 06:32:59 2012

Asterisk developer's documentation


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

Generated on Sat Feb 11 06:33:00 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6