[svn-commits] mmichelson: trunk r395151 - in /trunk: bridges/ include/asterisk/ main/
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Tue Jul 23 10:28:22 CDT 2013
Author: mmichelson
Date: Tue Jul 23 10:28:11 2013
New Revision: 395151
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395151
Log:
Make DTMF attended transfer support feature-complete.
This greatly modifies the operation of DTMF attended transfers so that
the full range of options from features.conf applies.
In addition, a new option has been added that allows for a transferer
to switch between bridges during a transfer before completing the
transfer.
(closes issue ASTERISK-21543)
reported by Matt Jordan
Review: https://reviewboard.asterisk.org/r/2654
Added:
trunk/include/asterisk/bridging_internal.h (with props)
Modified:
trunk/bridges/bridge_builtin_features.c
trunk/include/asterisk/bridging.h
trunk/include/asterisk/bridging_features.h
trunk/include/asterisk/bridging_roles.h
trunk/include/asterisk/features_config.h
trunk/include/asterisk/stasis_bridging.h
trunk/main/bridging.c
trunk/main/bridging_basic.c
trunk/main/bridging_roles.c
trunk/main/cel.c
trunk/main/features.c
trunk/main/features_config.c
trunk/main/stasis_bridging.c
Modified: trunk/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/trunk/bridges/bridge_builtin_features.c?view=diff&rev=395151&r1=395150&r2=395151
==============================================================================
--- trunk/bridges/bridge_builtin_features.c (original)
+++ trunk/bridges/bridge_builtin_features.c Tue Jul 23 10:28:11 2013
@@ -54,421 +54,6 @@
#include "asterisk/mixmonitor.h"
#include "asterisk/audiohook.h"
-/*!
- * \brief Helper function that presents dialtone and grabs extension
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)
-{
- int res;
- int digit_timeout;
- RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
-
- ast_channel_lock(chan);
- xfer_cfg = ast_get_chan_features_xfer_config(chan);
- if (!xfer_cfg) {
- ast_log(LOG_ERROR, "Unable to get transfer configuration\n");
- ast_channel_unlock(chan);
- return -1;
- }
- digit_timeout = xfer_cfg->transferdigittimeout;
- ast_channel_unlock(chan);
-
- /* Play the simple "transfer" prompt out and wait */
- res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
- ast_stopstream(chan);
- if (res < 0) {
- /* Hangup or error */
- return -1;
- }
- if (res) {
- /* Store the DTMF digit that interrupted playback of the file. */
- exten[0] = res;
- }
-
- /* Drop to dialtone so they can enter the extension they want to transfer to */
- res = ast_app_dtget(chan, context, exten, exten_len, exten_len - 1, digit_timeout);
- if (res < 0) {
- /* Hangup or error */
- res = -1;
- } else if (!res) {
- /* 0 for invalid extension dialed. */
- if (ast_strlen_zero(exten)) {
- ast_debug(1, "%s dialed no digits.\n", ast_channel_name(chan));
- } else {
- ast_debug(1, "%s dialed '%s@%s' does not exist.\n",
- ast_channel_name(chan), exten, context);
- }
- ast_stream_and_wait(chan, "pbx-invalid", AST_DIGIT_NONE);
- res = -1;
- } else {
- /* Dialed extension is valid. */
- res = 0;
- }
- return res;
-}
-
-static void copy_caller_data(struct ast_channel *dest, struct ast_channel *caller)
-{
- ast_channel_lock_both(caller, dest);
- ast_connected_line_copy_from_caller(ast_channel_connected(dest), ast_channel_caller(caller));
- ast_channel_inherit_variables(caller, dest);
- ast_channel_datastore_inherit(caller, dest);
- ast_channel_unlock(dest);
- ast_channel_unlock(caller);
-}
-
-/*! \brief Helper function that creates an outgoing channel and returns it immediately */
-static struct ast_channel *dial_transfer(struct ast_channel *caller, const char *exten, const char *context)
-{
- char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
- struct ast_channel *chan;
- int cause;
-
- /* Fill the variable with the extension and context we want to call */
- snprintf(destination, sizeof(destination), "%s@%s", exten, context);
-
- /* Now we request a local channel to prepare to call the destination */
- chan = ast_request("Local", ast_channel_nativeformats(caller), caller, destination,
- &cause);
- if (!chan) {
- return NULL;
- }
-
- /* Who is transferring the call. */
- pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", ast_channel_name(caller));
-
- /* To work as an analog to BLINDTRANSFER */
- pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFER", ast_channel_name(caller));
-
- /* Before we actually dial out let's inherit appropriate information. */
- copy_caller_data(chan, caller);
-
- /* Since the above worked fine now we actually call it and return the channel */
- if (ast_call(chan, destination, 0)) {
- ast_hangup(chan);
- return NULL;
- }
-
- return chan;
-}
-
-/*!
- * \internal
- * \brief Determine the transfer context to use.
- * \since 12.0.0
- *
- * \param transferer Channel initiating the transfer.
- * \param context User supplied context if available. May be NULL.
- *
- * \return The context to use for the transfer.
- */
-static const char *get_transfer_context(struct ast_channel *transferer, const char *context)
-{
- if (!ast_strlen_zero(context)) {
- return context;
- }
- context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
- if (!ast_strlen_zero(context)) {
- return context;
- }
- context = ast_channel_macrocontext(transferer);
- if (!ast_strlen_zero(context)) {
- return context;
- }
- context = ast_channel_context(transferer);
- if (!ast_strlen_zero(context)) {
- return context;
- }
- return "default";
-}
-
-static void blind_transfer_cb(struct ast_channel *new_channel, void *user_data,
- enum ast_transfer_type transfer_type)
-{
- struct ast_channel *transferer_channel = user_data;
-
- if (transfer_type == AST_BRIDGE_TRANSFER_MULTI_PARTY) {
- copy_caller_data(new_channel, transferer_channel);
- }
-}
-
-/*! \brief Internal built in feature for blind transfers */
-static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
- char exten[AST_MAX_EXTENSION] = "";
- struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
- const char *context;
- char *goto_on_blindxfr;
-
- ast_bridge_channel_write_hold(bridge_channel, NULL);
-
- ast_channel_lock(bridge_channel->chan);
- context = ast_strdupa(get_transfer_context(bridge_channel->chan,
- blind_transfer ? blind_transfer->context : NULL));
- goto_on_blindxfr = ast_strdupa(S_OR(pbx_builtin_getvar_helper(bridge_channel->chan,
- "GOTO_ON_BLINDXFR"), ""));
- ast_channel_unlock(bridge_channel->chan);
-
- /* Grab the extension to transfer to */
- if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
- ast_bridge_channel_write_unhold(bridge_channel);
- return 0;
- }
-
- if (!ast_strlen_zero(goto_on_blindxfr)) {
- ast_debug(1, "After transfer, transferer %s goes to %s\n",
- ast_channel_name(bridge_channel->chan), goto_on_blindxfr);
- ast_after_bridge_set_go_on(bridge_channel->chan, NULL, NULL, 0, goto_on_blindxfr);
- }
-
- if (ast_bridge_transfer_blind(0, bridge_channel->chan, exten, context, blind_transfer_cb,
- bridge_channel->chan) != AST_BRIDGE_TRANSFER_SUCCESS &&
- !ast_strlen_zero(goto_on_blindxfr)) {
- ast_after_bridge_goto_discard(bridge_channel->chan);
- }
-
- return 0;
-}
-
-/*! Attended transfer code */
-enum atxfer_code {
- /*! Party C hungup or other reason to abandon the transfer. */
- ATXFER_INCOMPLETE,
- /*! Transfer party C to party A. */
- ATXFER_COMPLETE,
- /*! Turn the transfer into a threeway call. */
- ATXFER_THREEWAY,
- /*! Hangup party C and return party B to the bridge. */
- ATXFER_ABORT,
-};
-
-/*! \brief Attended transfer feature to complete transfer */
-static int attended_transfer_complete(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
- enum atxfer_code *transfer_code = hook_pvt;
-
- *transfer_code = ATXFER_COMPLETE;
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
- return 0;
-}
-
-/*! \brief Attended transfer feature to turn it into a threeway call */
-static int attended_transfer_threeway(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
- enum atxfer_code *transfer_code = hook_pvt;
-
- *transfer_code = ATXFER_THREEWAY;
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
- return 0;
-}
-
-/*! \brief Attended transfer feature to abort transfer */
-static int attended_transfer_abort(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
- enum atxfer_code *transfer_code = hook_pvt;
-
- *transfer_code = ATXFER_ABORT;
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
- return 0;
-}
-
-/*! \brief Internal built in feature for attended transfers */
-static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
- char exten[AST_MAX_EXTENSION] = "";
- struct ast_channel *peer;
- struct ast_bridge *attended_bridge;
- struct ast_bridge_features caller_features;
- int xfer_failed;
- struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
- const char *complete_sound;
- const char *context;
- enum atxfer_code transfer_code = ATXFER_INCOMPLETE;
- const char *atxfer_abort;
- const char *atxfer_threeway;
- const char *atxfer_complete;
- const char *fail_sound;
- RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
-
- ast_bridge_channel_write_hold(bridge_channel, NULL);
-
- bridge = ast_bridge_channel_merge_inhibit(bridge_channel, +1);
-
- ast_channel_lock(bridge_channel->chan);
- context = ast_strdupa(get_transfer_context(bridge_channel->chan,
- attended_transfer ? attended_transfer->context : NULL));
- xfer_cfg = ast_get_chan_features_xfer_config(bridge_channel->chan);
- if (!xfer_cfg) {
- ast_log(LOG_ERROR, "Unable to get transfer configuration options\n");
- ast_channel_unlock(bridge_channel->chan);
- return 0;
- }
- if (attended_transfer) {
- atxfer_abort = ast_strdupa(S_OR(attended_transfer->abort, xfer_cfg->atxferabort));
- atxfer_threeway = ast_strdupa(S_OR(attended_transfer->threeway, xfer_cfg->atxferthreeway));
- atxfer_complete = ast_strdupa(S_OR(attended_transfer->complete, xfer_cfg->atxfercomplete));
- } else {
- atxfer_abort = ast_strdupa(xfer_cfg->atxferabort);
- atxfer_threeway = ast_strdupa(xfer_cfg->atxferthreeway);
- atxfer_complete = ast_strdupa(xfer_cfg->atxfercomplete);
- }
- fail_sound = ast_strdupa(xfer_cfg->xferfailsound);
- ast_channel_unlock(bridge_channel->chan);
-
- /* Grab the extension to transfer to */
- if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
- ast_bridge_merge_inhibit(bridge, -1);
- ao2_ref(bridge, -1);
- ast_bridge_channel_write_unhold(bridge_channel);
- return 0;
- }
-
- /* Get a channel that is the destination we wish to call */
- peer = dial_transfer(bridge_channel->chan, exten, context);
- if (!peer) {
- ast_bridge_merge_inhibit(bridge, -1);
- ao2_ref(bridge, -1);
- ast_stream_and_wait(bridge_channel->chan, fail_sound, AST_DIGIT_NONE);
- ast_bridge_channel_write_unhold(bridge_channel);
- return 0;
- }
-
-/* BUGBUG bridging API features does not support the features.conf atxfer bounce between C & B channels */
- /* Setup a DTMF menu to control the transfer. */
- if (ast_bridge_features_init(&caller_features)
- || ast_bridge_hangup_hook(&caller_features,
- attended_transfer_complete, &transfer_code, NULL, 0)
- || ast_bridge_dtmf_hook(&caller_features, atxfer_abort,
- attended_transfer_abort, &transfer_code, NULL, 0)
- || ast_bridge_dtmf_hook(&caller_features, atxfer_complete,
- attended_transfer_complete, &transfer_code, NULL, 0)
- || ast_bridge_dtmf_hook(&caller_features, atxfer_threeway,
- attended_transfer_threeway, &transfer_code, NULL, 0)) {
- ast_bridge_features_cleanup(&caller_features);
- ast_hangup(peer);
- ast_bridge_merge_inhibit(bridge, -1);
- ao2_ref(bridge, -1);
- ast_stream_and_wait(bridge_channel->chan, fail_sound, AST_DIGIT_NONE);
- ast_bridge_channel_write_unhold(bridge_channel);
- return 0;
- }
-
- /* Create a bridge to use to talk to the person we are calling */
- attended_bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX,
- AST_BRIDGE_FLAG_DISSOLVE_HANGUP);
- if (!attended_bridge) {
- ast_bridge_features_cleanup(&caller_features);
- ast_hangup(peer);
- ast_bridge_merge_inhibit(bridge, -1);
- ao2_ref(bridge, -1);
- ast_stream_and_wait(bridge_channel->chan, fail_sound, AST_DIGIT_NONE);
- ast_bridge_channel_write_unhold(bridge_channel);
- return 0;
- }
- ast_bridge_merge_inhibit(attended_bridge, +1);
-
- /* This is how this is going down, we are imparting the channel we called above into this bridge first */
-/* BUGBUG we should impart the peer as an independent and move it to the original bridge. */
- if (ast_bridge_impart(attended_bridge, peer, NULL, NULL, 0)) {
- ast_bridge_destroy(attended_bridge);
- ast_bridge_features_cleanup(&caller_features);
- ast_hangup(peer);
- ast_bridge_merge_inhibit(bridge, -1);
- ao2_ref(bridge, -1);
- ast_stream_and_wait(bridge_channel->chan, fail_sound, AST_DIGIT_NONE);
- ast_bridge_channel_write_unhold(bridge_channel);
- return 0;
- }
-
- /*
- * For the caller we want to join the bridge in a blocking
- * fashion so we don't spin around in this function doing
- * nothing while waiting.
- */
- ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features, NULL, 0);
-
-/*
- * BUGBUG there is a small window where the channel does not point to the bridge_channel.
- *
- * This window is expected to go away when atxfer is redesigned
- * to fully support existing functionality. There will be one
- * and only one ast_bridge_channel structure per channel.
- */
- /* Point the channel back to the original bridge and bridge_channel. */
- ast_bridge_channel_lock(bridge_channel);
- ast_channel_lock(bridge_channel->chan);
- ast_channel_internal_bridge_channel_set(bridge_channel->chan, bridge_channel);
- ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);
- ast_channel_unlock(bridge_channel->chan);
- ast_bridge_channel_unlock(bridge_channel);
-
- /* Wait for peer thread to exit bridge and die. */
- if (!ast_autoservice_start(bridge_channel->chan)) {
- ast_bridge_depart(peer);
- ast_autoservice_stop(bridge_channel->chan);
- } else {
- ast_bridge_depart(peer);
- }
-
- /* Now that all channels are out of it we can destroy the bridge and the feature structures */
- ast_bridge_destroy(attended_bridge);
- ast_bridge_features_cleanup(&caller_features);
-
- /* Is there a courtesy sound to play to the peer? */
- ast_channel_lock(bridge_channel->chan);
- complete_sound = pbx_builtin_getvar_helper(bridge_channel->chan,
- "ATTENDED_TRANSFER_COMPLETE_SOUND");
- if (!ast_strlen_zero(complete_sound)) {
- complete_sound = ast_strdupa(complete_sound);
- } else {
- complete_sound = NULL;
- }
- ast_channel_unlock(bridge_channel->chan);
- if (complete_sound) {
- pbx_builtin_setvar_helper(peer, "BRIDGE_PLAY_SOUND", complete_sound);
- }
-
- xfer_failed = -1;
- switch (transfer_code) {
- case ATXFER_INCOMPLETE:
- /* Peer hungup */
- break;
- case ATXFER_COMPLETE:
- /* The peer takes our place in the bridge. */
- ast_bridge_channel_write_unhold(bridge_channel);
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
- xfer_failed = ast_bridge_impart(bridge_channel->bridge, peer, bridge_channel->chan, NULL, 1);
- break;
- case ATXFER_THREEWAY:
- /*
- * Transferer wants to convert to a threeway call.
- *
- * Just impart the peer onto the bridge and have us return to it
- * as normal.
- */
- ast_bridge_channel_write_unhold(bridge_channel);
- xfer_failed = ast_bridge_impart(bridge_channel->bridge, peer, NULL, NULL, 1);
- break;
- case ATXFER_ABORT:
- /* Transferer decided not to transfer the call after all. */
- break;
- }
- ast_bridge_merge_inhibit(bridge, -1);
- ao2_ref(bridge, -1);
- if (xfer_failed) {
- ast_hangup(peer);
- if (!ast_check_hangup_locked(bridge_channel->chan)) {
- ast_stream_and_wait(bridge_channel->chan, fail_sound, AST_DIGIT_NONE);
- }
- ast_bridge_channel_write_unhold(bridge_channel);
- }
-
- return 0;
-}
-
enum set_touch_variables_res {
SET_TOUCH_SUCCESS,
SET_TOUCH_UNSET,
@@ -909,8 +494,6 @@
static int load_module(void)
{
- ast_bridge_features_register(AST_BRIDGE_BUILTIN_BLINDTRANSFER, feature_blind_transfer, NULL);
- ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMON, feature_automonitor, NULL);
ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMIXMON, feature_automixmonitor, NULL);
Modified: trunk/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridging.h?view=diff&rev=395151&r1=395150&r2=395151
==============================================================================
--- trunk/include/asterisk/bridging.h (original)
+++ trunk/include/asterisk/bridging.h Tue Jul 23 10:28:11 2013
@@ -396,6 +396,8 @@
struct ast_bridge {
/*! Bridge virtual method table. */
const struct ast_bridge_methods *v_table;
+ /*! "Personality" currently exhibited by bridge subclass */
+ void *personality;
/*! Immutable bridge UUID. */
char uniqueid[AST_UUID_STR_LEN];
/*! Bridge technology that is handling the bridge */
@@ -1785,6 +1787,16 @@
*/
struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channel *chan);
+/*!
+ * \brief Remove marked bridge channel feature hooks.
+ * \since 12.0.0
+ *
+ * \param features Bridge features structure
+ * \param flags Determinator for whether hook is removed.
+ *
+ * \return Nothing
+ */
+void ast_bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags flags);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
Modified: trunk/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridging_features.h?view=diff&rev=395151&r1=395150&r2=395151
==============================================================================
--- trunk/include/asterisk/bridging_features.h (original)
+++ trunk/include/asterisk/bridging_features.h Tue Jul 23 10:28:11 2013
@@ -183,6 +183,8 @@
enum ast_bridge_hook_remove_flags {
/*! The hook is removed when the channel is pulled from the bridge. */
AST_BRIDGE_HOOK_REMOVE_ON_PULL = (1 << 0),
+ /*! The hook is removed when the bridge's personality changes. */
+ AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE = (1 << 1),
};
/* BUGBUG Need to be able to selectively remove DTMF, hangup, and interval hooks. */
@@ -265,6 +267,8 @@
char threeway[MAXIMUM_DTMF_FEATURE_STRING];
/*! DTMF string used to complete the transfer (If not empty.) */
char complete[MAXIMUM_DTMF_FEATURE_STRING];
+ /*! DTMF string used to swap bridged targets (If not empty.) */
+ char swap[MAXIMUM_DTMF_FEATURE_STRING];
};
enum ast_bridge_features_monitor {
Added: trunk/include/asterisk/bridging_internal.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridging_internal.h?view=auto&rev=395151
==============================================================================
--- trunk/include/asterisk/bridging_internal.h (added)
+++ trunk/include/asterisk/bridging_internal.h Tue Jul 23 10:28:11 2013
@@ -1,0 +1,88 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Mark Michelson <mmichelson at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Private Bridging API
+ *
+ * \author Mark Michelson <mmichelson at digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+#ifndef _ASTERISK_PRIVATE_BRIDGING_H
+#define _ASTERISK_PRIVATE_BRIDGING_H
+
+struct ast_bridge;
+struct ast_bridge_channel;
+
+/*!
+ * \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.
+ * \param optimized Indicates whether the move is part of an unreal channel optimization.
+ *
+ * \note The dst_bridge and bridge_channel->bridge are assumed already locked.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int bridge_move_do(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bridge_channel,
+ int attempt_recovery, unsigned int optimized);
+
+/*!
+ * \internal
+ * \brief Do the merge of two bridges.
+ * \since 12.0.0
+ *
+ * \param dst_bridge Destination bridge of merge.
+ * \param src_bridge Source bridge of merge.
+ * \param kick_me Array of channels to kick from the bridges.
+ * \param num_kick Number of channels in the kick_me array.
+ * \param optimized Indicates whether the merge is part of an unreal channel optimization.
+ *
+ * \return Nothing
+ *
+ * \note The two bridges are assumed already locked.
+ *
+ * This moves the channels in src_bridge into the bridge pointed
+ * to by dst_bridge.
+ */
+void bridge_merge_do(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge,
+ struct ast_bridge_channel **kick_me, unsigned int num_kick, unsigned int optimized);
+
+/*!
+ * \internal
+ * \brief Helper function to find a bridge channel given a channel.
+ *
+ * \param bridge What to search
+ * \param chan What to search for.
+ *
+ * \note On entry, bridge is already locked.
+ *
+ * \retval bridge_channel if channel is in the bridge.
+ * \retval NULL if not in bridge.
+ */
+struct ast_bridge_channel *find_bridge_channel(struct ast_bridge *bridge, struct ast_channel *chan);
+
+#endif /* _ASTERISK_PRIVATE_BRIDGING_H */
Propchange: trunk/include/asterisk/bridging_internal.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: trunk/include/asterisk/bridging_internal.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: trunk/include/asterisk/bridging_internal.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: trunk/include/asterisk/bridging_roles.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridging_roles.h?view=diff&rev=395151&r1=395150&r2=395151
==============================================================================
--- trunk/include/asterisk/bridging_roles.h (original)
+++ trunk/include/asterisk/bridging_roles.h Tue Jul 23 10:28:11 2013
@@ -64,6 +64,37 @@
int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value);
/*!
+ * \brief Check if a role exists on a channel
+ *
+ * \param channel The channel to check
+ * \param role_name The name of the role to search for
+ *
+ * \retval 0 The requested role does not exist on the channel
+ * \retval 1 The requested role exists on the channel
+ *
+ * This is an alternative to \ref ast_bridge_channel_has_role that is useful if bridge
+ * roles have not yet been established on a channel's bridge_channel. A possible example of
+ * when this could be used is in a bridge v_table's push() callback.
+ */
+int ast_channel_has_role(struct ast_channel *channel, const char *role_name);
+
+/*!
+ * \brief Retrieve the value of a requested role option from a channel
+ *
+ * \param channel The channel to retrieve the requested option from
+ * \param role_name The role to which the option belongs
+ * \param option The name of the option to retrieve
+ *
+ * \retval NULL The option does not exist
+ * \retval non-NULL The value of the option
+ *
+ * This is an alternative to \ref ast_bridge_channel_get_role_option that is useful if bridge
+ * roles have not yet been esstablished on a channel's bridge_channel. A possible example of
+ * when this could be used is in a bridge v_table's push() callback.
+ */
+const char *ast_channel_get_role_option(struct ast_channel *channel, const char *role_name, const char *option);
+
+/*!
* \brief Check to see if a bridge channel inherited a specific role from its channel
*
* \param bridge_channel The bridge channel being checked
@@ -72,7 +103,7 @@
* \retval 0 The bridge channel does not have the requested role
* \retval 1 The bridge channel does have the requested role
*
- * \note Before a bridge_channel can effectively check roles against a bridge, ast_bridge_roles_bridge_channel_establish_roles
+ * \note Before a bridge_channel can effectively check roles against a bridge, ast_bridge_channel_establish_roles
* should be called on the bridge_channel so that roles and their respective role options can be copied from the channel
* datastore into the bridge_channel roles list. Otherwise this function will just return 0 because the list will be NULL.
*/
@@ -88,10 +119,10 @@
* \retval NULL If either the role does not exist on the bridge_channel or the role does exist but the option has not been set
* \retval The value of the option
*
- * \note See ast_bridge_roles_channel_set_role_option note about the need to call ast_bridge_roles_bridge_channel_establish_roles.
+ * \note See ast_channel_set_role_option note about the need to call ast_bridge_channel_establish_roles.
*
* \note The returned character pointer is only valid as long as the bridge_channel is guaranteed to be alive and hasn't had
- * ast_bridge_roles_bridge_channel_clear_roles called against it (as this will free all roles and role options in the bridge
+ * ast_bridge_channel_clear_roles called against it (as this will free all roles and role options in the bridge
* channel). If you need this value after one of these destruction events occurs, you must make a local copy while it is
* still valid.
*/
@@ -119,12 +150,12 @@
* \param bridge_channel the bridge channel that we are scrubbing
*
* \details
- * If roles are already established on a bridge channel, ast_bridge_roles_bridge_channel_establish_roles will fail unconditionally
+ * If roles are already established on a bridge channel, ast_bridge_channel_establish_roles will fail unconditionally
* without changing any roles. In order to update a bridge channel's roles, they must first be cleared from the bridge channel using
* this function.
*
* \note
- * ast_bridge_roles_bridge_channel_clear_roles also serves as the destructor for the role list of a bridge channel.
+ * ast_bridge_channel_clear_roles also serves as the destructor for the role list of a bridge channel.
*/
void ast_bridge_channel_clear_roles(struct ast_bridge_channel *bridge_channel);
Modified: trunk/include/asterisk/features_config.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/features_config.h?view=diff&rev=395151&r1=395150&r2=395151
==============================================================================
--- trunk/include/asterisk/features_config.h (original)
+++ trunk/include/asterisk/features_config.h Tue Jul 23 10:28:11 2013
@@ -66,6 +66,8 @@
AST_STRING_FIELD(atxfercomplete);
/*! DTMF sequence used to turn an attempted atxfer into a three-way call */
AST_STRING_FIELD(atxferthreeway);
+ /*! DTMF sequence used to swap which party the transferer is talking to */
+ AST_STRING_FIELD(atxferswap);
);
/*! Milliseconds allowed between digit presses when dialing transfer destination */
unsigned int transferdigittimeout;
Modified: trunk/include/asterisk/stasis_bridging.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/stasis_bridging.h?view=diff&rev=395151&r1=395150&r2=395151
==============================================================================
--- trunk/include/asterisk/stasis_bridging.h (original)
+++ trunk/include/asterisk/stasis_bridging.h Tue Jul 23 10:28:11 2013
@@ -256,6 +256,8 @@
AST_ATTENDED_TRANSFER_DEST_APP,
/*! The transfer results in both bridges remaining with a local channel linking them */
AST_ATTENDED_TRANSFER_DEST_LINK,
+ /*! The transfer results in a threeway call between transferer, transferee, and transfer target */
+ AST_ATTENDED_TRANSFER_DEST_THREEWAY,
};
/*!
@@ -279,6 +281,8 @@
char app[AST_MAX_APP];
/*! Pair of local channels linking the bridges. Applicable for AST_ATTENDED_TRANSFER_DEST_LINK */
struct ast_channel_snapshot *links[2];
+ /*! Transferer channel and bridge that survived the transition to a threeway call. Applicable for AST_ATTENDED_TRANSFER_DEST_THREEWAY */
+ struct ast_bridge_channel_snapshot_pair threeway;
} dest;
};
@@ -330,6 +334,25 @@
/*!
* \since 12
+ * \brief Publish an attended transfer that results in a threeway call.
+ *
+ * Publish an \ref ast_attended_transfer_message with the dest_type set to
+ * \c AST_ATTENDED_TRANSFER_DEST_THREEWAY. Like with \ref ast_bridge_publish_attended_transfer_bridge_merge,
+ * this results from merging two bridges together. The difference is that a
+ * transferer channel survives the bridge merge
+ *
+ * \param is_external Indicates if the transfer was initiated externally
+ * \param result The result of the transfer.
+ * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge
+ * \param target The bridge between the transferer and transfer targets as well as the transferer channel from that bridge
+ * \param final_pair The bridge that the parties end up in, and the transferer channel that is in this bridge.
+ */
+void ast_bridge_publish_attended_transfer_threeway(int is_external, enum ast_transfer_result result,
+ struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+ struct ast_bridge_channel_pair *final_pair);
+
+/*!
+ * \since 12
* \brief Publish an attended transfer that results in an application being run
*
* Publish an \ref ast_attended_transfer_message with the dest_type set to
Modified: trunk/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridging.c?view=diff&rev=395151&r1=395150&r2=395151
==============================================================================
--- trunk/main/bridging.c (original)
+++ trunk/main/bridging.c Tue Jul 23 10:28:11 2013
@@ -63,6 +63,7 @@
#include "asterisk/core_local.h"
#include "asterisk/core_unreal.h"
#include "asterisk/features_config.h"
+#include "asterisk/bridging_internal.h"
/*! All bridges container. */
static struct ao2_container *bridges;
@@ -77,7 +78,6 @@
static void cleanup_video_mode(struct ast_bridge *bridge);
static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
-static void bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags remove_flags);
/*! Default DTMF keys for built in features */
static char builtin_features_dtmf[AST_BRIDGE_BUILTIN_END][MAXIMUM_DTMF_FEATURE_STRING];
@@ -463,19 +463,7 @@
}
}
-/*!
- * \internal
- * \brief Helper function to find a bridge channel given a channel.
- *
- * \param bridge What to search
- * \param chan What to search for.
- *
- * \note On entry, bridge is already locked.
- *
- * \retval bridge_channel if channel is in the bridge.
- * \retval NULL if not in bridge.
- */
-static struct ast_bridge_channel *find_bridge_channel(struct ast_bridge *bridge, struct ast_channel *chan)
+struct ast_bridge_channel *find_bridge_channel(struct ast_bridge *bridge, struct ast_channel *chan)
{
struct ast_bridge_channel *bridge_channel;
@@ -757,7 +745,7 @@
|| ast_bridge_channel_establish_roles(bridge_channel)) {
ast_debug(1, "Bridge %s: pushing %p(%s) into bridge failed\n",
bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan));
- bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
+ ast_bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
return -1;
}
bridge_channel->in_bridge = 1;
@@ -1719,7 +1707,7 @@
*/
static void bridge_base_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
{
- bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
+ ast_bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
}
/*!
@@ -4164,24 +4152,7 @@
ao2_ref(old_bridge, -1);
}
-/*!
- * \internal
- * \brief Do the merge of two bridges.
- * \since 12.0.0
- *
- * \param dst_bridge Destination bridge of merge.
- * \param src_bridge Source bridge of merge.
- * \param kick_me Array of channels to kick from the bridges.
- * \param num_kick Number of channels in the kick_me array.
- *
- * \return Nothing
- *
- * \note The two bridges are assumed already locked.
- *
- * This moves the channels in src_bridge into the bridge pointed
- * to by dst_bridge.
- */
-static void bridge_merge_do(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_bridge_channel **kick_me, unsigned int num_kick,
+void bridge_merge_do(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_bridge_channel **kick_me, unsigned int num_kick,
unsigned int optimized)
{
struct ast_bridge_channel *bridge_channel;
@@ -4440,21 +4411,7 @@
return res;
}
-/*!
- * \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,
+int bridge_move_do(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bridge_channel, int attempt_recovery,
unsigned int optimized)
{
struct ast_bridge *orig_bridge;
@@ -5646,17 +5603,7 @@
ast_heap_unlock(hooks);
}
-/*!
- * \internal
- * \brief Remove marked bridge channel feature hooks.
- * \since 12.0.0
- *
- * \param features Bridge features structure
- * \param remove_flags Determinator for whether hook is removed.
- *
- * \return Nothing
- */
-static void bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags remove_flags)
+void ast_bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags remove_flags)
{
hooks_remove_container(features->dtmf_hooks, remove_flags);
hooks_remove_container(features->hangup_hooks, remove_flags);
Modified: trunk/main/bridging_basic.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridging_basic.c?view=diff&rev=395151&r1=395150&r2=395151
==============================================================================
--- trunk/main/bridging_basic.c (original)
+++ trunk/main/bridging_basic.c Tue Jul 23 10:28:11 2013
@@ -37,6 +37,43 @@
#include "asterisk/bridging.h"
#include "asterisk/bridging_basic.h"
#include "asterisk/astobj2.h"
+#include "asterisk/features_config.h"
+#include "asterisk/pbx.h"
+#include "asterisk/file.h"
+#include "asterisk/app.h"
+#include "asterisk/bridging_internal.h"
+#include "asterisk/dial.h"
+#include "asterisk/stasis_bridging.h"
+
+#define NORMAL_FLAGS (AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_DISSOLVE_EMPTY \
+ | AST_BRIDGE_FLAG_SMART)
+
+#define TRANSFER_FLAGS AST_BRIDGE_FLAG_SMART
+#define TRANSFERER_ROLE_NAME "transferer"
+
+struct attended_transfer_properties;
+
+enum bridge_basic_personality_type {
+ /*! Index for "normal" basic bridge personality */
+ BRIDGE_BASIC_PERSONALITY_NORMAL,
+ /*! Index for attended transfer basic bridge personality */
+ BRIDGE_BASIC_PERSONALITY_ATXFER,
+ /*! Indicates end of enum. Must always remain the last element */
+ BRIDGE_BASIC_PERSONALITY_END,
+};
+
+/*!
+ * \brief Change basic bridge personality
+ *
+ * Changing personalities allows for the bridge to remain in use but have
+ * properties such as its v_table and its flags change.
+ *
+ * \param bridge The bridge
+ * \param type The personality to change the bridge to
+ * \user_data Private data to attach to the personality.
+ */
+static void bridge_basic_change_personality(struct ast_bridge *bridge,
+ enum bridge_basic_personality_type type, void *user_data);
/* ------------------------------------------------------------------- */
@@ -117,6 +154,37 @@
}
/*!
+ * \brief Details for specific basic bridge personalities
+ */
+struct personality_details {
+ /*! The v_table to use for this personality */
+ struct ast_bridge_methods *v_table;
+ /*! Flags to set on this type of bridge */
+ unsigned int bridge_flags;
+ /*! User data for this personality. If used, must be an ao2 object */
+ void *pvt;
+ /*! Callback to be called when changing to the personality */
+ void (*on_personality_change)(struct ast_bridge *bridge);
+};
+
+/*!
+ * \brief structure that organizes different personalities for basic bridges.
+ */
+struct bridge_basic_personality {
+ /*! The current bridge personality in use */
+ enum bridge_basic_personality_type current;
+ /*! Array of details for the types of bridge personalities supported */
+ struct personality_details details[BRIDGE_BASIC_PERSONALITY_END];
+};
+
+static int add_normal_hooks(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+ return ast_bridge_hangup_hook(bridge_channel->features, basic_hangup_hook,
+ NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL)
+ || ast_bridge_channel_setup_features(bridge_channel);
+}
+
+/*!
* \internal
* \brief ast_bridge basic push method.
* \since 12.0.0
@@ -130,31 +198,2576 @@
* \retval 0 on success
* \retval -1 on failure
*/
-static int bridge_basic_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
-{
- if (ast_bridge_hangup_hook(bridge_channel->features, basic_hangup_hook, NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL)
- || ast_bridge_channel_setup_features(bridge_channel)) {
+static int bridge_personality_normal_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+{
+ if (add_normal_hooks(self, bridge_channel)) {
return -1;
}
ast_bridge_update_accountcodes(self, bridge_channel, swap);
ast_bridge_update_linkedids(self, bridge_channel, swap);
+ return 0;
+}
+
+static int bridge_basic_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+{
+ struct bridge_basic_personality *personality = self->personality;
+
+ ast_assert(personality != NULL);
+
+ if (personality->details[personality->current].v_table->push(self, bridge_channel, swap)) {
+ return -1;
+ }
return ast_bridge_base_v_table.push(self, bridge_channel, swap);
}
+static void bridge_basic_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
+{
+ struct bridge_basic_personality *personality = self->personality;
+
+ ast_assert(personality != NULL);
+
+ if (personality->details[personality->current].v_table->pull) {
+ personality->details[personality->current].v_table->pull(self, bridge_channel);
+ }
+
+ ast_bridge_base_v_table.pull(self, bridge_channel);
+}
+
[... 2805 lines stripped ...]
More information about the svn-commits
mailing list