[asterisk-commits] jrose: branch group/bridge_construction r386561 - in /team/group/bridge_const...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Apr 25 14:29:22 CDT 2013
Author: jrose
Date: Thu Apr 25 14:29:16 2013
New Revision: 386561
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386561
Log:
bridging/func_jitterbuffer: apply channel set jitterbuffers on bridge
Channel-driver set jitterbuffers are now applied using functionality
that was formerly provided exclusively through func_jitterbuffer.
In order to accomodate this, func_jitterbuffer was stripped down to
just parse the arguments and call new jitterbuffer application API
which was pulled into abstract_jb core from func_jitterbuffer.
(closes issue ASTERISK-21333)
Review: https://reviewboard.asterisk.org/r/2459/
Modified:
team/group/bridge_construction/CHANGES
team/group/bridge_construction/funcs/func_jitterbuffer.c
team/group/bridge_construction/include/asterisk/abstract_jb.h
team/group/bridge_construction/main/abstract_jb.c
team/group/bridge_construction/main/bridging.c
Modified: team/group/bridge_construction/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/CHANGES?view=diff&rev=386561&r1=386560&r2=386561
==============================================================================
--- team/group/bridge_construction/CHANGES (original)
+++ team/group/bridge_construction/CHANGES Thu Apr 25 14:29:16 2013
@@ -61,6 +61,11 @@
Channel Drivers
------------------
+ * When a channel driver is configured to enable jiterbuffers, they are now
+ applied unconditionally when a channel joins a bridge. If a jitterbuffer
+ is already set for that channel when it enters, such as by the JITTERBUFFER
+ function, then the existing jitterbuffer will be used and the one set by
+ the channel driver will not be applied.
chan_local
------------------
@@ -96,6 +101,12 @@
* You can now have the settings for a channel updated using the FEATURE()
and FEATUREMAP() functions inherited to child channels by setting
FEATURE(inherit)=yes.
+
+Functions
+------------------
+ * JITTERBUFFER now accepts an argument of 'disabled' which can be used
+ to remove jitterbuffers previously set on a channel with JITTERBUFFER.
+ The value of this setting is ignored when disabled is used for the argument.
Logging
-------------------
Modified: team/group/bridge_construction/funcs/func_jitterbuffer.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/funcs/func_jitterbuffer.c?view=diff&rev=386561&r1=386560&r2=386561
==============================================================================
--- team/group/bridge_construction/funcs/func_jitterbuffer.c (original)
+++ team/group/bridge_construction/funcs/func_jitterbuffer.c Thu Apr 25 14:29:16 2013
@@ -36,6 +36,7 @@
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/framehook.h"
+#include "asterisk/frame.h"
#include "asterisk/pbx.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/timing.h"
@@ -48,7 +49,8 @@
</synopsis>
<syntax>
<parameter name="jitterbuffer type" required="true">
- <para>Jitterbuffer type can be either <literal>fixed</literal> or <literal>adaptive</literal>.</para>
+ <para>Jitterbuffer type can be <literal>fixed</literal>, <literal>adaptive</literal>, or
+ <literal>disabled</literal>.</para>
<para>Used as follows. </para>
<para>Set(JITTERBUFFER(type)=max_size[,resync_threshold[,target_extra]])</para>
<para>Set(JITTERBUFFER(type)=default) </para>
@@ -70,85 +72,31 @@
<para>exten => 1,1,Set(JITTERBUFFER(fixed)=200,1500);Fixed with max size 200ms resync threshold 1500. </para>
<para>exten => 1,1,Set(JITTERBUFFER(adaptive)=default);Adaptive with defaults. </para>
<para>exten => 1,1,Set(JITTERBUFFER(adaptive)=200,,60);Adaptive with max size 200ms, default resync threshold and 40ms target extra. </para>
+ <para>exten => 1,n,Set(JITTERBUFFER(disabled)=);Remove previously applied jitterbuffer </para>
+ <note><para>If a channel specifies a jitterbuffer due to channel driver configuration and
+ the JITTERBUFFER function has set a jitterbuffer for that channel, the jitterbuffer set by
+ the JITTERBUFFER function will take priority and the jitterbuffer set by the channel
+ configuration will not be applied.</para></note>
</description>
</function>
***/
-#define DEFAULT_TIMER_INTERVAL 20
-#define DEFAULT_SIZE 200
-#define DEFAULT_TARGET_EXTRA 40
-#define DEFAULT_RESYNC 1000
-#define DEFAULT_TYPE AST_JB_FIXED
+static int jb_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ struct ast_jb_conf jb_conf;
-struct jb_framedata {
- const struct ast_jb_impl *jb_impl;
- struct ast_jb_conf jb_conf;
- struct timeval start_tv;
- struct ast_format last_format;
- struct ast_timer *timer;
- int timer_interval; /* ms between deliveries */
- int timer_fd;
- int first;
- void *jb_obj;
-};
-
-static void jb_framedata_destroy(struct jb_framedata *framedata)
-{
- if (framedata->timer) {
- ast_timer_close(framedata->timer);
- framedata->timer = NULL;
- }
- if (framedata->jb_impl && framedata->jb_obj) {
- struct ast_frame *f;
- while (framedata->jb_impl->remove(framedata->jb_obj, &f) == AST_JB_IMPL_OK) {
- ast_frfree(f);
- }
- framedata->jb_impl->destroy(framedata->jb_obj);
- framedata->jb_obj = NULL;
- }
- ast_free(framedata);
-}
-
-static void jb_conf_default(struct ast_jb_conf *conf)
-{
- conf->max_size = DEFAULT_SIZE;
- conf->resync_threshold = DEFAULT_RESYNC;
- ast_copy_string(conf->impl, "fixed", sizeof(conf->impl));
- conf->target_extra = DEFAULT_TARGET_EXTRA;
-}
-
-/* set defaults */
-static int jb_framedata_init(struct jb_framedata *framedata, const char *data, const char *value)
-{
- int jb_impl_type = DEFAULT_TYPE;
-
- /* Initialize defaults */
- framedata->timer_fd = -1;
- jb_conf_default(&framedata->jb_conf);
- if (!(framedata->jb_impl = ast_jb_get_impl(jb_impl_type))) {
- return -1;
- }
- if (!(framedata->timer = ast_timer_open())) {
- return -1;
- }
- framedata->timer_fd = ast_timer_fd(framedata->timer);
- framedata->timer_interval = DEFAULT_TIMER_INTERVAL;
- ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
- framedata->start_tv = ast_tvnow();
-
-
+ /* Initialize and set jb_conf */
+ ast_jb_conf_default(&jb_conf);
/* Now check user options to see if any of the defaults need to change. */
if (!ast_strlen_zero(data)) {
- if (!strcasecmp(data, "fixed")) {
- jb_impl_type = AST_JB_FIXED;
- } else if (!strcasecmp(data, "adaptive")) {
- jb_impl_type = AST_JB_ADAPTIVE;
- } else {
+ if (strcasecmp(data, "fixed") &&
+ strcasecmp(data, "adaptive") &&
+ strcasecmp(data, "disabled")) {
ast_log(LOG_WARNING, "Unknown Jitterbuffer type %s. Failed to create jitterbuffer.\n", data);
return -1;
}
- ast_copy_string(framedata->jb_conf.impl, data, sizeof(framedata->jb_conf.impl));
+ ast_copy_string(jb_conf.impl, data, sizeof(jb_conf.impl));
}
if (!ast_strlen_zero(value) && strcasecmp(value, "default")) {
@@ -162,17 +110,17 @@
AST_STANDARD_APP_ARGS(args, parse);
if (!ast_strlen_zero(args.max_size)) {
- res |= ast_jb_read_conf(&framedata->jb_conf,
+ res |= ast_jb_read_conf(&jb_conf,
"jbmaxsize",
args.max_size);
}
if (!ast_strlen_zero(args.resync_threshold)) {
- res |= ast_jb_read_conf(&framedata->jb_conf,
+ res |= ast_jb_read_conf(&jb_conf,
"jbresyncthreshold",
args.resync_threshold);
}
if (!ast_strlen_zero(args.target_extra)) {
- res |= ast_jb_read_conf(&framedata->jb_conf,
+ res |= ast_jb_read_conf(&jb_conf,
"jbtargetextra",
args.target_extra);
}
@@ -181,197 +129,11 @@
}
}
- /* now that all the user parsing is done and nothing will change, create the jb obj */
- framedata->jb_obj = framedata->jb_impl->create(&framedata->jb_conf);
+ ast_jb_create_framehook(chan, &jb_conf, 0);
+
return 0;
}
-static void datastore_destroy_cb(void *data) {
- ast_free(data);
- ast_debug(1, "JITTERBUFFER datastore destroyed\n");
-}
-
-static const struct ast_datastore_info jb_datastore = {
- .type = "jitterbuffer",
- .destroy = datastore_destroy_cb
-};
-
-static void hook_destroy_cb(void *framedata)
-{
- ast_debug(1, "JITTERBUFFER hook destroyed\n");
- jb_framedata_destroy((struct jb_framedata *) framedata);
-}
-
-static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
-{
- struct jb_framedata *framedata = data;
- struct timeval now_tv;
- unsigned long now;
- int putframe = 0; /* signifies if audio frame was placed into the buffer or not */
-
- switch (event) {
- case AST_FRAMEHOOK_EVENT_READ:
- break;
- case AST_FRAMEHOOK_EVENT_ATTACHED:
- case AST_FRAMEHOOK_EVENT_DETACHED:
- case AST_FRAMEHOOK_EVENT_WRITE:
- return frame;
- }
-
- if (ast_channel_fdno(chan) == AST_JITTERBUFFER_FD && framedata->timer) {
- if (ast_timer_ack(framedata->timer, 1) < 0) {
- ast_log(LOG_ERROR, "Failed to acknowledge timer in jitter buffer\n");
- return frame;
- }
- }
-
- if (!frame) {
- return frame;
- }
-
- now_tv = ast_tvnow();
- now = ast_tvdiff_ms(now_tv, framedata->start_tv);
-
- if (frame->frametype == AST_FRAME_VOICE) {
- int res;
- struct ast_frame *jbframe;
-
- if (!ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO) || frame->len < 2 || frame->ts < 0) {
- /* only frames with timing info can enter the jitterbuffer */
- return frame;
- }
-
- jbframe = ast_frisolate(frame);
- ast_format_copy(&framedata->last_format, &frame->subclass.format);
-
- if (frame->len && (frame->len != framedata->timer_interval)) {
- framedata->timer_interval = frame->len;
- ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
- }
- if (!framedata->first) {
- framedata->first = 1;
- res = framedata->jb_impl->put_first(framedata->jb_obj, jbframe, now);
- } else {
- res = framedata->jb_impl->put(framedata->jb_obj, jbframe, now);
- }
- if (res == AST_JB_IMPL_OK) {
- frame = &ast_null_frame;
- }
- putframe = 1;
- }
-
- if (frame->frametype == AST_FRAME_NULL) {
- int res;
- long next = framedata->jb_impl->next(framedata->jb_obj);
-
- /* If now is earlier than the next expected output frame
- * from the jitterbuffer we may choose to pass on retrieving
- * a frame during this read iteration. The only exception
- * to this rule is when an audio frame is placed into the buffer
- * and the time for the next frame to come out of the buffer is
- * at least within the timer_interval of the next output frame. By
- * doing this we are able to feed off the timing of the input frames
- * and only rely on our jitterbuffer timer when frames are dropped.
- * During testing, this hybrid form of timing gave more reliable results. */
- if (now < next) {
- long int diff = next - now;
- if (!putframe) {
- return frame;
- } else if (diff >= framedata->timer_interval) {
- return frame;
- }
- }
-
- res = framedata->jb_impl->get(framedata->jb_obj, &frame, now, framedata->timer_interval);
- switch (res) {
- case AST_JB_IMPL_OK:
- /* got it, and pass it through */
- break;
- case AST_JB_IMPL_DROP:
- ast_frfree(frame);
- frame = &ast_null_frame;
- break;
- case AST_JB_IMPL_INTERP:
- if (framedata->last_format.id) {
- struct ast_frame tmp = { 0, };
- tmp.frametype = AST_FRAME_VOICE;
- ast_format_copy(&tmp.subclass.format, &framedata->last_format);
- /* example: 8000hz / (1000 / 20ms) = 160 samples */
- tmp.samples = ast_format_rate(&framedata->last_format) / (1000 / framedata->timer_interval);
- tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000));
- tmp.offset = AST_FRIENDLY_OFFSET;
- tmp.src = "func_jitterbuffer interpolation";
- frame = ast_frdup(&tmp);
- break;
- }
- /* else fall through */
- case AST_JB_IMPL_NOFRAME:
- frame = &ast_null_frame;
- break;
- }
- }
-
- return frame;
-}
-
-static int jb_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
-{
- struct jb_framedata *framedata;
- struct ast_datastore *datastore = NULL;
- struct ast_framehook_interface interface = {
- .version = AST_FRAMEHOOK_INTERFACE_VERSION,
- .event_cb = hook_event_cb,
- .destroy_cb = hook_destroy_cb,
- };
- int i = 0;
-
- if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
- return 0;
- }
-
- if (jb_framedata_init(framedata, data, value)) {
- jb_framedata_destroy(framedata);
- return 0;
- }
-
- interface.data = framedata;
-
- ast_channel_lock(chan);
- i = ast_framehook_attach(chan, &interface);
- if (i >= 0) {
- int *id;
- if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
- id = datastore->data;
- ast_framehook_detach(chan, *id);
- ast_channel_datastore_remove(chan, datastore);
- }
-
- if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) {
- ast_framehook_detach(chan, i);
- ast_channel_unlock(chan);
- return 0;
- }
-
- if (!(id = ast_calloc(1, sizeof(int)))) {
- ast_datastore_free(datastore);
- ast_framehook_detach(chan, i);
- ast_channel_unlock(chan);
- return 0;
- }
-
- *id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
- datastore->data = id;
- ast_channel_datastore_add(chan, datastore);
-
- ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd);
- } else {
- jb_framedata_destroy(framedata);
- framedata = NULL;
- }
- ast_channel_unlock(chan);
-
- return 0;
-}
static struct ast_custom_function jb_function = {
.name = "JITTERBUFFER",
Modified: team/group/bridge_construction/include/asterisk/abstract_jb.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/abstract_jb.h?view=diff&rev=386561&r1=386560&r2=386561
==============================================================================
--- team/group/bridge_construction/include/asterisk/abstract_jb.h (original)
+++ team/group/bridge_construction/include/asterisk/abstract_jb.h Thu Apr 25 14:29:16 2013
@@ -246,6 +246,14 @@
*/
int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *value);
+/*!
+ * \since 12.0
+ * \brief Sets a jitterbuffer frame hook on the channel based on the channel's stored
+ * jitterbuffer configuration
+ *
+ * \param chan Which channel is being set up
+ */
+void ast_jb_enable_for_channel(struct ast_channel *chan);
/*!
* \brief Configures a jitterbuffer on a channel.
@@ -257,7 +265,6 @@
*/
void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf);
-
/*!
* \brief Copies a channel's jitterbuffer configuration.
* \param chan channel.
@@ -274,6 +281,25 @@
const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type);
+/*!
+ * \since 12
+ * \brief Sets the contents of an ast_jb_conf struct to the default jitterbuffer settings
+ *
+ * \param conf Which jitterbuffer is being set
+ */
+void ast_jb_conf_default(struct ast_jb_conf *conf);
+
+/*!
+ * \since 12
+ * \brief Applies a jitterbuffer framehook to a channel based on a provided jitterbuffer config
+ *
+ * \param chan Which channel the jitterbuffer is being set on
+ * \param jb_conf Configuration to use for the jitterbuffer
+ * \param prefer_existing If this is true and a jitterbuffer already exists for the channel,
+ * use the existing jitterbuffer
+ */
+void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_conf, int prefer_existing);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
Modified: team/group/bridge_construction/main/abstract_jb.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/abstract_jb.c?view=diff&rev=386561&r1=386560&r2=386561
==============================================================================
--- team/group/bridge_construction/main/abstract_jb.c (original)
+++ team/group/bridge_construction/main/abstract_jb.c Thu Apr 25 14:29:16 2013
@@ -41,6 +41,8 @@
#include "asterisk/channel.h"
#include "asterisk/term.h"
#include "asterisk/utils.h"
+#include "asterisk/pbx.h"
+#include "asterisk/timing.h"
#include "asterisk/abstract_jb.h"
#include "fixedjitterbuf.h"
@@ -567,10 +569,16 @@
return 0;
}
+void ast_jb_enable_for_channel(struct ast_channel *chan)
+{
+ struct ast_jb_conf conf = ast_channel_jb(chan)->conf;
+ if (ast_test_flag(&conf, AST_JB_ENABLED)) {
+ ast_jb_create_framehook(chan, &conf, 1);
+ }
+}
void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf)
{
-/* BUGBUG convert this to use func_jitterbuffer then the channel jitterbuffer may be able to go away. */
memcpy(&ast_channel_jb(chan)->conf, conf, sizeof(*conf));
}
@@ -801,3 +809,303 @@
}
return NULL;
}
+
+#define DEFAULT_TIMER_INTERVAL 20
+#define DEFAULT_SIZE 200
+#define DEFAULT_TARGET_EXTRA 40
+#define DEFAULT_RESYNC 1000
+#define DEFAULT_TYPE AST_JB_FIXED
+
+struct jb_framedata {
+ const struct ast_jb_impl *jb_impl;
+ struct ast_jb_conf jb_conf;
+ struct timeval start_tv;
+ struct ast_format last_format;
+ struct ast_timer *timer;
+ int timer_interval; /* ms between deliveries */
+ int timer_fd;
+ int first;
+ void *jb_obj;
+};
+
+static void jb_framedata_destroy(struct jb_framedata *framedata)
+{
+ if (framedata->timer) {
+ ast_timer_close(framedata->timer);
+ framedata->timer = NULL;
+ }
+ if (framedata->jb_impl && framedata->jb_obj) {
+ struct ast_frame *f;
+ while (framedata->jb_impl->remove(framedata->jb_obj, &f) == AST_JB_IMPL_OK) {
+ ast_frfree(f);
+ }
+ framedata->jb_impl->destroy(framedata->jb_obj);
+ framedata->jb_obj = NULL;
+ }
+ ast_free(framedata);
+}
+
+void ast_jb_conf_default(struct ast_jb_conf *conf)
+{
+ conf->max_size = DEFAULT_SIZE;
+ conf->resync_threshold = DEFAULT_RESYNC;
+ ast_copy_string(conf->impl, "fixed", sizeof(conf->impl));
+ conf->target_extra = DEFAULT_TARGET_EXTRA;
+}
+
+static void datastore_destroy_cb(void *data) {
+ ast_free(data);
+ ast_debug(1, "JITTERBUFFER datastore destroyed\n");
+}
+
+static const struct ast_datastore_info jb_datastore = {
+ .type = "jitterbuffer",
+ .destroy = datastore_destroy_cb
+};
+
+static void hook_destroy_cb(void *framedata)
+{
+ ast_debug(1, "JITTERBUFFER hook destroyed\n");
+ jb_framedata_destroy((struct jb_framedata *) framedata);
+}
+
+static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
+{
+ struct jb_framedata *framedata = data;
+ struct timeval now_tv;
+ unsigned long now;
+ int putframe = 0; /* signifies if audio frame was placed into the buffer or not */
+
+ switch (event) {
+ case AST_FRAMEHOOK_EVENT_READ:
+ break;
+ case AST_FRAMEHOOK_EVENT_ATTACHED:
+ case AST_FRAMEHOOK_EVENT_DETACHED:
+ case AST_FRAMEHOOK_EVENT_WRITE:
+ return frame;
+ }
+
+ if (ast_channel_fdno(chan) == AST_JITTERBUFFER_FD && framedata->timer) {
+ if (ast_timer_ack(framedata->timer, 1) < 0) {
+ ast_log(LOG_ERROR, "Failed to acknowledge timer in jitter buffer\n");
+ return frame;
+ }
+ }
+
+ if (!frame) {
+ return frame;
+ }
+
+ now_tv = ast_tvnow();
+ now = ast_tvdiff_ms(now_tv, framedata->start_tv);
+
+ if (frame->frametype == AST_FRAME_VOICE) {
+ int res;
+ struct ast_frame *jbframe;
+
+ if (!ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO) || frame->len < 2 || frame->ts < 0) {
+ /* only frames with timing info can enter the jitterbuffer */
+ return frame;
+ }
+
+ jbframe = ast_frisolate(frame);
+ ast_format_copy(&framedata->last_format, &frame->subclass.format);
+
+ if (frame->len && (frame->len != framedata->timer_interval)) {
+ framedata->timer_interval = frame->len;
+ ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
+ }
+ if (!framedata->first) {
+ framedata->first = 1;
+ res = framedata->jb_impl->put_first(framedata->jb_obj, jbframe, now);
+ } else {
+ res = framedata->jb_impl->put(framedata->jb_obj, jbframe, now);
+ }
+ if (res == AST_JB_IMPL_OK) {
+ frame = &ast_null_frame;
+ }
+ putframe = 1;
+ }
+
+ if (frame->frametype == AST_FRAME_NULL) {
+ int res;
+ long next = framedata->jb_impl->next(framedata->jb_obj);
+
+ /* If now is earlier than the next expected output frame
+ * from the jitterbuffer we may choose to pass on retrieving
+ * a frame during this read iteration. The only exception
+ * to this rule is when an audio frame is placed into the buffer
+ * and the time for the next frame to come out of the buffer is
+ * at least within the timer_interval of the next output frame. By
+ * doing this we are able to feed off the timing of the input frames
+ * and only rely on our jitterbuffer timer when frames are dropped.
+ * During testing, this hybrid form of timing gave more reliable results. */
+ if (now < next) {
+ long int diff = next - now;
+ if (!putframe) {
+ return frame;
+ } else if (diff >= framedata->timer_interval) {
+ return frame;
+ }
+ }
+
+ res = framedata->jb_impl->get(framedata->jb_obj, &frame, now, framedata->timer_interval);
+ switch (res) {
+ case AST_JB_IMPL_OK:
+ /* got it, and pass it through */
+ break;
+ case AST_JB_IMPL_DROP:
+ ast_frfree(frame);
+ frame = &ast_null_frame;
+ break;
+ case AST_JB_IMPL_INTERP:
+ if (framedata->last_format.id) {
+ struct ast_frame tmp = { 0, };
+ tmp.frametype = AST_FRAME_VOICE;
+ ast_format_copy(&tmp.subclass.format, &framedata->last_format);
+ /* example: 8000hz / (1000 / 20ms) = 160 samples */
+ tmp.samples = ast_format_rate(&framedata->last_format) / (1000 / framedata->timer_interval);
+ tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000));
+ tmp.offset = AST_FRIENDLY_OFFSET;
+ tmp.src = "func_jitterbuffer interpolation";
+ frame = ast_frdup(&tmp);
+ break;
+ }
+ /* else fall through */
+ case AST_JB_IMPL_NOFRAME:
+ frame = &ast_null_frame;
+ break;
+ }
+ }
+
+ if (frame->frametype == AST_FRAME_CONTROL) {
+ switch(frame->subclass.integer) {
+ case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_SRCCHANGE:
+ framedata->jb_impl->force_resync(framedata->jb_obj);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return frame;
+}
+
+/* set defaults */
+static int jb_framedata_init(struct jb_framedata *framedata, struct ast_jb_conf *jb_conf)
+{
+ int jb_impl_type = DEFAULT_TYPE;
+ /* Initialize defaults */
+ framedata->timer_fd = -1;
+ memcpy(&framedata->jb_conf, jb_conf, sizeof(*jb_conf));
+
+ /* Figure out implementation type from the configuration implementation string */
+ if (!ast_strlen_zero(jb_conf->impl)) {
+ if (!strcasecmp(jb_conf->impl, "fixed")) {
+ jb_impl_type = AST_JB_FIXED;
+ } else if (!strcasecmp(jb_conf->impl, "adaptive")) {
+ jb_impl_type = AST_JB_ADAPTIVE;
+ } else {
+ ast_log(LOG_WARNING, "Unknown Jitterbuffer type %s. Failed to create jitterbuffer.\n", jb_conf->impl);
+ return -1;
+ }
+ }
+
+ if (!(framedata->jb_impl = ast_jb_get_impl(jb_impl_type))) {
+ return -1;
+ }
+
+ if (!(framedata->timer = ast_timer_open())) {
+ return -1;
+ }
+
+ framedata->timer_fd = ast_timer_fd(framedata->timer);
+ framedata->timer_interval = DEFAULT_TIMER_INTERVAL;
+ ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
+ framedata->start_tv = ast_tvnow();
+
+ framedata->jb_obj = framedata->jb_impl->create(&framedata->jb_conf);
+ return 0;
+}
+
+
+void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_conf, int prefer_existing)
+{
+ struct jb_framedata *framedata;
+ struct ast_datastore *datastore = NULL;
+ struct ast_framehook_interface interface = {
+ .version = AST_FRAMEHOOK_INTERFACE_VERSION,
+ .event_cb = hook_event_cb,
+ .destroy_cb = hook_destroy_cb,
+ };
+ int i = 0;
+
+ /* If disabled, strip any existing jitterbuffer and don't replace it. */
+ if (!strcasecmp(jb_conf->impl, "disabled")) {
+ int *id;
+ ast_channel_lock(chan);
+ if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
+ id = datastore->data;
+ ast_framehook_detach(chan, *id);
+ ast_channel_datastore_remove(chan, datastore);
+ }
+ ast_channel_unlock(chan);
+ return;
+ }
+
+ if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
+ return;
+ }
+
+ if (jb_framedata_init(framedata, jb_conf)) {
+ jb_framedata_destroy(framedata);
+ return;
+ }
+
+ interface.data = framedata;
+
+ ast_channel_lock(chan);
+ i = ast_framehook_attach(chan, &interface);
+ if (i >= 0) {
+ int *id;
+ if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
+ /* There is already a jitterbuffer on the channel. */
+ if (prefer_existing) {
+ /* We prefer the existing jitterbuffer, so remove the new one and keep the old one. */
+ ast_framehook_detach(chan, i);
+ ast_channel_unlock(chan);
+ return;
+ }
+ /* We prefer the new jitterbuffer, so strip the old one. */
+ id = datastore->data;
+ ast_framehook_detach(chan, *id);
+ ast_channel_datastore_remove(chan, datastore);
+ }
+
+ if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) {
+ ast_framehook_detach(chan, i);
+ ast_channel_unlock(chan);
+ return;
+ }
+
+ if (!(id = ast_calloc(1, sizeof(int)))) {
+ ast_datastore_free(datastore);
+ ast_framehook_detach(chan, i);
+ ast_channel_unlock(chan);
+ return;
+ }
+
+ *id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
+ datastore->data = id;
+ ast_channel_datastore_add(chan, datastore);
+
+ ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd);
+ } else {
+ jb_framedata_destroy(framedata);
+ framedata = NULL;
+ }
+ ast_channel_unlock(chan);
+
+ return;
+}
Modified: team/group/bridge_construction/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/bridging.c?view=diff&rev=386561&r1=386560&r2=386561
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Thu Apr 25 14:29:16 2013
@@ -2290,6 +2290,9 @@
bridge_channel->bridge->uniqueid,
bridge_channel, ast_channel_name(bridge_channel->chan));
+ /* Add the jitterbuffer if the channel requires it */
+ ast_jb_enable_for_channel(bridge_channel->chan);
+
/*
* Directly locking the bridge is safe here because nobody else
* knows about this bridge_channel yet.
More information about the asterisk-commits
mailing list