Introduction of the JITTERBUFFER dialplan function.

Review: https://reviewboard.asterisk.org/r/1157/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@314509 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
David Vossel
2011-04-20 20:52:15 +00:00
parent 3b52f36551
commit 18d591cb48
6 changed files with 455 additions and 64 deletions

View File

@@ -49,43 +49,6 @@ enum {
JB_CREATED = (1 << 2)
};
/* Hooks for the abstract jb implementation */
/*! \brief Create */
typedef void * (*jb_create_impl)(struct ast_jb_conf *general_config, long resynch_threshold);
/*! \brief Destroy */
typedef void (*jb_destroy_impl)(void *jb);
/*! \brief Put first frame */
typedef int (*jb_put_first_impl)(void *jb, struct ast_frame *fin, long now);
/*! \brief Put frame */
typedef int (*jb_put_impl)(void *jb, struct ast_frame *fin, long now);
/*! \brief Get frame for now */
typedef int (*jb_get_impl)(void *jb, struct ast_frame **fout, long now, long interpl);
/*! \brief Get next */
typedef long (*jb_next_impl)(void *jb);
/*! \brief Remove first frame */
typedef int (*jb_remove_impl)(void *jb, struct ast_frame **fout);
/*! \brief Force resynch */
typedef void (*jb_force_resynch_impl)(void *jb);
/*! \brief Empty and reset jb */
typedef void (*jb_empty_and_reset_impl)(void *jb);
/*!
* \brief Jitterbuffer implementation private struct.
*/
struct ast_jb_impl
{
char name[AST_JB_IMPL_NAME_SIZE];
jb_create_impl create;
jb_destroy_impl destroy;
jb_put_first_impl put_first;
jb_put_impl put;
jb_get_impl get;
jb_next_impl next;
jb_remove_impl remove;
jb_force_resynch_impl force_resync;
jb_empty_and_reset_impl empty_and_reset;
};
/* Implementation functions */
/* fixed */
@@ -113,6 +76,7 @@ static void jb_empty_and_reset_adaptive(void *jb);
static const struct ast_jb_impl avail_impl[] = {
{
.name = "fixed",
.type = AST_JB_FIXED,
.create = jb_create_fixed,
.destroy = jb_destroy_fixed,
.put_first = jb_put_first_fixed,
@@ -125,6 +89,7 @@ static const struct ast_jb_impl avail_impl[] = {
},
{
.name = "adaptive",
.type = AST_JB_ADAPTIVE,
.create = jb_create_adaptive,
.destroy = jb_destroy_adaptive,
.put_first = jb_put_first_adaptive,
@@ -139,20 +104,11 @@ static const struct ast_jb_impl avail_impl[] = {
static int default_impl = 0;
/*! Abstract return codes */
enum {
JB_IMPL_OK,
JB_IMPL_DROP,
JB_IMPL_INTERP,
JB_IMPL_NOFRAME
};
/* Translations between impl and abstract return codes */
static const int fixed_to_abstract_code[] =
{JB_IMPL_OK, JB_IMPL_DROP, JB_IMPL_INTERP, JB_IMPL_NOFRAME};
{AST_JB_IMPL_OK, AST_JB_IMPL_DROP, AST_JB_IMPL_INTERP, AST_JB_IMPL_NOFRAME};
static const int adaptive_to_abstract_code[] =
{JB_IMPL_OK, JB_IMPL_NOFRAME, JB_IMPL_NOFRAME, JB_IMPL_INTERP, JB_IMPL_DROP, JB_IMPL_OK};
{AST_JB_IMPL_OK, AST_JB_IMPL_NOFRAME, AST_JB_IMPL_NOFRAME, AST_JB_IMPL_INTERP, AST_JB_IMPL_DROP, AST_JB_IMPL_OK};
/* JB_GET actions (used only for the frames log) */
static const char * const jb_get_actions[] = {"Delivered", "Dropped", "Interpolated", "No"};
@@ -346,7 +302,7 @@ int ast_jb_put(struct ast_channel *chan, struct ast_frame *f)
return 0;
} else {
now = get_now(jb, NULL);
if (jbimpl->put(jbobj, frr, now) != JB_IMPL_OK) {
if (jbimpl->put(jbobj, frr, now) != AST_JB_IMPL_OK) {
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;*/
@@ -403,16 +359,16 @@ static void jb_get_and_deliver(struct ast_channel *chan)
res = jbimpl->get(jbobj, &f, now, interpolation_len);
switch (res) {
case JB_IMPL_OK:
case AST_JB_IMPL_OK:
/* deliver the frame */
ast_write(chan, f);
case JB_IMPL_DROP:
case AST_JB_IMPL_DROP:
jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
now, jb_get_actions[res], f->ts, f->len);
ast_format_copy(&jb->last_format, &f->subclass.format);
ast_frfree(f);
break;
case JB_IMPL_INTERP:
case AST_JB_IMPL_INTERP:
/* interpolate a frame */
f = &finterp;
ast_format_copy(&f->subclass.format, &jb->last_format);
@@ -424,9 +380,9 @@ static void jb_get_and_deliver(struct ast_channel *chan)
ast_write(chan, f);
jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now, interpolation_len);
break;
case JB_IMPL_NOFRAME:
case AST_JB_IMPL_NOFRAME:
ast_log(LOG_WARNING,
"JB_IMPL_NOFRAME is returned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
"AST_JB_IMPL_NOFRAME is returned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
jbimpl->name, now, jb->next, jbimpl->next(jbobj));
jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now);
return;
@@ -464,7 +420,7 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
/* 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) {
if (res != AST_JB_IMPL_OK) {
ast_log(LOG_WARNING, "Failed to put first frame in the jitterbuffer on channel '%s'\n", chan->name);
/*
jbimpl->destroy(jbobj);
@@ -508,7 +464,7 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
}
}
if (res == JB_IMPL_OK) {
if (res == AST_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 {
@@ -520,7 +476,7 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
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 != AST_JB_IMPL_OK) {
ast_frfree(frr);
}
@@ -542,7 +498,7 @@ void ast_jb_destroy(struct ast_channel *chan)
if (ast_test_flag(jb, JB_CREATED)) {
/* Remove and free all frames still queued in jb */
while (jbimpl->remove(jbobj, &f) == JB_IMPL_OK) {
while (jbimpl->remove(jbobj, &f) == AST_JB_IMPL_OK) {
ast_frfree(f);
}
@@ -831,3 +787,14 @@ static void jb_empty_and_reset_adaptive(void *jb)
jb_reset(adaptivejb);
}
const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type)
{
int i;
for (i = 0; i < ARRAY_LEN(avail_impl); i++) {
if (avail_impl[i].type == type) {
return &avail_impl[i];
}
}
return NULL;
}