[asterisk-commits] rmudgett: branch group/bridge_construction r380679 - in /team/group/bridge_co...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Jan 31 13:18:47 CST 2013
Author: rmudgett
Date: Thu Jan 31 13:18:41 2013
New Revision: 380679
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=380679
Log:
Add an action queue to bridge_channels.
Modified:
team/group/bridge_construction/apps/app_confbridge.c
team/group/bridge_construction/bridges/bridge_multiplexed.c
team/group/bridge_construction/bridges/bridge_simple.c
team/group/bridge_construction/bridges/bridge_softmix.c
team/group/bridge_construction/funcs/func_frame_trace.c
team/group/bridge_construction/include/asterisk/bridging.h
team/group/bridge_construction/include/asterisk/bridging_features.h
team/group/bridge_construction/include/asterisk/bridging_technology.h
team/group/bridge_construction/include/asterisk/frame.h
team/group/bridge_construction/main/bridging.c
team/group/bridge_construction/main/channel.c
team/group/bridge_construction/main/frame.c
Modified: team/group/bridge_construction/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/app_confbridge.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/apps/app_confbridge.c (original)
+++ team/group/bridge_construction/apps/app_confbridge.c Thu Jan 31 13:18:41 2013
@@ -1373,21 +1373,9 @@
ast_free(pvt_data);
}
-static void conf_handle_talker_cb(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *pvt_data)
-{
- char *conf_name = pvt_data;
- int talking;
-
- switch (bridge_channel->state) {
- case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
- talking = 1;
- break;
- case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
- talking = 0;
- break;
- default:
- return; /* uhh this shouldn't happen, but bail if it does. */
- }
+static void conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking)
+{
+ const char *conf_name = pvt_data;
/* notify AMI someone is has either started or stopped talking */
/*** DOCUMENTATION
@@ -1405,11 +1393,14 @@
</managerEventInstance>
***/
ast_manager_event(bridge_channel->chan, EVENT_FLAG_CALL, "ConfbridgeTalking",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n"
- "Conference: %s\r\n"
- "TalkingStatus: %s\r\n",
- ast_channel_name(bridge_channel->chan), ast_channel_uniqueid(bridge_channel->chan), conf_name, talking ? "on" : "off");
+ "Channel: %s\r\n"
+ "Uniqueid: %s\r\n"
+ "Conference: %s\r\n"
+ "TalkingStatus: %s\r\n",
+ ast_channel_name(bridge_channel->chan),
+ ast_channel_uniqueid(bridge_channel->chan),
+ conf_name,
+ talking ? "on" : "off");
}
static int conf_get_pin(struct ast_channel *chan, struct conference_bridge_user *conference_bridge_user)
Modified: team/group/bridge_construction/bridges/bridge_multiplexed.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_multiplexed.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/bridges/bridge_multiplexed.c (original)
+++ team/group/bridge_construction/bridges/bridge_multiplexed.c Thu Jan 31 13:18:41 2013
@@ -465,9 +465,11 @@
return AST_BRIDGE_WRITE_FAILED;
}
- /* Write the frame out if they are in the waiting state... don't worry about freeing it, the bridging core will take care of it */
+ /* The bridging core takes care of freeing the passed in frame. */
if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
- ast_write(other->chan, frame);
+ if (!other->suspended) {
+ ast_write(other->chan, frame);
+ }
}
return AST_BRIDGE_WRITE_SUCCESS;
Modified: team/group/bridge_construction/bridges/bridge_simple.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_simple.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/bridges/bridge_simple.c (original)
+++ team/group/bridge_construction/bridges/bridge_simple.c Thu Jan 31 13:18:41 2013
@@ -80,9 +80,11 @@
return AST_BRIDGE_WRITE_FAILED;
}
- /* Write the frame out if they are in the waiting state... don't worry about freeing it, the bridging core will take care of it */
+ /* The bridging core takes care of freeing the passed in frame. */
if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
- ast_write(other->chan, frame);
+ if (!other->suspended) {
+ ast_write(other->chan, frame);
+ }
}
return AST_BRIDGE_WRITE_SUCCESS;
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=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/bridges/bridge_softmix.c (original)
+++ team/group/bridge_construction/bridges/bridge_softmix.c Thu Jan 31 13:18:41 2013
@@ -578,7 +578,7 @@
ast_mutex_unlock(&sc->lock);
if (update_talking != -1) {
- ast_bridge_notify_talking(bridge, bridge_channel, update_talking);
+ ast_bridge_notify_talking(bridge_channel, update_talking);
}
return res;
Modified: team/group/bridge_construction/funcs/func_frame_trace.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/funcs/func_frame_trace.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/funcs/func_frame_trace.c (original)
+++ team/group/bridge_construction/funcs/func_frame_trace.c Thu Jan 31 13:18:41 2013
@@ -376,6 +376,10 @@
ast_verbose("Digit: 0x%02X '%c'\n", frame->subclass.integer,
frame->subclass.integer < ' ' ? ' ' : frame->subclass.integer);
break;
+ case AST_FRAME_BRIDGE_ACTION:
+ ast_verbose("FrameType: Bridge\n");
+ ast_verbose("SubClass: %d\n", frame->subclass.integer);
+ break;
}
ast_verbose("Src: %s\n", ast_strlen_zero(frame->src) ? "NOT PRESENT" : frame->src);
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=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Thu Jan 31 13:18:41 2013
@@ -93,14 +93,6 @@
AST_BRIDGE_CHANNEL_STATE_HANGUP,
/*! Bridged channel was ast_bridge_depart() from the bridge without being hung up */
AST_BRIDGE_CHANNEL_STATE_DEPART,
- /*! Bridged channel is executing a feature hook */
- AST_BRIDGE_CHANNEL_STATE_FEATURE,
- /*! Bridged channel is sending a DTMF stream out */
- AST_BRIDGE_CHANNEL_STATE_DTMF,
- /*! Bridged channel began talking */
- AST_BRIDGE_CHANNEL_STATE_START_TALKING,
- /*! Bridged channel has stopped talking */
- AST_BRIDGE_CHANNEL_STATE_STOP_TALKING,
};
/*! \brief Return values for bridge technology write function */
@@ -161,12 +153,23 @@
/*! Technology optimization parameters used by bridging technologies capable of
* optimizing based upon talk detection. */
struct ast_bridge_tech_optimizations tech_args;
- /*! Queue of DTMF digits used for DTMF streaming */
- char dtmf_stream_q[8];
/*! Call ID associated with bridge channel */
struct ast_callid *callid;
/*! Linked list information */
AST_LIST_ENTRY(ast_bridge_channel) entry;
+ /*! Queue of actions to perform on the channel. */
+ AST_LIST_HEAD_NOLOCK(, ast_frame) action_queue;
+};
+
+enum ast_bridge_action_type {
+ /*! Bridged channel is to detect a feature hook */
+ AST_BRIDGE_ACTION_FEATURE,
+ /*! Bridged channel is to send a DTMF stream out */
+ AST_BRIDGE_ACTION_DTMF_STREAM,
+ /*! Bridged channel is to indicate talking start */
+ AST_BRIDGE_ACTION_TALKING_START,
+ /*! Bridged channel is to indicate talking stop */
+ AST_BRIDGE_ACTION_TALKING_STOP,
};
enum ast_bridge_video_mode_type {
@@ -557,6 +560,21 @@
void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state);
/*!
+ * \brief Put an action onto the specified bridge_channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to queue the action on.
+ * \param action What to do.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ *
+ * \note This API call is meant for internal bridging operations.
+ * \note BUGBUG This may get moved.
+ */
+int ast_bridge_channel_queue_action(struct ast_bridge_channel *bridge_channel, struct ast_frame *action);
+
+/*!
* \brief Adjust the internal mixing sample rate of a bridge
* used during multimix mode.
*
Modified: team/group/bridge_construction/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging_features.h?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_features.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_features.h Thu Jan 31 13:18:41 2013
@@ -107,13 +107,13 @@
* to receive updates on when a bridge_channel has started and stopped
* talking
*
- * \param bridge The bridge that the channel is part of
* \param bridge_channel Channel executing the feature
+ * \param talking TRUE if the channel is now talking
*
* \retval 0 success
* \retval -1 failure
*/
-typedef void (*ast_bridge_talking_indicate_callback)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *pvt_data);
+typedef void (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking);
typedef void (*ast_bridge_talking_indicate_destructor)(void *pvt_data);
Modified: team/group/bridge_construction/include/asterisk/bridging_technology.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging_technology.h?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_technology.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_technology.h Thu Jan 31 13:18:41 2013
@@ -155,12 +155,11 @@
* application, this function has been created to allow the bridging technology to communicate
* that information with the bridging core.
*
- * \param bridge The bridge that the channel is a part of.
* \param bridge_channel The bridge channel that has either started or stopped talking.
* \param started_talking set to 1 when this indicates the channel has started talking set to 0
* when this indicates the channel has stopped talking.
*/
-void ast_bridge_notify_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int started_talking);
+void ast_bridge_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking);
/*!
* \brief Suspend a bridge technology from consideration
Modified: team/group/bridge_construction/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/frame.h?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/include/asterisk/frame.h (original)
+++ team/group/bridge_construction/include/asterisk/frame.h Thu Jan 31 13:18:41 2013
@@ -120,6 +120,8 @@
AST_FRAME_MODEM,
/*! DTMF begin event, subclass is the digit */
AST_FRAME_DTMF_BEGIN,
+ /*! Internal bridge module action. */
+ AST_FRAME_BRIDGE_ACTION,
};
#define AST_FRAME_DTMF AST_FRAME_DTMF_END
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=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Thu Jan 31 13:18:41 2013
@@ -129,6 +129,9 @@
/*! \note This function assumes the bridge_channel is locked. */
static void ast_bridge_change_state_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
{
+ ast_debug(1, "BUGBUG Setting bridge channel %p state from:%d to:%d\n",
+ bridge_channel, bridge_channel->state, new_state);
+
/* Change the state on the bridge channel */
bridge_channel->state = new_state;
@@ -144,6 +147,30 @@
ao2_lock(bridge_channel);
ast_bridge_change_state_nolock(bridge_channel, new_state);
ao2_unlock(bridge_channel);
+}
+
+int ast_bridge_channel_queue_action(struct ast_bridge_channel *bridge_channel, struct ast_frame *action)
+{
+ struct ast_frame *dup;
+
+ dup = ast_frdup(action);
+ if (!dup) {
+ return -1;
+ }
+
+ ast_debug(1, "BUGBUG Queueing action type:%d sub:%d on bridge channel %p\n",
+ action->frametype, action->subclass.integer, bridge_channel);
+
+ ao2_lock(bridge_channel);
+ AST_LIST_INSERT_TAIL(&bridge_channel->action_queue, dup, frame_list);
+
+ /* Only poke the channel's thread if it is not us */
+ if (!pthread_equal(pthread_self(), bridge_channel->thread)) {
+ pthread_kill(bridge_channel->thread, SIGURG);
+ ast_cond_signal(&bridge_channel->cond);
+ }
+ ao2_unlock(bridge_channel);
+ return 0;
}
/*!
@@ -219,7 +246,8 @@
bridge_poke(bridge);
}
-/*! \brief Helper function to remove a channel from the bridge array
+/*!
+ * \brief Helper function to remove a channel from the bridge array
*
* \note This function assumes the bridge is locked.
*/
@@ -305,10 +333,15 @@
/*! \brief Internal function to handle DTMF from a channel */
static struct ast_frame *bridge_handle_dtmf(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
{
- struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
+ struct ast_bridge_features *features;
struct ast_bridge_features_hook *hook;
- /* If the features structure we grabbed is not usable immediately return the frame */
+ features = bridge_channel->features;
+ if (!features) {
+ features = &bridge->features;
+ }
+
+ /* If the features structure we grabbed is not usable, immediately return the frame */
if (!features->usable) {
return frame;
}
@@ -316,9 +349,14 @@
/* See if this DTMF matches the beginnings of any feature hooks, if so we switch to the feature state to either execute the feature or collect more DTMF */
AST_LIST_TRAVERSE(&features->hooks, hook, entry) {
if (hook->dtmf[0] == frame->subclass.integer) {
+ struct ast_frame action = {
+ .frametype = AST_FRAME_BRIDGE_ACTION,
+ .subclass.integer = AST_BRIDGE_ACTION_FEATURE,
+ };
+
ast_frfree(frame);
frame = NULL;
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_FEATURE);
+ ast_bridge_channel_queue_action(bridge_channel, &action);
break;
}
}
@@ -346,13 +384,15 @@
}
}
-void ast_bridge_notify_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int started_talking)
-{
- if (started_talking) {
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_START_TALKING);
- } else {
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_STOP_TALKING);
- }
+void ast_bridge_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking)
+{
+ struct ast_frame action = {
+ .frametype = AST_FRAME_BRIDGE_ACTION,
+ .subclass.integer = started_talking
+ ? AST_BRIDGE_ACTION_TALKING_START : AST_BRIDGE_ACTION_TALKING_STOP,
+ };
+
+ ast_bridge_channel_queue_action(bridge_channel, &action);
}
void ast_bridge_handle_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_channel *chan, int outfd)
@@ -375,7 +415,11 @@
/* This is pretty simple... see if they hung up */
if (!frame || (frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_HANGUP)) {
/* Signal the thread that is handling the bridged channel that it should be ended */
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+ ao2_lock(bridge_channel);
+ if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+ ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+ }
+ ao2_unlock(bridge_channel);
} else if (frame->frametype == AST_FRAME_CONTROL && bridge_drop_control_frame(frame->subclass.integer)) {
ast_debug(1, "Dropping control frame %d from bridge channel %p\n",
frame->subclass.integer, bridge_channel);
@@ -866,14 +910,18 @@
}
/*! \brief Run in a multithreaded model. Each joined channel does writing/reading in their own thread. TODO: Improve */
-static enum ast_bridge_channel_state bridge_channel_join_multithreaded(struct ast_bridge_channel *bridge_channel)
-{
- int fds[4] = { -1, }, nfds = 0, i = 0, outfd = -1, ms = -1;
+static void bridge_channel_join_multithreaded(struct ast_bridge_channel *bridge_channel)
+{
+ int fds[4] = { -1, };
+ int nfds = 0;
+ int outfd = -1;
+ int ms = -1;
+ int i;
struct ast_channel *chan;
/* Add any file descriptors we may want to monitor */
if (bridge_channel->bridge->technology->fd) {
- for (i = 0; i < 4; i ++) {
+ for (i = 0; i < 4; ++i) {
if (bridge_channel->fds[i] >= 0) {
fds[nfds++] = bridge_channel->fds[i];
}
@@ -882,30 +930,31 @@
ao2_unlock(bridge_channel->bridge);
+ /* Wait for data to either come from the channel or us to be signaled */
ao2_lock(bridge_channel);
- /* Wait for data to either come from the channel or us to be signalled */
- if (!bridge_channel->suspended) {
+ if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
ao2_unlock(bridge_channel);
- ast_debug(10, "Going into a multithreaded waitfor for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
- chan = ast_waitfor_nandfds(&bridge_channel->chan, 1, fds, nfds, NULL, &outfd, &ms);
- } else {
- ast_debug(10, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
+ ao2_lock(bridge_channel->bridge);
+ } else if (bridge_channel->suspended) {
+ ast_debug(10, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n",
+ bridge_channel, bridge_channel->bridge);
ast_cond_wait(&bridge_channel->cond, ao2_object_get_lockaddr(bridge_channel));
ao2_unlock(bridge_channel);
- chan = NULL;
- }
-
- ao2_lock(bridge_channel->bridge);
-
- if (!bridge_channel->suspended) {
- ast_bridge_handle_trip(bridge_channel->bridge, bridge_channel, chan, outfd);
- }
-
- return bridge_channel->state;
+ ao2_lock(bridge_channel->bridge);
+ } else {
+ ao2_unlock(bridge_channel);
+ ast_debug(10, "Going into a multithreaded waitfor for bridge channel %p of bridge %p\n",
+ bridge_channel, bridge_channel->bridge);
+ chan = ast_waitfor_nandfds(&bridge_channel->chan, 1, fds, nfds, NULL, &outfd, &ms);
+ ao2_lock(bridge_channel->bridge);
+ if (!bridge_channel->suspended) {
+ ast_bridge_handle_trip(bridge_channel->bridge, bridge_channel, chan, outfd);
+ }
+ }
}
/*! \brief Run in a singlethreaded model. Each joined channel yields itself to the main bridge thread. TODO: Improve */
-static enum ast_bridge_channel_state bridge_channel_join_singlethreaded(struct ast_bridge_channel *bridge_channel)
+static void bridge_channel_join_singlethreaded(struct ast_bridge_channel *bridge_channel)
{
ao2_unlock(bridge_channel->bridge);
ao2_lock(bridge_channel);
@@ -915,8 +964,6 @@
}
ao2_unlock(bridge_channel);
ao2_lock(bridge_channel->bridge);
-
- return bridge_channel->state;
}
/*! \brief Internal function that suspends a channel from a bridge */
@@ -1017,7 +1064,7 @@
*/
if (bridge_channel->chan && ast_check_hangup_locked(bridge_channel->chan)) {
ao2_lock(bridge_channel);
- if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_FEATURE) {
+ if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
}
ao2_unlock(bridge_channel);
@@ -1027,32 +1074,96 @@
}
}
-static void bridge_channel_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
- struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
-
- if (features && features->talker_cb) {
- features->talker_cb(bridge, bridge_channel, features->talker_pvt_data);
+static void bridge_channel_talking(struct ast_bridge_channel *bridge_channel, int talking)
+{
+ struct ast_bridge_features *features;
+
+ features = bridge_channel->features;
+ if (!features) {
+ features = &bridge_channel->bridge->features;
+ }
+ if (features->talker_cb) {
+ features->talker_cb(bridge_channel, features->talker_pvt_data, talking);
}
}
/*! \brief Internal function that plays back DTMF on a bridge channel */
-static void bridge_channel_dtmf_stream(struct ast_bridge_channel *bridge_channel)
-{
- char dtmf_q[8] = "";
-
- ast_copy_string(dtmf_q, bridge_channel->dtmf_stream_q, sizeof(dtmf_q));
- bridge_channel->dtmf_stream_q[0] = '\0';
-
- ast_debug(1, "Playing DTMF stream '%s' out to bridge channel %p\n", dtmf_q, bridge_channel);
- ast_dtmf_stream(bridge_channel->chan, NULL, dtmf_q, 250, 0);
+static void bridge_channel_dtmf_stream(struct ast_bridge_channel *bridge_channel, const char *dtmf)
+{
+ ast_debug(1, "Playing DTMF stream '%s' out to bridge channel %p\n", dtmf, bridge_channel);
+ ast_dtmf_stream(bridge_channel->chan, NULL, dtmf, 0, 0);
+}
+
+/*!
+ * \internal
+ * \brief Handle bridge action.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to execute the action on.
+ * \param action What to do.
+ *
+ * \return Nothing
+ *
+ * \note This function assumes the bridge is locked.
+ */
+static void bridge_channel_action_bridge(struct ast_bridge_channel *bridge_channel, struct ast_frame *action)
+{
+ switch (action->subclass.integer) {
+ case AST_BRIDGE_ACTION_FEATURE:
+ bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
+ ao2_unlock(bridge_channel->bridge);
+ bridge_channel_feature(bridge_channel->bridge, bridge_channel);
+ ao2_lock(bridge_channel->bridge);
+ bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
+ break;
+ case AST_BRIDGE_ACTION_DTMF_STREAM:
+ bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
+ ao2_unlock(bridge_channel->bridge);
+ bridge_channel_dtmf_stream(bridge_channel, action->data.ptr);
+ ao2_lock(bridge_channel->bridge);
+ bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
+ break;
+ case AST_BRIDGE_ACTION_TALKING_START:
+ case AST_BRIDGE_ACTION_TALKING_STOP:
+ ao2_unlock(bridge_channel->bridge);
+ bridge_channel_talking(bridge_channel,
+ action->subclass.integer == AST_BRIDGE_ACTION_TALKING_START);
+ ao2_lock(bridge_channel->bridge);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Handle control frame action.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to execute the control frame action on.
+ * \param action What to do.
+ *
+ * \return Nothing
+ *
+ * \note This function assumes the bridge is locked.
+ */
+static void bridge_channel_action_control(struct ast_bridge_channel *bridge_channel, struct ast_frame *action)
+{
+ switch (action->subclass.integer) {
+ case AST_CONTROL_CONNECTED_LINE:
+ break;
+ default:
+ break;
+ }
+ /*! \todo BUGBUG bridge_channel_action_control() not written */
}
/*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
-static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge_channel *bridge_channel)
-{
+static void bridge_channel_join(struct ast_bridge_channel *bridge_channel)
+{
+ struct ast_frame *action;
struct ast_format formats[2];
- enum ast_bridge_channel_state state;
+
ast_format_copy(&formats[0], ast_channel_readformat(bridge_channel->chan));
ast_format_copy(&formats[1], ast_channel_writeformat(bridge_channel->chan));
@@ -1086,7 +1197,11 @@
bridge_channel->swap = NULL;
if (bridge_channel2) {
ast_debug(1, "Swapping bridge channel %p out from bridge %p so bridge channel %p can slip in\n", bridge_channel2, bridge_channel->bridge, bridge_channel);
- ast_bridge_change_state(bridge_channel2, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ ao2_lock(bridge_channel2);
+ if (bridge_channel2->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+ ast_bridge_change_state_nolock(bridge_channel2, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ }
+ ao2_unlock(bridge_channel2);
}
} else if (ast_test_flag(&bridge_channel->bridge->feature_flags, AST_BRIDGE_FLAG_SMART)) {
/* Perform the smart bridge operation, basically see if we need to move around between technologies */
@@ -1127,55 +1242,43 @@
continue;
}
}
+
/* Execute the threading model */
- state = (bridge_channel->bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTITHREADED)
- ? bridge_channel_join_multithreaded(bridge_channel)
- : bridge_channel_join_singlethreaded(bridge_channel);
- /* Depending on the above state see what we need to do */
- switch (state) {
- case AST_BRIDGE_CHANNEL_STATE_FEATURE:
- bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
- ao2_unlock(bridge_channel->bridge);
- bridge_channel_feature(bridge_channel->bridge, bridge_channel);
- ao2_lock(bridge_channel->bridge);
- ao2_lock(bridge_channel);
- if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_FEATURE) {
- ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
- }
+ if (bridge_channel->bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTITHREADED) {
+ bridge_channel_join_multithreaded(bridge_channel);
+ } else {
+ bridge_channel_join_singlethreaded(bridge_channel);
+ }
+
+ /* Run any queued actions on the channel. */
+ ao2_lock(bridge_channel);
+ while (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT
+ && (action = AST_LIST_REMOVE_HEAD(&bridge_channel->action_queue, frame_list))) {
ao2_unlock(bridge_channel);
- bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
- break;
- case AST_BRIDGE_CHANNEL_STATE_DTMF:
- bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
- ao2_unlock(bridge_channel->bridge);
- bridge_channel_dtmf_stream(bridge_channel);
- ao2_lock(bridge_channel->bridge);
- ao2_lock(bridge_channel);
- if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_DTMF) {
- ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
- }
- ao2_unlock(bridge_channel);
- bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
- break;
- case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
- case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
- ao2_unlock(bridge_channel->bridge);
- bridge_channel_talking(bridge_channel->bridge, bridge_channel);
- ao2_lock(bridge_channel->bridge);
- ao2_lock(bridge_channel);
- switch (bridge_channel->state) {
- case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
- case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
- ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
+ switch (action->frametype) {
+ case AST_FRAME_BRIDGE_ACTION:
+ bridge_channel_action_bridge(bridge_channel, action);
+ break;
+ case AST_FRAME_CONTROL:
+ bridge_channel_action_control(bridge_channel, action);
+ break;
+ case AST_FRAME_TEXT:
+ case AST_FRAME_IMAGE:
+ case AST_FRAME_HTML:
+ /* Write the deferred frame to the channel. */
+ ao2_unlock(bridge_channel->bridge);
+ ast_write(bridge_channel->chan, action);
+ ao2_lock(bridge_channel->bridge);
break;
default:
+ /* Unexpected deferred frame type. Sould never happen. */
+ ast_assert(0);
break;
}
- ao2_unlock(bridge_channel);
- break;
- default:
- break;
- }
+ ast_frfree(action);
+ ao2_lock(bridge_channel);
+ }
+ ao2_unlock(bridge_channel);
}
ast_channel_internal_bridge_set(bridge_channel->chan, NULL);
@@ -1212,6 +1315,13 @@
ao2_unlock(bridge_channel->bridge);
+ /* Flush any unhandled actions. */
+ ao2_lock(bridge_channel);
+ while ((action = AST_LIST_REMOVE_HEAD(&bridge_channel->action_queue, frame_list))) {
+ ast_frfree(action);
+ }
+ ao2_unlock(bridge_channel);
+
/* Restore original formats of the channel as they came in */
if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), &formats[0]) == AST_FORMAT_CMP_NOT_EQUAL) {
ast_debug(1, "Bridge is returning %p to read format %s(%d)\n", bridge_channel, ast_getformatname(&formats[0]), formats[0].id);
@@ -1225,8 +1335,6 @@
ast_debug(1, "Bridge failed to return channel %p to write format %s(%d)\n", bridge_channel, ast_getformatname(&formats[1]), formats[1].id);
}
}
-
- return bridge_channel->state;
}
static void bridge_channel_destroy(void *obj)
@@ -1283,7 +1391,8 @@
bridge_channel->swap = swap;
bridge_channel->features = features;
- state = bridge_channel_join(bridge_channel);
+ bridge_channel_join(bridge_channel);
+ state = bridge_channel->state;
/* Cleanup all the data in the bridge channel after it leaves the bridge. */
bridge_channel->chan = NULL;
@@ -1324,8 +1433,8 @@
ast_callid_threadassoc_add(bridge_channel->callid);
}
- state = bridge_channel_join(bridge_channel);
-
+ bridge_channel_join(bridge_channel);
+ state = bridge_channel->state;
chan = bridge_channel->chan;
/* cleanup */
@@ -1453,7 +1562,11 @@
return -1;
}
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ ao2_lock(bridge_channel);
+ if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+ ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ }
+ ao2_unlock(bridge_channel);
ao2_unlock(bridge);
@@ -1736,6 +1849,12 @@
int ast_bridge_dtmf_stream(struct ast_bridge *bridge, const char *dtmf, struct ast_channel *chan)
{
struct ast_bridge_channel *bridge_channel;
+ struct ast_frame action = {
+ .frametype = AST_FRAME_BRIDGE_ACTION,
+ .subclass.integer = AST_BRIDGE_ACTION_DTMF_STREAM,
+ .datalen = strlen(dtmf) + 1,
+ .data.ptr = (char *) dtmf,
+ };
ao2_lock(bridge);
@@ -1743,8 +1862,7 @@
if (bridge_channel->chan == chan) {
continue;
}
- ast_copy_string(bridge_channel->dtmf_stream_q, dtmf, sizeof(bridge_channel->dtmf_stream_q));
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DTMF);
+ ast_bridge_channel_queue_action(bridge_channel, &action);
}
ao2_unlock(bridge);
Modified: team/group/bridge_construction/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/channel.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/main/channel.c (original)
+++ team/group/bridge_construction/main/channel.c Thu Jan 31 13:18:41 2013
@@ -1653,6 +1653,7 @@
* be queued up or not.
*/
switch (frame->frametype) {
+ case AST_FRAME_BRIDGE_ACTION:
case AST_FRAME_CONTROL:
case AST_FRAME_TEXT:
case AST_FRAME_IMAGE:
@@ -3072,6 +3073,7 @@
break;
case AST_FRAME_CONTROL:
case AST_FRAME_IAX:
+ case AST_FRAME_BRIDGE_ACTION:
case AST_FRAME_NULL:
case AST_FRAME_CNG:
break;
Modified: team/group/bridge_construction/main/frame.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/frame.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/main/frame.c (original)
+++ team/group/bridge_construction/main/frame.c Thu Jan 31 13:18:41 2013
@@ -628,6 +628,10 @@
/* Should never happen */
snprintf(subclass, slen, "IAX Frametype %d", f->subclass.integer);
break;
+ case AST_FRAME_BRIDGE_ACTION:
+ /* Should never happen */
+ snprintf(subclass, slen, "Bridge Frametype %d", f->subclass.integer);
+ break;
case AST_FRAME_TEXT:
ast_copy_string(subclass, "N/A", slen);
if (moreinfo) {
@@ -714,6 +718,10 @@
case AST_FRAME_IAX:
/* Should never happen */
ast_copy_string(ftype, "IAX Specific", len);
+ break;
+ case AST_FRAME_BRIDGE_ACTION:
+ /* Should never happen */
+ ast_copy_string(ftype, "Bridge Specific", len);
break;
case AST_FRAME_TEXT:
ast_copy_string(ftype, "Text", len);
More information about the asterisk-commits
mailing list