[asterisk-commits] jrose: branch jrose/bridge_projects r385510 - in /team/jrose/bridge_projects:...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Apr 12 12:12:13 CDT 2013
Author: jrose
Date: Fri Apr 12 12:12:09 2013
New Revision: 385510
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=385510
Log:
automerge is slow
Modified:
team/jrose/bridge_projects/ (props changed)
team/jrose/bridge_projects/include/asterisk/bridging.h
team/jrose/bridge_projects/main/bridging.c
team/jrose/bridge_projects/main/features.c
Propchange: team/jrose/bridge_projects/
------------------------------------------------------------------------------
--- bridge_projects-integrated (original)
+++ bridge_projects-integrated Fri Apr 12 12:12:09 2013
@@ -1,1 +1,1 @@
-/team/group/bridge_construction:1-385476
+/team/group/bridge_construction:1-385509
Modified: team/jrose/bridge_projects/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/include/asterisk/bridging.h?view=diff&rev=385510&r1=385509&r2=385510
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/bridging.h (original)
+++ team/jrose/bridge_projects/include/asterisk/bridging.h Fri Apr 12 12:12:09 2013
@@ -254,6 +254,19 @@
typedef void (*ast_bridge_destructor_fn)(struct ast_bridge *self);
/*!
+ * \brief The bridge is being dissolved.
+ *
+ * \param self Bridge to operate upon.
+ *
+ * \details
+ * The bridge is being dissolved. Remove any external
+ * references to the bridge so it can be destroyed.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_bridge_dissolving_fn)(struct ast_bridge *self);
+
+/*!
* \brief Can this channel be pushed into the bridge.
*
* \param self Bridge to operate upon.
@@ -330,6 +343,8 @@
const char *name;
/*! Destroy the bridge. */
ast_bridge_destructor_fn destroy;
+ /*! The bridge is being dissolved. Remove any references to the bridge. */
+ ast_bridge_dissolving_fn dissolving;
/*! TRUE if can push the bridge channel into the bridge. */
ast_bridge_can_push_channel_fn can_push;
/*! Push the bridge channel into the bridge. */
@@ -387,6 +402,37 @@
};
/*!
+ * \brief Register the new bridge with the system.
+ * \since 12.0.0
+ *
+ * \param bridge What to register. (Tolerates a NULL pointer)
+ *
+ * \code
+ * struct ast_bridge *ast_bridge_basic_new(uint32_t capabilities, int flags, uint32 dtmf_features)
+ * {
+ * void *bridge;
+ *
+ * bridge = ast_bridge_alloc(sizeof(struct ast_bridge_basic), &ast_bridge_basic_v_table);
+ * bridge = ast_bridge_base_init(bridge, capabilities, flags);
+ * bridge = ast_bridge_basic_init(bridge, dtmf_features);
+ * bridge = ast_bridge_register(bridge);
+ * return bridge;
+ * }
+ * \endcode
+ *
+ * \note This must be done after a bridge constructor has
+ * completed setting up the new bridge but before it returns.
+ *
+ * \note After a bridge is registered, the bridge must be
+ * explicitly destroyed by ast_bridge_destroy() to get rid of
+ * the bridge.
+ *
+ * \retval bridge on success.
+ * \retval NULL on error.
+ */
+struct ast_bridge *ast_bridge_register(struct ast_bridge *bridge);
+
+/*!
* \internal
* \brief Allocate the bridge class object memory.
* \since 12.0.0
@@ -405,7 +451,7 @@
/*!
* \brief Initialize the base class of the bridge.
*
- * \param self Bridge to operate upon. (Tollerates a NULL pointer)
+ * \param self Bridge to operate upon. (Tolerates a NULL pointer)
* \param capabilities The capabilities that we require to be used on the bridge
* \param flags Flags that will alter the behavior of the bridge
*
Modified: team/jrose/bridge_projects/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/bridging.c?view=diff&rev=385510&r1=385509&r2=385510
==============================================================================
--- team/jrose/bridge_projects/main/bridging.c (original)
+++ team/jrose/bridge_projects/main/bridging.c Fri Apr 12 12:12:09 2013
@@ -56,6 +56,10 @@
#include "asterisk/stringfields.h"
#include "asterisk/musiconhold.h"
#include "asterisk/features.h"
+#include "asterisk/cli.h"
+
+/*! All bridges container. */
+static struct ao2_container *bridges;
static AST_RWLIST_HEAD_STATIC(bridge_technologies, ast_bridge_technology);
@@ -398,6 +402,82 @@
/*!
* \internal
+ * \brief Dissolve the bridge.
+ * \since 12.0.0
+ *
+ * \param bridge Bridge to eject all channels
+ *
+ * \details
+ * Force out all channels that are not already going out of the
+ * bridge. Any new channels joining will leave immediately.
+ *
+ * \note On entry, bridge is already locked.
+ *
+ * \return Nothing
+ */
+static void bridge_dissolve(struct ast_bridge *bridge)
+{
+ struct ast_bridge_channel *bridge_channel;
+
+ if (bridge->dissolved) {
+ return;
+ }
+ bridge->dissolved = 1;
+
+ ast_debug(1, "Bridge %s: dissolving bridge\n", bridge->uniqueid);
+
+/* BUGBUG need a cause code on the bridge for the later ejected channels. */
+ AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ }
+ bridge->v_table->dissolving(bridge);
+}
+
+/*!
+ * \internal
+ * \brief Check if a bridge should dissolve and do it.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel causing the check.
+ *
+ * \note On entry, bridge_channel->bridge is already locked.
+ *
+ * \return Nothing
+ */
+static void bridge_dissolve_check(struct ast_bridge_channel *bridge_channel)
+{
+ struct ast_bridge *bridge = bridge_channel->bridge;
+
+ if (bridge->dissolved) {
+ return;
+ }
+
+ if (!bridge->num_channels
+ && ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_EMPTY)) {
+ /* Last channel leaving the bridge turns off the lights. */
+ bridge_dissolve(bridge);
+ return;
+ }
+
+ switch (bridge_channel->state) {
+ case AST_BRIDGE_CHANNEL_STATE_END:
+ /* Do we need to dissolve the bridge because this channel hung up? */
+ if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_HANGUP)
+ || (bridge_channel->features
+ && bridge_channel->features->usable
+ && ast_test_flag(&bridge_channel->features->feature_flags,
+ AST_BRIDGE_FLAG_DISSOLVE_HANGUP))) {
+ bridge_dissolve(bridge);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ * \internal
* \brief Pull the bridge channel out of its current bridge.
* \since 12.0.0
*
@@ -439,6 +519,8 @@
AST_LIST_REMOVE(&bridge->channels, bridge_channel, entry);
bridge->v_table->pull(bridge, bridge_channel);
+ bridge_dissolve_check(bridge_channel);
+
bridge->reconfigured = 1;
ast_bridge_publish_leave(bridge, bridge_channel->chan);
}
@@ -513,53 +595,6 @@
bridge->reconfigured = 1;
ast_bridge_publish_enter(bridge, bridge_channel->chan);
-}
-
-/*!
- * \internal
- * \brief Force out all channels that are not already going out of the bridge.
- * \since 12.0.0
- *
- * \param bridge Bridge to eject all channels
- *
- * \note On entry, bridge is already locked.
- *
- * \return Nothing
- */
-static void bridge_force_out_all(struct ast_bridge *bridge)
-{
- struct ast_bridge_channel *bridge_channel;
-
- bridge->dissolved = 1;
-
-/* BUGBUG need a cause code on the bridge for the later ejected channels. */
- AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
- }
-}
-
-/*!
- * \internal
- * \brief Check if a bridge should dissolve and then do it.
- * \since 12.0.0
- *
- * \param bridge_channel Channel causing the check.
- *
- * \note On entry, bridge_channel->bridge is already locked.
- *
- * \return Nothing
- */
-static void bridge_check_dissolve(struct ast_bridge_channel *bridge_channel)
-{
- if (!ast_test_flag(&bridge_channel->bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_HANGUP)
- && (!bridge_channel->features
- || !bridge_channel->features->usable
- || !ast_test_flag(&bridge_channel->features->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_HANGUP))) {
- return;
- }
-
- ast_debug(1, "Bridge %s: dissolving bridge\n", bridge_channel->bridge->uniqueid);
- bridge_force_out_all(bridge_channel->bridge);
}
/*! \brief Internal function to handle DTMF from a channel */
@@ -1134,13 +1169,13 @@
struct ast_bridge *bridge = obj;
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+ ast_debug(1, "Bridge %s: actually destroying %s bridge, nobody wants it anymore\n",
+ bridge->uniqueid, bridge->v_table->name);
+
msg = stasis_cache_clear_create(ast_bridge_snapshot_type(), bridge->uniqueid);
if (msg) {
stasis_publish(ast_bridge_topic(bridge), msg);
}
-
- ast_debug(1, "Bridge %s: actually destroying %s bridge, nobody wants it anymore\n",
- bridge->uniqueid, bridge->v_table->name);
/* Do any pending actions in the context of destruction. */
ast_bridge_lock(bridge);
@@ -1172,6 +1207,18 @@
cleanup_video_mode(bridge);
}
+struct ast_bridge *ast_bridge_register(struct ast_bridge *bridge)
+{
+ if (bridge) {
+ ast_bridge_publish_state(bridge);
+ if (!ao2_link(bridges, bridge)) {
+ ast_bridge_destroy(bridge);
+ bridge = NULL;
+ }
+ }
+ return bridge;
+}
+
struct ast_bridge *ast_bridge_alloc(size_t size, const struct ast_bridge_methods *v_table)
{
struct ast_bridge *bridge;
@@ -1180,6 +1227,7 @@
if (!v_table
|| !v_table->name
|| !v_table->destroy
+ || !v_table->dissolving
|| !v_table->can_push
|| !v_table->push
|| !v_table->pull
@@ -1263,6 +1311,20 @@
/*!
* \internal
+ * \brief The bridge is being dissolved.
+ * \since 12.0.0
+ *
+ * \param self Bridge to operate upon.
+ *
+ * \return Nothing
+ */
+static void bridge_base_dissolving(struct ast_bridge *self)
+{
+ ao2_unlink(bridges, self);
+}
+
+/*!
+ * \internal
* \brief ast_bridge base can_push method.
* \since 12.0.0
*
@@ -1337,6 +1399,7 @@
struct ast_bridge_methods ast_bridge_base_v_table = {
.name = "base",
.destroy = bridge_base_destroy,
+ .dissolving = bridge_base_dissolving,
.can_push = bridge_base_can_push,
.push = bridge_base_push,
.pull = bridge_base_pull,
@@ -1349,9 +1412,7 @@
bridge = ast_bridge_alloc(sizeof(struct ast_bridge), &ast_bridge_base_v_table);
bridge = ast_bridge_base_init(bridge, capabilities, flags);
- if (bridge) {
- ast_bridge_publish_state(bridge);
- }
+ bridge = ast_bridge_register(bridge);
return bridge;
}
@@ -1372,7 +1433,7 @@
{
ast_debug(1, "Bridge %s: telling all channels to leave the party\n", bridge->uniqueid);
ast_bridge_lock(bridge);
- bridge_force_out_all(bridge);
+ bridge_dissolve(bridge);
ast_bridge_unlock(bridge);
ao2_ref(bridge, -1);
@@ -1647,8 +1708,8 @@
bridge->reconfigured = 0;
if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_SMART)
&& smart_bridge_operation(bridge)) {
- /* Smart bridge failed. Dissolve the bridge. */
- bridge_force_out_all(bridge);
+ /* Smart bridge failed. */
+ bridge_dissolve(bridge);
return;
}
bridge_complete_join(bridge);
@@ -2314,15 +2375,6 @@
bridge_channel_pull(bridge_channel);
bridge_reconfigured(bridge_channel->bridge);
- /* See if we need to dissolve the bridge itself if they hung up */
- switch (bridge_channel->state) {
- case AST_BRIDGE_CHANNEL_STATE_END:
- bridge_check_dissolve(bridge_channel);
- break;
- default:
- break;
- }
-
ast_bridge_unlock(bridge_channel->bridge);
/* Indicate a source change since this channel is leaving the bridge system. */
@@ -4123,6 +4175,446 @@
/*!
* \internal
+ * \brief Bridge ao2 container sort function.
+ * \since 12.0.0
+ *
+ * \param obj_left pointer to the (user-defined part) of an object.
+ * \param obj_right pointer to the (user-defined part) of an object.
+ * \param flags flags from ao2_callback()
+ * OBJ_POINTER - if set, 'obj_right', is an object.
+ * OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
+ * OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
+ *
+ * \retval <0 if obj_left < obj_right
+ * \retval =0 if obj_left == obj_right
+ * \retval >0 if obj_left > obj_right
+ */
+static int bridge_sort_cmp(const void *obj_left, const void *obj_right, int flags)
+{
+ const struct ast_bridge *bridge_left = obj_left;
+ const struct ast_bridge *bridge_right = obj_right;
+ const char *right_key = obj_right;
+ int cmp;
+
+ switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+ default:
+ case OBJ_POINTER:
+ right_key = bridge_right->uniqueid;
+ /* Fall through */
+ case OBJ_KEY:
+ cmp = strcmp(bridge_left->uniqueid, right_key);
+ break;
+ case OBJ_PARTIAL_KEY:
+ cmp = strncmp(bridge_left->uniqueid, right_key, strlen(right_key));
+ break;
+ }
+ return cmp;
+}
+
+struct bridge_complete {
+ /*! Nth match to return. */
+ int state;
+ /*! Which match currently on. */
+ int which;
+};
+
+static int complete_bridge_search(void *obj, void *arg, void *data, int flags)
+{
+ struct bridge_complete *search = data;
+
+ if (++search->which > search->state) {
+ return CMP_MATCH;
+ }
+ return 0;
+}
+
+static char *complete_bridge(const char *word, int state)
+{
+ char *ret;
+ struct ast_bridge *bridge;
+ struct bridge_complete search = {
+ .state = state,
+ };
+
+ bridge = ao2_callback_data(bridges, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY,
+ complete_bridge_search, (char *) word, &search);
+ if (!bridge) {
+ return NULL;
+ }
+ ret = ast_strdup(bridge->uniqueid);
+ ao2_ref(bridge, -1);
+ return ret;
+}
+
+static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT_HDR "%-36s %5s %-15s %s\n"
+#define FORMAT_ROW "%-36s %5u %-15s %s\n"
+
+ struct ao2_iterator iter;
+ struct ast_bridge *bridge;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "bridge show all";
+ e->usage =
+ "Usage: bridge show all\n"
+ " List all bridges\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+/* BUGBUG this command may need to be changed to look at the stasis cache. */
+ ast_cli(a->fd, FORMAT_HDR, "Bridge-ID", "Chans", "Type", "Technology");
+ iter = ao2_iterator_init(bridges, 0);
+ for (; (bridge = ao2_iterator_next(&iter)); ao2_ref(bridge, -1)) {
+ ast_bridge_lock(bridge);
+ ast_cli(a->fd, FORMAT_ROW,
+ bridge->uniqueid,
+ bridge->num_channels,
+ bridge->v_table ? bridge->v_table->name : "<unknown>",
+ bridge->technology ? bridge->technology->name : "<unknown>");
+ ast_bridge_unlock(bridge);
+ }
+ ao2_iterator_destroy(&iter);
+ return CLI_SUCCESS;
+
+#undef FORMAT_HDR
+#undef FORMAT_ROW
+}
+
+static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ast_bridge *bridge;
+ struct ast_bridge_channel *bridge_channel;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "bridge show";
+ e->usage =
+ "Usage: bridge show <bridge-id>\n"
+ " Show information about the <bridge-id> bridge\n";
+ return NULL;
+ case CLI_GENERATE:
+ if (a->pos == 2) {
+ return complete_bridge(a->word, a->n);
+ }
+ return NULL;
+ }
+
+/* BUGBUG this command may need to be changed to look at the stasis cache. */
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+
+ bridge = ao2_find(bridges, a->argv[2], OBJ_KEY);
+ if (!bridge) {
+ ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);
+ return CLI_SUCCESS;
+ }
+
+ ast_bridge_lock(bridge);
+ ast_cli(a->fd, "Id: %s\n", bridge->uniqueid);
+ ast_cli(a->fd, "Type: %s\n", bridge->v_table ? bridge->v_table->name : "<unknown>");
+ ast_cli(a->fd, "Technology: %s\n",
+ bridge->technology ? bridge->technology->name : "<unknown>");
+ ast_cli(a->fd, "Num-Channels: %u\n", bridge->num_channels);
+ AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+ ast_cli(a->fd, "Channel: %s\n", ast_channel_name(bridge_channel->chan));
+ }
+ ast_bridge_unlock(bridge);
+ ao2_ref(bridge, -1);
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_bridge_destroy_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ast_bridge *bridge;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "bridge destroy";
+ e->usage =
+ "Usage: bridge destroy <bridge-id>\n"
+ " Destroy the <bridge-id> bridge\n";
+ return NULL;
+ case CLI_GENERATE:
+ if (a->pos == 2) {
+ return complete_bridge(a->word, a->n);
+ }
+ return NULL;
+ }
+
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+
+ bridge = ao2_find(bridges, a->argv[2], OBJ_KEY);
+ if (!bridge) {
+ ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);
+ return CLI_SUCCESS;
+ }
+
+ ast_cli(a->fd, "Destroying bridge '%s'\n", a->argv[2]);
+ ast_bridge_destroy(bridge);
+
+ return CLI_SUCCESS;
+}
+
+static char *complete_bridge_participant(const char *bridge_name, const char *line, const char *word, int pos, int state)
+{
+ RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+ struct ast_bridge_channel *bridge_channel;
+ int which;
+ int wordlen;
+
+ bridge = ao2_find(bridges, bridge_name, OBJ_KEY);
+ if (!bridge) {
+ return NULL;
+ }
+
+ {
+ SCOPED_LOCK(bridge_lock, bridge, ast_bridge_lock, ast_bridge_unlock);
+
+ which = 0;
+ wordlen = strlen(word);
+ AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+ if (!strncasecmp(ast_channel_name(bridge_channel->chan), word, wordlen)
+ && ++which > state) {
+ return ast_strdup(ast_channel_name(bridge_channel->chan));
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static char *handle_bridge_kick_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "bridge kick";
+ e->usage =
+ "Usage: bridge kick <bridge-id> <channel-name>\n"
+ " Kick the <channel-name> channel out of the <bridge-id> bridge\n";
+ return NULL;
+ case CLI_GENERATE:
+ if (a->pos == 2) {
+ return complete_bridge(a->word, a->n);
+ }
+ if (a->pos == 3) {
+ return complete_bridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
+ }
+ return NULL;
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ bridge = ao2_find(bridges, a->argv[2], OBJ_KEY);
+ if (!bridge) {
+ ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);
+ return CLI_SUCCESS;
+ }
+
+ chan = ast_channel_get_by_name_prefix(a->argv[3], strlen(a->argv[3]));
+ if (!chan) {
+ ast_cli(a->fd, "Channel '%s' not found\n", a->argv[3]);
+ return CLI_SUCCESS;
+ }
+
+/*
+ * BUGBUG the CLI kick needs to get the bridge to decide if it should dissolve.
+ *
+ * Likely the best way to do this is to add a kick method. The
+ * basic bridge class can then decide to dissolve the bridge if
+ * one of two channels is kicked.
+ *
+ * SIP/foo -- Local;1==Local;2 -- .... -- Local;1==Local;2 -- SIP/bar
+ * Kick a ;1 channel and the chain toward SIP/foo goes away.
+ * Kick a ;2 channel and the chain toward SIP/bar goes away.
+ *
+ * This can leave a local channel chain between the kicked ;1
+ * and ;2 channels that are orphaned until you manually request
+ * one of those channels to hangup or request the bridge to
+ * dissolve.
+ */
+ ast_cli(a->fd, "Kicking channel '%s' from bridge '%s'\n",
+ ast_channel_name(chan), a->argv[2]);
+ ast_bridge_remove(bridge, chan);
+
+ return CLI_SUCCESS;
+}
+
+/*! Bridge technology capabilities to string. */
+static const char *tech_capability2str(uint32_t capabilities)
+{
+ const char *type;
+
+ if (capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
+ type = "Holding";
+ } else if (capabilities & AST_BRIDGE_CAPABILITY_EARLY) {
+ type = "Early";
+ } else if (capabilities & AST_BRIDGE_CAPABILITY_NATIVE) {
+ type = "Native";
+ } else if (capabilities & AST_BRIDGE_CAPABILITY_1TO1MIX) {
+ type = "1to1Mix";
+ } else if (capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
+ type = "MultiMix";
+ } else {
+ type = "<Unknown>";
+ }
+ return type;
+}
+
+/*! Bridge technology priority preference to string. */
+static const char *tech_preference2str(enum ast_bridge_preference preference)
+{
+ const char *priority;
+
+ priority = "<Unknown>";
+ switch (preference) {
+ case AST_BRIDGE_PREFERENCE_HIGH:
+ priority = "High";
+ break;
+ case AST_BRIDGE_PREFERENCE_MEDIUM:
+ priority = "Medium";
+ break;
+ case AST_BRIDGE_PREFERENCE_LOW:
+ priority = "Low";
+ break;
+ }
+ return priority;
+}
+
+static char *handle_bridge_technology_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT "%-20s %-20s %-10s %s\n"
+
+ struct ast_bridge_technology *cur;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "bridge technology show";
+ e->usage =
+ "Usage: bridge technology show\n"
+ " List registered bridge technologies\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ ast_cli(a->fd, FORMAT, "Name", "Type", "Priority", "Suspended");
+ AST_RWLIST_RDLOCK(&bridge_technologies);
+ AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
+ const char *type;
+ const char *priority;
+
+ /* Decode type for display */
+ type = tech_capability2str(cur->capabilities);
+
+ /* Decode priority preference for display */
+ priority = tech_preference2str(cur->preference);
+
+ ast_cli(a->fd, FORMAT, cur->name, type, priority, AST_CLI_YESNO(cur->suspended));
+ }
+ AST_RWLIST_UNLOCK(&bridge_technologies);
+ return CLI_SUCCESS;
+
+#undef FORMAT
+}
+
+static char *complete_bridge_technology(const char *word, int state)
+{
+ struct ast_bridge_technology *cur;
+ char *res;
+ int which;
+ int wordlen;
+
+ which = 0;
+ wordlen = strlen(word);
+ AST_RWLIST_RDLOCK(&bridge_technologies);
+ AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
+ if (!strncasecmp(cur->name, word, wordlen) && ++which > state) {
+ res = ast_strdup(cur->name);
+ AST_RWLIST_UNLOCK(&bridge_technologies);
+ return res;
+ }
+ }
+ AST_RWLIST_UNLOCK(&bridge_technologies);
+ return NULL;
+}
+
+static char *handle_bridge_technology_suspend(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ast_bridge_technology *cur;
+ int suspend;
+ int successful;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "bridge technology {suspend|unsuspend}";
+ e->usage =
+ "Usage: bridge technology {suspend|unsuspend} <technology-name>\n"
+ " Suspend or unsuspend a bridge technology.\n";
+ return NULL;
+ case CLI_GENERATE:
+ if (a->pos == 3) {
+ return complete_bridge_technology(a->word, a->n);
+ }
+ return NULL;
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ suspend = !strcasecmp(a->argv[2], "suspend");
+ successful = 0;
+ AST_RWLIST_WRLOCK(&bridge_technologies);
+ AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
+ if (!strcasecmp(cur->name, a->argv[3])) {
+ successful = 1;
+ if (suspend) {
+ ast_bridge_technology_suspend(cur);
+ } else {
+ ast_bridge_technology_unsuspend(cur);
+ }
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&bridge_technologies);
+
+ if (successful) {
+ if (suspend) {
+ ast_cli(a->fd, "Suspended bridge technology '%s'\n", a->argv[3]);
+ } else {
+ ast_cli(a->fd, "Unsuspended bridge technology '%s'\n", a->argv[3]);
+ }
+ } else {
+ ast_cli(a->fd, "Bridge technology '%s' not found\n", a->argv[3]);
+ }
+
+ return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry bridge_cli[] = {
+ AST_CLI_DEFINE(handle_bridge_show_all, "List all bridges"),
+ AST_CLI_DEFINE(handle_bridge_show_specific, "Show information about a bridge"),
+ AST_CLI_DEFINE(handle_bridge_destroy_specific, "Destroy a bridge"),
+ AST_CLI_DEFINE(handle_bridge_kick_channel, "Kick a channel from a bridge"),
+ AST_CLI_DEFINE(handle_bridge_technology_show, "List registered bridge technologies"),
+ AST_CLI_DEFINE(handle_bridge_technology_suspend, "Suspend/unsuspend a bridge technology"),
+};
+
+/*!
+ * \internal
* \brief Shutdown the bridging system.
* \since 12.0.0
*
@@ -4130,6 +4622,9 @@
*/
static void bridge_shutdown(void)
{
+ ast_cli_unregister_multiple(bridge_cli, ARRAY_LEN(bridge_cli));
+ ao2_cleanup(bridges);
+ bridges = NULL;
ao2_cleanup(bridge_manager);
bridge_manager = NULL;
ast_stasis_bridging_shutdown();
@@ -4144,8 +4639,19 @@
bridge_manager = bridge_manager_create();
if (!bridge_manager) {
+ bridge_shutdown();
return -1;
}
+
+ bridges = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX,
+ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, bridge_sort_cmp, NULL);
+ if (!bridges) {
+ bridge_shutdown();
+ return -1;
+ }
+
+/* BUGBUG need AMI action equivalents to the CLI commands. */
+ ast_cli_register_multiple(bridge_cli, ARRAY_LEN(bridge_cli));
ast_register_atexit(bridge_shutdown);
return 0;
Modified: team/jrose/bridge_projects/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/features.c?view=diff&rev=385510&r1=385509&r2=385510
==============================================================================
--- team/jrose/bridge_projects/main/features.c (original)
+++ team/jrose/bridge_projects/main/features.c Fri Apr 12 12:12:09 2013
@@ -4432,7 +4432,7 @@
/* BUGBUG need to create the basic bridge class that will manage the DTMF feature hooks. */
bridge = ast_bridge_base_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_DISSOLVE_EMPTY | AST_BRIDGE_FLAG_SMART);
if (!bridge) {
ast_bridge_features_destroy(peer_features);
ast_bridge_features_cleanup(&chan_features);
More information about the asterisk-commits
mailing list