|
|
|
@ -23,7 +23,7 @@
|
|
|
|
|
/*! \file
|
|
|
|
|
*
|
|
|
|
|
* \brief Common implementation-independent jitterbuffer stuff.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* \author Slav Klenov <slav@securax.org>
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
@ -110,7 +110,7 @@ static void jb_force_resynch_adaptive(void *jb);
|
|
|
|
|
static void jb_empty_and_reset_adaptive(void *jb);
|
|
|
|
|
|
|
|
|
|
/* Available jb implementations */
|
|
|
|
|
static struct ast_jb_impl avail_impl[] =
|
|
|
|
|
static struct ast_jb_impl avail_impl[] =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
.name = "fixed",
|
|
|
|
@ -183,12 +183,13 @@ static void jb_choose_impl(struct ast_channel *chan)
|
|
|
|
|
struct ast_jb_conf *jbconf = &jb->conf;
|
|
|
|
|
struct ast_jb_impl *test_impl;
|
|
|
|
|
int i, avail_impl_count = ARRAY_LEN(avail_impl);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
jb->impl = &avail_impl[default_impl];
|
|
|
|
|
|
|
|
|
|
if (ast_strlen_zero(jbconf->impl))
|
|
|
|
|
|
|
|
|
|
if (ast_strlen_zero(jbconf->impl)) {
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < avail_impl_count; i++) {
|
|
|
|
|
test_impl = &avail_impl[i];
|
|
|
|
|
if (!strcasecmp(jbconf->impl, test_impl->name)) {
|
|
|
|
@ -229,14 +230,14 @@ int ast_jb_do_usecheck(struct ast_channel *c0, struct ast_channel *c1)
|
|
|
|
|
}
|
|
|
|
|
ast_set_flag(jb0, JB_TIMEBASE_INITIALIZED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!c0_jb_created) {
|
|
|
|
|
jb_choose_impl(c0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inuse = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Determine whether audio going to c1 needs a jitter buffer */
|
|
|
|
|
if (((!c1_wants_jitter && c0_creates_jitter) || (c1_force_jb && c0_creates_jitter)) && c1_jb_enabled) {
|
|
|
|
|
ast_set_flag(jb1, JB_USE);
|
|
|
|
@ -248,7 +249,7 @@ int ast_jb_do_usecheck(struct ast_channel *c0, struct ast_channel *c1)
|
|
|
|
|
}
|
|
|
|
|
ast_set_flag(jb1, JB_TIMEBASE_INITIALIZED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!c1_jb_created) {
|
|
|
|
|
jb_choose_impl(c1);
|
|
|
|
|
}
|
|
|
|
@ -269,32 +270,32 @@ int ast_jb_get_when_to_wakeup(struct ast_channel *c0, struct ast_channel *c1, in
|
|
|
|
|
int c1_jb_is_created = ast_test_flag(jb1, JB_CREATED);
|
|
|
|
|
int wait, wait0, wait1;
|
|
|
|
|
struct timeval tv_now;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (time_left == 0) {
|
|
|
|
|
/* No time left - the bridge will be retried */
|
|
|
|
|
/* TODO: Test disable this */
|
|
|
|
|
/*return 0;*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (time_left < 0) {
|
|
|
|
|
time_left = INT_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gettimeofday(&tv_now, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wait0 = (c0_use_jb && c0_jb_is_created) ? jb0->next - get_now(jb0, &tv_now) : time_left;
|
|
|
|
|
wait1 = (c1_use_jb && c1_jb_is_created) ? jb1->next - get_now(jb1, &tv_now) : time_left;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wait = wait0 < wait1 ? wait0 : wait1;
|
|
|
|
|
wait = wait < time_left ? wait : time_left;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (wait == INT_MAX) {
|
|
|
|
|
wait = -1;
|
|
|
|
|
} else if (wait < 1) {
|
|
|
|
|
/* don't let wait=0, because this can cause the pbx thread to loop without any sleeping at all */
|
|
|
|
|
wait = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return wait;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -306,7 +307,7 @@ int ast_jb_put(struct ast_channel *chan, struct ast_frame *f)
|
|
|
|
|
void *jbobj = jb->jbobj;
|
|
|
|
|
struct ast_frame *frr;
|
|
|
|
|
long now = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!ast_test_flag(jb, JB_USE))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
@ -315,7 +316,7 @@ int ast_jb_put(struct ast_channel *chan, struct ast_frame *f)
|
|
|
|
|
jb_framelog("JB_PUT {now=%ld}: Received DTMF frame. Force resynching jb...\n", now);
|
|
|
|
|
jbimpl->force_resync(jbobj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -350,7 +351,7 @@ int ast_jb_put(struct ast_channel *chan, struct ast_frame *f)
|
|
|
|
|
jb_framelog("JB_PUT {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len);
|
|
|
|
|
ast_frfree(frr);
|
|
|
|
|
/*return -1;*/
|
|
|
|
|
/* TODO: Check this fix - should return 0 here, because the dropped frame shouldn't
|
|
|
|
|
/* TODO: Check this fix - should return 0 here, because the dropped frame shouldn't
|
|
|
|
|
be delivered at all */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -372,10 +373,10 @@ void ast_jb_get_and_deliver(struct ast_channel *c0, struct ast_channel *c1)
|
|
|
|
|
int c0_jb_is_created = ast_test_flag(jb0, JB_CREATED);
|
|
|
|
|
int c1_use_jb = ast_test_flag(jb1, JB_USE);
|
|
|
|
|
int c1_jb_is_created = ast_test_flag(jb1, JB_CREATED);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (c0_use_jb && c0_jb_is_created)
|
|
|
|
|
jb_get_and_deliver(c0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (c1_use_jb && c1_jb_is_created)
|
|
|
|
|
jb_get_and_deliver(c1);
|
|
|
|
|
}
|
|
|
|
@ -389,19 +390,19 @@ static void jb_get_and_deliver(struct ast_channel *chan)
|
|
|
|
|
struct ast_frame *f, finterp;
|
|
|
|
|
long now;
|
|
|
|
|
int interpolation_len, res;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
now = get_now(jb, NULL);
|
|
|
|
|
jb->next = jbimpl->next(jbobj);
|
|
|
|
|
if (now < jb->next) {
|
|
|
|
|
jb_framelog("\tJB_GET {now=%ld}: now < next=%ld\n", now, jb->next);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (now >= jb->next) {
|
|
|
|
|
interpolation_len = ast_codec_interp_len(jb->last_format);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = jbimpl->get(jbobj, &f, now, interpolation_len);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (res) {
|
|
|
|
|
case JB_IMPL_OK:
|
|
|
|
|
/* deliver the frame */
|
|
|
|
@ -439,7 +440,7 @@ static void jb_get_and_deliver(struct ast_channel *chan)
|
|
|
|
|
ast_assert("JB type unknown" == NULL);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
jb->next = jbimpl->next(jbobj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -462,10 +463,10 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
|
|
|
|
|
ast_log(LOG_WARNING, "Failed to create jitterbuffer on channel '%s'\n", chan->name);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
now = get_now(jb, NULL);
|
|
|
|
|
res = jbimpl->put_first(jbobj, frr, now);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The result of putting the first frame should not differ from OK. However, its possible
|
|
|
|
|
some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */
|
|
|
|
|
if (res != JB_IMPL_OK) {
|
|
|
|
@ -475,30 +476,30 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
|
|
|
|
|
return -1;
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Init next */
|
|
|
|
|
jb->next = jbimpl->next(jbobj);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Init last format for a first time. */
|
|
|
|
|
jb->last_format = frr->subclass;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create a frame log file */
|
|
|
|
|
if (ast_test_flag(jbconf, AST_JB_LOG)) {
|
|
|
|
|
char safe_logfile[30] = "/tmp/logfile-XXXXXX";
|
|
|
|
|
int safe_fd;
|
|
|
|
|
snprintf(name2, sizeof(name2), "%s", chan->name);
|
|
|
|
|
tmp = strchr(name2, '/');
|
|
|
|
|
if (tmp)
|
|
|
|
|
if ((tmp = strchr(name2, '/'))) {
|
|
|
|
|
*tmp = '#';
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bridged = ast_bridged_channel(chan);
|
|
|
|
|
/* We should always have bridged chan if a jitterbuffer is in use */
|
|
|
|
|
ast_assert(bridged != NULL);
|
|
|
|
|
|
|
|
|
|
snprintf(name1, sizeof(name1), "%s", bridged->name);
|
|
|
|
|
tmp = strchr(name1, '/');
|
|
|
|
|
if (tmp)
|
|
|
|
|
if ((tmp = strchr(name1, '/'))) {
|
|
|
|
|
*tmp = '#';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snprintf(logfile_pathname, sizeof(logfile_pathname),
|
|
|
|
|
"/tmp/ast_%s_jb_%s--%s.log", jbimpl->name, name1, name2);
|
|
|
|
@ -510,20 +511,22 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
|
|
|
|
|
ast_log(LOG_ERROR, "Failed to create frame log file with pathname '%s': %s\n", logfile_pathname, strerror(errno));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (res == JB_IMPL_OK)
|
|
|
|
|
if (res == JB_IMPL_OK) {
|
|
|
|
|
jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n",
|
|
|
|
|
now, frr->ts, frr->len);
|
|
|
|
|
else
|
|
|
|
|
} else {
|
|
|
|
|
jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n",
|
|
|
|
|
now, frr->ts, frr->len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ast_verb(3, "%s jitterbuffer created on channel %s\n", jbimpl->name, chan->name);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Free the frame if it has not been queued in the jb */
|
|
|
|
|
if (res != JB_IMPL_OK)
|
|
|
|
|
if (res != JB_IMPL_OK) {
|
|
|
|
|
ast_frfree(frr);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -539,16 +542,16 @@ void ast_jb_destroy(struct ast_channel *chan)
|
|
|
|
|
fclose(jb->logfile);
|
|
|
|
|
jb->logfile = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ast_test_flag(jb, JB_CREATED)) {
|
|
|
|
|
/* Remove and free all frames still queued in jb */
|
|
|
|
|
while (jbimpl->remove(jbobj, &f) == JB_IMPL_OK) {
|
|
|
|
|
ast_frfree(f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
jbimpl->destroy(jbobj);
|
|
|
|
|
jb->jbobj = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ast_clear_flag(jb, JB_CREATED);
|
|
|
|
|
|
|
|
|
|
ast_verb(3, "%s jitterbuffer destroyed on channel %s\n", jbimpl->name, chan->name);
|
|
|
|
@ -574,12 +577,13 @@ int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *
|
|
|
|
|
int prefixlen = sizeof(AST_JB_CONF_PREFIX) - 1;
|
|
|
|
|
const char *name;
|
|
|
|
|
int tmp;
|
|
|
|
|
|
|
|
|
|
if (strncasecmp(AST_JB_CONF_PREFIX, varname, prefixlen))
|
|
|
|
|
|
|
|
|
|
if (strncasecmp(AST_JB_CONF_PREFIX, varname, prefixlen)) {
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name = varname + prefixlen;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!strcasecmp(name, AST_JB_CONF_ENABLE)) {
|
|
|
|
|
ast_set2_flag(conf, ast_true(value), AST_JB_ENABLED);
|
|
|
|
|
} else if (!strcasecmp(name, AST_JB_CONF_FORCE)) {
|
|
|
|
@ -598,7 +602,7 @@ int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *
|
|
|
|
|
} else {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -648,7 +652,7 @@ static void * jb_create_fixed(struct ast_jb_conf *general_config, long resynch_t
|
|
|
|
|
static void jb_destroy_fixed(void *jb)
|
|
|
|
|
{
|
|
|
|
|
struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* destroy the jb */
|
|
|
|
|
fixed_jb_destroy(fixedjb);
|
|
|
|
|
}
|
|
|
|
@ -658,9 +662,9 @@ static int jb_put_first_fixed(void *jb, struct ast_frame *fin, long now)
|
|
|
|
|
{
|
|
|
|
|
struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = fixed_jb_put_first(fixedjb, fin, fin->len, fin->ts, now);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fixed_to_abstract_code[res];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -669,9 +673,9 @@ static int jb_put_fixed(void *jb, struct ast_frame *fin, long now)
|
|
|
|
|
{
|
|
|
|
|
struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = fixed_jb_put(fixedjb, fin, fin->len, fin->ts, now);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fixed_to_abstract_code[res];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -681,10 +685,10 @@ static int jb_get_fixed(void *jb, struct ast_frame **fout, long now, long interp
|
|
|
|
|
struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
|
|
|
|
|
struct fixed_jb_frame frame;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = fixed_jb_get(fixedjb, &frame, now, interpl);
|
|
|
|
|
*fout = frame.data;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fixed_to_abstract_code[res];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -692,7 +696,7 @@ static int jb_get_fixed(void *jb, struct ast_frame **fout, long now, long interp
|
|
|
|
|
static long jb_next_fixed(void *jb)
|
|
|
|
|
{
|
|
|
|
|
struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fixed_jb_next(fixedjb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -702,10 +706,10 @@ static int jb_remove_fixed(void *jb, struct ast_frame **fout)
|
|
|
|
|
struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
|
|
|
|
|
struct fixed_jb_frame frame;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = fixed_jb_remove(fixedjb, &frame);
|
|
|
|
|
*fout = frame.data;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fixed_to_abstract_code[res];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -713,7 +717,7 @@ static int jb_remove_fixed(void *jb, struct ast_frame **fout)
|
|
|
|
|
static void jb_force_resynch_fixed(void *jb)
|
|
|
|
|
{
|
|
|
|
|
struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fixed_jb_set_force_resynch(fixedjb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -741,7 +745,7 @@ static void *jb_create_adaptive(struct ast_jb_conf *general_config, long resynch
|
|
|
|
|
jbconf.max_contig_interp = 10;
|
|
|
|
|
jb_setconf(adaptivejb, &jbconf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return adaptivejb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -749,7 +753,7 @@ static void *jb_create_adaptive(struct ast_jb_conf *general_config, long resynch
|
|
|
|
|
static void jb_destroy_adaptive(void *jb)
|
|
|
|
|
{
|
|
|
|
|
jitterbuf *adaptivejb = (jitterbuf *) jb;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
jb_destroy(adaptivejb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -764,9 +768,9 @@ static int jb_put_adaptive(void *jb, struct ast_frame *fin, long now)
|
|
|
|
|
{
|
|
|
|
|
jitterbuf *adaptivejb = (jitterbuf *) jb;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = jb_put(adaptivejb, fin, JB_TYPE_VOICE, fin->len, fin->ts, now);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return adaptive_to_abstract_code[res];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -776,10 +780,10 @@ static int jb_get_adaptive(void *jb, struct ast_frame **fout, long now, long int
|
|
|
|
|
jitterbuf *adaptivejb = (jitterbuf *) jb;
|
|
|
|
|
jb_frame frame;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = jb_get(adaptivejb, &frame, now, interpl);
|
|
|
|
|
*fout = frame.data;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return adaptive_to_abstract_code[res];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -787,7 +791,7 @@ static int jb_get_adaptive(void *jb, struct ast_frame **fout, long now, long int
|
|
|
|
|
static long jb_next_adaptive(void *jb)
|
|
|
|
|
{
|
|
|
|
|
jitterbuf *adaptivejb = (jitterbuf *) jb;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return jb_next(adaptivejb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -797,10 +801,10 @@ static int jb_remove_adaptive(void *jb, struct ast_frame **fout)
|
|
|
|
|
jitterbuf *adaptivejb = (jitterbuf *) jb;
|
|
|
|
|
jb_frame frame;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = jb_getall(adaptivejb, &frame);
|
|
|
|
|
*fout = frame.data;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return adaptive_to_abstract_code[res];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|