From bf22391b8d3ab34d8bfea29cf8a8ac66a80c2733 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 23 Jul 2013 15:28:11 +0000 Subject: 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 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@395151 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- include/asterisk/bridging.h | 12 +++++ include/asterisk/bridging_features.h | 4 ++ include/asterisk/bridging_internal.h | 88 ++++++++++++++++++++++++++++++++++++ include/asterisk/bridging_roles.h | 41 +++++++++++++++-- include/asterisk/features_config.h | 2 + include/asterisk/stasis_bridging.h | 23 ++++++++++ 6 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 include/asterisk/bridging_internal.h (limited to 'include') diff --git a/include/asterisk/bridging.h b/include/asterisk/bridging.h index d770937a6..01565818b 100644 --- a/include/asterisk/bridging.h +++ b/include/asterisk/bridging.h @@ -396,6 +396,8 @@ struct ast_bridge_methods { 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_nolock(struct ast_bridge *bridge, struct ast */ 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 diff --git a/include/asterisk/bridging_features.h b/include/asterisk/bridging_features.h index d03219705..736441f6a 100644 --- a/include/asterisk/bridging_features.h +++ b/include/asterisk/bridging_features.h @@ -183,6 +183,8 @@ struct ast_bridge_hook_timer { 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 @@ struct ast_bridge_features_attended_transfer { 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 { diff --git a/include/asterisk/bridging_internal.h b/include/asterisk/bridging_internal.h new file mode 100644 index 000000000..132c42b76 --- /dev/null +++ b/include/asterisk/bridging_internal.h @@ -0,0 +1,88 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2013 Digium, Inc. + * + * Mark Michelson + * + * 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 + * + * 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 */ diff --git a/include/asterisk/bridging_roles.h b/include/asterisk/bridging_roles.h index 3acb67fae..d90e564b7 100644 --- a/include/asterisk/bridging_roles.h +++ b/include/asterisk/bridging_roles.h @@ -63,6 +63,37 @@ void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_n */ 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 * @@ -72,7 +103,7 @@ int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char * * \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 @@ int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const * \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 @@ int ast_bridge_channel_establish_roles(struct ast_bridge_channel *bridge_channel * \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); diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h index 7be019cd2..083496951 100644 --- a/include/asterisk/features_config.h +++ b/include/asterisk/features_config.h @@ -66,6 +66,8 @@ struct ast_features_xfer_config { 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; diff --git a/include/asterisk/stasis_bridging.h b/include/asterisk/stasis_bridging.h index 606884fb2..336d7dd5d 100644 --- a/include/asterisk/stasis_bridging.h +++ b/include/asterisk/stasis_bridging.h @@ -256,6 +256,8 @@ enum ast_attended_transfer_dest_type { 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 @@ struct ast_attended_transfer_message { 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; }; @@ -328,6 +332,25 @@ void ast_bridge_publish_attended_transfer_bridge_merge(int is_external, enum ast struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target, struct ast_bridge *final_bridge); +/*! + * \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 -- cgit v1.2.3