[asterisk-commits] jrose: branch jrose/bridge_projects r386683 - in /team/jrose/bridge_projects:...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Apr 26 16:31:06 CDT 2013
Author: jrose
Date: Fri Apr 26 16:31:02 2013
New Revision: 386683
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386683
Log:
merge new bridging changes including Richachard's ast_bridge_move function which replaces my hack implementation of it
Modified:
team/jrose/bridge_projects/ (props changed)
team/jrose/bridge_projects/apps/app_bridgewait.c
team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c
team/jrose/bridge_projects/bridges/bridge_simple.c
team/jrose/bridge_projects/configs/res_sip.conf.sample
team/jrose/bridge_projects/include/asterisk/bridging.h
team/jrose/bridge_projects/include/asterisk/bridging_features.h
team/jrose/bridge_projects/main/bridging.c
team/jrose/bridge_projects/res/parking/parking_applications.c
team/jrose/bridge_projects/res/parking/parking_bridge.c
team/jrose/bridge_projects/res/parking/parking_bridge_features.c
team/jrose/bridge_projects/res/parking/parking_controller.c
team/jrose/bridge_projects/res/parking/parking_ui.c
Propchange: team/jrose/bridge_projects/
------------------------------------------------------------------------------
--- bridge_construction-integrated (original)
+++ bridge_construction-integrated Fri Apr 26 16:31:02 2013
@@ -1,1 +1,1 @@
-/trunk:1-386543
+/trunk:1-386590
Propchange: team/jrose/bridge_projects/
------------------------------------------------------------------------------
--- bridge_projects-integrated (original)
+++ bridge_projects-integrated Fri Apr 26 16:31:02 2013
@@ -1,1 +1,1 @@
-/team/group/bridge_construction:1-386561
+/team/group/bridge_construction:1-386625
Modified: team/jrose/bridge_projects/apps/app_bridgewait.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/apps/app_bridgewait.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/apps/app_bridgewait.c (original)
+++ team/jrose/bridge_projects/apps/app_bridgewait.c Fri Apr 26 16:31:02 2013
@@ -196,7 +196,8 @@
ast_mutex_lock(&bridgewait_lock);
if (!holding_bridge) {
holding_bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
- AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM);
+ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
+ | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM);
}
ast_mutex_unlock(&bridgewait_lock);
if (!holding_bridge) {
Modified: team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c (original)
+++ team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c Fri Apr 26 16:31:02 2013
@@ -1915,6 +1915,7 @@
/* This option should only be used with the CONFBRIDGE dialplan function */
aco_option_register_custom(&cfg_info, "template", ACO_EXACT, user_types, NULL, user_template_handler, 0);
+/* BUGBUG need a user supplied bridge merge_priority to merge ConfBridges (default = 1, range 1-INT_MAX) */
/* Bridge options */
aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);
Modified: team/jrose/bridge_projects/bridges/bridge_simple.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/bridges/bridge_simple.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/bridges/bridge_simple.c (original)
+++ team/jrose/bridge_projects/bridges/bridge_simple.c Fri Apr 26 16:31:02 2013
@@ -70,15 +70,10 @@
{
struct ast_bridge_channel *other;
- /* If this is the only channel in this bridge then immediately exit */
- if (AST_LIST_FIRST(&bridge->channels) == AST_LIST_LAST(&bridge->channels)) {
+ /* Find the channel we actually want to write to */
+ other = ast_bridge_channel_peer(bridge_channel);
+ if (!other) {
return -1;
- }
-
- /* Find the channel we actually want to write to */
- other = AST_LIST_FIRST(&bridge->channels);
- if (other == bridge_channel) {
- other = AST_LIST_LAST(&bridge->channels);
}
/* The bridging core takes care of freeing the passed in frame. */
Modified: team/jrose/bridge_projects/configs/res_sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/configs/res_sip.conf.sample?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/configs/res_sip.conf.sample (original)
+++ team/jrose/bridge_projects/configs/res_sip.conf.sample Fri Apr 26 16:31:02 2013
@@ -1,10 +1,10 @@
; This is an in-flux configuration file for the res_sip module, it will change as things progress
;;; Transports
-[local]
-type=transport
-protocol=udp ; Supported protocols are udp, tcp, and tls
-bind=0.0.0.0 ; This supports both IPv4 and IPv6, port is optional
+;[local]
+;type=transport
+;protocol=udp ; Supported protocols are udp, tcp, and tls
+;bind=0.0.0.0 ; This supports both IPv4 and IPv6, port is optional
;;; Endpoints
[endpoint]
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=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/bridging.h (original)
+++ team/jrose/bridge_projects/include/asterisk/bridging.h Fri Apr 26 16:31:02 2013
@@ -351,6 +351,17 @@
typedef void (*ast_bridge_notify_masquerade_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel);
/*!
+ * \brief Get the merge priority of this bridge.
+ *
+ * \param self Bridge to operate upon.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \return Merge priority
+ */
+typedef int (*ast_bridge_merge_priority_fn)(struct ast_bridge *self);
+
+/*!
* \brief Bridge virtual methods table definition.
*
* \note Any changes to this struct must be reflected in
@@ -369,6 +380,8 @@
ast_bridge_pull_channel_fn pull;
/*! Notify the bridge of a masquerade with the channel. */
ast_bridge_notify_masquerade_fn notify_masquerade;
+ /*! Get the bridge merge priority. */
+ ast_bridge_merge_priority_fn get_merge_priority;
};
/*!
@@ -768,20 +781,19 @@
int ast_bridge_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge);
/*!
- * \brief XXX Hack function for moving a channel from one bridge to another
- *
- * \param bridge_src bridge the channel is being moved from
- * \param bridge_dst bridge the chnanel is being moved to
- * \param chan Channel being moved
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \code
- * ast_bridge_move(old_bridge, new_bridge, chan);
- * \endcode
- */
-int ast_bridge_move(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan);
+ * \brief Move a channel from one bridge to another.
+ * \since 12.0.0
+ *
+ * \param dst_bridge Destination bridge of bridge channel move.
+ * \param src_bridge Source bridge of bridge channel move.
+ * \param chan Channel to move.
+ * \param swap Channel to replace in dst_bridge.
+ * \param attempt_recovery TRUE if failure attempts to push channel back into original bridge.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery);
/*!
* \brief Adjust the bridge merge inhibit request count.
@@ -1197,6 +1209,21 @@
void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel);
/*!
+ * \brief Get the peer bridge channel of a two party bridge.
+ * \since 12.0.0
+ *
+ * \param bridge_channel What to get the peer of.
+ *
+ * \note On entry, bridge_channel->bridge is already locked.
+ *
+ * \note This is an internal bridge function.
+ *
+ * \retval peer on success.
+ * \retval NULL no peer channel.
+ */
+struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel);
+
+/*!
* \brief Adjust the internal mixing sample rate of a bridge
* used during multimix mode.
*
Modified: team/jrose/bridge_projects/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/include/asterisk/bridging_features.h?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/bridging_features.h (original)
+++ team/jrose/bridge_projects/include/asterisk/bridging_features.h Fri Apr 26 16:31:02 2013
@@ -40,8 +40,12 @@
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 cannot be local channel swap optimized from this bridge. */
+ AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM = (1 << 5),
+ /*! Bridge channels cannot be local channel swap optimized to this bridge. */
+ AST_BRIDGE_FLAG_SWAP_INHIBIT_TO = (1 << 6),
/*! Bridge channels can be moved to another bridge only by masquerade (ConfBridge) */
- AST_BRIDGE_FLAG_MASQUERADE_ONLY = (1 << 5),
+ AST_BRIDGE_FLAG_MASQUERADE_ONLY = (1 << 7),
};
/*! \brief Flags used for per bridge channel features */
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=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/main/bridging.c (original)
+++ team/jrose/bridge_projects/main/bridging.c Fri Apr 26 16:31:02 2013
@@ -1261,7 +1261,8 @@
|| !v_table->dissolving
|| !v_table->push
|| !v_table->pull
- || !v_table->notify_masquerade) {
+ || !v_table->notify_masquerade
+ || !v_table->get_merge_priority) {
ast_log(LOG_ERROR, "Virtual method table for bridge class %s not complete.\n",
v_table && v_table->name ? v_table->name : "<unknown>");
ast_assert(0);
@@ -1407,6 +1408,22 @@
self->reconfigured = 1;
}
+/*!
+ * \internal
+ * \brief Get the merge priority of this bridge.
+ * \since 12.0.0
+ *
+ * \param self Bridge to operate upon.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \return Merge priority
+ */
+static int bridge_base_get_merge_priority(struct ast_bridge *self)
+{
+ return 0;
+}
+
struct ast_bridge_methods ast_bridge_base_v_table = {
.name = "base",
.destroy = bridge_base_destroy,
@@ -1414,6 +1431,7 @@
.push = bridge_base_push,
.pull = bridge_base_pull,
.notify_masquerade = bridge_base_notify_masquerade,
+ .get_merge_priority = bridge_base_get_merge_priority,
};
struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags)
@@ -3073,66 +3091,6 @@
return 0;
}
-static void ast_bridge_move_do(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan)
-{
- struct ast_bridge_channel *bridge_channel;
-
- ast_debug(1, "Moving channel %s from bridge %p into bridge %p\n", ast_channel_name(chan), bridge_src, bridge_dst);
-
- AST_LIST_TRAVERSE(&bridge_src->channels, bridge_channel, entry) {
- if (bridge_channel->chan == chan) {
- break;
- }
- }
-
- bridge_channel_pull(bridge_channel);
-
- /* Point to new bridge. */
- ao2_ref(bridge_dst, +1);
- ast_bridge_channel_lock(bridge_channel);
- bridge_channel->bridge = bridge_dst;
- ast_bridge_channel_unlock(bridge_channel);
- ao2_ref(bridge_src, -1);
-
- bridge_channel_push(bridge_channel);
-
- bridge_reconfigured(bridge_dst);
- bridge_reconfigured(bridge_src);
-
- ast_debug(1, "Moved channel %s from bridge %p into bridge %p\n", ast_channel_name(chan), bridge_src, bridge_dst);
-}
-
-int ast_bridge_move(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan)
-{
- int res = -1;
-
- /* Deadlock avoidance. */
- for (;;) {
- ast_bridge_lock(bridge_src);
- if (!ast_bridge_trylock(bridge_dst)) {
- break;
- }
- ast_bridge_unlock(bridge_src);
- sched_yield();
- }
-
- if (bridge_src->dissolved || bridge_dst->dissolved) {
- ast_debug(1, "Can't move from bridge %p into bridge %p, one or both bridges are dissolved.\n",
- bridge_src, bridge_dst);
- } else {
- ++bridge_src->inhibit_merge;
- ++bridge_dst->inhibit_merge;
- ast_bridge_move_do(bridge_src, bridge_dst, chan);
- --bridge_dst->inhibit_merge;
- --bridge_src->inhibit_merge;
- res = 0;
- }
-
- ast_bridge_unlock(bridge_dst);
- ast_bridge_unlock(bridge_src);
- return res;
-}
-
/*!
* \internal
* \brief Do the merge of two bridges.
@@ -3227,6 +3185,114 @@
/*!
* \internal
+ * \brief Move a bridge channel from one bridge to another.
+ * \since 12.0.0
+ *
+ * \param dst_bridge Destination bridge of bridge channel move.
+ * \param bridge_channel Channel moving from one bridge to another.
+ * \param attempt_recovery TRUE if failure attempts to push channel back into original bridge.
+ *
+ * \note The dst_bridge and bridge_channel->bridge are assumed already locked.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+static int bridge_move_do(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bridge_channel, int attempt_recovery)
+{
+ struct ast_bridge *orig_bridge;
+ int was_in_bridge;
+ int res = 0;
+
+/* BUGBUG need bridge move stasis event and a success/fail event. */
+ if (bridge_channel->swap) {
+ ast_debug(1, "Moving %p(%s) into bridge %s swapping with %s\n",
+ bridge_channel, ast_channel_name(bridge_channel->chan), dst_bridge->uniqueid,
+ ast_channel_name(bridge_channel->swap));
+ } else {
+ ast_debug(1, "Moving %p(%s) into bridge %s\n",
+ bridge_channel, ast_channel_name(bridge_channel->chan), dst_bridge->uniqueid);
+ }
+
+ orig_bridge = bridge_channel->bridge;
+ was_in_bridge = bridge_channel->in_bridge;
+
+ bridge_channel_pull(bridge_channel);
+
+ /* Point to new bridge.*/
+ ao2_ref(dst_bridge, +1);
+ ast_bridge_channel_lock(bridge_channel);
+ bridge_channel->bridge = dst_bridge;
+ ast_bridge_channel_unlock(bridge_channel);
+
+ if (bridge_channel_push(bridge_channel)) {
+ /* Try to put the channel back into the original bridge. */
+ if (attempt_recovery && was_in_bridge) {
+ /* Point back to original bridge. */
+ ao2_ref(orig_bridge, +1);
+ ast_bridge_channel_lock(bridge_channel);
+ bridge_channel->bridge = orig_bridge;
+ ast_bridge_channel_unlock(bridge_channel);
+ ao2_ref(dst_bridge, -1);
+
+ if (bridge_channel_push(bridge_channel)) {
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ }
+ res = -1;
+ }
+
+ bridge_reconfigured(dst_bridge);
+ bridge_reconfigured(orig_bridge);
+ ao2_ref(orig_bridge, -1);
+ return res;
+}
+
+int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery)
+{
+ struct ast_bridge_channel *bridge_channel;
+ int res = -1;
+
+ ast_bridge_lock_both(dst_bridge, src_bridge);
+
+ bridge_channel = find_bridge_channel(src_bridge, chan);
+ if (!bridge_channel) {
+ ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, channel not in bridge.\n",
+ ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
+ } else if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+ ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, channel leaving bridge.\n",
+ ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
+ } else if (dst_bridge->dissolved || src_bridge->dissolved) {
+ ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, one or both bridges are dissolved.\n",
+ ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
+ } else {
+ bridge_channel->swap = swap;
+ res = bridge_move_do(dst_bridge, bridge_channel, attempt_recovery);
+ }
+
+ ast_bridge_unlock(src_bridge);
+ ast_bridge_unlock(dst_bridge);
+ return res;
+}
+
+struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
+{
+ struct ast_bridge *bridge = bridge_channel->bridge;
+ struct ast_bridge_channel *other = NULL;
+
+ if (bridge_channel->in_bridge && bridge->num_channels == 2) {
+ other = AST_LIST_FIRST(&bridge->channels);
+ if (other == bridge_channel) {
+ other = AST_LIST_LAST(&bridge->channels);
+ }
+ }
+
+ return other;
+}
+
+/*!
+ * \internal
* \brief Lock the local channel stack for chan and prequalify it.
* \since 12.0.0
*
@@ -3259,6 +3325,7 @@
if (bridge->inhibit_merge
|| bridge->dissolved
|| ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)
+ || !bridge_channel->in_bridge
|| !AST_LIST_EMPTY(&bridge_channel->wr_queue)) {
ast_bridge_unlock(bridge);
ast_bridge_channel_unlock(bridge_channel);
@@ -3305,6 +3372,7 @@
if (bridge->inhibit_merge
|| bridge->dissolved
|| ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)
+ || !bridge_channel->in_bridge
|| !AST_LIST_EMPTY(&bridge_channel->wr_queue)) {
ast_bridge_unlock(bridge);
ast_bridge_channel_unlock(bridge_channel);
@@ -3314,76 +3382,207 @@
return bridge;
}
-int ast_bridge_local_optimized_out(struct ast_channel *chan, struct ast_channel *peer)
-{
- struct ast_bridge *chan_bridge;
- struct ast_bridge *peer_bridge;
- struct ast_bridge_channel *chan_bridge_channel;
- struct ast_bridge_channel *peer_bridge_channel;
+/*!
+ * \internal
+ * \brief Check and attempt to swap optimize out the local channels.
+ * \since 12.0.0
+ *
+ * \param chan_bridge
+ * \param chan_bridge_channel
+ * \param peer_bridge
+ * \param peer_bridge_channel
+ *
+ * \retval 1 if local channels failed to optimize out.
+ * \retval 0 if local channels were not optimized out.
+ * \retval -1 if local channels were optimized out.
+ */
+static int check_swap_optimize_out(struct ast_bridge *chan_bridge,
+ struct ast_bridge_channel *chan_bridge_channel, struct ast_bridge *peer_bridge,
+ struct ast_bridge_channel *peer_bridge_channel)
+{
+ struct ast_bridge *dst_bridge = NULL;
+ struct ast_bridge *src_bridge = NULL;
+ struct ast_bridge_channel *dst_bridge_channel = NULL;
+ struct ast_bridge_channel *src_bridge_channel = NULL;
+ int peer_priority;
+ int chan_priority;
int res = 0;
- chan_bridge = optimize_lock_chan_stack(chan);
- if (!chan_bridge) {
- return res;
- }
- chan_bridge_channel = ast_channel_internal_bridge_channel(chan);
-
- peer_bridge = optimize_lock_peer_stack(peer);
- if (peer_bridge) {
- struct ast_bridge *dst_bridge = NULL;
- struct ast_bridge *src_bridge = NULL;
-
- peer_bridge_channel = ast_channel_internal_bridge_channel(peer);
-
- if (!ast_test_flag(&chan_bridge->feature_flags,
- AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)
- && !ast_test_flag(&peer_bridge->feature_flags,
- AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
-/* BUGBUG need to have a merge priority bridge class method to help determine which way to optimize merge. */
- /* Can merge either way. */
+ if (!ast_test_flag(&chan_bridge->feature_flags,
+ AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM)
+ && !ast_test_flag(&peer_bridge->feature_flags,
+ AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM)) {
+ /*
+ * Can swap either way. Swap to the higher priority merge
+ * bridge.
+ */
+ chan_priority = chan_bridge->v_table->get_merge_priority(chan_bridge);
+ peer_priority = peer_bridge->v_table->get_merge_priority(peer_bridge);
+ if (chan_bridge->num_channels == 2
+ && chan_priority <= peer_priority) {
+ dst_bridge = peer_bridge;
+ src_bridge = chan_bridge;
+ dst_bridge_channel = peer_bridge_channel;
+ src_bridge_channel = chan_bridge_channel;
+ } else if (peer_bridge->num_channels == 2
+ && peer_priority <= chan_priority) {
+ dst_bridge = chan_bridge;
+ src_bridge = peer_bridge;
+ dst_bridge_channel = chan_bridge_channel;
+ src_bridge_channel = peer_bridge_channel;
+ }
+ } else if (chan_bridge->num_channels == 2
+ && !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM)
+ && !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_TO)) {
+ /* Can swap optimize only one way. */
+ dst_bridge = peer_bridge;
+ src_bridge = chan_bridge;
+ dst_bridge_channel = peer_bridge_channel;
+ src_bridge_channel = chan_bridge_channel;
+ } else if (peer_bridge->num_channels == 2
+ && !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM)
+ && !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_TO)) {
+ /* Can swap optimize only one way. */
+ dst_bridge = chan_bridge;
+ src_bridge = peer_bridge;
+ dst_bridge_channel = chan_bridge_channel;
+ src_bridge_channel = peer_bridge_channel;
+ }
+ if (dst_bridge) {
+ struct ast_bridge_channel *other;
+
+ res = 1;
+ other = ast_bridge_channel_peer(src_bridge_channel);
+ if (other) {
+ ast_debug(1, "Move-swap optimizing %s <-- %s.\n",
+ ast_channel_name(dst_bridge_channel->chan),
+ ast_channel_name(other->chan));
+
+ other->swap = dst_bridge_channel->chan;
+ if (!bridge_move_do(dst_bridge, other, 1)) {
+ ast_bridge_change_state(src_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ res = -1;
+ }
+ }
+ }
+ return res;
+}
+
+/*!
+ * \internal
+ * \brief Check and attempt to merge optimize out the local channels.
+ * \since 12.0.0
+ *
+ * \param chan_bridge
+ * \param chan_bridge_channel
+ * \param peer_bridge
+ * \param peer_bridge_channel
+ *
+ * \retval 0 if local channels were not optimized out.
+ * \retval -1 if local channels were optimized out.
+ */
+static int check_merge_optimize_out(struct ast_bridge *chan_bridge,
+ struct ast_bridge_channel *chan_bridge_channel, struct ast_bridge *peer_bridge,
+ struct ast_bridge_channel *peer_bridge_channel)
+{
+ struct ast_bridge *dst_bridge = NULL;
+ struct ast_bridge *src_bridge = NULL;
+ int peer_priority;
+ int chan_priority;
+ int res = 0;
+
+ if (!ast_test_flag(&chan_bridge->feature_flags,
+ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)
+ && !ast_test_flag(&peer_bridge->feature_flags,
+ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
+ /*
+ * Can merge either way. Merge to the higher priority merge
+ * bridge. Otherwise merge to the larger bridge.
+ */
+ chan_priority = chan_bridge->v_table->get_merge_priority(chan_bridge);
+ peer_priority = peer_bridge->v_table->get_merge_priority(peer_bridge);
+ if (peer_priority < chan_priority) {
+ dst_bridge = chan_bridge;
+ src_bridge = peer_bridge;
+ } else if (chan_priority < peer_priority) {
+ dst_bridge = peer_bridge;
+ src_bridge = chan_bridge;
+ } else {
+ /* Merge to the larger bridge. */
if (peer_bridge->num_channels <= chan_bridge->num_channels) {
- /* Merge to the larger bridge. */
dst_bridge = chan_bridge;
src_bridge = peer_bridge;
} else {
dst_bridge = peer_bridge;
src_bridge = chan_bridge;
}
- } else if (!ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
- && !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
- /* Can merge only one way. */
- dst_bridge = chan_bridge;
- src_bridge = peer_bridge;
- } else if (!ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
- && !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
- /* Can merge only one way. */
- dst_bridge = peer_bridge;
- src_bridge = chan_bridge;
- }
-
- if (dst_bridge) {
- if (src_bridge->num_channels < 2 || dst_bridge->num_channels < 2) {
- ast_debug(4, "Can't optimize %s -- %s out, not enough channels in a bridge.\n",
- ast_channel_name(chan), ast_channel_name(peer));
- } else if ((2 + 2) < dst_bridge->num_channels + src_bridge->num_channels
- && !(dst_bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX)
- && !ast_test_flag(&dst_bridge->feature_flags, AST_BRIDGE_FLAG_SMART)) {
- ast_debug(4, "Can't optimize %s -- %s out, multimix is needed and it cannot be acquired.\n",
- ast_channel_name(chan), ast_channel_name(peer));
- } else {
- struct ast_bridge_channel *kick_me[] = {
- chan_bridge_channel,
- peer_bridge_channel,
- };
-
- ast_debug(1, "Optimizing %s -- %s out.\n",
- ast_channel_name(chan), ast_channel_name(peer));
-
- bridge_merge_do(dst_bridge, src_bridge, kick_me, ARRAY_LEN(kick_me));
- res = -1;
- }
+ }
+ } else if (!ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
+ && !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
+ /* Can merge only one way. */
+ dst_bridge = chan_bridge;
+ src_bridge = peer_bridge;
+ } else if (!ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
+ && !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
+ /* Can merge only one way. */
+ dst_bridge = peer_bridge;
+ src_bridge = chan_bridge;
+ }
+
+ if (dst_bridge) {
+ if (src_bridge->num_channels < 2 || dst_bridge->num_channels < 2) {
+ ast_debug(4, "Can't optimize %s -- %s out, not enough channels in a bridge.\n",
+ ast_channel_name(chan_bridge_channel->chan),
+ ast_channel_name(peer_bridge_channel->chan));
+ } else if ((2 + 2) < dst_bridge->num_channels + src_bridge->num_channels
+ && !(dst_bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX)
+ && !ast_test_flag(&dst_bridge->feature_flags, AST_BRIDGE_FLAG_SMART)) {
+ ast_debug(4, "Can't optimize %s -- %s out, multimix is needed and it cannot be acquired.\n",
+ ast_channel_name(chan_bridge_channel->chan),
+ ast_channel_name(peer_bridge_channel->chan));
} else {
-/* BUGBUG this is where we would decide if we can swap a channel instead of merging. */
+ struct ast_bridge_channel *kick_me[] = {
+ chan_bridge_channel,
+ peer_bridge_channel,
+ };
+
+ ast_debug(1, "Merge optimizing %s -- %s out.\n",
+ ast_channel_name(chan_bridge_channel->chan),
+ ast_channel_name(peer_bridge_channel->chan));
+
+ bridge_merge_do(dst_bridge, src_bridge, kick_me, ARRAY_LEN(kick_me));
+ res = -1;
+ }
+ }
+
+ return res;
+}
+
+int ast_bridge_local_optimized_out(struct ast_channel *chan, struct ast_channel *peer)
+{
+ struct ast_bridge *chan_bridge;
+ struct ast_bridge *peer_bridge;
+ struct ast_bridge_channel *chan_bridge_channel;
+ struct ast_bridge_channel *peer_bridge_channel;
+ int res = 0;
+
+ chan_bridge = optimize_lock_chan_stack(chan);
+ if (!chan_bridge) {
+ return res;
+ }
+ chan_bridge_channel = ast_channel_internal_bridge_channel(chan);
+
+ peer_bridge = optimize_lock_peer_stack(peer);
+ if (peer_bridge) {
+ peer_bridge_channel = ast_channel_internal_bridge_channel(peer);
+
+ res = check_swap_optimize_out(chan_bridge, chan_bridge_channel,
+ peer_bridge, peer_bridge_channel);
+ if (!res) {
+ res = check_merge_optimize_out(chan_bridge, chan_bridge_channel,
+ peer_bridge, peer_bridge_channel);
+ } else if (0 < res) {
+ res = 0;
}
/* Release peer locks. */
Modified: team/jrose/bridge_projects/res/parking/parking_applications.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_applications.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_applications.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_applications.c Fri Apr 26 16:31:02 2013
@@ -494,7 +494,7 @@
}
/* Move the parkee into the new bridge */
- if (ast_bridge_move(lot->parking_bridge, retrieval_bridge, pu->chan)) {
+ if (ast_bridge_move(retrieval_bridge, lot->parking_bridge, pu->chan, NULL, 0)) {
ast_bridge_destroy(retrieval_bridge);
return -1;
}
Modified: team/jrose/bridge_projects/res/parking/parking_bridge.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_bridge.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_bridge.c Fri Apr 26 16:31:02 2013
@@ -192,7 +192,8 @@
if (swap) {
pu = swap->bridge_pvt;
if (!pu) {
- /* This should be impossible since the only way a channel can enter in the first place is if it has a parked user associated with it */
+ /* This should be impossible since the only way a channel can enter in the first place
+ * is if it has a parked user associated with it */
publish_parked_call_failure(bridge_channel->chan);
return -1;
}
@@ -210,6 +211,20 @@
get_park_common_datastore_data(bridge_channel->chan, &parker_uuid, &randomize, &time_limit, &silence);
parker = ast_channel_get_by_name(parker_uuid);
+ /* If the parker and the parkee are the same channel pointer, then the channel entered using
+ * the park application. It's possible the the blindtransfer channel is still alive (particularly
+ * when a multichannel bridge is parked), so try to get the real parker if possible. */
+ blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"),
+ ast_channel_name(bridge_channel->chan));
+
+ if (parker == bridge_channel->chan) {
+ struct ast_channel *real_parker = ast_channel_get_by_name(blind_transfer);
+ if (real_parker) {
+ ao2_cleanup(parker);
+ parker = real_parker;
+ }
+ }
+
if (!parker) {
return -1;
}
@@ -228,8 +243,6 @@
/* Raise bridged flag so that the call can actually be retrieved. XXX this whole concept probably isn't necessary any more. */
pu->bridged = 1;
-
- blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"), ast_channel_name(bridge_channel->chan));
/* If the parkee and the parker are the same and silence_announce isn't set, play the announcement to the parkee */
if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !silence) {
@@ -328,6 +341,11 @@
static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
{
ast_bridge_base_v_table.notify_masquerade(&self->base, bridge_channel);
+}
+
+static void bridge_parking_get_merge_priority(struct ast_bridge_parking *self)
+{
+ ast_bridge_base_v_table.get_merge_priority(&self->base);
}
struct ast_bridge_methods ast_bridge_parking_v_table = {
@@ -337,6 +355,7 @@
.push = (ast_bridge_push_channel_fn) bridge_parking_push,
.pull = (ast_bridge_pull_channel_fn) bridge_parking_pull,
.notify_masquerade = (ast_bridge_notify_masquerade_fn) bridge_parking_notify_masquerade,
+ .get_merge_priority = (ast_bridge_merge_priority_fn) bridge_parking_get_merge_priority,
};
static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot *bridge_lot)
@@ -363,7 +382,8 @@
bridge = ast_bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
bridge = ast_bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
- AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM);
+ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
+ | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM);
bridge = ast_bridge_parking_init(bridge, bridge_lot);
bridge = ast_bridge_register(bridge);
return bridge;
Modified: team/jrose/bridge_projects/res/parking/parking_bridge_features.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_bridge_features.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge_features.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_bridge_features.c Fri Apr 26 16:31:02 2013
@@ -350,7 +350,9 @@
return;
}
- if (ast_bridge_move(bridge_channel->bridge, parking_bridge, bridge_channel->chan)) {
+ pbx_builtin_setvar_helper(bridge_channel->chan, "BLINDTRANSFER", ast_channel_name(parker));
+
+ if (ast_bridge_move(parking_bridge, bridge_channel->bridge, bridge_channel->chan, NULL, 1)) {
ast_log(LOG_ERROR, "Failed to move %s into the parking bridge.\n",
ast_channel_name(bridge_channel->chan));
}
Modified: team/jrose/bridge_projects/res/parking/parking_controller.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_controller.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_controller.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_controller.c Fri Apr 26 16:31:02 2013
@@ -252,7 +252,13 @@
int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
{
struct ast_channel *chan = pu->chan;
- char *peername = ast_strdupa(pu->parker->name);
+ char *peername;
+ const char *blindtransfer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
+
+ peername = blindtransfer ? ast_strdupa(blindtransfer) : ast_strdupa(pu->parker->name);
+
+ /* XXX Comeback to origin mode: Generate an extension in park-dial to Dial the peer */
+
/* Flatten the peername so that it can be used for performing the timeout PBX operations */
flatten_peername(peername);
Modified: team/jrose/bridge_projects/res/parking/parking_ui.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_ui.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_ui.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_ui.c Fri Apr 26 16:31:02 2013
@@ -42,6 +42,7 @@
{
ast_cli(fd, " Space: %d\n", user->parking_space);
ast_cli(fd, " Channel: %s\n", ast_channel_name(user->chan));
+ ast_cli(fd, " Parker: %s\n", user->parker ? user->parker->name : "<unknown>");
ast_cli(fd, "\n");
}
More information about the asterisk-commits
mailing list