mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-21 20:40:10 +00:00
ARI: Add method to Dial a created channel.
This adds a new ARI method that allows for you to dial a channel that you previously created in ARI. By combining this with the create method for channels, it allows for a workflow where a channel can be created, manipulated, and then dialed. The channel is under control of the ARI application during all stages of the Dial and can even be manipulated based on channel state changes observed within an ARI application. The overarching goal for this is to eventually be able to add a dialed channel to a Stasis bridge earlier than the "Up" state. However, at the moment more work is needed in the Dial and Bridge APIs in order to facilitate that. ASTERISK-25889 #close Change-Id: Ic6c399c791e66c4aa52454222fe4f8b02483a205
This commit is contained in:
committed by
Joshua Colp
parent
dd48d60c5b
commit
abbb2edd4c
@@ -77,6 +77,10 @@ struct stasis_app_control {
|
||||
* The app for which this control was created
|
||||
*/
|
||||
struct stasis_app *app;
|
||||
/*!
|
||||
* If channel is being dialed, the dial structure.
|
||||
*/
|
||||
struct ast_dial *dial;
|
||||
/*!
|
||||
* When set, /c app_stasis should exit and continue in the dialplan.
|
||||
*/
|
||||
@@ -272,89 +276,6 @@ static struct stasis_app_command *exec_command(
|
||||
return exec_command_on_condition(control, command_fn, data, data_destructor, NULL);
|
||||
}
|
||||
|
||||
struct stasis_app_control_dial_data {
|
||||
char endpoint[AST_CHANNEL_NAME];
|
||||
int timeout;
|
||||
};
|
||||
|
||||
static int app_control_dial(struct stasis_app_control *control,
|
||||
struct ast_channel *chan, void *data)
|
||||
{
|
||||
RAII_VAR(struct ast_dial *, dial, ast_dial_create(), ast_dial_destroy);
|
||||
struct stasis_app_control_dial_data *dial_data = data;
|
||||
enum ast_dial_result res;
|
||||
char *tech, *resource;
|
||||
struct ast_channel *new_chan;
|
||||
RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
|
||||
|
||||
tech = dial_data->endpoint;
|
||||
if (!(resource = strchr(tech, '/'))) {
|
||||
return -1;
|
||||
}
|
||||
*resource++ = '\0';
|
||||
|
||||
if (!dial) {
|
||||
ast_log(LOG_ERROR, "Failed to create dialing structure.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_dial_append(dial, tech, resource, NULL) < 0) {
|
||||
ast_log(LOG_ERROR, "Failed to add %s/%s to dialing structure.\n", tech, resource);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_dial_set_global_timeout(dial, dial_data->timeout);
|
||||
|
||||
res = ast_dial_run(dial, NULL, 0);
|
||||
if (res != AST_DIAL_RESULT_ANSWERED || !(new_chan = ast_dial_answered_steal(dial))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(bridge = ast_bridge_basic_new())) {
|
||||
ast_log(LOG_ERROR, "Failed to create basic bridge.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_bridge_impart(bridge, new_chan, NULL, NULL,
|
||||
AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
|
||||
ast_hangup(new_chan);
|
||||
} else {
|
||||
control_add_channel_to_bridge(control, chan, bridge);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, const char *exten, const char *context,
|
||||
int timeout)
|
||||
{
|
||||
struct stasis_app_control_dial_data *dial_data;
|
||||
|
||||
if (!(dial_data = ast_calloc(1, sizeof(*dial_data)))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(endpoint)) {
|
||||
ast_copy_string(dial_data->endpoint, endpoint, sizeof(dial_data->endpoint));
|
||||
} else if (!ast_strlen_zero(exten) && !ast_strlen_zero(context)) {
|
||||
snprintf(dial_data->endpoint, sizeof(dial_data->endpoint), "Local/%s@%s", exten, context);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
dial_data->timeout = timeout * 1000;
|
||||
} else if (timeout == -1) {
|
||||
dial_data->timeout = -1;
|
||||
} else {
|
||||
dial_data->timeout = 30000;
|
||||
}
|
||||
|
||||
stasis_app_send_command_async(control, app_control_dial, dial_data, ast_free_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int app_control_add_role(struct stasis_app_control *control,
|
||||
struct ast_channel *chan, void *data)
|
||||
{
|
||||
@@ -1185,3 +1106,84 @@ struct stasis_app *control_app(struct stasis_app_control *control)
|
||||
{
|
||||
return control->app;
|
||||
}
|
||||
|
||||
static void app_control_dial_destroy(void *data)
|
||||
{
|
||||
struct ast_dial *dial = data;
|
||||
|
||||
ast_dial_join(dial);
|
||||
ast_dial_destroy(dial);
|
||||
}
|
||||
|
||||
static int app_control_remove_dial(struct stasis_app_control *control,
|
||||
struct ast_channel *chan, void *data)
|
||||
{
|
||||
if (ast_dial_state(control->dial) != AST_DIAL_RESULT_ANSWERED) {
|
||||
ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
|
||||
}
|
||||
control->dial = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void on_dial_state(struct ast_dial *dial)
|
||||
{
|
||||
enum ast_dial_result state;
|
||||
struct stasis_app_control *control;
|
||||
struct ast_channel *chan;
|
||||
|
||||
state = ast_dial_state(dial);
|
||||
control = ast_dial_get_user_data(dial);
|
||||
|
||||
switch (state) {
|
||||
case AST_DIAL_RESULT_ANSWERED:
|
||||
/* Need to steal the reference to the answered channel so that dial doesn't
|
||||
* try to hang it up when we destroy the dial structure.
|
||||
*/
|
||||
chan = ast_dial_answered_steal(dial);
|
||||
ast_channel_unref(chan);
|
||||
/* Fall through intentionally */
|
||||
case AST_DIAL_RESULT_INVALID:
|
||||
case AST_DIAL_RESULT_FAILED:
|
||||
case AST_DIAL_RESULT_TIMEOUT:
|
||||
case AST_DIAL_RESULT_HANGUP:
|
||||
case AST_DIAL_RESULT_UNANSWERED:
|
||||
/* The dial has completed, so we need to break the Stasis loop so
|
||||
* that the channel's frames are handled in the proper place now.
|
||||
*/
|
||||
stasis_app_send_command_async(control, app_control_remove_dial, dial, app_control_dial_destroy);
|
||||
break;
|
||||
case AST_DIAL_RESULT_TRYING:
|
||||
case AST_DIAL_RESULT_RINGING:
|
||||
case AST_DIAL_RESULT_PROGRESS:
|
||||
case AST_DIAL_RESULT_PROCEEDING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int app_control_dial(struct stasis_app_control *control,
|
||||
struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_dial *dial = data;
|
||||
|
||||
ast_dial_set_state_callback(dial, on_dial_state);
|
||||
/* The dial API gives the option of providing a caller channel, but for
|
||||
* Stasis, we really don't want to do that. The Dial API will take liberties such
|
||||
* as passing frames along to the calling channel (think ringing, progress, etc.).
|
||||
* This is not desirable in ARI applications since application writers should have
|
||||
* control over what does/does not get indicated to the calling channel
|
||||
*/
|
||||
ast_dial_run(dial, NULL, 1);
|
||||
control->dial = dial;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ast_dial *stasis_app_get_dial(struct stasis_app_control *control)
|
||||
{
|
||||
return control->dial;
|
||||
}
|
||||
|
||||
int stasis_app_control_dial(struct stasis_app_control *control, struct ast_dial *dial)
|
||||
{
|
||||
return stasis_app_send_command_async(control, app_control_dial, dial, NULL);
|
||||
}
|
||||
|
Reference in New Issue
Block a user