diff options
-rw-r--r-- | include/asterisk/stasis_bridges.h | 10 | ||||
-rw-r--r-- | main/bridge.c | 53 | ||||
-rw-r--r-- | main/stasis_bridges.c | 28 | ||||
-rw-r--r-- | res/ari/ari_model_validators.c | 9 | ||||
-rw-r--r-- | res/ari/ari_model_validators.h | 1 | ||||
-rw-r--r-- | res/stasis/app.c | 31 | ||||
-rw-r--r-- | rest-api/api-docs/events.json | 5 | ||||
-rw-r--r-- | tests/test_cel.c | 2 |
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"); |