summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/stasis_bridges.h10
-rw-r--r--main/bridge.c53
-rw-r--r--main/stasis_bridges.c28
-rw-r--r--res/ari/ari_model_validators.c9
-rw-r--r--res/ari/ari_model_validators.h1
-rw-r--r--res/stasis/app.c31
-rw-r--r--rest-api/api-docs/events.json5
-rw-r--r--tests/test_cel.c2
8 files changed, 106 insertions, 33 deletions
diff --git a/include/asterisk/stasis_bridges.h b/include/asterisk/stasis_bridges.h
index a4e46cdb0..699e27626 100644
--- a/include/asterisk/stasis_bridges.h
+++ b/include/asterisk/stasis_bridges.h
@@ -300,6 +300,8 @@ struct ast_blind_transfer_message {
char exten[AST_MAX_EXTENSION];
/*! Transferee channel. NULL if there were multiple transferee channels */
struct ast_channel_snapshot *transferee;
+ /*! The channel replacing the transferer when multiple parties are being transferred */
+ struct ast_channel_snapshot *replace_channel;
};
/*!
@@ -312,11 +314,15 @@ struct ast_blind_transfer_message {
* \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
- * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
+ * \param transferee_channel If a single channel is being transferred, this is it. If
+ * multiple parties are being transferred, this is NULL.
+ * \param replace_channel If multiple parties are being transferred or the transfer
+ * 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 *transferee_channel, struct ast_channel *replace_channel);
enum ast_attended_transfer_dest_type {
/*! The transfer failed, so there is no appropriate final state */
diff --git a/main/bridge.c b/main/bridge.c
index 66c495a0c..a3ca8a976 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -3805,6 +3805,26 @@ struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channe
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.
@@ -3817,16 +3837,21 @@ struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channe
* bridges, this method is only used for multi-party bridges since this method would
* be less efficient for two-party bridges.
*
+ * \param is_external Whether the transfer is externally initiated
* \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
+ *
* \return The success or failure of the operation
*/
-static enum ast_transfer_result blind_transfer_bridge(struct ast_channel *transferer,
- struct ast_bridge *bridge, const char *exten, const char *context,
- transfer_channel_cb new_channel_cb, struct transfer_channel_data *user_data_wrapper)
+static enum ast_transfer_result blind_transfer_bridge(int is_external,
+ 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 ast_channel *local;
char chan_name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
@@ -3858,6 +3883,8 @@ static enum ast_transfer_result blind_transfer_bridge(struct ast_channel *transf
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;
}
@@ -4214,16 +4241,8 @@ static void publish_blind_transfer(int is_external, enum ast_transfer_result res
struct ast_channel *transferer, struct ast_bridge *bridge,
const char *context, const char *exten, struct ast_channel *transferee_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);
- if (bridge) {
- ast_bridge_unlock(bridge);
- }
+ 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,
@@ -4301,8 +4320,12 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
set_transfer_variables_all(transferer, channels, 0);
if (do_bridge_transfer) {
- transfer_result = blind_transfer_bridge(transferer, bridge, exten, context,
- new_channel_cb, user_data_wrapper);
+ /* 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;
+ }
goto publish;
}
diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c
index 7b61ce31d..16fda2d49 100644
--- a/main/stasis_bridges.c
+++ b/main/stasis_bridges.c
@@ -636,7 +636,10 @@ static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
const struct stasis_message_sanitizer *sanitize)
{
struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
- struct ast_json *json_transferer, *json_transferee = NULL, *out;
+ struct ast_json *json_transferer;
+ struct ast_json *json_transferee = NULL;
+ struct ast_json *out;
+ 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);
@@ -647,6 +650,16 @@ static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
if (transfer_msg->transferee) {
json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
if (!json_transferee) {
+ ast_json_unref(json_transferer);
+ return NULL;
+ }
+ }
+
+ if (transfer_msg->replace_channel) {
+ json_replace = ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize);
+ if (!json_replace) {
+ ast_json_unref(json_transferee);
+ ast_json_unref(json_transferer);
return NULL;
}
}
@@ -661,11 +674,19 @@ static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
"is_external", ast_json_boolean(transfer_msg->is_external));
if (!out) {
+ ast_json_unref(json_transferee);
+ ast_json_unref(json_replace);
return NULL;
}
if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
ast_json_unref(out);
+ ast_json_unref(json_replace);
+ return NULL;
+ }
+
+ if (json_replace && ast_json_object_set(out, "replace_channel", json_replace)) {
+ ast_json_unref(out);
return NULL;
}
@@ -741,7 +762,7 @@ static void blind_transfer_dtor(void *obj)
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 *transferee_channel, struct ast_channel *replace_channel)
{
struct ast_blind_transfer_message *msg;
struct stasis_message *stasis;
@@ -759,6 +780,9 @@ void ast_bridge_publish_blind_transfer(int is_external, enum ast_transfer_result
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));
diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c
index be1a244df..06c3cf7ee 100644
--- a/res/ari/ari_model_validators.c
+++ b/res/ari/ari_model_validators.c
@@ -2062,6 +2062,15 @@ int ast_ari_validate_bridge_blind_transfer(struct ast_json *json)
res = 0;
}
} else
+ if (strcmp("replace_channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field replace_channel failed validation\n");
+ res = 0;
+ }
+ } else
if (strcmp("result", ast_json_object_iter_key(iter)) == 0) {
int prop_is_valid;
has_result = 1;
diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h
index 64dd1b071..3a0bdb94a 100644
--- a/res/ari/ari_model_validators.h
+++ b/res/ari/ari_model_validators.h
@@ -1304,6 +1304,7 @@ ari_validator ast_ari_validate_application_fn(void);
* - context: string (required)
* - exten: string (required)
* - is_external: boolean (required)
+ * - replace_channel: Channel
* - result: string (required)
* - transferee: Channel
* BridgeCreated
diff --git a/res/stasis/app.c b/res/stasis/app.c
index 245936734..9440cf1bd 100644
--- a/res/stasis/app.c
+++ b/res/stasis/app.c
@@ -696,19 +696,6 @@ static int bridge_app_subscribed_involved(struct stasis_app *app, struct ast_bri
return subscribed;
}
-static void bridge_blind_transfer_handler(void *data, struct stasis_subscription *sub,
- struct stasis_message *message)
-{
- 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;
-
- if (bridge_app_subscribed(app, transfer_msg->to_transferee.channel_snapshot->uniqueid) ||
- (bridge && bridge_app_subscribed_involved(app, bridge))) {
- stasis_publish(app->topic, message);
- }
-}
-
static void set_replacement_channel(struct ast_channel_snapshot *to_be_replaced,
struct ast_channel_snapshot *replacing)
{
@@ -726,6 +713,24 @@ static void set_replacement_channel(struct ast_channel_snapshot *to_be_replaced,
ao2_cleanup(control);
}
+static void bridge_blind_transfer_handler(void *data, struct stasis_subscription *sub,
+ struct stasis_message *message)
+{
+ 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;
+
+ if (transfer_msg->replace_channel) {
+ set_replacement_channel(transfer_msg->to_transferee.channel_snapshot,
+ transfer_msg->replace_channel);
+ }
+
+ if (bridge_app_subscribed(app, transfer_msg->to_transferee.channel_snapshot->uniqueid) ||
+ (bridge && bridge_app_subscribed_involved(app, bridge))) {
+ stasis_publish(app->topic, message);
+ }
+}
+
static void bridge_attended_transfer_handler(void *data, struct stasis_subscription *sub,
struct stasis_message *message)
{
diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json
index 9288ac055..2623801ae 100644
--- a/rest-api/api-docs/events.json
+++ b/rest-api/api-docs/events.json
@@ -285,6 +285,11 @@
"required": true,
"type": "Channel"
},
+ "replace_channel": {
+ "description": "The channel that is replacing transferer when the transferee(s) can not be transferred directly",
+ "required": false,
+ "type": "Channel"
+ },
"transferee": {
"description": "The channel that is being transferred",
"required": false,
diff --git a/tests/test_cel.c b/tests/test_cel.c
index b2a1fd3e5..017c48b47 100644
--- a/tests/test_cel.c
+++ b/tests/test_cel.c
@@ -1257,7 +1257,7 @@ AST_TEST_DEFINE(test_cel_blind_transfer)
pair.channel = chan_alice;
ast_bridge_lock(bridge);
ast_bridge_publish_blind_transfer(1, AST_BRIDGE_TRANSFER_SUCCESS,
- &pair, "transfer_context", "transfer_extension", NULL);
+ &pair, "transfer_context", "transfer_extension", NULL, NULL);
ast_bridge_unlock(bridge);
BLINDTRANSFER_EVENT(chan_alice, bridge, "transfer_extension", "transfer_context");