ao2_lock(queue_data);
if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
- strcmp(queue_data->bridge_uniqueid, transfer_msg->to_transferee.bridge_snapshot->uniqueid)) {
+ strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
ao2_unlock(queue_data);
return;
}
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;
-};
-
/*!
* \since 12
* \brief Message type for \ref ast_blind_transfer_message.
enum ast_transfer_result result;
/*! True if the transfer was initiated by an external source (i.e. not DTMF-initiated) */
int is_external;
- /*! Transferer and its bridge */
- struct ast_bridge_channel_snapshot_pair to_transferee;
+ /*! The transferring channel */
+ struct ast_channel_snapshot *transferer;
+ /*! The bridge between the transferer and the transferee */
+ struct ast_bridge_snapshot *bridge;
/*! Destination context */
char context[AST_MAX_CONTEXT];
/*! Destination extension */
struct ast_channel_snapshot *replace_channel;
};
+/*!
+ * \brief Create a blind transfer message to be published
+ *
+ * \param is_external Whether the blind transfer was initiated externally (e.g. via AMI or native protocol)
+ * \param transferer The transferer's channel that is bridged to the transferee
+ * \param bridge The bridge the transferer and transferee are in
+ * \param context The destination context for the blind transfer
+ * \param exten The destination extension for the blind transfer
+ *
+ * \retval NULL Failure to allocate or create snapshots
+ * \retval non-NULL The created blind transfer message
+ */
+struct ast_blind_transfer_message *ast_blind_transfer_message_create(int is_external,
+ struct ast_channel *transferer, const char *exten, const char *context);
+
/*!
* \brief Publish a blind transfer event
*
* cannot reach across the bridge due to bridge flags, this is
* the channel connecting their bridge to the destination.
*/
-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,
- struct ast_channel *transferee_channel, struct ast_channel *replace_channel);
+void ast_bridge_publish_blind_transfer(struct ast_blind_transfer_message *transfer_message);
enum ast_attended_transfer_dest_type {
/*! The transfer failed, so there is no appropriate final state */
};
/*!
- * \since 12
- * \brief Message type for \ref ast_attended_transfer_message.
+ * \brief Create an Attended transfer message to be published.
*
- * \retval Message type for \ref ast_attended_transfer_message.
+ * The parameters to this function are the basic necessities in order to create the
+ * initial attended transfer message.
+ *
+ * The transferee and transfer_target parameters are optional. If not provided, then this
+ * function will attempt to determine who the transferee and transfer target are based on
+ * the input transferer channels and bridges. You typically will not need to provide an
+ * explicit transferee and transfer target channel unless your attended transfer is implemented
+ * in a strange way.
+ *
+ * \param is_external Non-zero if the transfer was initiated by a native channel driver protocol.
+ * \param to_transferee The transferer channel that is bridged to the transferee channel.
+ * \param transferee_bridge The bridge between the transferer and transferee. May be NULL.
+ * \param to_transfer_target The transferer channel that is bridged to the transfer target.
+ * \param target_bridge The bridge between the transferer and transfer target. May be NULL.
+ * \param transferee The channel that is being transferred. Optional.
+ * \param transfer_target The channel that is being transferred to. Optional.
+ *
+ * \retval NULL Failure to allocate or create snapshots
+ * \retval non-NULL The created attended transfer message
*/
-struct stasis_message_type *ast_attended_transfer_type(void);
+struct ast_attended_transfer_message *ast_attended_transfer_message_create(
+ int is_external, struct ast_channel *to_transferee, struct ast_bridge *transferee_bridge,
+ struct ast_channel *to_transfer_target, struct ast_bridge *target_bridge,
+ struct ast_channel *transferee, struct ast_channel *transfer_target);
/*!
- * \since 12
- * \brief Publish an attended transfer failure
+ * \brief Add details for a bridge merge to an attended transfer message.
*
- * Publish an \ref ast_attended_transfer_message with the dest_type set to
- * \c AST_ATTENDED_TRANSFER_DEST_FAIL.
+ * If the transfer is accomplished by a bridge merge (or swap optimization), then this should
+ * be called on the created attended transfer message to have the appropriate details added on.
*
- * \pre Bridges involved are locked. Channels involved are not locked.
+ * \param transfer_msg The transfer message to add details to
+ * \param final_bridge The bridge where the surviving parties reside
*
- * \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
- * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
- * \param target_channel If a single channel is being transferred to, this is it. If multiple parties are being transferred to, this is NULL.
+ * \retval 0 Success
+ * \retval -1 Failure
*/
-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,
- struct ast_channel *transferee_channel, struct ast_channel *target_channel);
+int ast_attended_transfer_message_add_merge(struct ast_attended_transfer_message *transfer_msg,
+ struct ast_bridge *final_bridge);
/*!
- * \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
+ * \brief Add details for an attended transfer that was resolved as a three-way call
*
- * \li Merging the two bridges together
- * \li Moving a channel from one bridge to the other, thus emptying a bridge
+ * If the transfer results in a three-way call between the transferer, the transferee, and the
+ * transfer target, then this should be called in order to add appropriate details to the
+ * transfer message to be published.
*
- * In either case, two bridges enter, one leaves.
+ * \param transfer_msg The message to add details to
+ * \param survivor_channel The transferer channel that exists in the three-way call
+ * \param survivor_bridge The bridge where the three-way call takes place.
*
- * \pre Bridges involved are locked. Channels involved are not locked.
- *
- * \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.
- * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
- * \param target_channel If a single channel is being transferred to, this is it. If multiple parties are being transferred to, this is NULL.
+ * \retval 0 Success
+ * \retval -1 Failure
*/
-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, struct ast_channel *transferee_channel,
- struct ast_channel *target_channel);
+int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_message *transfer_msg,
+ struct ast_channel *survivor_channel, struct ast_bridge *survivor_bridge);
/*!
- * \since 12
- * \brief Publish an attended transfer that results in a threeway call.
+ * \brief Add details for an attended transfer to an application
*
- * 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
+ * If the transfer is sending one or more parties into an application, then this should be called
+ * to add appropriate details to the transfer message being published.
*
- * \pre Bridges involved are locked. Channels involved are not locked.
+ * \param transfer_msg The message to add details to
+ * \param app The name of the application that the parties are being transferred to
+ * \param replace_channel The local channel that is in the bridge and running the application
*
- * \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.
- * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
- * \param target_channel If a single channel is being transferred to, this is it. If multiple parties are being transferred to, this is NULL.
+ * \retval 0 Success
+ * \retval -1 Failure
*/
-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, struct ast_channel *transferee_channel,
- struct ast_channel *target_channel);
+int ast_attended_transfer_message_add_app(struct ast_attended_transfer_message *transfer_msg,
+ const char *app, struct ast_channel *replace_channel);
/*!
- * \since 12
- * \brief Publish an attended transfer that results in an application being run
+ * \brief Add details for an attended transfer that has a link between bridges.
*
- * 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:
+ * An attended transfer may be accomplished by linking two bridges together with local channels.
+ * If this is how the transfer is to be completed, call this function in order to fill in details
+ * about the transfer.
*
- * \li A transferee channel leaving a bridge to run an app
- * \li A bridge of transferees running an app (via a local channel)
+ * \param transfer_msg The message to add details to.
+ * \param locals An array of local channel halves that each are in one of the involved bridges.
*
- * \pre Bridges involved are locked. Channels involved are not locked.
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_attended_transfer_message_add_link(struct ast_attended_transfer_message *transfer_msg,
+ struct ast_channel *locals[2]);
+
+/*!
+ * \brief Publish an attended transfer
*
- * \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 replace_channel The channel that will be replacing the transferee bridge
- * transferer channel when a local channel is involved
- * \param dest_app The application that the channel or bridge is running upon transfer
- * completion.
- * \param transferee_channel If a single channel is being transferred, this is it.
- * If multiple parties are being transferred, this is NULL.
- * \param target_channel If a single channel is being transferred to, this is it.
- * If multiple parties are being transferred to, this is NULL.
- */
-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,
- struct ast_channel *replace_channel, const char *dest_app,
- struct ast_channel *transferee_channel, struct ast_channel *target_channel);
+ * \param transfer_msg The transfer message to publish
+ */
+void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message *transfer_msg);
/*!
* \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.
- *
- * \pre Bridges involved are locked. Channels involved are not locked.
+ * \brief Message type for \ref ast_attended_transfer_message.
*
- * \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.
- * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
- * \param target_channel If a single channel is being transferred to, this is it. If multiple parties are being transferred to, this is NULL.
- */
-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], struct ast_channel *transferee_channel,
- struct ast_channel *target_channel);
+ * \retval Message type for \ref ast_attended_transfer_message.
+ */
+struct stasis_message_type *ast_attended_transfer_type(void);
/*!
* \brief Returns the most recent snapshot for the bridge.
return peer;
}
-static void publish_blind_transfer_full(int is_external, enum ast_transfer_result result,
- struct ast_channel *transferer, struct ast_bridge *bridge,
- const char *context, const char *exten, struct ast_channel *transferee_channel,
- struct ast_channel *replace_channel)
-{
- struct ast_bridge_channel_pair pair;
-
- pair.channel = transferer;
- pair.bridge = bridge;
-
- if (bridge) {
- ast_bridge_lock(bridge);
- }
- ast_bridge_publish_blind_transfer(is_external, result, &pair, context, exten,
- transferee_channel, replace_channel);
- if (bridge) {
- ast_bridge_unlock(bridge);
- }
-}
-
/*!
* \internal
* \brief Transfer an entire bridge to a specific destination.
* \param transferer The channel performing a transfer
* \param bridge The bridge where the transfer is being performed
* \param exten The destination extension for the blind transfer
- * \param transferee The party being transferred if there is only one
* \param context The destination context for the blind transfer
- * \param hook Framehook to attach to local channel
+ * \param transferee The party being transferred if there is only one
+ * \param new_channel_cb Callback to call on channel that is created to
+ * facilitate the blind transfer.
+ * \param user_data_wrapper User-provided data needed in new_channel_cb
+ * \param transfer_message The Stasis publication for this transfer.
*
* \return The success or failure of the operation
*/
struct ast_channel *transferer, struct ast_bridge *bridge,
const char *exten, const char *context, struct ast_channel *transferee,
transfer_channel_cb new_channel_cb,
- struct transfer_channel_data *user_data_wrapper)
+ struct transfer_channel_data *user_data_wrapper,
+ struct ast_blind_transfer_message *transfer_message)
{
struct ast_channel *local;
char chan_name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
return AST_BRIDGE_TRANSFER_FAIL;
}
+ transfer_message->replace_channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(local));
+ if (!transfer_message->replace_channel) {
+ ast_hangup(local);
+ return AST_BRIDGE_TRANSFER_FAIL;
+ }
+
pbx_builtin_setvar_helper(local, BLINDTRANSFER, ast_channel_name(transferer));
if (new_channel_cb) {
ast_hangup(local);
return AST_BRIDGE_TRANSFER_FAIL;
}
+
if (ast_bridge_impart(bridge, local, transferer, NULL,
AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
ast_hangup(local);
return AST_BRIDGE_TRANSFER_FAIL;
}
- publish_blind_transfer_full(is_external, AST_BRIDGE_TRANSFER_SUCCESS, transferer, bridge,
- context, exten, transferee, local);
+
return AST_BRIDGE_TRANSFER_SUCCESS;
}
-/*!
- * \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;
- /* The Local;1 that will replace the transferee bridge transferer channel */
- struct ast_channel *replace_channel;
- /* The transferee channel. NULL if there is no transferee channel or if multiple parties are transferred */
- struct ast_channel *transferee_channel;
- /* The transfer target channel. NULL if there is no transfer target channel or if multiple parties are transferred */
- struct ast_channel *target_channel;
-};
-
/*!
* \internal
* \brief Get the transferee channel
return transferee;
}
-
-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);
- ast_channel_cleanup(publication->transferee_channel);
- ast_channel_cleanup(publication->target_channel);
- ao2_cleanup(publication->to_transferee.bridge);
- ao2_cleanup(publication->to_transfer_target.bridge);
- ao2_cleanup(publication->replace_channel);
-}
-
-/*!
- * \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;
- }
-
- if (to_transferee_bridge) {
- publication->transferee_channel = ast_bridge_peer(to_transferee_bridge, to_transferee);
- }
- if (to_target_bridge) {
- publication->target_channel = ast_bridge_peer(to_target_bridge, to_transfer_target);
- }
-}
-
-/*
- * \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,
- publication->transferee_channel, publication->target_channel);
-}
-
-/*
- * \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,
- publication->replace_channel, app,
- publication->transferee_channel, publication->target_channel);
-}
-
-/*
- * \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,
- publication->transferee_channel, publication->target_channel);
-}
-
-/*
- * \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, publication->transferee_channel,
- publication->target_channel);
-}
-
/*!
* \brief Perform an attended transfer of a 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 stasis_attended_transfer_publish_data *publication)
+ struct ast_attended_transfer_message *transfer_msg)
{
static const char *dest = "_attended@transfer/m";
struct ast_channel *local_chan;
if (bridge2) {
RAII_VAR(struct ast_channel *, local_chan2, NULL, ao2_cleanup);
+ struct ast_channel *locals[2];
ast_channel_lock(local_chan);
local_chan2 = ast_local_get_peer(local_chan);
ast_assert(local_chan2 != NULL);
- publish_attended_transfer_link(publication,
- local_chan, local_chan2);
+ locals[0] = local_chan;
+ locals[1] = local_chan2;
+
+ ast_attended_transfer_message_add_link(transfer_msg, locals);
} else {
- publication->replace_channel = ao2_bump(local_chan);
- publish_attended_transfer_app(publication, app);
+ ast_attended_transfer_message_add_app(transfer_msg, app, local_chan);
}
ao2_cleanup(local_chan);
return bridge;
}
-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_channel *transferee_channel)
-{
- publish_blind_transfer_full(is_external, result, transferer, bridge, context,
- exten, transferee_channel, NULL);
-}
-
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 ao2_container *, channels, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel *, transferee, NULL, ast_channel_cleanup);
RAII_VAR(struct transfer_channel_data *, user_data_wrapper, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_blind_transfer_message *, transfer_message, NULL, ao2_cleanup);
int do_bridge_transfer;
int transfer_prohibited;
enum ast_transfer_result transfer_result;
+ transfer_message = ast_blind_transfer_message_create(is_external, transferer, exten, context);
+ if (!transfer_message) {
+ /* Out of memory. Not even possible to publish a Stasis message about the
+ * failure
+ */
+ ast_log(LOG_ERROR, "Unable to allocate memory for blind transfer publication from %s\n",
+ ast_channel_name(transferer));
+ return AST_BRIDGE_TRANSFER_FAIL;
+ }
+
bridge = acquire_bridge(transferer);
if (!bridge) {
transfer_result = AST_BRIDGE_TRANSFER_INVALID;
goto publish;
}
+ ast_bridge_lock(bridge);
+ transfer_message->bridge = ast_bridge_snapshot_create(bridge);
+ ast_bridge_unlock(bridge);
+ if (!transfer_message->bridge) {
+ transfer_result = AST_BRIDGE_TRANSFER_FAIL;
+ goto publish;
+ }
+
transferee = ast_bridge_peer(bridge, transferer);
+ if (transferee) {
+ transfer_message->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
+ if (!transfer_message->transferee) {
+ transfer_result = AST_BRIDGE_TRANSFER_FAIL;
+ goto publish;
+ }
+ }
ast_channel_lock(transferer);
bridge_channel = ast_channel_get_bridge_channel(transferer);
set_transfer_variables_all(transferer, channels, 0);
if (do_bridge_transfer) {
- /* if blind_transfer_bridge succeeds, it publishes its own message */
transfer_result = blind_transfer_bridge(is_external, transferer, bridge,
- exten, context, transferee, new_channel_cb, user_data_wrapper);
- if (transfer_result == AST_BRIDGE_TRANSFER_SUCCESS) {
- return transfer_result;
- }
+ exten, context, transferee, new_channel_cb, user_data_wrapper, transfer_message);
goto publish;
}
transfer_result = AST_BRIDGE_TRANSFER_SUCCESS;
publish:
- publish_blind_transfer(is_external, transfer_result, transferer, bridge, context, exten, transferee);
+ transfer_message->result = transfer_result;
+ ast_bridge_publish_blind_transfer(transfer_message);
return transfer_result;
}
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 stasis_attended_transfer_publish_data *publication)
+ struct ast_attended_transfer_message *transfer_msg)
{
struct ast_bridge_channel *kick_me[] = {
to_transferee_bridge_channel,
*/
if (to_transferee_bridge->inhibit_merge || to_transferee_bridge->dissolved ||
to_target_bridge->inhibit_merge || to_target_bridge->dissolved) {
- res = AST_BRIDGE_TRANSFER_INVALID;
- goto end;
+ return AST_BRIDGE_TRANSFER_INVALID;
}
- /* 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, publication);
+ to_transferee_bridge, to_target_bridge, transfer_msg);
}
end:
if (res == AST_BRIDGE_TRANSFER_SUCCESS) {
- publish_attended_transfer_bridge_merge(publication, final_bridge);
+ ast_attended_transfer_message_add_merge(transfer_msg, final_bridge);
}
return res;
RAII_VAR(struct ast_bridge_channel *, to_target_bridge_channel, NULL, ao2_cleanup);
RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel *, transferee, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
struct ast_bridge *the_bridge = NULL;
struct ast_channel *chan_bridged;
struct ast_channel *chan_unbridged;
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);
+ transfer_msg = ast_attended_transfer_message_create(1, to_transferee, to_transferee_bridge,
+ to_transfer_target, to_target_bridge, NULL, NULL);
+ if (!transfer_msg) {
+ ast_log(LOG_ERROR, "Unable to create Stasis publication for attended transfer from %s\n",
+ ast_channel_name(to_transferee));
+ return AST_BRIDGE_TRANSFER_FAIL;
+ }
/* They can't both be unbridged, you silly goose! */
if (!to_transferee_bridge && !to_target_bridge) {
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, &publication);
+ to_transferee_bridge, to_target_bridge, transfer_msg);
ast_bridge_unlock(to_transferee_bridge);
ast_bridge_unlock(to_target_bridge);
if (do_bridge_transfer) {
ast_bridge_lock(the_bridge);
- res = attended_transfer_bridge(chan_bridged, chan_unbridged, the_bridge, NULL, &publication);
+ res = attended_transfer_bridge(chan_bridged, chan_unbridged, the_bridge, NULL, transfer_msg);
ast_bridge_unlock(the_bridge);
goto end;
}
ast_bridge_remove(the_bridge, chan_bridged);
- ast_bridge_lock(the_bridge);
- publish_attended_transfer_app(&publication, app);
- ast_bridge_unlock(the_bridge);
+ ast_attended_transfer_message_add_app(transfer_msg, app, NULL);
res = 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) {
- if (to_transferee_bridge && to_target_bridge) {
- ast_bridge_lock_both(to_transferee_bridge, to_target_bridge);
- } else if (the_bridge) {
- ast_bridge_lock(the_bridge);
- }
-
- publish_attended_transfer_fail(&publication, res);
-
- if (to_transferee_bridge && to_target_bridge) {
- ast_bridge_unlock(to_transferee_bridge);
- ast_bridge_unlock(to_target_bridge);
- } else if (the_bridge) {
- ast_bridge_unlock(the_bridge);
- }
- }
- stasis_publish_data_cleanup(&publication);
+ transfer_msg->result = res;
+ ast_bridge_publish_attended_transfer(transfer_msg);
return res;
}
static void publish_transfer_success(struct attended_transfer_properties *props,
struct ast_channel *transferee_channel, struct ast_channel *target_channel)
{
- struct ast_bridge_channel_pair transferee = {
- .channel = props->transferer,
- .bridge = props->transferee_bridge,
- };
- struct ast_bridge_channel_pair transfer_target = {
- .channel = props->transferer,
- .bridge = props->target_bridge,
- };
-
- if (transferee.bridge && transfer_target.bridge) {
- ast_bridge_lock_both(transferee.bridge, transfer_target.bridge);
- } else if (transferee.bridge) {
- ast_bridge_lock(transferee.bridge);
- } else if (transfer_target.bridge) {
- ast_bridge_lock(transfer_target.bridge);
- }
+ struct ast_attended_transfer_message *transfer_msg;
- ast_bridge_publish_attended_transfer_bridge_merge(0, AST_BRIDGE_TRANSFER_SUCCESS,
- &transferee, &transfer_target, props->transferee_bridge, transferee_channel,
- target_channel);
+ transfer_msg = ast_attended_transfer_message_create(0, props->transferer,
+ props->transferee_bridge, props->transferer, props->target_bridge,
+ transferee_channel, target_channel);
- if (transferee.bridge) {
- ast_bridge_unlock(transferee.bridge);
- }
- if (transfer_target.bridge) {
- ast_bridge_unlock(transfer_target.bridge);
+ if (!transfer_msg) {
+ ast_log(LOG_ERROR, "Unable to publish successful attended transfer from %s\n",
+ ast_channel_name(props->transferer));
+ return;
}
+
+ ast_attended_transfer_message_add_merge(transfer_msg, props->transferee_bridge);
+ ast_bridge_publish_attended_transfer(transfer_msg);
+ ao2_cleanup(transfer_msg);
}
/*!
static void publish_transfer_threeway(struct attended_transfer_properties *props,
struct ast_channel *transferee_channel, struct ast_channel *target_channel)
{
- struct ast_bridge_channel_pair transferee = {
- .channel = props->transferer,
- .bridge = props->transferee_bridge,
- };
- struct ast_bridge_channel_pair transfer_target = {
- .channel = props->transferer,
- .bridge = props->target_bridge,
- };
- struct ast_bridge_channel_pair threeway = {
- .channel = props->transferer,
- .bridge = props->transferee_bridge,
- };
+ struct ast_attended_transfer_message *transfer_msg;
- if (transferee.bridge && transfer_target.bridge) {
- ast_bridge_lock_both(transferee.bridge, transfer_target.bridge);
- } else if (transferee.bridge) {
- ast_bridge_lock(transferee.bridge);
- } else if (transfer_target.bridge) {
- ast_bridge_lock(transfer_target.bridge);
- }
+ transfer_msg = ast_attended_transfer_message_create(0, props->transferer,
+ props->transferee_bridge, props->transferer, props->target_bridge,
+ transferee_channel, target_channel);
- ast_bridge_publish_attended_transfer_threeway(0, AST_BRIDGE_TRANSFER_SUCCESS,
- &transferee, &transfer_target, &threeway, transferee_channel,
- target_channel);
-
- if (transferee.bridge) {
- ast_bridge_unlock(transferee.bridge);
- }
- if (transfer_target.bridge) {
- ast_bridge_unlock(transfer_target.bridge);
+ if (!transfer_msg) {
+ ast_log(LOG_ERROR, "Unable to publish successful three-way transfer from %s\n",
+ ast_channel_name(props->transferer));
+ return;
}
+
+ ast_attended_transfer_message_add_threeway(transfer_msg, props->transferer,
+ props->transferee_bridge);
+ ast_bridge_publish_attended_transfer(transfer_msg);
+ ao2_cleanup(transfer_msg);
}
/*!
*/
static void publish_transfer_fail(struct attended_transfer_properties *props)
{
- struct ast_bridge_channel_pair transferee = {
- .channel = props->transferer,
- .bridge = props->transferee_bridge,
- };
- struct ast_bridge_channel_pair transfer_target = {
- .channel = props->transferer,
- .bridge = props->target_bridge,
- };
- struct ast_channel *transferee_channel;
- struct ast_channel *target_channel;
-
- if (transferee.bridge && transfer_target.bridge) {
- ast_bridge_lock_both(transferee.bridge, transfer_target.bridge);
- } else if (transferee.bridge) {
- ast_bridge_lock(transferee.bridge);
- } else if (transfer_target.bridge) {
- ast_bridge_lock(transfer_target.bridge);
- }
+ struct ast_attended_transfer_message *transfer_msg;
- get_transfer_parties(props->transferer, props->transferee_bridge, props->target_bridge,
- &transferee_channel, &target_channel);
- ast_bridge_publish_attended_transfer_fail(0, AST_BRIDGE_TRANSFER_FAIL,
- &transferee, &transfer_target, transferee_channel, target_channel);
- ast_channel_cleanup(transferee_channel);
- ast_channel_cleanup(target_channel);
+ transfer_msg = ast_attended_transfer_message_create(0, props->transferer,
+ props->transferee_bridge, props->transferer, props->target_bridge,
+ NULL, NULL);
- if (transferee.bridge) {
- ast_bridge_unlock(transferee.bridge);
- }
- if (transfer_target.bridge) {
- ast_bridge_unlock(transfer_target.bridge);
+ if (!transfer_msg) {
+ ast_log(LOG_ERROR, "Unable to publish failed transfer from %s\n",
+ ast_channel_name(props->transferer));
+ return;
}
+
+ transfer_msg->result = AST_BRIDGE_TRANSFER_FAIL;
+ ast_bridge_publish_attended_transfer(transfer_msg);
+ ao2_cleanup(transfer_msg);
}
/*!
struct stasis_message *message)
{
struct ast_blind_transfer_message *transfer_msg = stasis_message_data(message);
- struct ast_channel_snapshot *chan_snapshot = transfer_msg->to_transferee.channel_snapshot;
- struct ast_bridge_snapshot *bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
+ struct ast_channel_snapshot *chan_snapshot = transfer_msg->transferer;
+ struct ast_bridge_snapshot *bridge_snapshot = transfer_msg->bridge;
struct ast_json *extra;
if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
* \retval 0 Success
* \retval non-zero Failure
*/
-static int bridge_channel_snapshot_pair_init(struct ast_bridge_channel_pair *pair, struct ast_bridge_channel_snapshot_pair *snapshot_pair)
+static int bridge_channel_snapshot_pair_init(struct ast_channel *channel, struct ast_bridge *bridge,
+ struct ast_bridge_channel_snapshot_pair *snapshot_pair)
{
- if (pair->bridge) {
- snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(pair->bridge);
+ if (bridge) {
+ ast_bridge_lock(bridge);
+ snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(bridge);
+ ast_bridge_unlock(bridge);
if (!snapshot_pair->bridge_snapshot) {
return -1;
}
}
- snapshot_pair->channel_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(pair->channel));
+ snapshot_pair->channel_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(channel));
if (!snapshot_pair->channel_snapshot) {
return -1;
}
struct ast_json *json_replace = NULL;
const struct timeval *tv = stasis_message_timestamp(msg);
- json_transferer = ast_channel_snapshot_to_json(transfer_msg->to_transferee.channel_snapshot, sanitize);
+ json_transferer = ast_channel_snapshot_to_json(transfer_msg->transferer, sanitize);
if (!json_transferer) {
return NULL;
}
return NULL;
}
- if (transfer_msg->to_transferee.bridge_snapshot) {
+ if (transfer_msg->bridge) {
struct ast_json *json_bridge = ast_bridge_snapshot_to_json(
- transfer_msg->to_transferee.bridge_snapshot, sanitize);
+ transfer_msg->bridge, sanitize);
if (!json_bridge || ast_json_object_set(out, "bridge", json_bridge)) {
ast_json_unref(out);
}
transferer_state = ast_manager_build_channel_state_string_prefix(
- transfer_msg->to_transferee.channel_snapshot, "Transferer");
+ transfer_msg->transferer, "Transferer");
if (!transferer_state) {
return NULL;
}
- if (transfer_msg->to_transferee.bridge_snapshot) {
- bridge_state = ast_manager_build_bridge_state_string(transfer_msg->to_transferee.bridge_snapshot);
+ if (transfer_msg->bridge) {
+ bridge_state = ast_manager_build_bridge_state_string(transfer_msg->bridge);
if (!bridge_state) {
return NULL;
}
{
struct ast_blind_transfer_message *msg = obj;
- bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
+ ao2_cleanup(msg->transferer);
+ ao2_cleanup(msg->bridge);
ao2_cleanup(msg->transferee);
+ ao2_cleanup(msg->replace_channel);
}
-void ast_bridge_publish_blind_transfer(int is_external, enum ast_transfer_result result,
- struct ast_bridge_channel_pair *transferer, const char *context, const char *exten,
- struct ast_channel *transferee_channel, struct ast_channel *replace_channel)
+struct ast_blind_transfer_message *ast_blind_transfer_message_create(int is_external,
+ struct ast_channel *transferer, const char *exten, const char *context)
{
struct ast_blind_transfer_message *msg;
- struct stasis_message *stasis;
msg = ao2_alloc(sizeof(*msg), blind_transfer_dtor);
if (!msg) {
- return;
+ return NULL;
}
- if (bridge_channel_snapshot_pair_init(transferer, &msg->to_transferee)) {
+ msg->transferer = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferer));
+ if (!msg->transferer) {
ao2_cleanup(msg);
- return;
+ return NULL;
}
- if (transferee_channel) {
- msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee_channel));
- }
- if (replace_channel) {
- msg->replace_channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(replace_channel));
- }
msg->is_external = is_external;
- msg->result = result;
ast_copy_string(msg->context, context, sizeof(msg->context));
ast_copy_string(msg->exten, exten, sizeof(msg->exten));
- stasis = stasis_message_create(ast_blind_transfer_type(), msg);
+ return msg;
+}
+
+
+void ast_bridge_publish_blind_transfer(struct ast_blind_transfer_message *transfer_message)
+{
+ struct stasis_message *stasis;
+
+ stasis = stasis_message_create(ast_blind_transfer_type(), transfer_message);
if (!stasis) {
- ao2_cleanup(msg);
return;
}
stasis_publish(ast_bridge_topic_all(), stasis);
ao2_cleanup(stasis);
- ao2_cleanup(msg);
}
static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
}
}
-static struct ast_attended_transfer_message *attended_transfer_message_create(int is_external,
- enum ast_transfer_result result, struct ast_bridge_channel_pair *transferee,
- struct ast_bridge_channel_pair *target, struct ast_channel *replace_channel,
- struct ast_channel *transferee_channel, struct ast_channel *target_channel)
+struct ast_attended_transfer_message *ast_attended_transfer_message_create(int is_external,
+ struct ast_channel *to_transferee, struct ast_bridge *transferee_bridge,
+ struct ast_channel *to_transfer_target, struct ast_bridge *target_bridge,
+ struct ast_channel *transferee, struct ast_channel *transfer_target)
{
- RAII_VAR(struct ast_attended_transfer_message *, msg, NULL, ao2_cleanup);
+ struct ast_attended_transfer_message *transfer_msg;
- msg = ao2_alloc(sizeof(*msg), attended_transfer_dtor);
- if (!msg) {
+ transfer_msg = ao2_alloc(sizeof(*transfer_msg), attended_transfer_dtor);
+ if (!transfer_msg) {
return NULL;
}
- if (bridge_channel_snapshot_pair_init(transferee, &msg->to_transferee) ||
- bridge_channel_snapshot_pair_init(target, &msg->to_transfer_target)) {
+ if (bridge_channel_snapshot_pair_init(to_transferee, transferee_bridge, &transfer_msg->to_transferee) ||
+ bridge_channel_snapshot_pair_init(to_transfer_target, target_bridge, &transfer_msg->to_transfer_target)) {
+ ao2_cleanup(transfer_msg);
return NULL;
}
- if (replace_channel) {
- msg->replace_channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(replace_channel));
- if (!msg->replace_channel) {
+ if (transferee) {
+ transfer_msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
+ if (!transfer_msg->transferee) {
+ ao2_cleanup(transfer_msg);
return NULL;
}
+ } else if (transferee_bridge) {
+ transferee = ast_bridge_peer(transferee_bridge, to_transferee);
+ if (transferee) {
+ transfer_msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
+ ao2_cleanup(transferee);
+ if (!transfer_msg->transferee) {
+ ao2_cleanup(transfer_msg);
+ return NULL;
+ }
+ }
}
- if (transferee_channel) {
- msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee_channel));
- }
- if (target_channel) {
- msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(target_channel));
- }
- msg->is_external = is_external;
- msg->result = result;
-
- ao2_ref(msg, +1);
- return msg;
-}
-
-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,
- struct ast_channel *transferee_channel, struct ast_channel *target_channel)
-{
- RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
- transfer_msg = attended_transfer_message_create(is_external, result,
- transferee, target, NULL, transferee_channel, target_channel);
- if (!transfer_msg) {
- return;
- }
-
- transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_FAIL;
-
- msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
- if (!msg) {
- return;
+ if (transfer_target) {
+ transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
+ if (!transfer_msg->target) {
+ ao2_cleanup(transfer_msg);
+ return NULL;
+ }
+ } else if (target_bridge) {
+ transfer_target = ast_bridge_peer(target_bridge, to_transfer_target);
+ if (transfer_target) {
+ transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
+ ao2_cleanup(transfer_target);
+ if (!transfer_msg->target) {
+ ao2_cleanup(transfer_msg);
+ return NULL;
+ }
+ }
}
- stasis_publish(ast_bridge_topic_all(), msg);
+ return transfer_msg;
}
-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, struct ast_channel *transferee_channel,
- struct ast_channel *target_channel)
+int ast_attended_transfer_message_add_merge(struct ast_attended_transfer_message *transfer_msg,
+ struct ast_bridge *final_bridge)
{
- RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
- transfer_msg = attended_transfer_message_create(is_external, result,
- transferee, target, NULL, transferee_channel, target_channel);
- if (!transfer_msg) {
- return;
- }
-
transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE;
ast_copy_string(transfer_msg->dest.bridge, final_bridge->uniqueid,
sizeof(transfer_msg->dest.bridge));
- msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
- if (!msg) {
- return;
- }
-
- stasis_publish(ast_bridge_topic_all(), msg);
+ return 0;
}
-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, struct ast_channel *transferee_channel,
- struct ast_channel *target_channel)
+int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_message *transfer_msg,
+ struct ast_channel *survivor_channel, struct ast_bridge *survivor_bridge)
{
- RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
- transfer_msg = attended_transfer_message_create(is_external, result,
- transferee, target, NULL, transferee_channel, target_channel);
- if (!transfer_msg) {
- return;
- }
-
transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
- if (final_pair->channel == transferee->channel) {
+
+ if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->uniqueid)) {
transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
} else {
transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
}
- if (final_pair->bridge == transferee->bridge) {
+ if (!strcmp(survivor_bridge->uniqueid, transfer_msg->to_transferee.bridge_snapshot->uniqueid)) {
transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
} else {
transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transfer_target.bridge_snapshot;
}
- msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
- if (!msg) {
- return;
- }
-
- stasis_publish(ast_bridge_topic_all(), msg);
+ return 0;
}
-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,
- struct ast_channel *replace_channel, const char *dest_app,
- struct ast_channel *transferee_channel, struct ast_channel *target_channel)
+int ast_attended_transfer_message_add_app(struct ast_attended_transfer_message *transfer_msg,
+ const char *app, struct ast_channel *replace_channel)
{
- RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
- transfer_msg = attended_transfer_message_create(is_external, result,
- transferee, target, replace_channel, transferee_channel, target_channel);
- if (!transfer_msg) {
- return;
- }
-
transfer_msg->dest_type = replace_channel ? AST_ATTENDED_TRANSFER_DEST_LOCAL_APP : AST_ATTENDED_TRANSFER_DEST_APP;
- ast_copy_string(transfer_msg->dest.app, dest_app, sizeof(transfer_msg->dest.app));
- msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
- if (!msg) {
- return;
+ if (replace_channel) {
+ transfer_msg->replace_channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(replace_channel));
+ if (!transfer_msg->replace_channel) {
+ return -1;
+ }
}
- stasis_publish(ast_bridge_topic_all(), msg);
+ ast_copy_string(transfer_msg->dest.app, app, sizeof(transfer_msg->dest.app));
+
+ return 0;
}
-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], struct ast_channel *transferee_channel,
- struct ast_channel *target_channel)
+int ast_attended_transfer_message_add_link(struct ast_attended_transfer_message *transfer_msg,
+ struct ast_channel *locals[2])
{
- RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
int i;
- transfer_msg = attended_transfer_message_create(is_external, result,
- transferee, target, NULL, transferee_channel, target_channel);
- if (!transfer_msg) {
- return;
- }
-
transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
for (i = 0; i < 2; ++i) {
transfer_msg->dest.links[i] = ast_channel_snapshot_get_latest(ast_channel_uniqueid(locals[i]));
if (!transfer_msg->dest.links[i]) {
- return;
+ return -1;
}
}
+ return 0;
+}
+
+void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message *transfer_msg)
+{
+ RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
if (!msg) {
return;
{
struct stasis_app *app = data;
struct ast_blind_transfer_message *transfer_msg = stasis_message_data(message);
- struct ast_bridge_snapshot *bridge = transfer_msg->to_transferee.bridge_snapshot;
+ struct ast_bridge_snapshot *bridge = transfer_msg->bridge;
if (transfer_msg->replace_channel) {
- set_replacement_channel(transfer_msg->to_transferee.channel_snapshot,
- transfer_msg->replace_channel);
+ set_replacement_channel(transfer_msg->transferer, transfer_msg->replace_channel);
}
- if (bridge_app_subscribed(app, transfer_msg->to_transferee.channel_snapshot->uniqueid) ||
+ if (bridge_app_subscribed(app, transfer_msg->transferer->uniqueid) ||
(bridge && bridge_app_subscribed_involved(app, bridge))) {
stasis_publish(app->topic, message);
}