[asterisk-commits] rmudgett: branch group/bridge_construction r385010 - in /team/group/bridge_co...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Apr 8 15:04:44 CDT 2013
Author: rmudgett
Date: Mon Apr 8 15:04:41 2013
New Revision: 385010
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=385010
Log:
Add support for playing a file and running an application on a bridge channel.
* Added AST_BRIDGE_ACTION_PLAY_FILE and AST_BRIDGE_ACTION_RUN_APP.
* Refactored bridge write frame code to make it easier to put action and
control frames into the bridge.
* Refactored code to make it easier to put action frames onto the bridge
channel write queue.
Modified:
team/group/bridge_construction/bridges/bridge_builtin_interval_features.c
team/group/bridge_construction/bridges/bridge_softmix.c
team/group/bridge_construction/configs/features.conf.sample
team/group/bridge_construction/include/asterisk/bridging.h
team/group/bridge_construction/main/bridging.c
Modified: team/group/bridge_construction/bridges/bridge_builtin_interval_features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_builtin_interval_features.c?view=diff&rev=385010&r1=385009&r2=385010
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_interval_features.c (original)
+++ team/group/bridge_construction/bridges/bridge_builtin_interval_features.c Mon Apr 8 15:04:41 2013
@@ -98,7 +98,13 @@
ast_stream_and_wait(bridge_channel->chan, file, AST_DIGIT_NONE);
}
- /* It may be necessary to resume music on hold after we finish playing the announcment. */
+ /*
+ * It may be necessary to resume music on hold after we finish
+ * playing the announcment.
+ *
+ * XXX We have no idea what MOH class was in use before playing
+ * the file.
+ */
if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) {
ast_moh_start(bridge_channel->chan, NULL, NULL);
}
Modified: team/group/bridge_construction/bridges/bridge_softmix.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_softmix.c?view=diff&rev=385010&r1=385009&r2=385010
==============================================================================
--- team/group/bridge_construction/bridges/bridge_softmix.c (original)
+++ team/group/bridge_construction/bridges/bridge_softmix.c Mon Apr 8 15:04:41 2013
@@ -382,12 +382,7 @@
*/
static void softmix_src_change(struct ast_bridge_channel *bridge_channel)
{
- struct ast_frame frame = {
- .frametype = AST_FRAME_CONTROL,
- .subclass.integer = AST_CONTROL_SRCCHANGE
- };
-
- ast_bridge_channel_queue_frame(bridge_channel, &frame);
+ ast_bridge_channel_queue_control_data(bridge_channel, AST_CONTROL_SRCCHANGE, NULL, 0);
}
/*! \brief Function called when a channel is joined into the bridge */
Modified: team/group/bridge_construction/configs/features.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/configs/features.conf.sample?view=diff&rev=385010&r1=385009&r2=385010
==============================================================================
--- team/group/bridge_construction/configs/features.conf.sample (original)
+++ team/group/bridge_construction/configs/features.conf.sample Mon Apr 8 15:04:41 2013
@@ -157,7 +157,7 @@
;
; Set(__DYNAMIC_FEATURES=myfeature1#myfeature2#myfeature3)
;
-; (Note: The two leading underscores allow these feature settings to be set on
+; (Note: The two leading underscores allow these feature settings to be set
; on the outbound channels, as well. Otherwise, only the original channel
; will have access to these features.)
;
Modified: team/group/bridge_construction/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging.h?view=diff&rev=385010&r1=385009&r2=385010
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Mon Apr 8 15:04:41 2013
@@ -188,6 +188,10 @@
AST_BRIDGE_ACTION_TALKING_START,
/*! Bridged channel is to indicate talking stop */
AST_BRIDGE_ACTION_TALKING_STOP,
+ /*! Bridge channel is to play the indicated sound file. */
+ AST_BRIDGE_ACTION_PLAY_FILE,
+ /*! Bridge channel is to run the indicated application. */
+ AST_BRIDGE_ACTION_RUN_APP,
/*
* Bridge actions put after this comment must never be put onto
@@ -850,6 +854,173 @@
int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr);
/*!
+ * \brief Used to queue an action frame onto a bridge channel and write an action frame into a bridge.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel work with.
+ * \param action Type of bridge action frame.
+ * \param data Frame payload data to pass.
+ * \param datalen Frame payload data length to pass.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_bridge_channel_post_action_data)(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen);
+
+/*!
+ * \brief Queue an action frame onto the bridge channel with data.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to queue the frame onto.
+ * \param action Type of bridge action frame.
+ * \param data Frame payload data to pass.
+ * \param datalen Frame payload data length to pass.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen);
+
+/*!
+ * \brief Write an action frame into the bridge with data.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel is putting the frame into the bridge.
+ * \param action Type of bridge action frame.
+ * \param data Frame payload data to pass.
+ * \param datalen Frame payload data length to pass.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen);
+
+/*!
+ * \brief Queue a control frame onto the bridge channel with data.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to queue the frame onto.
+ * \param control Type of control frame.
+ * \param data Frame payload data to pass.
+ * \param datalen Frame payload data length to pass.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_queue_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen);
+
+/*!
+ * \brief Write a control frame into the bridge with data.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel is putting the frame into the bridge.
+ * \param control Type of control frame.
+ * \param data Frame payload data to pass.
+ * \param datalen Frame payload data length to pass.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_write_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen);
+
+/*!
+ * \brief Run an application on the bridge channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to run the application on.
+ * \param app_name Dialplan application name.
+ * \param app_args Arguments for the application. (NULL tolerant)
+ * \param moh_class MOH class to request bridge peers to hear while application is running.
+ * NULL if no MOH.
+ * Empty if default MOH class.
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class);
+
+/*!
+ * \brief Write a bridge action run application frame into the bridge.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel is putting the frame into the bridge
+ * \param app_name Dialplan application name.
+ * \param app_args Arguments for the application. (NULL or empty for no arguments)
+ * \param moh_class MOH class to request bridge peers to hear while application is running.
+ * NULL if no MOH.
+ * Empty if default MOH class.
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_write_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class);
+
+/*!
+ * \brief Queue a bridge action run application frame onto the bridge channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to put the frame onto
+ * \param app_name Dialplan application name.
+ * \param app_args Arguments for the application. (NULL or empty for no arguments)
+ * \param moh_class MOH class to request bridge peers to hear while application is running.
+ * NULL if no MOH.
+ * Empty if default MOH class.
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_queue_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class);
+
+/*!
+ * \brief Play a file on the bridge channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to play the file on
+ * \param custom_play Call this function to play the playfile. (NULL if normal sound file to play)
+ * \param playfile Sound filename to play.
+ * \param moh_class MOH class to request bridge peers to hear while file is played.
+ * NULL if no MOH.
+ * Empty if default MOH class.
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, void (*custom_play)(const char *playfile), const char *playfile, const char *moh_class);
+
+/*!
+ * \brief Write a bridge action play file frame into the bridge.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel is putting the frame into the bridge
+ * \param custom_play Call this function to play the playfile. (NULL if normal sound file to play)
+ * \param playfile Sound filename to play.
+ * \param moh_class MOH class to request bridge peers to hear while file is played.
+ * NULL if no MOH.
+ * Empty if default MOH class.
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_write_playfile(struct ast_bridge_channel *bridge_channel, void (*custom_play)(const char *playfile), const char *playfile, const char *moh_class);
+
+/*!
+ * \brief Queue a bridge action play file frame onto the bridge channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to put the frame onto.
+ * \param custom_play Call this function to play the playfile. (NULL if normal sound file to play)
+ * \param playfile Sound filename to play.
+ * \param moh_class MOH class to request bridge peers to hear while file is played.
+ * NULL if no MOH.
+ * Empty if default MOH class.
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, void (*custom_play)(const char *playfile), const char *playfile, const char *moh_class);
+
+/*!
* \brief Restore the formats of a bridge channel's channel to how they were before bridge_channel_join
* \since 12.0.0
*
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=385010&r1=385009&r2=385010
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Mon Apr 8 15:04:41 2013
@@ -327,6 +327,30 @@
return 0;
}
+void ast_bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen)
+{
+ struct ast_frame frame = {
+ .frametype = AST_FRAME_BRIDGE_ACTION,
+ .subclass.integer = action,
+ .datalen = datalen,
+ .data.ptr = (void *) data,
+ };
+
+ ast_bridge_channel_queue_frame(bridge_channel, &frame);
+}
+
+void ast_bridge_channel_queue_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
+{
+ struct ast_frame frame = {
+ .frametype = AST_FRAME_CONTROL,
+ .subclass.integer = control,
+ .datalen = datalen,
+ .data.ptr = (void *) data,
+ };
+
+ ast_bridge_channel_queue_frame(bridge_channel, &frame);
+}
+
void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel)
{
/* Restore original formats of the channel as they came in */
@@ -638,6 +662,225 @@
};
ast_bridge_channel_queue_frame(bridge_channel, &action);
+}
+
+static void bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
+{
+ bridge_channel_lock_bridge(bridge_channel);
+ bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame);
+ ast_bridge_unlock(bridge_channel->bridge);
+}
+
+void ast_bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen)
+{
+ struct ast_frame frame = {
+ .frametype = AST_FRAME_BRIDGE_ACTION,
+ .subclass.integer = action,
+ .datalen = datalen,
+ .data.ptr = (void *) data,
+ };
+
+ bridge_channel_write_frame(bridge_channel, &frame);
+}
+
+void ast_bridge_channel_write_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
+{
+ struct ast_frame frame = {
+ .frametype = AST_FRAME_CONTROL,
+ .subclass.integer = control,
+ .datalen = datalen,
+ .data.ptr = (void *) data,
+ };
+
+ bridge_channel_write_frame(bridge_channel, &frame);
+}
+
+static void run_app_helper(struct ast_channel *chan, const char *app_name, const char *app_args)
+{
+ if (!strcasecmp("Gosub", app_name)) {
+ ast_app_exec_sub(NULL, chan, app_args, 0);
+ } else if (!strcasecmp("Macro", app_name)) {
+ ast_app_exec_macro(NULL, chan, app_args);
+ } else {
+ struct ast_app *app;
+
+ app = pbx_findapp(app_name);
+ if (!app) {
+ ast_log(LOG_WARNING, "Could not find application (%s)\n", app_name);
+ } else {
+ pbx_exec(chan, app, app_args);
+ }
+ }
+}
+
+void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
+{
+ if (moh_class) {
+ if (ast_strlen_zero(moh_class)) {
+ ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD,
+ NULL, 0);
+ } else {
+ ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD,
+ moh_class, strlen(moh_class) + 1);
+ }
+ }
+ run_app_helper(bridge_channel->chan, app_name, S_OR(app_args, ""));
+ if (moh_class) {
+ ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_UNHOLD,
+ NULL, 0);
+ }
+}
+
+struct bridge_run_app {
+ /*! Offset into app_name[] where the MOH class name starts. (zero if no MOH)*/
+ int moh_offset;
+ /*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */
+ int app_args_offset;
+ /*! Application name to run. */
+ char app_name[0];
+};
+
+/*!
+ * \internal
+ * \brief Handle the run application bridge action.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to run the application on.
+ * \param data Action frame data to run the application.
+ *
+ * \return Nothing
+ */
+static void bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, struct bridge_run_app *data)
+{
+ ast_bridge_channel_run_app(bridge_channel, data->app_name,
+ data->app_args_offset ? &data->app_name[data->app_args_offset] : NULL,
+ data->moh_offset ? &data->app_name[data->moh_offset] : NULL);
+}
+
+static void payload_helper_app(ast_bridge_channel_post_action_data post_it,
+ struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
+{
+ struct bridge_run_app *app_data;
+ size_t len_name = strlen(app_name) + 1;
+ size_t len_args = ast_strlen_zero(app_args) ? 0 : strlen(app_args) + 1;
+ size_t len_moh = !moh_class ? 0 : strlen(moh_class) + 1;
+ size_t len_data = sizeof(*app_data) + len_name + len_args + len_moh;
+
+ /* Fill in application run frame data. */
+ app_data = alloca(len_data);
+ app_data->app_args_offset = len_args ? len_name : 0;
+ app_data->moh_offset = len_moh ? len_name + len_args : 0;
+ strcpy(app_data->app_name, app_name);/* Safe */
+ if (len_args) {
+ strcpy(&app_data->app_name[app_data->app_args_offset], app_args);/* Safe */
+ }
+ if (moh_class) {
+ strcpy(&app_data->app_name[app_data->moh_offset], moh_class);/* Safe */
+ }
+
+ post_it(bridge_channel, AST_BRIDGE_ACTION_RUN_APP, app_data, len_data);
+}
+
+void ast_bridge_channel_write_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
+{
+ payload_helper_app(ast_bridge_channel_write_action_data,
+ bridge_channel, app_name, app_args, moh_class);
+}
+
+void ast_bridge_channel_queue_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
+{
+ payload_helper_app(ast_bridge_channel_queue_action_data,
+ bridge_channel, app_name, app_args, moh_class);
+}
+
+void ast_bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, void (*custom_play)(const char *playfile), const char *playfile, const char *moh_class)
+{
+ if (moh_class) {
+ if (ast_strlen_zero(moh_class)) {
+ ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD,
+ NULL, 0);
+ } else {
+ ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD,
+ moh_class, strlen(moh_class) + 1);
+ }
+ }
+ if (custom_play) {
+ custom_play(playfile);
+ } else {
+ ast_stream_and_wait(bridge_channel->chan, playfile, AST_DIGIT_NONE);
+ }
+ if (moh_class) {
+ ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_UNHOLD,
+ NULL, 0);
+ }
+
+ /*
+ * It may be necessary to resume music on hold after we finish
+ * playing the announcment.
+ *
+ * XXX We have no idea what MOH class was in use before playing
+ * the file.
+ */
+ if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) {
+ ast_moh_start(bridge_channel->chan, NULL, NULL);
+ }
+}
+
+struct bridge_playfile {
+ /*! Call this function to play the playfile. (NULL if normal sound file to play) */
+ void (*custom_play)(const char *playfile);
+ /*! Offset into playfile[] where the MOH class name starts. (zero if no MOH)*/
+ int moh_offset;
+ /*! Filename to play. */
+ char playfile[0];
+};
+
+/*!
+ * \internal
+ * \brief Handle the playfile bridge action.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to play a file on.
+ * \param payload Action frame payload to play a file.
+ *
+ * \return Nothing
+ */
+static void bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, struct bridge_playfile *payload)
+{
+ ast_bridge_channel_playfile(bridge_channel, payload->custom_play, payload->playfile,
+ payload->moh_offset ? &payload->playfile[payload->moh_offset] : NULL);
+}
+
+static void payload_helper_playfile(ast_bridge_channel_post_action_data post_it,
+ struct ast_bridge_channel *bridge_channel, void (*custom_play)(const char *playfile), const char *playfile, const char *moh_class)
+{
+ struct bridge_playfile *payload;
+ size_t len_name = strlen(playfile) + 1;
+ size_t len_moh = !moh_class ? 0 : strlen(moh_class) + 1;
+ size_t len_payload = sizeof(*payload) + len_name + len_moh;
+
+ /* Fill in play file frame data. */
+ payload = alloca(len_payload);
+ payload->custom_play = custom_play;
+ payload->moh_offset = len_moh ? len_name : 0;
+ strcpy(payload->playfile, playfile);/* Safe */
+ if (moh_class) {
+ strcpy(&payload->playfile[payload->moh_offset], moh_class);/* Safe */
+ }
+
+ post_it(bridge_channel, AST_BRIDGE_ACTION_PLAY_FILE, payload, len_payload);
+}
+
+void ast_bridge_channel_write_playfile(struct ast_bridge_channel *bridge_channel, void (*custom_play)(const char *playfile), const char *playfile, const char *moh_class)
+{
+ payload_helper_playfile(ast_bridge_channel_write_action_data,
+ bridge_channel, custom_play, playfile, moh_class);
+}
+
+void ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, void (*custom_play)(const char *playfile), const char *playfile, const char *moh_class)
+{
+ payload_helper_playfile(ast_bridge_channel_queue_action_data,
+ bridge_channel, custom_play, playfile, moh_class);
}
/*!
@@ -696,11 +939,9 @@
/* BUGBUG bridge join or impart needs to do CONNECTED_LINE updates if the channels are being swapped and it is a 1-1 bridge. */
/* Simply write the frame out to the bridge technology. */
- bridge_channel_lock_bridge(bridge_channel);
/* BUGBUG The tech is where AST_CONTROL_ANSWER hook should go. (early bridge) */
/* BUGBUG The tech is where incoming BUSY/CONGESTION hangup should happen? (early bridge) */
- bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame);
- ast_bridge_unlock(bridge_channel->bridge);
+ bridge_channel_write_frame(bridge_channel, frame);
ast_frfree(frame);
}
@@ -1550,16 +1791,8 @@
static void bridge_channel_write_dtmf_stream(struct ast_bridge_channel *bridge_channel, const char *dtmf)
{
- struct ast_frame action = {
- .frametype = AST_FRAME_BRIDGE_ACTION,
- .subclass.integer = AST_BRIDGE_ACTION_DTMF_STREAM,
- .datalen = strlen(dtmf) + 1,
- .data.ptr = (char *) dtmf,
- };
-
- bridge_channel_lock_bridge(bridge_channel);
- bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, &action);
- ast_bridge_unlock(bridge_channel->bridge);
+ ast_bridge_channel_write_action_data(bridge_channel,
+ AST_BRIDGE_ACTION_DTMF_STREAM, dtmf, strlen(dtmf) + 1);
}
/*!
@@ -1707,6 +1940,20 @@
case AST_BRIDGE_ACTION_TALKING_STOP:
bridge_channel_talking(bridge_channel,
action->subclass.integer == AST_BRIDGE_ACTION_TALKING_START);
+ break;
+ case AST_BRIDGE_ACTION_PLAY_FILE:
+ bridge_channel_suspend(bridge_channel);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_playfile(bridge_channel, action->data.ptr);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_unsuspend(bridge_channel);
+ break;
+ case AST_BRIDGE_ACTION_RUN_APP:
+ bridge_channel_suspend(bridge_channel);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_run_app(bridge_channel, action->data.ptr);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_unsuspend(bridge_channel);
break;
default:
break;
More information about the asterisk-commits
mailing list