[asterisk-commits] mmichelson: trunk r393182 - in /trunk: bridges/ channels/ include/asterisk/ m...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jun 28 13:42:36 CDT 2013
Author: mmichelson
Date: Fri Jun 28 13:42:24 2013
New Revision: 393182
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=393182
Log:
Add stasis publications for blind and attended transfers.
This creates stasis messages that are sent during a blind or
attended transfer. The stasis messages also are converted to
AMI events.
Review: https://reviewboard.asterisk.org/r/2619
(closes issue ASTERISK-21337)
Reported by Matt Jordan
Modified:
trunk/bridges/bridge_builtin_features.c
trunk/channels/chan_iax2.c
trunk/channels/chan_sip.c
trunk/channels/chan_skinny.c
trunk/include/asterisk/bridging.h
trunk/include/asterisk/stasis_bridging.h
trunk/main/bridging.c
trunk/main/manager.c
trunk/main/manager_bridging.c
trunk/main/stasis_bridging.c
trunk/res/res_sip_refer.c
Modified: trunk/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/trunk/bridges/bridge_builtin_features.c?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/bridges/bridge_builtin_features.c (original)
+++ trunk/bridges/bridge_builtin_features.c Fri Jun 28 13:42:24 2013
@@ -218,7 +218,7 @@
ast_after_bridge_set_go_on(bridge_channel->chan, NULL, NULL, 0, goto_on_blindxfr);
}
- if (ast_bridge_transfer_blind(bridge_channel->chan, exten, context, blind_transfer_cb,
+ 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);
Modified: trunk/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_iax2.c?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/channels/chan_iax2.c (original)
+++ trunk/channels/chan_iax2.c Fri Jun 28 13:42:24 2013
@@ -10684,7 +10684,7 @@
ast_channel_unlock(owner);
ast_mutex_unlock(&iaxsl[fr->callno]);
- if (ast_bridge_transfer_blind(owner, ies.called_number,
+ if (ast_bridge_transfer_blind(1, owner, ies.called_number,
context, NULL, NULL) != AST_BRIDGE_TRANSFER_SUCCESS) {
ast_log(LOG_WARNING, "Blind transfer of '%s' to '%s@%s' failed\n",
ast_channel_name(owner), ies.called_number,
Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Fri Jun 28 13:42:24 2013
@@ -26191,7 +26191,7 @@
}
sip_pvt_unlock(p);
- transfer_res = ast_bridge_transfer_blind(transferer, refer_to, refer_to_context, blind_transfer_cb, &cb_data);
+ transfer_res = ast_bridge_transfer_blind(1, transferer, refer_to, refer_to_context, blind_transfer_cb, &cb_data);
sip_pvt_lock(p);
switch (transfer_res) {
Modified: trunk/channels/chan_skinny.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_skinny.c?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/channels/chan_skinny.c (original)
+++ trunk/channels/chan_skinny.c Fri Jun 28 13:42:24 2013
@@ -5288,7 +5288,7 @@
xferee->related = NULL;
ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
- res = ast_bridge_transfer_blind(xferee->owner, sub->exten, sub->line->context, NULL, NULL);
+ res = ast_bridge_transfer_blind(1, xferee->owner, sub->exten, sub->line->context, NULL, NULL);
if (res != AST_BRIDGE_TRANSFER_SUCCESS) {
SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d failed to blind transfer %d to '%s'@'%s' - %d\n",
Modified: trunk/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridging.h?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/include/asterisk/bridging.h (original)
+++ trunk/include/asterisk/bridging.h Fri Jun 28 13:42:24 2013
@@ -1499,6 +1499,7 @@
* \note Absolutely _NO_ channel locks should be held before
* calling this function.
*
+ * \param is_external Indicates that transfer was initiated externally
* \param transferer The channel performing the blind transfer
* \param exten The dialplan extension to send the call to
* \param context The dialplan context to send the call to
@@ -1507,8 +1508,8 @@
* \param user_data Argument for new_channel_cb
* \return The success or failure result of the blind transfer
*/
-enum ast_transfer_result ast_bridge_transfer_blind(struct ast_channel *transferer,
- const char *exten, const char *context,
+enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
+ struct ast_channel *transferer, const char *exten, const char *context,
transfer_channel_cb new_channel_cb, void *user_data);
/*!
Modified: trunk/include/asterisk/stasis_bridging.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/stasis_bridging.h?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/include/asterisk/stasis_bridging.h (original)
+++ trunk/include/asterisk/stasis_bridging.h Fri Jun 28 13:42:24 2013
@@ -29,6 +29,7 @@
#include "asterisk/linkedlists.h"
#include "asterisk/channel.h"
#include "asterisk/bridging.h"
+#include "asterisk/pbx.h"
/*!
* \brief Structure that contains a snapshot of information about a bridge
@@ -211,6 +212,185 @@
struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot);
/*!
+ * \brief Pair showing a bridge snapshot and a specific channel snapshot belonging to the bridge
+ */
+struct ast_bridge_channel_snapshot_pair {
+ struct ast_bridge_snapshot *bridge_snapshot;
+ struct ast_channel_snapshot *channel_snapshot;
+};
+
+/*!
+ * \brief Pair showing a bridge and a specific channel belonging to the bridge
+ */
+struct ast_bridge_channel_pair {
+ struct ast_bridge *bridge;
+ struct ast_channel *channel;
+};
+
+/*!
+ * \brief Message representing blind transfer
+ */
+struct ast_blind_transfer_message {
+ AST_DECLARE_STRING_FIELDS(
+ /*! The destination context for the blind transfer */
+ AST_STRING_FIELD(context);
+ /*! The destination extension for the blind transfer */
+ AST_STRING_FIELD(exten);
+ );
+ /*! Result of the blind transfer */
+ enum ast_transfer_result result;
+ /*! If 0, was core DTMF transfer, otherwise occurred externally*/
+ int is_external;
+ /*! The transferer and its bridge before starting the transfer*/
+ struct ast_bridge_channel_snapshot_pair transferer;
+};
+
+/*!
+ * \since 12
+ * \brief Message type for \ref ast_blind_transfer_message.
+ *
+ * \retval Message type for \ref ast_blind_transfer_message.
+ */
+struct stasis_message_type *ast_blind_transfer_type(void);
+
+/*!
+ * \brief Publish a blind transfer event
+ *
+ * \param is_external Whether the blind transfer was initiated externally (e.g. via AMI or native protocol)
+ * \param result The success or failure of the transfer
+ * \param to_transferee The bridge between the transferer and transferee plus the transferer channel
+ * \param context The destination context for the blind transfer
+ * \param exten The destination extension for the blind transfer
+ */
+void ast_bridge_publish_blind_transfer(int is_external, enum ast_transfer_result result,
+ struct ast_bridge_channel_pair *to_transferee, const char *context, const char *exten);
+
+enum ast_attended_transfer_dest_type {
+ /*! The transfer failed, so there is no appropriate final state */
+ AST_ATTENDED_TRANSFER_DEST_FAIL,
+ /*! The transfer results in a single bridge remaining due to a merge or swap */
+ AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE,
+ /*! The transfer results in a channel or bridge running an application */
+ AST_ATTENDED_TRANSFER_DEST_APP,
+ /*! The transfer results in both bridges remaining with a local channel linking them */
+ AST_ATTENDED_TRANSFER_DEST_LINK,
+};
+
+/*!
+ * \brief Message representing attended transfer
+ */
+struct ast_attended_transfer_message {
+ /*! Result of the attended transfer */
+ enum ast_transfer_result result;
+ /*! Indicates if the transfer was initiated externally*/
+ int is_external;
+ /*! Bridge between transferer <-> transferee and the transferer channel in that bridge. May be NULL */
+ struct ast_bridge_channel_snapshot_pair to_transferee;
+ /*! Bridge between transferer <-> transfer target and the transferer channel in that bridge. May be NULL */
+ struct ast_bridge_channel_snapshot_pair to_transfer_target;
+ /*! Indicates the final state of the transfer */
+ enum ast_attended_transfer_dest_type dest_type;
+ union {
+ /*! ID of the surviving bridge. Applicable for AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE */
+ char bridge[AST_UUID_STR_LEN];
+ /*! Destination application of transfer. Applicable for AST_ATTENDED_TRANSFER_DEST_APP */
+ 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];
+ } dest;
+};
+
+/*!
+ * \since 12
+ * \brief Message type for \ref ast_attended_transfer_message.
+ *
+ * \retval Message type for \ref ast_attended_transfer_message.
+ */
+struct stasis_message_type *ast_attended_transfer_type(void);
+
+/*!
+ * \since 12
+ * \brief Publish an attended transfer failure
+ *
+ * Publish an \ref ast_attended_transfer_message with the dest_type set to
+ * \c AST_ATTENDED_TRANSFER_DEST_FAIL.
+ *
+ * \param is_external Indicates if the transfer was initiated externally
+ * \param result The result of the transfer. Will always be a type of failure.
+ * \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
+ */
+void ast_bridge_publish_attended_transfer_fail(int is_external, enum ast_transfer_result result,
+ struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target);
+
+/*!
+ * \since 12
+ * \brief Publish an attended transfer that results in two bridges becoming one.
+ *
+ * Publish an \ref ast_attended_transfer_message with the dest_type set to
+ * \c AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE. This type of attended transfer results from
+ * having two bridges involved and either
+ *
+ * \li Merging the two bridges together
+ * \li Moving a channel from one bridge to the other, thus emptying a bridge
+ *
+ * In either case, two bridges enter, one leaves.
+ *
+ * \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_bridge The bridge that the parties end up in. Will be a bridge from the transferee or target pair.
+ */
+void ast_bridge_publish_attended_transfer_bridge_merge(int is_external, enum ast_transfer_result result,
+ 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 an application being run
+ *
+ * Publish an \ref ast_attended_transfer_message with the dest_type set to
+ * \c AST_ATTENDED_TRANSFER_DEST_APP. This occurs when an attended transfer
+ * results in either:
+ *
+ * \li A transferee channel leaving a bridge to run an app
+ * \li A bridge of transferees running an app (via a local channel)
+ *
+ * \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 dest_app The application that the channel or bridge is running upon transfer completion.
+ */
+void ast_bridge_publish_attended_transfer_app(int is_external, enum ast_transfer_result result,
+ struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+ const char *dest_app);
+
+/*!
+ * \since 12
+ * \brief Publish an attended transfer that results in two bridges linked by a local channel
+ *
+ * Publish an \ref ast_attended_transfer_message with the dest_type set to
+ * \c AST_ATTENDED_TRANSFER_DEST_LINK. This occurs when two bridges are involved
+ * in an attended transfer, but their properties do not allow for the bridges to
+ * merge or to have channels moved off of the bridge. An example of this occurs when
+ * attempting to transfer a ConfBridge to another bridge.
+ *
+ * When this type of transfer occurs, the two bridges continue to exist after the
+ * transfer and a local channel is used to link the two bridges together.
+ *
+ * \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 locals The local channels linking the bridges together.
+ */
+void ast_bridge_publish_attended_transfer_link(int is_external, enum ast_transfer_result result,
+ struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+ struct ast_channel *locals[2]);
+
+/*!
* \brief Returns the most recent snapshot for the bridge.
*
* The returned pointer is AO2 managed, so ao2_cleanup() when you're done.
Modified: trunk/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridging.c?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/main/bridging.c (original)
+++ trunk/main/bridging.c Fri Jun 28 13:42:24 2013
@@ -5924,6 +5924,113 @@
}
/*!
+ * \internal
+ * \brief Base data to publish for stasis attended transfer messages
+ */
+struct stasis_attended_transfer_publish_data {
+ /* The bridge between the transferer and transferee, and the transferer channel in this bridge */
+ struct ast_bridge_channel_pair to_transferee;
+ /* The bridge between the transferer and transfer target, and the transferer channel in this bridge */
+ struct ast_bridge_channel_pair to_transfer_target;
+};
+
+static void stasis_publish_data_cleanup(struct stasis_attended_transfer_publish_data *publication)
+{
+ ast_channel_unref(publication->to_transferee.channel);
+ ast_channel_unref(publication->to_transfer_target.channel);
+ ao2_cleanup(publication->to_transferee.bridge);
+ ao2_cleanup(publication->to_transfer_target.bridge);
+}
+
+/*!
+ * \internal
+ * \brief Set up base data for an attended transfer stasis publication
+ *
+ * \param to_transferee The original transferer channel, which may be bridged to a transferee
+ * \param to_transferee_bridge The bridge that to_transferee is in.
+ * \param to_transfer_target The second transferer channel, which may be bridged to a transfer target
+ * \param to_target_bridge The bridge that to_transfer_target_is in.
+ * \param[out] publication A structure to hold the other parameters
+ */
+static void stasis_publish_data_init(struct ast_channel *to_transferee,
+ struct ast_bridge *to_transferee_bridge, struct ast_channel *to_transfer_target,
+ struct ast_bridge *to_target_bridge,
+ struct stasis_attended_transfer_publish_data *publication)
+{
+ memset(publication, 0, sizeof(*publication));
+ publication->to_transferee.channel = ast_channel_ref(to_transferee);
+ if (to_transferee_bridge) {
+ ao2_ref(to_transferee_bridge, +1);
+ publication->to_transferee.bridge = to_transferee_bridge;
+ }
+
+ publication->to_transfer_target.channel = ast_channel_ref(to_transfer_target);
+ if (to_target_bridge) {
+ ao2_ref(to_target_bridge, +1);
+ publication->to_transfer_target.bridge = to_target_bridge;
+ }
+}
+
+/*
+ * \internal
+ * \brief Publish a stasis attended transfer resulting in a bridge merge
+ *
+ * \param publication Base data about the attended transfer
+ * \param final_bridge The surviving bridge of the attended transfer
+ */
+static void publish_attended_transfer_bridge_merge(struct stasis_attended_transfer_publish_data *publication,
+ struct ast_bridge *final_bridge)
+{
+ ast_bridge_publish_attended_transfer_bridge_merge(1, AST_BRIDGE_TRANSFER_SUCCESS,
+ &publication->to_transferee, &publication->to_transfer_target, final_bridge);
+}
+
+/*
+ * \internal
+ * \brief Publish a stasis attended transfer to an application
+ *
+ * \param publication Base data about the attended transfer
+ * \param app The app that is running at the conclusion of the transfer
+ */
+static void publish_attended_transfer_app(struct stasis_attended_transfer_publish_data *publication,
+ const char *app)
+{
+ ast_bridge_publish_attended_transfer_app(1, AST_BRIDGE_TRANSFER_SUCCESS,
+ &publication->to_transferee, &publication->to_transfer_target, app);
+}
+
+/*
+ * \internal
+ * \brief Publish a stasis attended transfer showing a link between bridges
+ *
+ * \param publication Base data about the attended transfer
+ * \param local_channel1 Local channel in the original bridge
+ * \param local_channel2 Local channel in the second bridge
+ */
+static void publish_attended_transfer_link(struct stasis_attended_transfer_publish_data *publication,
+ struct ast_channel *local_channel1, struct ast_channel *local_channel2)
+{
+ struct ast_channel *locals[2] = { local_channel1, local_channel2 };
+
+ ast_bridge_publish_attended_transfer_link(1, AST_BRIDGE_TRANSFER_SUCCESS,
+ &publication->to_transferee, &publication->to_transfer_target, locals);
+}
+
+/*
+ * \internal
+ * \brief Publish a stasis attended transfer failure
+ *
+ * \param publication Base data about the attended transfer
+ * \param result The transfer result
+ */
+static void publish_attended_transfer_fail(struct stasis_attended_transfer_publish_data *publication,
+ enum ast_transfer_result result)
+{
+ ast_bridge_publish_attended_transfer_fail(1, result, &publication->to_transferee,
+ &publication->to_transfer_target);
+}
+
+/*!
* \brief Perform an attended transfer of a bridge
*
* This performs an attended transfer of an entire bridge to a target.
@@ -5941,16 +6048,19 @@
* \param chan2 Other transferer channel. May or may not be bridged.
* \param bridge1 Bridge that chan1 is in. Guaranteed to be non-NULL.
* \param bridge2 Bridge that chan2 is in. If NULL, then chan2 is not bridged.
+ * \param publication Data to publish for a stasis attended transfer message.
* \retval AST_BRIDGE_TRANSFER_FAIL Internal error occurred
* \retval AST_BRIDGE_TRANSFER_SUCCESS Succesfully transferred the bridge
*/
static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *chan1,
- struct ast_channel *chan2, struct ast_bridge *bridge1, struct ast_bridge *bridge2)
+ struct ast_channel *chan2, struct ast_bridge *bridge1, struct ast_bridge *bridge2,
+ struct stasis_attended_transfer_publish_data *publication)
{
static const char *dest = "_attended at transfer/m";
struct ast_channel *local_chan;
int cause;
int res;
+ const char *app = NULL;
local_chan = ast_request("Local", ast_channel_nativeformats(chan1), chan1,
dest, &cause);
@@ -5962,6 +6072,7 @@
if (bridge2) {
res = ast_local_setup_bridge(local_chan, bridge2, chan2, NULL);
} else {
+ app = ast_strdupa(ast_channel_appl(chan2));
res = ast_local_setup_masquerade(local_chan, chan2);
}
@@ -5980,6 +6091,20 @@
return AST_BRIDGE_TRANSFER_FAIL;
}
+ if (bridge2) {
+ RAII_VAR(struct ast_channel *, local_chan2, NULL, ao2_cleanup);
+
+ ast_channel_lock(local_chan);
+ local_chan2 = ast_local_get_peer(local_chan);
+ ast_channel_unlock(local_chan);
+
+ ast_assert(local_chan2 != NULL);
+
+ publish_attended_transfer_link(publication,
+ local_chan, local_chan2);
+ } else {
+ publish_attended_transfer_app(publication, app);
+ }
return AST_BRIDGE_TRANSFER_SUCCESS;
}
@@ -6162,8 +6287,18 @@
return bridge;
}
-enum ast_transfer_result ast_bridge_transfer_blind(struct ast_channel *transferer,
- const char *exten, const char *context,
+static void publish_blind_transfer(int is_external, enum ast_transfer_result result,
+ struct ast_channel *transferer, struct ast_bridge *bridge,
+ const char *context, const char *exten)
+{
+ struct ast_bridge_channel_pair pair;
+ pair.channel = transferer;
+ pair.bridge = bridge;
+ ast_bridge_publish_blind_transfer(is_external, result, &pair, context, exten);
+}
+
+enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
+ struct ast_channel *transferer, const char *exten, const char *context,
transfer_channel_cb new_channel_cb, void *user_data)
{
RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
@@ -6173,16 +6308,19 @@
int do_bridge_transfer;
int transfer_prohibited;
enum try_parking_result parking_result;
+ enum ast_transfer_result transfer_result;
bridge = acquire_bridge(transferer);
if (!bridge) {
- return AST_BRIDGE_TRANSFER_INVALID;
+ transfer_result = AST_BRIDGE_TRANSFER_INVALID;
+ goto publish;
}
ast_channel_lock(transferer);
bridge_channel = ast_channel_get_bridge_channel(transferer);
ast_channel_unlock(transferer);
if (!bridge_channel) {
- return AST_BRIDGE_TRANSFER_INVALID;
+ transfer_result = AST_BRIDGE_TRANSFER_INVALID;
+ goto publish;
}
/* Take off hold if they are on hold. */
@@ -6191,9 +6329,11 @@
parking_result = try_parking(bridge, transferer, exten, context);
switch (parking_result) {
case PARKING_SUCCESS:
- return AST_BRIDGE_TRANSFER_SUCCESS;
+ transfer_result = AST_BRIDGE_TRANSFER_SUCCESS;
+ goto publish;
case PARKING_FAILURE:
- return AST_BRIDGE_TRANSFER_FAIL;
+ transfer_result = AST_BRIDGE_TRANSFER_FAIL;
+ goto publish;
case PARKING_NOT_APPLICABLE:
default:
break;
@@ -6204,10 +6344,12 @@
channels = ast_bridge_peers_nolock(bridge);
if (!channels) {
- return AST_BRIDGE_TRANSFER_FAIL;
+ transfer_result = AST_BRIDGE_TRANSFER_FAIL;
+ goto publish;
}
if (ao2_container_count(channels) <= 1) {
- return AST_BRIDGE_TRANSFER_INVALID;
+ transfer_result = AST_BRIDGE_TRANSFER_INVALID;
+ goto publish;
}
transfer_prohibited = ast_test_flag(&bridge->feature_flags,
AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
@@ -6217,30 +6359,38 @@
}
if (transfer_prohibited) {
- return AST_BRIDGE_TRANSFER_NOT_PERMITTED;
+ transfer_result = AST_BRIDGE_TRANSFER_NOT_PERMITTED;
+ goto publish;
}
set_blind_transfer_variables(transferer, channels);
if (do_bridge_transfer) {
- return blind_transfer_bridge(transferer, bridge, exten, context,
+ transfer_result = blind_transfer_bridge(transferer, bridge, exten, context,
new_channel_cb, user_data);
+ goto publish;
}
/* Reaching this portion means that we're dealing with a two-party bridge */
transferee = get_transferee(channels, transferer);
if (!transferee) {
- return AST_BRIDGE_TRANSFER_FAIL;
+ transfer_result = AST_BRIDGE_TRANSFER_FAIL;
+ goto publish;
}
if (bridge_channel_queue_blind_transfer(transferee, exten, context,
new_channel_cb, user_data)) {
- return AST_BRIDGE_TRANSFER_FAIL;
+ transfer_result = AST_BRIDGE_TRANSFER_FAIL;
+ goto publish;
}
ast_bridge_remove(bridge, transferer);
- return AST_BRIDGE_TRANSFER_SUCCESS;
+ transfer_result = AST_BRIDGE_TRANSFER_SUCCESS;
+
+publish:
+ publish_blind_transfer(is_external, transfer_result, transferer, bridge, context, exten);
+ return transfer_result;
}
/*!
@@ -6297,30 +6447,42 @@
* \param to_target_bridge_channel to_transfer_target's bridge_channel
* \param to_transferee_bridge The bridge between to_transferee and the transferee
* \param to_target_bridge The bridge between to_transfer_target and the transfer_target
+ * \param publication Data to publish for a stasis attended transfer message
* \return The success or failure of the attended transfer
*/
static enum ast_transfer_result two_bridge_attended_transfer(struct ast_channel *to_transferee,
struct ast_bridge_channel *to_transferee_bridge_channel,
struct ast_channel *to_transfer_target,
struct ast_bridge_channel *to_target_bridge_channel,
- struct ast_bridge *to_transferee_bridge, struct ast_bridge *to_target_bridge)
+ struct ast_bridge *to_transferee_bridge, struct ast_bridge *to_target_bridge,
+ struct stasis_attended_transfer_publish_data *publication)
{
struct ast_bridge_channel *kick_me[] = {
to_transferee_bridge_channel,
to_target_bridge_channel,
};
+ enum ast_transfer_result res;
+ struct ast_bridge *final_bridge = NULL;
switch (ast_bridges_allow_optimization(to_transferee_bridge, to_target_bridge)) {
case AST_BRIDGE_OPTIMIZE_SWAP_TO_CHAN_BRIDGE:
- return bridge_swap_attended_transfer(to_transferee_bridge, to_target_bridge_channel, to_transferee);
+ final_bridge = to_transferee_bridge;
+ res = bridge_swap_attended_transfer(to_transferee_bridge, to_target_bridge_channel, to_transferee);
+ goto end;
case AST_BRIDGE_OPTIMIZE_SWAP_TO_PEER_BRIDGE:
- return bridge_swap_attended_transfer(to_target_bridge, to_transferee_bridge_channel, to_transfer_target);
+ final_bridge = to_target_bridge;
+ res = bridge_swap_attended_transfer(to_target_bridge, to_transferee_bridge_channel, to_transfer_target);
+ goto end;
case AST_BRIDGE_OPTIMIZE_MERGE_TO_CHAN_BRIDGE:
+ final_bridge = to_transferee_bridge;
bridge_merge_do(to_transferee_bridge, to_target_bridge, kick_me, ARRAY_LEN(kick_me));
- return AST_BRIDGE_TRANSFER_SUCCESS;
+ res = AST_BRIDGE_TRANSFER_SUCCESS;
+ goto end;
case AST_BRIDGE_OPTIMIZE_MERGE_TO_PEER_BRIDGE:
+ final_bridge = to_target_bridge;
bridge_merge_do(to_target_bridge, to_transferee_bridge, kick_me, ARRAY_LEN(kick_me));
- return AST_BRIDGE_TRANSFER_SUCCESS;
+ res = AST_BRIDGE_TRANSFER_SUCCESS;
+ goto end;
case AST_BRIDGE_OPTIMIZE_PROHIBITED:
default:
/* Just because optimization wasn't doable doesn't necessarily mean
@@ -6329,11 +6491,23 @@
*/
if (to_transferee_bridge->inhibit_merge || to_transferee_bridge->dissolved ||
to_target_bridge->inhibit_merge || to_target_bridge->dissolved) {
- return AST_BRIDGE_TRANSFER_INVALID;
- }
+ res = AST_BRIDGE_TRANSFER_INVALID;
+ goto end;
+ }
+
+ /* Don't goto end here. attended_transfer_bridge will publish its own
+ * stasis message if it succeeds
+ */
return attended_transfer_bridge(to_transferee, to_transfer_target,
- to_transferee_bridge, to_target_bridge);
- }
+ to_transferee_bridge, to_target_bridge, publication);
+ }
+
+end:
+ if (res == AST_BRIDGE_TRANSFER_SUCCESS) {
+ publish_attended_transfer_bridge_merge(publication, final_bridge);
+ }
+
+ return res;
}
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee,
@@ -6350,13 +6524,20 @@
struct ast_channel *chan_unbridged;
int transfer_prohibited;
int do_bridge_transfer;
+ enum ast_transfer_result res;
+ const char *app = NULL;
+ struct stasis_attended_transfer_publish_data publication;
to_transferee_bridge = acquire_bridge(to_transferee);
to_target_bridge = acquire_bridge(to_transfer_target);
+ stasis_publish_data_init(to_transferee, to_transferee_bridge,
+ to_transfer_target, to_target_bridge, &publication);
+
/* They can't both be unbridged, you silly goose! */
if (!to_transferee_bridge && !to_target_bridge) {
- return AST_BRIDGE_TRANSFER_INVALID;
+ res = AST_BRIDGE_TRANSFER_INVALID;
+ goto end;
}
ast_channel_lock(to_transferee);
@@ -6407,20 +6588,20 @@
/* Let's get the easy one out of the way first */
if (to_transferee_bridge && to_target_bridge) {
- enum ast_transfer_result res;
if (!to_transferee_bridge_channel || !to_target_bridge_channel) {
- return AST_BRIDGE_TRANSFER_INVALID;
+ res = AST_BRIDGE_TRANSFER_INVALID;
+ goto end;
}
ast_bridge_lock_both(to_transferee_bridge, to_target_bridge);
res = two_bridge_attended_transfer(to_transferee, to_transferee_bridge_channel,
to_transfer_target, to_target_bridge_channel,
- to_transferee_bridge, to_target_bridge);
+ to_transferee_bridge, to_target_bridge, &publication);
ast_bridge_unlock(to_transferee_bridge);
ast_bridge_unlock(to_target_bridge);
- return res;
+ goto end;
}
the_bridge = to_transferee_bridge ?: to_target_bridge;
@@ -6433,11 +6614,13 @@
channels = ast_bridge_peers_nolock(the_bridge);
if (!channels) {
- return AST_BRIDGE_TRANSFER_FAIL;
+ res = AST_BRIDGE_TRANSFER_FAIL;
+ goto end;
}
chan_count = ao2_container_count(channels);
if (chan_count <= 1) {
- return AST_BRIDGE_TRANSFER_INVALID;
+ res = AST_BRIDGE_TRANSFER_INVALID;
+ goto end;
}
transfer_prohibited = ast_test_flag(&the_bridge->feature_flags,
AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
@@ -6447,24 +6630,41 @@
}
if (transfer_prohibited) {
- return AST_BRIDGE_TRANSFER_NOT_PERMITTED;
+ res = AST_BRIDGE_TRANSFER_NOT_PERMITTED;
+ goto end;
}
if (do_bridge_transfer) {
- return attended_transfer_bridge(chan_bridged, chan_unbridged, the_bridge, NULL);
+ res = attended_transfer_bridge(chan_bridged, chan_unbridged, the_bridge, NULL, &publication);
+ goto end;
}
transferee = get_transferee(channels, chan_bridged);
if (!transferee) {
- return AST_BRIDGE_TRANSFER_FAIL;
- }
-
+ res = AST_BRIDGE_TRANSFER_FAIL;
+ goto end;
+ }
+
+ app = ast_strdupa(ast_channel_appl(chan_unbridged));
if (bridge_channel_queue_attended_transfer(transferee, chan_unbridged)) {
- return AST_BRIDGE_TRANSFER_FAIL;
+ res = AST_BRIDGE_TRANSFER_FAIL;
+ goto end;
}
ast_bridge_remove(the_bridge, chan_bridged);
+
+ publish_attended_transfer_app(&publication, app);
return AST_BRIDGE_TRANSFER_SUCCESS;
+
+end:
+ /* All successful transfer paths have published an appropriate stasis message.
+ * All failure paths have deferred publishing a stasis message until this point
+ */
+ if (res != AST_BRIDGE_TRANSFER_SUCCESS) {
+ publish_attended_transfer_fail(&publication, res);
+ }
+ stasis_publish_data_cleanup(&publication);
+ return res;
}
/*!
Modified: trunk/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/manager.c?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/main/manager.c (original)
+++ trunk/main/manager.c Fri Jun 28 13:42:24 2013
@@ -4064,7 +4064,7 @@
context = ast_channel_context(chan);
}
- switch (ast_bridge_transfer_blind(chan, exten, context, NULL, NULL)) {
+ switch (ast_bridge_transfer_blind(1, chan, exten, context, NULL, NULL)) {
case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
astman_send_error(s, m, "Transfer not permitted");
break;
Modified: trunk/main/manager_bridging.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/manager_bridging.c?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/main/manager_bridging.c (original)
+++ trunk/main/manager_bridging.c Fri Jun 28 13:42:24 2013
@@ -108,6 +108,11 @@
</manager>
***/
+/*! \brief The \ref stasis subscription returned by the forwarding of the channel topic
+ * to the manager topic
+ */
+static struct stasis_subscription *topic_forwarder;
+
struct ast_str *ast_manager_build_bridge_state_string(
const struct ast_bridge_snapshot *snapshot,
const char *suffix)
@@ -409,10 +414,16 @@
return 0;
}
-static void manager_bridging_shutdown(void)
+static void manager_bridging_cleanup(void)
{
stasis_message_router_unsubscribe(bridge_state_router);
bridge_state_router = NULL;
+ stasis_unsubscribe(topic_forwarder);
+ topic_forwarder = NULL;
+}
+
+static void manager_bridging_shutdown(void)
+{
ast_manager_unregister("BridgeList");
ast_manager_unregister("BridgeInfo");
}
@@ -420,6 +431,8 @@
int manager_bridging_init(void)
{
int ret = 0;
+ struct stasis_topic *manager_topic;
+ struct stasis_topic *bridge_topic;
if (bridge_state_router) {
/* Already initialized */
@@ -427,10 +440,29 @@
}
ast_register_atexit(manager_bridging_shutdown);
-
- bridge_state_router = stasis_message_router_create(
- stasis_caching_get_topic(ast_bridge_topic_all_cached()));
-
+ ast_register_cleanup(manager_bridging_cleanup);
+
+ manager_topic = ast_manager_get_topic();
+ if (!manager_topic) {
+ return -1;
+ }
+
+ bridge_topic = stasis_caching_get_topic(ast_bridge_topic_all_cached());
+ if (!bridge_topic) {
+ return -1;
+ }
+
+ topic_forwarder = stasis_forward_all(bridge_topic, manager_topic);
+ if (!topic_forwarder) {
+ return -1;
+ }
+
+ /* BUGBUG - This should really route off of the manager_router, but
+ * can't b/c manager_channels is already routing the
+ * stasis_cache_update_type() messages. Having a separate router can
+ * cause some message ordering issues with bridge and channel messages.
+ */
+ bridge_state_router = stasis_message_router_create(bridge_topic);
if (!bridge_state_router) {
return -1;
}
Modified: trunk/main/stasis_bridging.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/stasis_bridging.c?view=diff&rev=393182&r1=393181&r2=393182
==============================================================================
--- trunk/main/stasis_bridging.c (original)
+++ trunk/main/stasis_bridging.c Fri Jun 28 13:42:24 2013
@@ -41,6 +41,321 @@
#define SNAPSHOT_CHANNELS_BUCKETS 13
+/*** DOCUMENTATION
+ <managerEvent language="en_US" name="BlindTransfer">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a blind transfer is complete.</synopsis>
+ <syntax>
+ <parameter name="Result">
+ <para>Indicates if the transfer was successful or if it failed.</para>
+ <enumlist>
+ <enum name="Fail"><para>An internal error occurred.</para></enum>
+ <enum name="Invalid"><para>Invalid configuration for transfer (e.g. Not bridged)</para></enum>
+ <enum name="Not Permitted"><para>Bridge does not permit transfers</para></enum>
+ <enum name="Success"><para>Transfer completed successfully</para></enum>
+ </enumlist>
+ <note><para>A result of <literal>Success</literal> does not necessarily mean that a target was succesfully
+ contacted. It means that a party was succesfully placed into the dialplan at the expected location.</para></note>
+ </parameter>
+ <parameter name="TransfererChannel">
+ <para>The name of the channel that performed the transfer</para>
+ </parameter>
+ <parameter name="TransfererChannelStateDesc">
+ <enumlist>
+ <enum name="Down"/>
+ <enum name="Rsrvd"/>
+ <enum name="OffHook"/>
+ <enum name="Dialing"/>
+ <enum name="Ring"/>
+ <enum name="Ringing"/>
+ <enum name="Up"/>
+ <enum name="Busy"/>
+ <enum name="Dialing Offhook"/>
+ <enum name="Pre-ring"/>
+ <enum name="Unknown"/>
+ </enumlist>
+ </parameter>
+ <parameter name="TransfererCallerIDNum">
+ </parameter>
+ <parameter name="TransfererCallerIDName">
+ </parameter>
+ <parameter name="TransfererConnectedLineNum">
+ </parameter>
+ <parameter name="TransfererConnectedLineName">
+ </parameter>
+ <parameter name="TransfererAccountCode">
+ </parameter>
+ <parameter name="TransfererContext">
+ </parameter>
+ <parameter name="TransfererExten">
+ </parameter>
+ <parameter name="TransfererPriority">
+ </parameter>
+ <parameter name="TransfererUniqueid">
+ </parameter>
+ <parameter name="BridgeUniqueid">
+ <para>The ID of the bridge where the Transferer performed the transfer</para>
+ </parameter>
+ <parameter name="BridgeType">
+ <para>The type of the bridge where the Transferer performed the transfer</para>
+ </parameter>
+ <parameter name="IsExternal">
+ <para>Indicates if the transfer was performed outside of Asterisk. For instance,
+ a channel protocol native transfer is external. A DTMF transfer is internal.</para>
+ <enumlist>
+ <enum name="Yes" />
+ <enum name="No" />
+ </enumlist>
+ </parameter>
+ <parameter name="Context">
+ <para>Destination context for the blind transfer.</para>
+ </parameter>
+ <parameter name="Extension">
+ <para>Destination extension for the blind transfer.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="AttendedTransfer">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when an attended transfer is complete.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(docs/managerEvent[@name='BlindTransfer']/managerEventInstance/syntax/parameter[@name='Result'])" />
+ <parameter name="OrigTransfererChannel">
+ <para>The original transferer channel that performed the attended transfer.</para>
+ </parameter>
+ <parameter name="OrigTransfererChannelState">
+ <para>A numeric code for the channel's current state, related to DestChannelStateDesc</para>
+ </parameter>
+ <parameter name="OrigTransfererChannelStateDesc">
+ <enumlist>
+ <enum name="Down"/>
+ <enum name="Rsrvd"/>
+ <enum name="OffHook"/>
+ <enum name="Dialing"/>
+ <enum name="Ring"/>
+ <enum name="Ringing"/>
+ <enum name="Up"/>
+ <enum name="Busy"/>
+ <enum name="Dialing Offhook"/>
+ <enum name="Pre-ring"/>
+ <enum name="Unknown"/>
+ </enumlist>
+ </parameter>
+ <parameter name="OrigTransfererCallerIDNum">
+ </parameter>
+ <parameter name="OrigTransfererCallerIDName">
+ </parameter>
+ <parameter name="OrigTransfererConnectedLineNum">
+ </parameter>
+ <parameter name="OrigTransfererConnectedLineName">
+ </parameter>
+ <parameter name="OrigTransfererAccountCode">
+ </parameter>
+ <parameter name="OrigTransfererContext">
+ </parameter>
+ <parameter name="OrigTransfererExten">
+ </parameter>
+ <parameter name="OrigTransfererPriority">
+ </parameter>
+ <parameter name="OrigTransfererUniqueid">
+ </parameter>
+ <parameter name="BridgeUniqueidOrig">
+ <para>The ID of the bridge where the Transferer performed the transfer</para>
+ <note><para>This header will not be present if the original transferer was not in a bridge.</para></note>
+ </parameter>
+ <parameter name="BridgeTypeOrig">
+ <para>The type of the bridge where the Transferer performed the transfer</para>
+ <note><para>This header will not be present if the original transferer was not in a bridge.</para></note>
+ </parameter>
+ <parameter name="SecondTransfererChannel">
+ <para>The second transferer channel involved in the attended transfer.</para>
+ </parameter>
+ <parameter name="SecondTransfererChannelState">
+ <para>A numeric code for the channel's current state, related to SecondTransfererChannelStateDesc</para>
+ </parameter>
+ <parameter name="SecondTransfererChannelStateDesc">
+ <enumlist>
+ <enum name="Down"/>
+ <enum name="Rsrvd"/>
+ <enum name="OffHook"/>
+ <enum name="Dialing"/>
+ <enum name="Ring"/>
+ <enum name="Ringing"/>
+ <enum name="Up"/>
+ <enum name="Busy"/>
+ <enum name="Dialing Offhook"/>
+ <enum name="Pre-ring"/>
+ <enum name="Unknown"/>
+ </enumlist>
+ </parameter>
+ <parameter name="SecondTransfererCallerIDNum">
+ </parameter>
+ <parameter name="SecondTransfererCallerIDName">
+ </parameter>
+ <parameter name="SecondTransfererConnectedLineNum">
+ </parameter>
[... 551 lines stripped ...]
More information about the asterisk-commits
mailing list