[asterisk-commits] rmudgett: branch rmudgett/bridge_tasks r383438 - in /team/rmudgett/bridge_tas...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Mar 20 11:55:17 CDT 2013
Author: rmudgett
Date: Wed Mar 20 11:55:13 2013
New Revision: 383438
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383438
Log:
* Add support for bridge personality to support queue, parking,
confbridge and other bridge encapsulation applications.
* Convert ao2 locking for bridge and bridge_channel to wrapper functions
for easier where used queries and type safety.
Modified:
team/rmudgett/bridge_tasks/apps/app_bridgewait.c
team/rmudgett/bridge_tasks/apps/app_confbridge.c
team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c
team/rmudgett/bridge_tasks/bridges/bridge_softmix.c
team/rmudgett/bridge_tasks/include/asterisk/bridging.h
team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h
team/rmudgett/bridge_tasks/main/bridging.c
team/rmudgett/bridge_tasks/main/features.c
Modified: team/rmudgett/bridge_tasks/apps/app_bridgewait.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/apps/app_bridgewait.c?view=diff&rev=383438&r1=383437&r2=383438
==============================================================================
--- team/rmudgett/bridge_tasks/apps/app_bridgewait.c (original)
+++ team/rmudgett/bridge_tasks/apps/app_bridgewait.c Wed Mar 20 11:55:13 2013
@@ -195,7 +195,9 @@
ast_mutex_lock(&bridgewait_lock);
if (!holding_bridge) {
- holding_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_HOLDING, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM);
+/* BUGBUG this holding bridge needs a personality to manage the timeout. Otherwise, the timer will move to the next bridge which is likely not desireable. */
+ holding_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_HOLDING,
+ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM, NULL);
}
ast_mutex_unlock(&bridgewait_lock);
Modified: team/rmudgett/bridge_tasks/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/apps/app_confbridge.c?view=diff&rev=383438&r1=383437&r2=383438
==============================================================================
--- team/rmudgett/bridge_tasks/apps/app_confbridge.c (original)
+++ team/rmudgett/bridge_tasks/apps/app_confbridge.c Wed Mar 20 11:55:13 2013
@@ -1286,7 +1286,7 @@
/* Create an actual bridge that will do the audio mixing */
if (!(conference->bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_MULTIMIX,
- AST_BRIDGE_FLAG_MASQUERADE_ONLY))) {
+ AST_BRIDGE_FLAG_MASQUERADE_ONLY, NULL))) {
ao2_ref(conference, -1);
conference = NULL;
ao2_unlock(conference_bridges);
Modified: team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c?view=diff&rev=383438&r1=383437&r2=383438
==============================================================================
--- team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c (original)
+++ team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c Wed Mar 20 11:55:13 2013
@@ -277,7 +277,7 @@
/* Create a bridge to use to talk to the person we are calling */
attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX,
- AST_BRIDGE_FLAG_DISSOLVE_HANGUP);
+ AST_BRIDGE_FLAG_DISSOLVE_HANGUP, NULL);
if (!attended_bridge) {
ast_hangup(peer);
/* BUGBUG beeperr needs to be configurable from features.conf */
Modified: team/rmudgett/bridge_tasks/bridges/bridge_softmix.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/bridges/bridge_softmix.c?view=diff&rev=383438&r1=383437&r2=383438
==============================================================================
--- team/rmudgett/bridge_tasks/bridges/bridge_softmix.c (original)
+++ team/rmudgett/bridge_tasks/bridges/bridge_softmix.c Wed Mar 20 11:55:13 2013
@@ -845,17 +845,17 @@
}
stat_iteration_counter--;
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
/* cleanup any translation frame data from the previous mixing iteration. */
softmix_translate_helper_cleanup(&trans_helper);
/* Wait for the timing source to tell us to wake up and get things done */
ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
if (ast_timer_ack(timer, 1) < 0) {
ast_log(LOG_ERROR, "Failed to acknowledge timer in softmix bridge.\n");
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
goto softmix_cleanup;
}
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
/* make sure to detect mixing interval changes if they occur. */
if (bridge->internal_mixing_interval && (bridge->internal_mixing_interval != softmix_data->internal_mixing_interval)) {
@@ -887,7 +887,7 @@
struct ast_bridge *bridge = data;
struct softmix_bridge_data *softmix_data;
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
if (bridge->callid) {
ast_callid_threadassoc_add(bridge->callid);
}
@@ -898,13 +898,13 @@
while (!softmix_data->stop) {
if (!bridge->num_active) {
/* Wait for something to happen to the bridge. */
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
ast_mutex_lock(&softmix_data->lock);
if (!softmix_data->stop) {
ast_cond_wait(&softmix_data->cond, &softmix_data->lock);
}
ast_mutex_unlock(&softmix_data->lock);
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
continue;
}
@@ -913,13 +913,13 @@
* A mixing error occurred. Sleep and try again later so we
* won't flood the logs.
*/
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
sleep(1);
- ao2_lock(bridge);
- }
- }
-
- ao2_unlock(bridge);
+ ast_bridge_lock(bridge);
+ }
+ }
+
+ ast_bridge_unlock(bridge);
ast_debug(1, "Stopping mixing thread for bridge %p\n", bridge);
Modified: team/rmudgett/bridge_tasks/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/include/asterisk/bridging.h?view=diff&rev=383438&r1=383437&r2=383438
==============================================================================
--- team/rmudgett/bridge_tasks/include/asterisk/bridging.h (original)
+++ team/rmudgett/bridge_tasks/include/asterisk/bridging.h Wed Mar 20 11:55:13 2013
@@ -115,9 +115,138 @@
};
/*!
+ * \brief Create the bridge personality.
+ *
+ * \param self Bridge to operate upon.
+ *
+ * \details
+ * Allocate and setup the self->personality_pvt.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+typedef int (*ast_personality_create_fn)(struct ast_bridge *self);
+
+/*!
+ * \brief Destroy the bridge personality.
+ *
+ * \param self Bridge to operate upon.
+ *
+ * \details
+ * Release any resources held by self->personality_pvt and
+ * release self->personality_pvt.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_personality_destroy_fn)(struct ast_bridge *self);
+
+/*!
+ * \brief Can this channel be pushed into its bridge.
+ *
+ * \param self Bridge channel to operate upon.
+ * \param swap Bridge channel to swap places with if not NULL.
+ *
+ * \note On entry, self->bridge is already locked.
+ *
+ * \retval TRUE if can push this channel into its bridge.
+ */
+typedef int (*ast_personality_channel_can_push_fn)(struct ast_bridge_channel *self, struct ast_bridge_channel *swap);
+
+/*!
+ * \brief Push this channel into its bridge.
+ *
+ * \param self Bridge channel to operate upon.
+ * \param swap Bridge channel to swap places with if not NULL.
+ *
+ * \details
+ * Setup any channel hooks controlled by the personality,
+ * allocate and setup the self->personality_pvt. If there is a
+ * swap channel, use it as a guide to setting up the self
+ * channel.
+ *
+ * \note On entry, self->bridge is already locked.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+typedef int (*ast_personality_channel_push_fn)(struct ast_bridge_channel *self, struct ast_bridge_channel *swap);
+
+/*!
+ * \brief Pull this channel from its bridge.
+ *
+ * \param self Bridge channel to operate upon.
+ *
+ * \details
+ * Remove any channel hooks controlled by the personality.
+ * Release any resources held by self->personality_pvt and
+ * release self->personality_pvt.
+ *
+ * \note On entry, self->bridge is already locked.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_personality_channel_pull_fn)(struct ast_bridge_channel *self);
+
+/*!
+ * \brief Masquerade push this channel into its bridge.
+ *
+ * \param self Bridge channel to operate upon.
+ *
+ * \note This is a virtual push into the bridge because a
+ * masquerade swaps the guts of the channel to give it a new
+ * identity. This is mostly for external bridge monitor
+ * bookkeeping.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_personality_channel_push_masquerade_fn)(struct ast_bridge_channel *self);
+
+/*!
+ * \brief Masquerade pull this channel from its bridge.
+ *
+ * \param self Bridge channel to operate upon.
+ *
+ * \note This is a virtual pull from the bridge because a
+ * masquerade swaps the guts of the channel to give it a new
+ * identity. This is mostly for external bridge monitor
+ * bookkeeping.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_personality_channel_pull_masquerade_fn)(struct ast_bridge_channel *self);
+
+/*! Bridge personality virtual methods table definition. */
+struct ast_personality_methods {
+ /*! Bridge personality name for log messages. */
+ const char *name;
+ /*! Create the bridge personality. */
+ ast_personality_create_fn create;
+ /*! Destroy the bridge personality. */
+ ast_personality_destroy_fn destroy;
+ /*! TRUE if can push the bridge channel into its bridge. */
+ ast_personality_channel_can_push_fn can_push;
+ /*! Push the bridge channel into its bridge. */
+ ast_personality_channel_push_fn push;
+ /*! Pull the bridge channel from its bridge. */
+ ast_personality_channel_pull_fn pull;
+/*
+ * BUGBUG push_masquerade may just have to change into masquerade_complete so the bridge will need to check compatibility again.
+ * Otherwise, the bridge channel will have to constantly check if the set formats have changed before reading frames.
+ * Race conditions may force the bridge channel to constantly check anyway. .
+ */
+ /*! Virtually push the bridge channel into its bridge. */
+ ast_personality_channel_push_masquerade_fn push_masquerade;
+ /*! Virtually pull the bridge channel from its bridge. */
+ ast_personality_channel_pull_masquerade_fn pull_masquerade;
+};
+
+/*!
* \brief Structure that contains information regarding a channel in a bridge
*/
struct ast_bridge_channel {
+/* BUGBUG cond is only here because of external party suspend/unsuspend support. */
/*! Condition, used if we want to wake up a thread waiting on the bridged channel */
ast_cond_t cond;
/*! Current bridged channel state */
@@ -128,7 +257,21 @@
struct ast_channel *swap;
/*! Bridge this channel is participating in */
struct ast_bridge *bridge;
- /*! Private information unique to the bridge technology */
+ /*!
+ * \brief Bridge personality private bridge channel data.
+ *
+ * \note This information is added when the channel is pushed
+ * into the bridge and removed when it is pulled from the
+ * bridge.
+ */
+ void *personality_pvt;
+ /*!
+ * \brief Private information unique to the bridge technology.
+ *
+ * \note This information is added when the channel joins the
+ * bridge's technology and removed when it leaves the bridge's
+ * technology.
+ */
void *tech_pvt;
/*! Thread handling the bridged channel (Needed by ast_bridge_depart) */
pthread_t thread;
@@ -217,12 +360,32 @@
* \brief Structure that contains information about a bridge
*/
struct ast_bridge {
+ /*! Bridge personality virtual method table. */
+ const struct ast_personality_methods *personality;
+ /*!
+ * \brief Bridge personality private bridge data.
+ *
+ * \note This information is added when the bridge is created.
+ */
+ void *personality_pvt;
+ /*! Bridge technology that is handling the bridge */
+ struct ast_bridge_technology *technology;
+ /*! Private information unique to the bridge technology */
+ void *tech_pvt;
+ /*! Call ID associated with the bridge */
+ struct ast_callid *callid;
+ /*! Linked list of channels participating in the bridge */
+ AST_LIST_HEAD_NOLOCK(, ast_bridge_channel) channels;
+ /*! Queue of actions to perform on the bridge. */
+ AST_LIST_HEAD_NOLOCK(, ast_frame) action_queue;
+ /*! The video mode this bridge is using */
+ struct ast_bridge_video_mode video_mode;
+ /*! Bridge flags to tweak behavior */
+ struct ast_flags feature_flags;
/*! Number of channels participating in the bridge */
unsigned int num_channels;
/*! Number of active channels in the bridge. */
unsigned int num_active;
- /*! The video mode this bridge is using */
- struct ast_bridge_video_mode video_mode;
/*!
* \brief Count of the active temporary requests to inhibit bridge merges.
* Zero if merges are allowed.
@@ -241,18 +404,6 @@
unsigned int reconfigured:1;
/*! TRUE if the bridge has been dissolved. Any channel that now tries to join is immediately ejected. */
unsigned int dissolved:1;
- /*! Bridge flags to tweak behavior */
- struct ast_flags feature_flags;
- /*! Bridge technology that is handling the bridge */
- struct ast_bridge_technology *technology;
- /*! Private information unique to the bridge technology */
- void *tech_pvt;
- /*! Call ID associated with the bridge */
- struct ast_callid *callid;
- /*! Linked list of channels participating in the bridge */
- AST_LIST_HEAD_NOLOCK(, ast_bridge_channel) channels;
- /*! Queue of actions to perform on the bridge. */
- AST_LIST_HEAD_NOLOCK(, ast_frame) action_queue;
};
/*!
@@ -260,6 +411,7 @@
*
* \param capabilities The capabilities that we require to be used on the bridge
* \param flags Flags that will alter the behavior of the bridge
+ * \param personality Personality of the new bridge (NULL if none)
*
* \retval a pointer to a new bridge on success
* \retval NULL on failure
@@ -274,7 +426,21 @@
* This creates a simple two party bridge that will be destroyed once one of
* the channels hangs up.
*/
-struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags);
+struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags, const struct ast_personality_methods *personality);
+
+/*!
+ * \brief Try locking the bridge.
+ *
+ * \param bridge Bridge to try locking
+ *
+ * \retval 0 on success.
+ * \retval non-zero on error.
+ */
+#define ast_bridge_trylock(bridge) _ast_bridge_trylock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge)
+static inline int _ast_bridge_trylock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var)
+{
+ return __ao2_trylock(bridge, AO2_LOCK_REQ_MUTEX, file, function, line, var);
+}
/*!
* \brief Lock the bridge.
@@ -558,6 +724,46 @@
int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan);
/*!
+ * \brief Try locking the bridge_channel.
+ *
+ * \param bridge_channel What to try locking
+ *
+ * \retval 0 on success.
+ * \retval non-zero on error.
+ */
+#define ast_bridge_channel_trylock(bridge_channel) _ast_bridge_channel_trylock(bridge_channel, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge_channel)
+static inline int _ast_bridge_channel_trylock(struct ast_bridge_channel *bridge_channel, const char *file, const char *function, int line, const char *var)
+{
+ return __ao2_trylock(bridge_channel, AO2_LOCK_REQ_MUTEX, file, function, line, var);
+}
+
+/*!
+ * \brief Lock the bridge_channel.
+ *
+ * \param bridge_channel What to lock
+ *
+ * \return Nothing
+ */
+#define ast_bridge_channel_lock(bridge_channel) _ast_bridge_channel_lock(bridge_channel, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge_channel)
+static inline void _ast_bridge_channel_lock(struct ast_bridge_channel *bridge_channel, const char *file, const char *function, int line, const char *var)
+{
+ __ao2_lock(bridge_channel, AO2_LOCK_REQ_MUTEX, file, function, line, var);
+}
+
+/*!
+ * \brief Unlock the bridge_channel.
+ *
+ * \param bridge_channel What to unlock
+ *
+ * \return Nothing
+ */
+#define ast_bridge_channel_unlock(bridge_channel) _ast_bridge_channel_unlock(bridge_channel, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge_channel)
+static inline void _ast_bridge_channel_unlock(struct ast_bridge_channel *bridge_channel, const char *file, const char *function, int line, const char *var)
+{
+ __ao2_unlock(bridge_channel, file, function, line, var);
+}
+
+/*!
* \brief Set bridge channel state to leave bridge (if not leaving already) with no lock.
*
* \param bridge_channel Channel to change the state on
Modified: team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h?view=diff&rev=383438&r1=383437&r2=383438
==============================================================================
--- team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h (original)
+++ team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h Wed Mar 20 11:55:13 2013
@@ -32,16 +32,19 @@
enum ast_bridge_feature_flags {
/*! Upon channel hangup all bridge participants should be kicked out. */
AST_BRIDGE_FLAG_DISSOLVE_HANGUP = (1 << 0),
+ /*! The last channel to leave the bridge dissolves it. */
+ AST_BRIDGE_FLAG_DISSOLVE_EMPTY = (1 << 1),
/*! Move between bridging technologies as needed. */
- AST_BRIDGE_FLAG_SMART = (1 << 1),
- /*! This channel leaves the bridge if all participants have this flag set. */
- AST_BRIDGE_FLAG_LONELY = (1 << 2),
+ AST_BRIDGE_FLAG_SMART = (1 << 2),
/*! Bridge channels cannot be merged from this bridge. */
AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM = (1 << 3),
/*! Bridge channels cannot be merged to this bridge. */
AST_BRIDGE_FLAG_MERGE_INHIBIT_TO = (1 << 4),
/*! Bridge channels can be moved to another bridge only by masquerade (ConfBridge) */
AST_BRIDGE_FLAG_MASQUERADE_ONLY = (1 << 5),
+
+ /*! This channel leaves the bridge if all participants have this flag set. */
+ AST_BRIDGE_FLAG_LONELY = (1 << 10),
};
/*! \brief Built in DTMF features */
Modified: team/rmudgett/bridge_tasks/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/main/bridging.c?view=diff&rev=383438&r1=383437&r2=383438
==============================================================================
--- team/rmudgett/bridge_tasks/main/bridging.c (original)
+++ team/rmudgett/bridge_tasks/main/bridging.c Wed Mar 20 11:55:13 2013
@@ -216,21 +216,21 @@
for (;;) {
/* Safely get the bridge pointer */
- ao2_lock(bridge_channel);
+ ast_bridge_channel_lock(bridge_channel);
bridge = bridge_channel->bridge;
ao2_ref(bridge, +1);
- ao2_unlock(bridge_channel);
+ ast_bridge_channel_unlock(bridge_channel);
/*
* The bridge pointer cannot change while the bridge or
* bridge_channel is locked.
*/
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
if (bridge == bridge_channel->bridge) {
ao2_ref(bridge, -1);
return;
}
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
ao2_ref(bridge, -1);
}
}
@@ -252,9 +252,9 @@
void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
{
- ao2_lock(bridge_channel);
+ ast_bridge_channel_lock(bridge_channel);
ast_bridge_change_state_nolock(bridge_channel, new_state);
- ao2_unlock(bridge_channel);
+ ast_bridge_channel_unlock(bridge_channel);
}
/*!
@@ -272,9 +272,9 @@
ast_debug(1, "Queueing action type:%d sub:%d on bridge %p\n",
action->frametype, action->subclass.integer, bridge);
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
AST_LIST_INSERT_TAIL(&bridge->action_queue, action, frame_list);
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
ast_bridge_manager_service_req(bridge);
}
@@ -302,13 +302,13 @@
return -1;
}
- ao2_lock(bridge_channel);
+ ast_bridge_channel_lock(bridge_channel);
AST_LIST_INSERT_TAIL(&bridge_channel->wr_queue, dup, frame_list);
if (write(bridge_channel->alert_pipe[1], &nudge, sizeof(nudge)) != sizeof(nudge)) {
ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n",
bridge_channel, ast_channel_name(bridge_channel->chan));
}
- ao2_unlock(bridge_channel);
+ ast_bridge_channel_unlock(bridge_channel);
return 0;
}
@@ -366,20 +366,10 @@
{
struct ast_bridge *bridge = bridge_channel->bridge;
- ao2_lock(bridge_channel);
if (!bridge_channel->in_bridge) {
- ao2_unlock(bridge_channel);
return;
}
bridge_channel->in_bridge = 0;
-
- /* Remove channel from the bridge */
- if (!bridge_channel->suspended) {
- --bridge->num_active;
- }
- --bridge->num_channels;
- AST_LIST_REMOVE(&bridge->channels, bridge_channel, entry);
- ao2_unlock(bridge_channel);
ast_debug(1, "Pulling bridge channel %p(%s) from bridge %p\n",
bridge_channel, ast_channel_name(bridge_channel->chan), bridge);
@@ -394,6 +384,16 @@
}
}
+ /* Remove channel from the bridge */
+ if (!bridge_channel->suspended) {
+ --bridge->num_active;
+ }
+ --bridge->num_channels;
+ AST_LIST_REMOVE(&bridge->channels, bridge_channel, entry);
+ if (bridge->personality && bridge->personality->pull) {
+ bridge->personality->pull(bridge_channel);
+ }
+
bridge->reconfigured = 1;
}
@@ -411,50 +411,62 @@
static void ast_bridge_channel_push(struct ast_bridge_channel *bridge_channel)
{
struct ast_bridge *bridge = bridge_channel->bridge;
- struct ast_channel *swap;
-
- ao2_lock(bridge_channel);
+ struct ast_bridge_channel *swap;
+ int chan_leaving;
+
ast_assert(!bridge_channel->in_bridge);
- if (bridge->dissolved) {
- /* Force out channel being pushed into a dissolved bridge. */
+ swap = find_bridge_channel(bridge, bridge_channel->swap);
+ bridge_channel->swap = NULL;
+
+ chan_leaving = bridge->dissolved
+ || (bridge->personality && bridge->personality->can_push
+ && !bridge->personality->can_push(bridge_channel, swap));
+
+ ast_bridge_channel_lock(bridge_channel);
+ if (chan_leaving) {
+ /*
+ * Force out channel being pushed into a dissolved bridge or it
+ * is not allowed into the bridge.
+ */
ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
}
- if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+ chan_leaving = bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT;
+ ast_bridge_channel_unlock(bridge_channel);
+ if (chan_leaving) {
/* Don't push a channel in the process of leaving. */
- ao2_unlock(bridge_channel);
return;
}
+ if (swap) {
+ ast_debug(1, "Pushing bridge channel %p(%s) into bridge %p by swapping with %p(%s)\n",
+ bridge_channel, ast_channel_name(bridge_channel->chan), bridge,
+ swap, ast_channel_name(swap->chan));
+ } else {
+ ast_debug(1, "Pushing bridge channel %p(%s) into bridge %p\n",
+ bridge_channel, ast_channel_name(bridge_channel->chan), bridge);
+ }
+
+ /* Add channel to the bridge */
+ if (bridge->personality && bridge->personality->push
+ && bridge->personality->push(bridge_channel, swap)) {
+/* BUGBUG need to use bridge id in the diagnostic message */
+ ast_log(LOG_ERROR, "Pushing channel %s into bridge %p failed\n",
+ ast_channel_name(bridge_channel->chan), bridge);
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ return;
+ }
bridge_channel->in_bridge = 1;
bridge_channel->just_joined = 1;
- swap = bridge_channel->swap;
- bridge_channel->swap = NULL;
-
- /* Add channel to the bridge */
AST_LIST_INSERT_TAIL(&bridge->channels, bridge_channel, entry);
++bridge->num_channels;
if (!bridge_channel->suspended) {
++bridge->num_active;
}
- ao2_unlock(bridge_channel);
-
if (swap) {
- struct ast_bridge_channel *bridge_channel2;
-
- bridge_channel2 = find_bridge_channel(bridge, swap);
- if (bridge_channel2) {
- ast_debug(1, "Swapping bridge channel %p(%s) out from bridge %p so bridge channel %p(%s) can slip in\n",
- bridge_channel2, ast_channel_name(bridge_channel2->chan), bridge,
- bridge_channel, ast_channel_name(bridge_channel->chan));
- ast_bridge_change_state(bridge_channel2, AST_BRIDGE_CHANNEL_STATE_HANGUP);
-
- ast_bridge_channel_pull(bridge_channel2);
- }
- }
-
- ast_debug(1, "Pushing bridge channel %p(%s) into bridge %p\n",
- bridge_channel, ast_channel_name(bridge_channel->chan), bridge);
+ ast_bridge_change_state(swap, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ ast_bridge_channel_pull(swap);
+ }
bridge->reconfigured = 1;
}
@@ -694,7 +706,7 @@
/* Simply write the frame out to the bridge technology. */
ast_bridge_channel_lock_bridge(bridge_channel);
bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame);
- ao2_unlock(bridge_channel->bridge);
+ ast_bridge_unlock(bridge_channel->bridge);
ast_frfree(frame);
}
@@ -743,9 +755,7 @@
ast_channel_name(bridge_channel->chan), bridge);
}
- ao2_lock(bridge_channel);
bridge_channel->just_joined = 0;
- ao2_unlock(bridge_channel);
}
}
@@ -838,9 +848,9 @@
switch (action->subclass.integer) {
case AST_BRIDGE_ACTION_DEFERRED_TECH_DESTROY:
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
bridge_tech_deferred_destroy(bridge, action);
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
break;
default:
/* Unexpected deferred action type. Should never happen. */
@@ -886,9 +896,9 @@
ast_debug(1, "Actually destroying bridge %p, nobody wants it anymore\n", bridge);
/* Do any pending actions in the context of destruction. */
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
bridge_handle_actions(bridge);
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
/* There should not be any channels left in the bridge. */
ast_assert(AST_LIST_EMPTY(&bridge->channels));
@@ -901,6 +911,14 @@
}
ast_module_unref(bridge->technology->mod);
+ if (bridge->personality) {
+ ast_debug(1, "Giving bridge personality %s the bridge structure %p to destroy\n",
+ bridge->personality->name, bridge);
+ if (bridge->personality->destroy) {
+ bridge->personality->destroy(bridge);
+ }
+ }
+
if (bridge->callid) {
bridge->callid = ast_callid_unref(bridge->callid);
}
@@ -908,7 +926,7 @@
cleanup_video_mode(bridge);
}
-struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags)
+struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags, const struct ast_personality_methods *personality)
{
struct ast_bridge *bridge;
struct ast_bridge_technology *bridge_technology;
@@ -942,9 +960,21 @@
return NULL;
}
+ bridge->personality = personality;
bridge->technology = bridge_technology;
ast_set_flag(&bridge->feature_flags, flags);
+
+ if (bridge->personality) {
+ ast_debug(1, "Giving bridge personality %s the bridge structure %p to setup\n",
+ bridge->personality->name, bridge);
+ if (bridge->personality->create && bridge->personality->create(bridge)) {
+ ast_debug(1, "Bridge personality %s failed to setup bridge structure %p\n",
+ bridge->personality->name, bridge);
+ ao2_ref(bridge, -1);
+ return NULL;
+ }
+ }
/* Pass off the bridge to the technology to manipulate if needed */
ast_debug(1, "Giving bridge technology %s the bridge structure %p to setup\n",
@@ -975,9 +1005,9 @@
int ast_bridge_destroy(struct ast_bridge *bridge)
{
ast_debug(1, "Telling all channels in bridge %p to leave the party\n", bridge);
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
bridge_force_out_all(bridge);
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
ao2_ref(bridge, -1);
@@ -1266,12 +1296,10 @@
*/
static void bridge_channel_suspend_nolock(struct ast_bridge_channel *bridge_channel)
{
- ao2_lock(bridge_channel);
bridge_channel->suspended = 1;
if (bridge_channel->in_bridge) {
--bridge_channel->bridge->num_active;
}
- ao2_unlock(bridge_channel);
/* Get technology bridge threads off of the channel. */
if (bridge_channel->bridge->technology->suspend) {
@@ -1291,7 +1319,7 @@
{
ast_bridge_channel_lock_bridge(bridge_channel);
bridge_channel_suspend_nolock(bridge_channel);
- ao2_unlock(bridge_channel->bridge);
+ ast_bridge_unlock(bridge_channel->bridge);
}
/*!
@@ -1306,20 +1334,20 @@
*/
static void bridge_channel_unsuspend_nolock(struct ast_bridge_channel *bridge_channel)
{
- ao2_lock(bridge_channel);
bridge_channel->suspended = 0;
if (bridge_channel->in_bridge) {
++bridge_channel->bridge->num_active;
}
- /* Wake suspended channel. */
- ast_cond_signal(&bridge_channel->cond);
- ao2_unlock(bridge_channel);
-
/* Wake technology bridge threads to take care of channel again. */
if (bridge_channel->bridge->technology->unsuspend) {
bridge_channel->bridge->technology->unsuspend(bridge_channel->bridge, bridge_channel);
}
+
+ /* Wake suspended channel. */
+ ast_bridge_channel_lock(bridge_channel);
+ ast_cond_signal(&bridge_channel->cond);
+ ast_bridge_channel_unlock(bridge_channel);
}
/*!
@@ -1334,7 +1362,7 @@
{
ast_bridge_channel_lock_bridge(bridge_channel);
bridge_channel_unsuspend_nolock(bridge_channel);
- ao2_unlock(bridge_channel->bridge);
+ ast_bridge_unlock(bridge_channel->bridge);
}
/*! \brief Internal function that activates interval hooks on a bridge channel */
@@ -1592,7 +1620,7 @@
struct ast_frame *fr;
char nudge;
- ao2_lock(bridge_channel);
+ ast_bridge_channel_lock(bridge_channel);
if (read(bridge_channel->alert_pipe[0], &nudge, sizeof(nudge)) < 0) {
if (errno != EINTR && errno != EAGAIN) {
ast_log(LOG_WARNING, "read() failed for alert pipe on bridge channel %p(%s): %s\n",
@@ -1600,7 +1628,7 @@
}
}
fr = AST_LIST_REMOVE_HEAD(&bridge_channel->wr_queue, frame_list);
- ao2_unlock(bridge_channel);
+ ast_bridge_channel_unlock(bridge_channel);
if (!fr) {
return;
}
@@ -1669,9 +1697,10 @@
struct ast_channel *chan;
/* Wait for data to either come from the channel or us to be signaled */
- ao2_lock(bridge_channel);
+ ast_bridge_channel_lock(bridge_channel);
if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
} else if (bridge_channel->suspended) {
+/* BUGBUG the external party use of suspended will go away as will these references because this is the bridge channel thread */
ast_debug(1, "Going into a signal wait for bridge channel %p(%s) of bridge %p\n",
bridge_channel, ast_channel_name(bridge_channel->chan),
bridge_channel->bridge);
@@ -1680,7 +1709,7 @@
ast_debug(10, "Going into a waitfor for bridge channel %p(%s) of bridge %p\n",
bridge_channel, ast_channel_name(bridge_channel->chan),
bridge_channel->bridge);
- ao2_unlock(bridge_channel);
+ ast_bridge_channel_unlock(bridge_channel);
outfd = -1;
/* BUGBUG need to make the next expiring active interval setup ms timeout rather than holding up the chan reads. */
chan = ast_waitfor_nandfds(&bridge_channel->chan, 1,
@@ -1696,7 +1725,7 @@
}
return;
}
- ao2_unlock(bridge_channel);
+ ast_bridge_channel_unlock(bridge_channel);
}
/*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
@@ -1714,7 +1743,7 @@
* Directly locking the bridge is safe here because nobody else
* knows about this bridge_channel yet.
*/
- ao2_lock(bridge_channel->bridge);
+ ast_bridge_lock(bridge_channel->bridge);
if (!bridge_channel->bridge->callid) {
bridge_channel->bridge->callid = ast_read_threadstorage_callid();
@@ -1724,7 +1753,7 @@
ast_bridge_reconfigured(bridge_channel->bridge);
/* Wait for something to do. */
- ao2_unlock(bridge_channel->bridge);
+ ast_bridge_unlock(bridge_channel->bridge);
while (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
/* Update bridge pointer on channel */
ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);
@@ -1745,15 +1774,15 @@
break;
}
- ao2_unlock(bridge_channel->bridge);
+ ast_bridge_unlock(bridge_channel->bridge);
/* Flush any unhandled frames. */
- ao2_lock(bridge_channel);
+ ast_bridge_channel_lock(bridge_channel);
/* BUGBUG need to destroy unused bridge action frames specially since they can have referenced pointers. */
while ((fr = AST_LIST_REMOVE_HEAD(&bridge_channel->wr_queue, frame_list))) {
ast_frfree(fr);
}
- ao2_unlock(bridge_channel);
+ ast_bridge_channel_unlock(bridge_channel);
/* BUGBUG Revisit in regards to moving channels between bridges and local channel optimization. */
/* Complete any partial DTMF digit before exiting the bridge. */
@@ -2362,17 +2391,17 @@
{
struct ast_bridge_channel *bridge_channel;
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
/* Try to find the channel that we want to remove */
if (!(bridge_channel = find_bridge_channel(bridge, chan))) {
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
return -1;
}
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
return 0;
}
@@ -2409,9 +2438,9 @@
/* Point to new bridge.*/
ao2_ref(bridge1, +1);
- ao2_lock(bridge_channel);
+ ast_bridge_channel_lock(bridge_channel);
bridge_channel->bridge = bridge1;
- ao2_unlock(bridge_channel);
+ ast_bridge_channel_unlock(bridge_channel);
ao2_ref(bridge2, -1);
ast_bridge_channel_push(bridge_channel);
@@ -2428,11 +2457,11 @@
/* Deadlock avoidance. */
for (;;) {
- ao2_lock(bridge1);
- if (!ao2_trylock(bridge2)) {
+ ast_bridge_lock(bridge1);
+ if (!ast_bridge_trylock(bridge2)) {
break;
}
- ao2_unlock(bridge1);
+ ast_bridge_unlock(bridge1);
sched_yield();
}
@@ -2459,8 +2488,8 @@
res = 0;
}
- ao2_unlock(bridge2);
- ao2_unlock(bridge1);
+ ast_bridge_unlock(bridge2);
+ ast_bridge_unlock(bridge1);
return res;
}
@@ -2468,13 +2497,13 @@
{
int new_request;
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
new_request = bridge->inhibit_merge + request;
if (new_request < 0) {
new_request = 0;
}
bridge->inhibit_merge = new_request;
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
}
int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan)
@@ -2484,16 +2513,16 @@
/* BUGBUG suspend/unsuspend needs to be rethought. The caller must block until it has successfully suspended the channel for temporary control. */
/* BUGBUG external suspend/unsuspend needs to be eliminated. The channel may be playing a file at the time and stealing it then is not good. */
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
if (!(bridge_channel = find_bridge_channel(bridge, chan))) {
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
return -1;
}
bridge_channel_suspend_nolock(bridge_channel);
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
return 0;
}
@@ -2503,16 +2532,16 @@
struct ast_bridge_channel *bridge_channel;
/* BUGBUG the case of a disolved bridge while channel is suspended is not handled. */
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
if (!(bridge_channel = find_bridge_channel(bridge, chan))) {
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
return -1;
}
bridge_channel_unsuspend_nolock(bridge_channel);
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
return 0;
}
@@ -2866,7 +2895,7 @@
.data.ptr = (char *) dtmf,
};
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
if (bridge_channel->chan == chan) {
@@ -2875,24 +2904,23 @@
ast_bridge_channel_queue_frame(bridge_channel, &action);
}
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
return 0;
}
void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixing_interval)
{
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
bridge->internal_mixing_interval = mixing_interval;
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
}
void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate)
{
-
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
bridge->internal_sample_rate = sample_rate;
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
}
static void cleanup_video_mode(struct ast_bridge *bridge)
@@ -2918,22 +2946,22 @@
void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_channel *video_src_chan)
{
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
cleanup_video_mode(bridge);
bridge->video_mode.mode = AST_BRIDGE_VIDEO_MODE_SINGLE_SRC;
bridge->video_mode.mode_data.single_src_data.chan_vsrc = ast_channel_ref(video_src_chan);
ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to single source\r\nVideo Mode: %d\r\nVideo Channel: %s", bridge->video_mode.mode, ast_channel_name(video_src_chan));
ast_indicate(video_src_chan, AST_CONTROL_VIDUPDATE);
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
}
void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge)
{
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
cleanup_video_mode(bridge);
bridge->video_mode.mode = AST_BRIDGE_VIDEO_MODE_TALKER_SRC;
ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to talker source\r\nVideo Mode: %d", bridge->video_mode.mode);
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
}
void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyframe)
@@ -2944,7 +2972,7 @@
return;
}
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
data = &bridge->video_mode.mode_data.talker_src_data;
if (data->chan_vsrc == chan) {
@@ -2972,14 +3000,14 @@
data->chan_old_vsrc = ast_channel_ref(chan);
ast_indicate(chan, AST_CONTROL_VIDUPDATE);
}
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
}
int ast_bridge_number_video_src(struct ast_bridge *bridge)
{
int res = 0;
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
switch (bridge->video_mode.mode) {
case AST_BRIDGE_VIDEO_MODE_NONE:
break;
@@ -2996,7 +3024,7 @@
res++;
}
}
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
return res;
}
@@ -3004,7 +3032,7 @@
{
int res = 0;
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
switch (bridge->video_mode.mode) {
case AST_BRIDGE_VIDEO_MODE_NONE:
break;
@@ -3021,13 +3049,13 @@
}
}
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
return res;
}
void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
{
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
switch (bridge->video_mode.mode) {
case AST_BRIDGE_VIDEO_MODE_NONE:
break;
@@ -3054,7 +3082,7 @@
bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc = NULL;
}
}
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
}
/*!
@@ -3068,14 +3096,14 @@
*/
static void bridge_manager_service(struct ast_bridge *bridge)
{
- ao2_lock(bridge);
+ ast_bridge_lock(bridge);
if (bridge->callid) {
ast_callid_threadassoc_change(bridge->callid);
}
/* Do any pending bridge actions. */
bridge_handle_actions(bridge);
- ao2_unlock(bridge);
+ ast_bridge_unlock(bridge);
}
/*!
Modified: team/rmudgett/bridge_tasks/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/main/features.c?view=diff&rev=383438&r1=383437&r2=383438
==============================================================================
--- team/rmudgett/bridge_tasks/main/features.c (original)
+++ team/rmudgett/bridge_tasks/main/features.c Wed Mar 20 11:55:13 2013
@@ -4535,8 +4535,9 @@
}
/* Create bridge */
+/* BUGBUG need to create the basic bridge personality that will manage the DTMF feature hooks. */
bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_MULTIMIX,
- AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_SMART);
+ AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_SMART, NULL);
if (!bridge) {
ast_bridge_features_destroy(peer_features);
ast_bridge_features_cleanup(&chan_features);
More information about the asterisk-commits
mailing list