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

Generated on Mon Oct 8 12:38:55 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7