diff options
Diffstat (limited to 'res/stasis/control.c')
-rw-r--r-- | res/stasis/control.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/res/stasis/control.c b/res/stasis/control.c new file mode 100644 index 000000000..e32781b5f --- /dev/null +++ b/res/stasis/control.c @@ -0,0 +1,199 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2013, Digium, Inc. + * + * David M. Lee, II <dlee@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Stasis application control support. + * + * \author David M. Lee, II <dlee@digium.com> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/stasis_channels.h" + +#include "command.h" +#include "control.h" + +struct stasis_app_control { + /*! Queue of commands to dispatch on the channel */ + struct ao2_container *command_queue; + /*! + * When set, /c app_stasis should exit and continue in the dialplan. + */ + int is_done:1; + /*! + * The associated channel. + * Be very careful with the threading associated w/ manipulating + * the channel. + */ + struct ast_channel *channel; +}; + +struct stasis_app_control *control_create(struct ast_channel *channel) +{ + struct stasis_app_control *control; + + control = ao2_alloc(sizeof(*control), NULL); + if (!control) { + return NULL; + } + + control->command_queue = ao2_container_alloc_list(0, 0, NULL, NULL); + + control->channel = channel; + + return control; +} + +static struct stasis_app_command *exec_command( + struct stasis_app_control *control, stasis_app_command_cb command_fn, + void *data) +{ + RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup); + + command = command_create(command_fn, data); + + if (!command) { + return NULL; + } + + ao2_lock(control); + ao2_ref(command, +1); + ao2_link(control->command_queue, command); + ao2_unlock(control); + + ao2_ref(command, +1); + return command; +} + +int control_is_done(struct stasis_app_control *control) +{ + /* Called from stasis_app_exec thread; no lock needed */ + return control->is_done; +} + +static void *app_control_continue(struct stasis_app_control *control, + struct ast_channel *chan, void *data) +{ + /* Called from stasis_app_exec thread; no lock needed */ + control->is_done = 1; + return NULL; +} + +void stasis_app_control_continue(struct stasis_app_control *control) +{ + stasis_app_send_command_async(control, app_control_continue, NULL); +} + +struct ast_channel_snapshot *stasis_app_control_get_snapshot( + const struct stasis_app_control *control) +{ + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct stasis_caching_topic *caching_topic; + struct ast_channel_snapshot *snapshot; + + caching_topic = ast_channel_topic_all_cached(); + ast_assert(caching_topic != NULL); + + msg = stasis_cache_get(caching_topic, ast_channel_snapshot_type(), + stasis_app_control_get_channel_id(control)); + if (!msg) { + return NULL; + } + + snapshot = stasis_message_data(msg); + ast_assert(snapshot != NULL); + + ao2_ref(snapshot, +1); + return snapshot; +} + +void *stasis_app_send_command(struct stasis_app_control *control, + stasis_app_command_cb command_fn, void *data) +{ + RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup); + + if (control == NULL) { + return NULL; + } + + command = exec_command(control, command_fn, data); + if (!command) { + return NULL; + } + + return command_join(command); +} + +int stasis_app_send_command_async(struct stasis_app_control *control, + stasis_app_command_cb command_fn, void *data) +{ + RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup); + + if (control == NULL) { + return -1; + } + + command = exec_command(control, command_fn, data); + if (!command) { + return -1; + } + + return 0; +} + +const char *stasis_app_control_get_channel_id( + const struct stasis_app_control *control) +{ + return ast_channel_uniqueid(control->channel); +} + +void stasis_app_control_publish( + struct stasis_app_control *control, struct stasis_message *message) +{ + if (!control || !control->channel || !message) { + return; + } + stasis_publish(ast_channel_topic(control->channel), message); +} + +int control_dispatch_all(struct stasis_app_control *control, + struct ast_channel *chan) +{ + int count = 0; + struct ao2_iterator i; + void *obj; + + SCOPED_AO2LOCK(lock, control); + + ast_assert(control->channel == chan); + + i = ao2_iterator_init(control->command_queue, AO2_ITERATOR_UNLINK); + + while ((obj = ao2_iterator_next(&i))) { + RAII_VAR(struct stasis_app_command *, command, obj, ao2_cleanup); + command_invoke(command, control, chan); + ++count; + } + + ao2_iterator_destroy(&i); + return count; +} |