[asterisk-commits] mmichelson: branch mmichelson/queue_bugbug r395152 - in /team/mmichelson/queu...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jul 23 10:37:45 CDT 2013
Author: mmichelson
Date: Tue Jul 23 10:37:43 2013
New Revision: 395152
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395152
Log:
Pull in attended transfer changes since I require them.
Added:
team/mmichelson/queue_bugbug/include/asterisk/bridging_internal.h
- copied unchanged from r395151, trunk/include/asterisk/bridging_internal.h
Modified:
team/mmichelson/queue_bugbug/ (props changed)
team/mmichelson/queue_bugbug/bridges/bridge_builtin_features.c
team/mmichelson/queue_bugbug/include/asterisk/bridging.h
team/mmichelson/queue_bugbug/include/asterisk/bridging_features.h
team/mmichelson/queue_bugbug/include/asterisk/bridging_roles.h
team/mmichelson/queue_bugbug/include/asterisk/features_config.h
team/mmichelson/queue_bugbug/include/asterisk/stasis_bridging.h
team/mmichelson/queue_bugbug/main/bridging.c
team/mmichelson/queue_bugbug/main/bridging_basic.c
team/mmichelson/queue_bugbug/main/bridging_roles.c
team/mmichelson/queue_bugbug/main/cel.c
team/mmichelson/queue_bugbug/main/features.c
team/mmichelson/queue_bugbug/main/features_config.c
team/mmichelson/queue_bugbug/main/stasis_bridging.c
Propchange: team/mmichelson/queue_bugbug/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue Jul 23 10:37:43 2013
@@ -1,1 +1,1 @@
-/trunk:1-395141
+/trunk:1-395151
Modified: team/mmichelson/queue_bugbug/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/bridges/bridge_builtin_features.c?view=diff&rev=395152&r1=395151&r2=395152
==============================================================================
--- team/mmichelson/queue_bugbug/bridges/bridge_builtin_features.c (original)
+++ team/mmichelson/queue_bugbug/bridges/bridge_builtin_features.c Tue Jul 23 10:37:43 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: team/mmichelson/queue_bugbug/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/include/asterisk/bridging.h?view=diff&rev=395152&r1=395151&r2=395152
==============================================================================
--- team/mmichelson/queue_bugbug/include/asterisk/bridging.h (original)
+++ team/mmichelson/queue_bugbug/include/asterisk/bridging.h Tue Jul 23 10:37:43 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: team/mmichelson/queue_bugbug/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/include/asterisk/bridging_features.h?view=diff&rev=395152&r1=395151&r2=395152
==============================================================================
--- team/mmichelson/queue_bugbug/include/asterisk/bridging_features.h (original)
+++ team/mmichelson/queue_bugbug/include/asterisk/bridging_features.h Tue Jul 23 10:37:43 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 {
Modified: team/mmichelson/queue_bugbug/include/asterisk/bridging_roles.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/include/asterisk/bridging_roles.h?view=diff&rev=395152&r1=395151&r2=395152
==============================================================================
--- team/mmichelson/queue_bugbug/include/asterisk/bridging_roles.h (original)
+++ team/mmichelson/queue_bugbug/include/asterisk/bridging_roles.h Tue Jul 23 10:37:43 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: team/mmichelson/queue_bugbug/include/asterisk/features_config.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/include/asterisk/features_config.h?view=diff&rev=395152&r1=395151&r2=395152
==============================================================================
--- team/mmichelson/queue_bugbug/include/asterisk/features_config.h (original)
+++ team/mmichelson/queue_bugbug/include/asterisk/features_config.h Tue Jul 23 10:37:43 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: team/mmichelson/queue_bugbug/include/asterisk/stasis_bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/include/asterisk/stasis_bridging.h?view=diff&rev=395152&r1=395151&r2=395152
==============================================================================
--- team/mmichelson/queue_bugbug/include/asterisk/stasis_bridging.h (original)
+++ team/mmichelson/queue_bugbug/include/asterisk/stasis_bridging.h Tue Jul 23 10:37:43 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: team/mmichelson/queue_bugbug/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/main/bridging.c?view=diff&rev=395152&r1=395151&r2=395152
==============================================================================
--- team/mmichelson/queue_bugbug/main/bridging.c (original)
+++ team/mmichelson/queue_bugbug/main/bridging.c Tue Jul 23 10:37:43 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;
@@ -79,7 +80,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];
@@ -465,19 +465,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;
@@ -759,7 +747,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;
@@ -1721,7 +1709,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);
}
/*!
@@ -4166,24 +4154,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;
@@ -4442,21 +4413,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;
@@ -5667,17 +5624,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: team/mmichelson/queue_bugbug/main/bridging_basic.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/main/bridging_basic.c?view=diff&rev=395152&r1=395151&r2=395152
==============================================================================
--- team/mmichelson/queue_bugbug/main/bridging_basic.c (original)
+++ team/mmichelson/queue_bugbug/main/bridging_basic.c Tue Jul 23 10:37:43 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);
+}
+
+static void bridge_basic_destroy(struct ast_bridge *self)
+{
+ struct bridge_basic_personality *personality = self->personality;
+
+ ao2_cleanup(personality);
+
+ ast_bridge_base_v_table.destroy(self);
+}
+
+/*!
+ * \brief Remove appropriate hooks when basic bridge personality changes
+ *
+ * Hooks that have the AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE flag
+ * set will be removed from all bridge channels in the bridge.
+ *
+ * \param bridge Basic bridge undergoing personality change
+ */
+static void remove_hooks_on_personality_change(struct ast_bridge *bridge)
+{
+ struct ast_bridge_channel *iter;
+
+ AST_LIST_TRAVERSE(&bridge->channels, iter, entry) {
+ SCOPED_LOCK(lock, iter, ast_bridge_channel_lock, ast_bridge_channel_unlock);
+ ast_bridge_features_remove(iter->features, AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE);
+ }
+}
+
+/*!
+ * \brief Attended transfer superstates.
+ *
+ * An attended transfer's progress is facilitated by a state machine.
+ * The individual states of the state machine fall into the realm of
+ * one of two superstates.
+ */
+enum attended_transfer_superstate {
+ /*!
+ * \brief Transfer superstate
+ *
+ * The attended transfer state machine begins in this superstate. The
+ * goal of this state is for a transferer channel to facilitate a
+ * transfer from a transferee to a transfer target.
+ *
+ * There are two bridges used in this superstate. The transferee bridge is
+ * the bridge that the transferer and transferee channels originally
+ * communicate in, and the target bridge is the bridge where the transfer
+ * target is being dialed.
+ *
+ * The transferer channel is capable of moving between the bridges using
+ * the DTMF swap sequence.
+ */
+ SUPERSTATE_TRANSFER,
+ /*!
+ * \brief Recall superstate
+ *
+ * The attended transfer state machine moves to this superstate if
+ * atxferdropcall is set to "no" and the transferer channel hangs up
+ * during a transfer. The goal in this superstate is to call back either
+ * the transfer target or transferer and rebridge with the transferee
+ * channel(s).
+ *
+ * In this superstate, there is only a single bridge used, the original
+ * transferee bridge. Rather than distinguishing between a transferer
+ * and transfer target, all outbound calls are toward a "recall_target"
+ * channel.
+ */
+ SUPERSTATE_RECALL,
+};
+
+/*!
+ * The states in the attended transfer state machine.
+ */
+enum attended_transfer_state {
+ /*!
+ * \brief Calling Target state
+ *
+ * This state describes the initial state of a transfer. The transferer
[... 2729 lines stripped ...]
More information about the asterisk-commits
mailing list