mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
res_stasis: Add ability to switch applications.
Added the ability to move between Stasis applications within Stasis. This can be done by calling 'move' in an application, providing (at minimum) the channel's id and the application to switch to. If the application is not registered or active, nothing will happen and the channel will remain in the current application, and an event will be triggered to let the application know that the move failed. The event name is "ApplicationMoveFailed", and provides the "destination" that the channel was attempting to move to, as well as the usual channel information. Optionally, a list of arguments can be passed to the function call for the receiving application. A full example of a 'move' call would look like this: client.channels.move(channelId, app, appArgs) The control object used to control the channel in Stasis can now switch which application it belongs to, rather than belonging to one Stasis application for its lifetime. This allows us to use the same control object instead of having to tear down the current one and create another. ASTERISK-28267 #close Change-Id: I43d12b10045a98a8d42541889b85695be26f288a
This commit is contained in:
@@ -83,9 +83,19 @@ struct stasis_app_control {
|
||||
*/
|
||||
struct ast_silence_generator *silgen;
|
||||
/*!
|
||||
* The app for which this control was created
|
||||
* The app for which this control is currently controlling.
|
||||
* This can change through the use of the /channels/{channelId}/move
|
||||
* command.
|
||||
*/
|
||||
struct stasis_app *app;
|
||||
/*!
|
||||
* The name of the next Stasis application to move to.
|
||||
*/
|
||||
char *next_app;
|
||||
/*!
|
||||
* The list of arguments to pass to StasisStart when moving to another app.
|
||||
*/
|
||||
AST_VECTOR(, char *) next_app_args;
|
||||
/*!
|
||||
* When set, /c app_stasis should exit and continue in the dialplan.
|
||||
*/
|
||||
@@ -101,6 +111,8 @@ static void control_dtor(void *obj)
|
||||
ast_channel_cleanup(control->channel);
|
||||
ao2_cleanup(control->app);
|
||||
|
||||
control_move_cleanup(control);
|
||||
|
||||
ast_cond_destroy(&control->wait_cond);
|
||||
AST_LIST_HEAD_DESTROY(&control->add_rules);
|
||||
AST_LIST_HEAD_DESTROY(&control->remove_rules);
|
||||
@@ -141,6 +153,9 @@ struct stasis_app_control *control_create(struct ast_channel *channel, struct st
|
||||
return NULL;
|
||||
}
|
||||
|
||||
control->next_app = NULL;
|
||||
AST_VECTOR_INIT(&control->next_app_args, 0);
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
@@ -391,6 +406,73 @@ int stasis_app_control_continue(struct stasis_app_control *control, const char *
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct stasis_app_control_move_data {
|
||||
char *app_name;
|
||||
char *app_args;
|
||||
};
|
||||
|
||||
static int app_control_move(struct stasis_app_control *control,
|
||||
struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct stasis_app_control_move_data *move_data = data;
|
||||
|
||||
control->next_app = ast_strdup(move_data->app_name);
|
||||
if (!control->next_app) {
|
||||
ast_log(LOG_ERROR, "Allocation failed for next app\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (move_data->app_args) {
|
||||
char *token;
|
||||
|
||||
while ((token = strtok_r(move_data->app_args, ",", &move_data->app_args))) {
|
||||
int res;
|
||||
char *arg;
|
||||
|
||||
if (!(arg = ast_strdup(token))) {
|
||||
ast_log(LOG_ERROR, "Allocation failed for next app arg\n");
|
||||
control_move_cleanup(control);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = AST_VECTOR_APPEND(&control->next_app_args, arg);
|
||||
if (res) {
|
||||
ast_log(LOG_ERROR, "Failed to append arg to next app args\n");
|
||||
ast_free(arg);
|
||||
control_move_cleanup(control);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stasis_app_control_move(struct stasis_app_control *control, const char *app_name, const char *app_args)
|
||||
{
|
||||
struct stasis_app_control_move_data *move_data;
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*move_data) + strlen(app_name) + strlen(app_args) + 2;
|
||||
if (!(move_data = ast_calloc(1, size))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
move_data->app_name = (char *)move_data + sizeof(*move_data);
|
||||
move_data->app_args = move_data->app_name + strlen(app_name) + 1;
|
||||
|
||||
strcpy(move_data->app_name, app_name); /* Safe */
|
||||
if (app_args) {
|
||||
strcpy(move_data->app_args, app_args); /* Safe */
|
||||
} else {
|
||||
move_data->app_args = NULL;
|
||||
}
|
||||
|
||||
stasis_app_send_command_async(control, app_control_move, move_data, ast_free_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int app_control_redirect(struct stasis_app_control *control,
|
||||
struct ast_channel *chan, void *data)
|
||||
{
|
||||
@@ -1590,3 +1672,32 @@ void stasis_app_control_shutdown(void)
|
||||
}
|
||||
ast_mutex_unlock(&dial_bridge_lock);
|
||||
}
|
||||
|
||||
void control_set_app(struct stasis_app_control *control, struct stasis_app *app)
|
||||
{
|
||||
ao2_cleanup(control->app);
|
||||
control->app = ao2_bump(app);
|
||||
}
|
||||
|
||||
char *control_next_app(struct stasis_app_control *control)
|
||||
{
|
||||
return control->next_app;
|
||||
}
|
||||
|
||||
void control_move_cleanup(struct stasis_app_control *control)
|
||||
{
|
||||
ast_free(control->next_app);
|
||||
control->next_app = NULL;
|
||||
|
||||
AST_VECTOR_RESET(&control->next_app_args, ast_free_ptr);
|
||||
}
|
||||
|
||||
char **control_next_app_args(struct stasis_app_control *control)
|
||||
{
|
||||
return AST_VECTOR_STEAL_ELEMENTS(&control->next_app_args);
|
||||
}
|
||||
|
||||
int control_next_app_args_size(struct stasis_app_control *control)
|
||||
{
|
||||
return AST_VECTOR_SIZE(&control->next_app_args);
|
||||
}
|
||||
|
Reference in New Issue
Block a user