mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 12:16:00 +00:00
ARI: Fix a crash caused by hanging during playback to a channel in a bridge
ASTERISK-24147 #close Reported by: Edvin Vidmar Review: https://reviewboard.asterisk.org/r/3908/ ........ Merged revisions 421879 from http://svn.asterisk.org/svn/asterisk/branches/12 ........ Merged revisions 421880 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@421881 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -48,6 +48,19 @@
|
|||||||
int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
|
int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
|
||||||
char *argv[]);
|
char *argv[]);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Typedef for data destructor for stasis app commands
|
||||||
|
*
|
||||||
|
* \param data Data to destroy.
|
||||||
|
*
|
||||||
|
* \details
|
||||||
|
* This is called during destruction of the command or if we fail to schedule
|
||||||
|
* a command. It is passed a pointer to the user-defined data of the command.
|
||||||
|
*
|
||||||
|
* \return Nothing
|
||||||
|
*/
|
||||||
|
typedef void (*command_data_destructor_fn)(void *data);
|
||||||
|
|
||||||
/*! Callback type for stasis app commands */
|
/*! Callback type for stasis app commands */
|
||||||
typedef int (*stasis_app_command_cb)(struct stasis_app_control *control,
|
typedef int (*stasis_app_command_cb)(struct stasis_app_control *control,
|
||||||
struct ast_channel *chan, void *data);
|
struct ast_channel *chan, void *data);
|
||||||
@@ -63,16 +76,19 @@ typedef int (*stasis_app_command_cb)(struct stasis_app_control *control,
|
|||||||
* \param control Control object for the channel to send the command to.
|
* \param control Control object for the channel to send the command to.
|
||||||
* \param command Command function to execute.
|
* \param command Command function to execute.
|
||||||
* \param data Optional data to pass along with the control function.
|
* \param data Optional data to pass along with the control function.
|
||||||
|
* \param data_destructor Optional function which will be called on
|
||||||
|
* the data in either the event of command completion or failure
|
||||||
|
* to schedule or complete the command
|
||||||
*
|
*
|
||||||
* \return zero on success.
|
* \return zero on success.
|
||||||
* \return error code otherwise.
|
* \return error code otherwise.
|
||||||
*/
|
*/
|
||||||
int stasis_app_send_command(struct stasis_app_control *control,
|
int stasis_app_send_command(struct stasis_app_control *control,
|
||||||
stasis_app_command_cb command, void *data);
|
stasis_app_command_cb command, void *data, command_data_destructor_fn data_destructor);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \since 12
|
* \since 12
|
||||||
* \brief Asynchronous version of stasis_app_send().
|
* \brief Asynchronous version of stasis_app_send_command().
|
||||||
*
|
*
|
||||||
* This function enqueues a command for execution, but returns immediately
|
* This function enqueues a command for execution, but returns immediately
|
||||||
* without waiting for the response.
|
* without waiting for the response.
|
||||||
@@ -80,10 +96,13 @@ int stasis_app_send_command(struct stasis_app_control *control,
|
|||||||
* \param control Control object for the channel to send the command to.
|
* \param control Control object for the channel to send the command to.
|
||||||
* \param command Command function to execute.
|
* \param command Command function to execute.
|
||||||
* \param data Optional data to pass along with the control function.
|
* \param data Optional data to pass along with the control function.
|
||||||
|
* \param data_destructor Optional function which will be called on
|
||||||
|
* the data in either the event of command completion or failure
|
||||||
|
* to schedule or complete the command
|
||||||
* \return 0 on success.
|
* \return 0 on success.
|
||||||
* \return Non-zero on error.
|
* \return Non-zero on error.
|
||||||
*/
|
*/
|
||||||
int stasis_app_send_command_async(struct stasis_app_control *control,
|
int stasis_app_send_command_async(struct stasis_app_control *control,
|
||||||
stasis_app_command_cb command, void *data);
|
stasis_app_command_cb command, void *data, command_data_destructor_fn data_destructor);
|
||||||
|
|
||||||
#endif /* _ASTERISK_RES_STASIS_H */
|
#endif /* _ASTERISK_RES_STASIS_H */
|
||||||
|
@@ -1190,6 +1190,7 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
|
|||||||
RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
|
RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
|
||||||
struct ast_bridge *bridge = NULL;
|
struct ast_bridge *bridge = NULL;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
int needs_depart;
|
||||||
|
|
||||||
ast_assert(chan != NULL);
|
ast_assert(chan != NULL);
|
||||||
|
|
||||||
@@ -1305,6 +1306,13 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast_channel_lock(chan);
|
||||||
|
needs_depart = ast_channel_is_bridged(chan);
|
||||||
|
ast_channel_unlock(chan);
|
||||||
|
if (needs_depart) {
|
||||||
|
ast_bridge_depart(chan);
|
||||||
|
}
|
||||||
|
|
||||||
app_unsubscribe_bridge(app, stasis_app_get_bridge(control));
|
app_unsubscribe_bridge(app, stasis_app_get_bridge(control));
|
||||||
ao2_cleanup(bridge);
|
ao2_cleanup(bridge);
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@ int stasis_app_control_answer(struct stasis_app_control *control)
|
|||||||
ast_debug(3, "%s: Sending answer command\n",
|
ast_debug(3, "%s: Sending answer command\n",
|
||||||
stasis_app_control_get_channel_id(control));
|
stasis_app_control_get_channel_id(control));
|
||||||
|
|
||||||
retval = stasis_app_send_command(control, app_control_answer, NULL);
|
retval = stasis_app_send_command(control, app_control_answer, NULL, NULL);
|
||||||
|
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
ast_log(LOG_WARNING, "%s: Failed to answer channel\n",
|
ast_log(LOG_WARNING, "%s: Failed to answer channel\n",
|
||||||
|
@@ -366,21 +366,21 @@ static void play_on_channel_in_bridge(struct ast_bridge_channel *bridge_channel,
|
|||||||
* \brief \ref RAII_VAR function to remove a playback from the global list when
|
* \brief \ref RAII_VAR function to remove a playback from the global list when
|
||||||
* leaving scope.
|
* leaving scope.
|
||||||
*/
|
*/
|
||||||
static void remove_from_playbacks(struct stasis_app_playback *playback)
|
static void remove_from_playbacks(void *data)
|
||||||
{
|
{
|
||||||
|
struct stasis_app_playback *playback = data;
|
||||||
|
|
||||||
ao2_unlink_flags(playbacks, playback,
|
ao2_unlink_flags(playbacks, playback,
|
||||||
OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
|
OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
|
||||||
|
ao2_ref(playback, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int play_uri(struct stasis_app_control *control,
|
static int play_uri(struct stasis_app_control *control,
|
||||||
struct ast_channel *chan, void *data)
|
struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_playback *, playback, NULL,
|
struct stasis_app_playback *playback = data;
|
||||||
remove_from_playbacks);
|
|
||||||
struct ast_bridge *bridge;
|
struct ast_bridge *bridge;
|
||||||
|
|
||||||
playback = data;
|
|
||||||
|
|
||||||
if (!control) {
|
if (!control) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -434,7 +434,7 @@ struct stasis_app_playback *stasis_app_control_play_uri(
|
|||||||
enum stasis_app_playback_target_type target_type,
|
enum stasis_app_playback_target_type target_type,
|
||||||
int skipms, long offsetms, const char *id)
|
int skipms, long offsetms, const char *id)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
|
struct stasis_app_playback *playback;
|
||||||
|
|
||||||
if (skipms < 0 || offsetms < 0) {
|
if (skipms < 0 || offsetms < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -444,6 +444,9 @@ struct stasis_app_playback *stasis_app_control_play_uri(
|
|||||||
stasis_app_control_get_channel_id(control), uri);
|
stasis_app_control_get_channel_id(control), uri);
|
||||||
|
|
||||||
playback = playback_create(control, id);
|
playback = playback_create(control, id);
|
||||||
|
if (!playback) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (skipms == 0) {
|
if (skipms == 0) {
|
||||||
skipms = PLAYBACK_DEFAULT_SKIPMS;
|
skipms = PLAYBACK_DEFAULT_SKIPMS;
|
||||||
@@ -459,11 +462,8 @@ struct stasis_app_playback *stasis_app_control_play_uri(
|
|||||||
playback->state = STASIS_PLAYBACK_STATE_QUEUED;
|
playback->state = STASIS_PLAYBACK_STATE_QUEUED;
|
||||||
playback_publish(playback);
|
playback_publish(playback);
|
||||||
|
|
||||||
/* A ref is kept in the playbacks container; no need to bump */
|
stasis_app_send_command_async(control, play_uri, ao2_bump(playback), remove_from_playbacks);
|
||||||
stasis_app_send_command_async(control, play_uri, playback);
|
|
||||||
|
|
||||||
/* Although this should be bumped for the caller */
|
|
||||||
ao2_ref(playback, +1);
|
|
||||||
return playback;
|
return playback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -279,21 +279,22 @@ static void recording_fail(struct stasis_app_control *control,
|
|||||||
recording, STASIS_APP_RECORDING_STATE_FAILED, cause);
|
recording, STASIS_APP_RECORDING_STATE_FAILED, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recording_cleanup(struct stasis_app_recording *recording)
|
static void recording_cleanup(void *data)
|
||||||
{
|
{
|
||||||
|
struct stasis_app_recording *recording = data;
|
||||||
|
|
||||||
ao2_unlink_flags(recordings, recording,
|
ao2_unlink_flags(recordings, recording,
|
||||||
OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
|
OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
|
||||||
|
ao2_ref(recording, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int record_file(struct stasis_app_control *control,
|
static int record_file(struct stasis_app_control *control,
|
||||||
struct ast_channel *chan, void *data)
|
struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_recording *, recording,
|
struct stasis_app_recording *recording = data;
|
||||||
NULL, recording_cleanup);
|
|
||||||
char *acceptdtmf;
|
char *acceptdtmf;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
recording = data;
|
|
||||||
ast_assert(recording != NULL);
|
ast_assert(recording != NULL);
|
||||||
|
|
||||||
if (stasis_app_get_bridge(control)) {
|
if (stasis_app_get_bridge(control)) {
|
||||||
@@ -364,7 +365,7 @@ struct stasis_app_recording *stasis_app_control_record(
|
|||||||
struct stasis_app_control *control,
|
struct stasis_app_control *control,
|
||||||
struct stasis_app_recording_options *options)
|
struct stasis_app_recording_options *options)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
|
struct stasis_app_recording *recording;
|
||||||
char *last_slash;
|
char *last_slash;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@@ -395,6 +396,7 @@ struct stasis_app_recording *stasis_app_control_record(
|
|||||||
|
|
||||||
if (recording->absolute_name == NULL) {
|
if (recording->absolute_name == NULL) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
|
ao2_ref(recording, -1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,6 +405,7 @@ struct stasis_app_recording *stasis_app_control_record(
|
|||||||
if (ast_safe_mkdir(ast_config_AST_RECORDING_DIR,
|
if (ast_safe_mkdir(ast_config_AST_RECORDING_DIR,
|
||||||
recording->absolute_name, 0777) != 0) {
|
recording->absolute_name, 0777) != 0) {
|
||||||
/* errno set by ast_mkdir */
|
/* errno set by ast_mkdir */
|
||||||
|
ao2_ref(recording, -1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*last_slash = '/';
|
*last_slash = '/';
|
||||||
@@ -418,6 +421,7 @@ struct stasis_app_recording *stasis_app_control_record(
|
|||||||
ast_log(LOG_WARNING, "Recording file '%s' already exists and ifExists option is failure.\n",
|
ast_log(LOG_WARNING, "Recording file '%s' already exists and ifExists option is failure.\n",
|
||||||
recording->absolute_name);
|
recording->absolute_name);
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
|
ao2_ref(recording, -1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,6 +438,7 @@ struct stasis_app_recording *stasis_app_control_record(
|
|||||||
"Recording %s already in progress\n",
|
"Recording %s already in progress\n",
|
||||||
recording->options->name);
|
recording->options->name);
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
|
ao2_ref(recording, -1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ao2_link(recordings, recording);
|
ao2_link(recordings, recording);
|
||||||
@@ -441,11 +446,8 @@ struct stasis_app_recording *stasis_app_control_record(
|
|||||||
|
|
||||||
stasis_app_control_register_add_rule(control, &rule_recording);
|
stasis_app_control_register_add_rule(control, &rule_recording);
|
||||||
|
|
||||||
/* A ref is kept in the recordings container; no need to bump */
|
stasis_app_send_command_async(control, record_file, ao2_bump(recording), recording_cleanup);
|
||||||
stasis_app_send_command_async(control, record_file, recording);
|
|
||||||
|
|
||||||
/* Although this should be bumped for the caller */
|
|
||||||
ao2_ref(recording, +1);
|
|
||||||
return recording;
|
return recording;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -37,6 +37,7 @@ struct stasis_app_command {
|
|||||||
ast_cond_t condition;
|
ast_cond_t condition;
|
||||||
stasis_app_command_cb callback;
|
stasis_app_command_cb callback;
|
||||||
void *data;
|
void *data;
|
||||||
|
command_data_destructor_fn data_destructor;
|
||||||
int retval;
|
int retval;
|
||||||
int is_done:1;
|
int is_done:1;
|
||||||
};
|
};
|
||||||
@@ -44,17 +45,25 @@ struct stasis_app_command {
|
|||||||
static void command_dtor(void *obj)
|
static void command_dtor(void *obj)
|
||||||
{
|
{
|
||||||
struct stasis_app_command *command = obj;
|
struct stasis_app_command *command = obj;
|
||||||
|
|
||||||
|
if (command->data_destructor) {
|
||||||
|
command->data_destructor(command->data);
|
||||||
|
}
|
||||||
|
|
||||||
ast_mutex_destroy(&command->lock);
|
ast_mutex_destroy(&command->lock);
|
||||||
ast_cond_destroy(&command->condition);
|
ast_cond_destroy(&command->condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stasis_app_command *command_create(
|
struct stasis_app_command *command_create(
|
||||||
stasis_app_command_cb callback, void *data)
|
stasis_app_command_cb callback, void *data, command_data_destructor_fn data_destructor)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
|
struct stasis_app_command *command;
|
||||||
|
|
||||||
command = ao2_alloc(sizeof(*command), command_dtor);
|
command = ao2_alloc(sizeof(*command), command_dtor);
|
||||||
if (!command) {
|
if (!command) {
|
||||||
|
if (data_destructor) {
|
||||||
|
data_destructor(data);
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +71,8 @@ struct stasis_app_command *command_create(
|
|||||||
ast_cond_init(&command->condition, 0);
|
ast_cond_init(&command->condition, 0);
|
||||||
command->callback = callback;
|
command->callback = callback;
|
||||||
command->data = data;
|
command->data = data;
|
||||||
|
command->data_destructor = data_destructor;
|
||||||
|
|
||||||
ao2_ref(command, +1);
|
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +99,10 @@ void command_invoke(struct stasis_app_command *command,
|
|||||||
struct stasis_app_control *control, struct ast_channel *chan)
|
struct stasis_app_control *control, struct ast_channel *chan)
|
||||||
{
|
{
|
||||||
int retval = command->callback(control, chan, command->data);
|
int retval = command->callback(control, chan, command->data);
|
||||||
|
if (command->data_destructor) {
|
||||||
|
command->data_destructor(command->data);
|
||||||
|
command->data_destructor = NULL;
|
||||||
|
}
|
||||||
command_complete(command, retval);
|
command_complete(command, retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,12 +118,12 @@ static const struct ast_datastore_info command_queue_prestart = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int command_prestart_queue_command(struct ast_channel *chan,
|
int command_prestart_queue_command(struct ast_channel *chan,
|
||||||
stasis_app_command_cb command_fn, void *data)
|
stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor)
|
||||||
{
|
{
|
||||||
struct ast_datastore *datastore;
|
struct ast_datastore *datastore;
|
||||||
struct ao2_container *command_queue;
|
struct ao2_container *command_queue;
|
||||||
RAII_VAR(struct stasis_app_command *, command,
|
RAII_VAR(struct stasis_app_command *, command,
|
||||||
command_create(command_fn, data), ao2_cleanup);
|
command_create(command_fn, data, data_destructor), ao2_cleanup);
|
||||||
|
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@@ -32,7 +32,8 @@
|
|||||||
struct stasis_app_command;
|
struct stasis_app_command;
|
||||||
|
|
||||||
struct stasis_app_command *command_create(
|
struct stasis_app_command *command_create(
|
||||||
stasis_app_command_cb callback, void *data);
|
stasis_app_command_cb callback, void *data,
|
||||||
|
command_data_destructor_fn data_destructor);
|
||||||
|
|
||||||
void command_complete(struct stasis_app_command *command, int retval);
|
void command_complete(struct stasis_app_command *command, int retval);
|
||||||
|
|
||||||
@@ -49,12 +50,16 @@ int command_join(struct stasis_app_command *command);
|
|||||||
* \param chan The channel on which to queue the prestart command
|
* \param chan The channel on which to queue the prestart command
|
||||||
* \param command_fn The callback to call for the command
|
* \param command_fn The callback to call for the command
|
||||||
* \param data The data to pass to the command callback
|
* \param data The data to pass to the command callback
|
||||||
|
* \param data_destructor Optional function which will be called on
|
||||||
|
* the data in either the event of command completion or failure
|
||||||
|
* to schedule or complete the command
|
||||||
*
|
*
|
||||||
* \retval zero on success
|
* \retval zero on success
|
||||||
* \retval non-zero on failure
|
* \retval non-zero on failure
|
||||||
*/
|
*/
|
||||||
int command_prestart_queue_command(struct ast_channel *chan,
|
int command_prestart_queue_command(struct ast_channel *chan,
|
||||||
stasis_app_command_cb command_fn, void *data);
|
stasis_app_command_cb command_fn, void *data,
|
||||||
|
command_data_destructor_fn data_destructor);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Get the Stasis() prestart commands for a channel
|
* \brief Get the Stasis() prestart commands for a channel
|
||||||
|
@@ -238,14 +238,15 @@ typedef int (*app_command_can_exec_cb)(struct stasis_app_control *control);
|
|||||||
|
|
||||||
static struct stasis_app_command *exec_command_on_condition(
|
static struct stasis_app_command *exec_command_on_condition(
|
||||||
struct stasis_app_control *control, stasis_app_command_cb command_fn,
|
struct stasis_app_control *control, stasis_app_command_cb command_fn,
|
||||||
void *data, app_command_can_exec_cb can_exec_fn)
|
void *data, command_data_destructor_fn data_destructor,
|
||||||
|
app_command_can_exec_cb can_exec_fn)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
struct stasis_app_command *command;
|
struct stasis_app_command *command;
|
||||||
|
|
||||||
command_fn = command_fn ? : noop_cb;
|
command_fn = command_fn ? : noop_cb;
|
||||||
|
|
||||||
command = command_create(command_fn, data);
|
command = command_create(command_fn, data, data_destructor);
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -266,9 +267,9 @@ static struct stasis_app_command *exec_command_on_condition(
|
|||||||
|
|
||||||
static struct stasis_app_command *exec_command(
|
static struct stasis_app_command *exec_command(
|
||||||
struct stasis_app_control *control, stasis_app_command_cb command_fn,
|
struct stasis_app_control *control, stasis_app_command_cb command_fn,
|
||||||
void *data)
|
void *data, command_data_destructor_fn data_destructor)
|
||||||
{
|
{
|
||||||
return exec_command_on_condition(control, command_fn, data, NULL);
|
return exec_command_on_condition(control, command_fn, data, data_destructor, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stasis_app_control_dial_data {
|
struct stasis_app_control_dial_data {
|
||||||
@@ -280,7 +281,7 @@ static int app_control_dial(struct stasis_app_control *control,
|
|||||||
struct ast_channel *chan, void *data)
|
struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct ast_dial *, dial, ast_dial_create(), ast_dial_destroy);
|
RAII_VAR(struct ast_dial *, dial, ast_dial_create(), ast_dial_destroy);
|
||||||
RAII_VAR(struct stasis_app_control_dial_data *, dial_data, data, ast_free);
|
struct stasis_app_control_dial_data *dial_data = data;
|
||||||
enum ast_dial_result res;
|
enum ast_dial_result res;
|
||||||
char *tech, *resource;
|
char *tech, *resource;
|
||||||
struct ast_channel *new_chan;
|
struct ast_channel *new_chan;
|
||||||
@@ -349,7 +350,7 @@ int stasis_app_control_dial(struct stasis_app_control *control, const char *endp
|
|||||||
dial_data->timeout = 30000;
|
dial_data->timeout = 30000;
|
||||||
}
|
}
|
||||||
|
|
||||||
stasis_app_send_command_async(control, app_control_dial, dial_data);
|
stasis_app_send_command_async(control, app_control_dial, dial_data, ast_free_ptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -389,7 +390,7 @@ struct stasis_app_control_continue_data {
|
|||||||
static int app_control_continue(struct stasis_app_control *control,
|
static int app_control_continue(struct stasis_app_control *control,
|
||||||
struct ast_channel *chan, void *data)
|
struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_control_continue_data *, continue_data, data, ast_free);
|
struct stasis_app_control_continue_data *continue_data = data;
|
||||||
|
|
||||||
ast_assert(control->channel != NULL);
|
ast_assert(control->channel != NULL);
|
||||||
|
|
||||||
@@ -422,7 +423,7 @@ int stasis_app_control_continue(struct stasis_app_control *control, const char *
|
|||||||
continue_data->priority = -1;
|
continue_data->priority = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
stasis_app_send_command_async(control, app_control_continue, continue_data);
|
stasis_app_send_command_async(control, app_control_continue, continue_data, ast_free_ptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -438,7 +439,7 @@ struct stasis_app_control_dtmf_data {
|
|||||||
static int app_control_dtmf(struct stasis_app_control *control,
|
static int app_control_dtmf(struct stasis_app_control *control,
|
||||||
struct ast_channel *chan, void *data)
|
struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_control_dtmf_data *, dtmf_data, data, ast_free);
|
struct stasis_app_control_dtmf_data *dtmf_data = data;
|
||||||
|
|
||||||
if (ast_channel_state(chan) != AST_STATE_UP) {
|
if (ast_channel_state(chan) != AST_STATE_UP) {
|
||||||
ast_indicate(chan, AST_CONTROL_PROGRESS);
|
ast_indicate(chan, AST_CONTROL_PROGRESS);
|
||||||
@@ -471,7 +472,7 @@ int stasis_app_control_dtmf(struct stasis_app_control *control, const char *dtmf
|
|||||||
dtmf_data->after = after;
|
dtmf_data->after = after;
|
||||||
strcpy(dtmf_data->dtmf, dtmf);
|
strcpy(dtmf_data->dtmf, dtmf);
|
||||||
|
|
||||||
stasis_app_send_command_async(control, app_control_dtmf, dtmf_data);
|
stasis_app_send_command_async(control, app_control_dtmf, dtmf_data, ast_free_ptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -486,7 +487,7 @@ static int app_control_ring(struct stasis_app_control *control,
|
|||||||
|
|
||||||
int stasis_app_control_ring(struct stasis_app_control *control)
|
int stasis_app_control_ring(struct stasis_app_control *control)
|
||||||
{
|
{
|
||||||
stasis_app_send_command_async(control, app_control_ring, NULL);
|
stasis_app_send_command_async(control, app_control_ring, NULL, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -501,7 +502,7 @@ static int app_control_ring_stop(struct stasis_app_control *control,
|
|||||||
|
|
||||||
int stasis_app_control_ring_stop(struct stasis_app_control *control)
|
int stasis_app_control_ring_stop(struct stasis_app_control *control)
|
||||||
{
|
{
|
||||||
stasis_app_send_command_async(control, app_control_ring_stop, NULL);
|
stasis_app_send_command_async(control, app_control_ring_stop, NULL, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -514,7 +515,7 @@ struct stasis_app_control_mute_data {
|
|||||||
static int app_control_mute(struct stasis_app_control *control,
|
static int app_control_mute(struct stasis_app_control *control,
|
||||||
struct ast_channel *chan, void *data)
|
struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_control_mute_data *, mute_data, data, ast_free);
|
struct stasis_app_control_mute_data *mute_data = data;
|
||||||
SCOPED_CHANNELLOCK(lockvar, chan);
|
SCOPED_CHANNELLOCK(lockvar, chan);
|
||||||
|
|
||||||
ast_channel_suppress(control->channel, mute_data->direction, mute_data->frametype);
|
ast_channel_suppress(control->channel, mute_data->direction, mute_data->frametype);
|
||||||
@@ -533,7 +534,7 @@ int stasis_app_control_mute(struct stasis_app_control *control, unsigned int dir
|
|||||||
mute_data->direction = direction;
|
mute_data->direction = direction;
|
||||||
mute_data->frametype = frametype;
|
mute_data->frametype = frametype;
|
||||||
|
|
||||||
stasis_app_send_command_async(control, app_control_mute, mute_data);
|
stasis_app_send_command_async(control, app_control_mute, mute_data, ast_free_ptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -541,7 +542,7 @@ int stasis_app_control_mute(struct stasis_app_control *control, unsigned int dir
|
|||||||
static int app_control_unmute(struct stasis_app_control *control,
|
static int app_control_unmute(struct stasis_app_control *control,
|
||||||
struct ast_channel *chan, void *data)
|
struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_control_mute_data *, mute_data, data, ast_free);
|
struct stasis_app_control_mute_data *mute_data = data;
|
||||||
SCOPED_CHANNELLOCK(lockvar, chan);
|
SCOPED_CHANNELLOCK(lockvar, chan);
|
||||||
|
|
||||||
ast_channel_unsuppress(control->channel, mute_data->direction, mute_data->frametype);
|
ast_channel_unsuppress(control->channel, mute_data->direction, mute_data->frametype);
|
||||||
@@ -560,7 +561,7 @@ int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int d
|
|||||||
mute_data->direction = direction;
|
mute_data->direction = direction;
|
||||||
mute_data->frametype = frametype;
|
mute_data->frametype = frametype;
|
||||||
|
|
||||||
stasis_app_send_command_async(control, app_control_unmute, mute_data);
|
stasis_app_send_command_async(control, app_control_unmute, mute_data, ast_free_ptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -580,7 +581,7 @@ static int app_control_hold(struct stasis_app_control *control,
|
|||||||
|
|
||||||
void stasis_app_control_hold(struct stasis_app_control *control)
|
void stasis_app_control_hold(struct stasis_app_control *control)
|
||||||
{
|
{
|
||||||
stasis_app_send_command_async(control, app_control_hold, NULL);
|
stasis_app_send_command_async(control, app_control_hold, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int app_control_unhold(struct stasis_app_control *control,
|
static int app_control_unhold(struct stasis_app_control *control,
|
||||||
@@ -593,7 +594,7 @@ static int app_control_unhold(struct stasis_app_control *control,
|
|||||||
|
|
||||||
void stasis_app_control_unhold(struct stasis_app_control *control)
|
void stasis_app_control_unhold(struct stasis_app_control *control)
|
||||||
{
|
{
|
||||||
stasis_app_send_command_async(control, app_control_unhold, NULL);
|
stasis_app_send_command_async(control, app_control_unhold, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int app_control_moh_start(struct stasis_app_control *control,
|
static int app_control_moh_start(struct stasis_app_control *control,
|
||||||
@@ -607,7 +608,6 @@ static int app_control_moh_start(struct stasis_app_control *control,
|
|||||||
|
|
||||||
ast_moh_start(chan, moh_class, NULL);
|
ast_moh_start(chan, moh_class, NULL);
|
||||||
|
|
||||||
ast_free(moh_class);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,7 +619,7 @@ void stasis_app_control_moh_start(struct stasis_app_control *control, const char
|
|||||||
data = ast_strdup(moh_class);
|
data = ast_strdup(moh_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
stasis_app_send_command_async(control, app_control_moh_start, data);
|
stasis_app_send_command_async(control, app_control_moh_start, data, ast_free_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int app_control_moh_stop(struct stasis_app_control *control,
|
static int app_control_moh_stop(struct stasis_app_control *control,
|
||||||
@@ -631,7 +631,7 @@ static int app_control_moh_stop(struct stasis_app_control *control,
|
|||||||
|
|
||||||
void stasis_app_control_moh_stop(struct stasis_app_control *control)
|
void stasis_app_control_moh_stop(struct stasis_app_control *control)
|
||||||
{
|
{
|
||||||
stasis_app_send_command_async(control, app_control_moh_stop, NULL);
|
stasis_app_send_command_async(control, app_control_moh_stop, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int app_control_silence_start(struct stasis_app_control *control,
|
static int app_control_silence_start(struct stasis_app_control *control,
|
||||||
@@ -665,7 +665,7 @@ static int app_control_silence_start(struct stasis_app_control *control,
|
|||||||
|
|
||||||
void stasis_app_control_silence_start(struct stasis_app_control *control)
|
void stasis_app_control_silence_start(struct stasis_app_control *control)
|
||||||
{
|
{
|
||||||
stasis_app_send_command_async(control, app_control_silence_start, NULL);
|
stasis_app_send_command_async(control, app_control_silence_start, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int app_control_silence_stop(struct stasis_app_control *control,
|
static int app_control_silence_stop(struct stasis_app_control *control,
|
||||||
@@ -684,7 +684,7 @@ static int app_control_silence_stop(struct stasis_app_control *control,
|
|||||||
|
|
||||||
void stasis_app_control_silence_stop(struct stasis_app_control *control)
|
void stasis_app_control_silence_stop(struct stasis_app_control *control)
|
||||||
{
|
{
|
||||||
stasis_app_send_command_async(control, app_control_silence_stop, NULL);
|
stasis_app_send_command_async(control, app_control_silence_stop, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ast_channel_snapshot *stasis_app_control_get_snapshot(
|
struct ast_channel_snapshot *stasis_app_control_get_snapshot(
|
||||||
@@ -708,6 +708,7 @@ struct ast_channel_snapshot *stasis_app_control_get_snapshot(
|
|||||||
|
|
||||||
static int app_send_command_on_condition(struct stasis_app_control *control,
|
static int app_send_command_on_condition(struct stasis_app_control *control,
|
||||||
stasis_app_command_cb command_fn, void *data,
|
stasis_app_command_cb command_fn, void *data,
|
||||||
|
command_data_destructor_fn data_destructor,
|
||||||
app_command_can_exec_cb can_exec_fn)
|
app_command_can_exec_cb can_exec_fn)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
|
RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
|
||||||
@@ -717,7 +718,7 @@ static int app_send_command_on_condition(struct stasis_app_control *control,
|
|||||||
}
|
}
|
||||||
|
|
||||||
command = exec_command_on_condition(
|
command = exec_command_on_condition(
|
||||||
control, command_fn, data, can_exec_fn);
|
control, command_fn, data, data_destructor, can_exec_fn);
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -726,13 +727,14 @@ static int app_send_command_on_condition(struct stasis_app_control *control,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int stasis_app_send_command(struct stasis_app_control *control,
|
int stasis_app_send_command(struct stasis_app_control *control,
|
||||||
stasis_app_command_cb command_fn, void *data)
|
stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor)
|
||||||
{
|
{
|
||||||
return app_send_command_on_condition(control, command_fn, data, NULL);
|
return app_send_command_on_condition(control, command_fn, data, data_destructor, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int stasis_app_send_command_async(struct stasis_app_control *control,
|
int stasis_app_send_command_async(struct stasis_app_control *control,
|
||||||
stasis_app_command_cb command_fn, void *data)
|
stasis_app_command_cb command_fn, void *data,
|
||||||
|
command_data_destructor_fn data_destructor)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
|
RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
|
||||||
|
|
||||||
@@ -740,7 +742,7 @@ int stasis_app_send_command_async(struct stasis_app_control *control,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
command = exec_command(control, command_fn, data);
|
command = exec_command(control, command_fn, data, data_destructor);
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -761,7 +763,7 @@ struct ast_bridge *stasis_app_get_bridge(struct stasis_app_control *control)
|
|||||||
static int bridge_channel_depart(struct stasis_app_control *control,
|
static int bridge_channel_depart(struct stasis_app_control *control,
|
||||||
struct ast_channel *chan, void *data)
|
struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct ast_bridge_channel *, bridge_channel, data, ao2_cleanup);
|
struct ast_bridge_channel *bridge_channel = data;
|
||||||
|
|
||||||
{
|
{
|
||||||
SCOPED_CHANNELLOCK(lock, chan);
|
SCOPED_CHANNELLOCK(lock, chan);
|
||||||
@@ -807,9 +809,7 @@ static void bridge_after_cb(struct ast_channel *chan, void *data)
|
|||||||
ast_channel_unlock(chan);
|
ast_channel_unlock(chan);
|
||||||
|
|
||||||
/* Depart this channel from the bridge using the command queue if possible */
|
/* Depart this channel from the bridge using the command queue if possible */
|
||||||
if (stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel)) {
|
stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup);
|
||||||
ao2_cleanup(bridge_channel);
|
|
||||||
}
|
|
||||||
if (stasis_app_channel_is_stasis_end_published(chan)) {
|
if (stasis_app_channel_is_stasis_end_published(chan)) {
|
||||||
/* The channel has had a StasisEnd published on it, but until now had remained in
|
/* The channel has had a StasisEnd published on it, but until now had remained in
|
||||||
* the bridging system. This means that the channel moved from a Stasis bridge to a
|
* the bridging system. This means that the channel moved from a Stasis bridge to a
|
||||||
@@ -918,7 +918,7 @@ int stasis_app_control_add_channel_to_bridge(
|
|||||||
stasis_app_control_get_channel_id(control));
|
stasis_app_control_get_channel_id(control));
|
||||||
|
|
||||||
return app_send_command_on_condition(
|
return app_send_command_on_condition(
|
||||||
control, control_add_channel_to_bridge, bridge,
|
control, control_add_channel_to_bridge, bridge, NULL,
|
||||||
app_control_can_add_channel_to_bridge);
|
app_control_can_add_channel_to_bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -954,7 +954,7 @@ int stasis_app_control_remove_channel_from_bridge(
|
|||||||
ast_debug(3, "%s: Sending channel remove_from_bridge command\n",
|
ast_debug(3, "%s: Sending channel remove_from_bridge command\n",
|
||||||
stasis_app_control_get_channel_id(control));
|
stasis_app_control_get_channel_id(control));
|
||||||
return app_send_command_on_condition(
|
return app_send_command_on_condition(
|
||||||
control, app_control_remove_channel_from_bridge, bridge,
|
control, app_control_remove_channel_from_bridge, bridge, NULL,
|
||||||
app_control_can_remove_channel_from_bridge);
|
app_control_can_remove_channel_from_bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -85,7 +85,6 @@ static int add_channel_to_bridge(
|
|||||||
|
|
||||||
res = control_add_channel_to_bridge(control,
|
res = control_add_channel_to_bridge(control,
|
||||||
chan, bridge);
|
chan, bridge);
|
||||||
ao2_cleanup(bridge);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,9 +92,8 @@ static void bridge_stasis_queue_join_action(struct ast_bridge *self,
|
|||||||
struct ast_bridge_channel *bridge_channel)
|
struct ast_bridge_channel *bridge_channel)
|
||||||
{
|
{
|
||||||
ast_channel_lock(bridge_channel->chan);
|
ast_channel_lock(bridge_channel->chan);
|
||||||
if (command_prestart_queue_command(bridge_channel->chan, add_channel_to_bridge, ao2_bump(self))) {
|
command_prestart_queue_command(bridge_channel->chan, add_channel_to_bridge,
|
||||||
ao2_cleanup(self);
|
ao2_bump(self), __ao2_cleanup);
|
||||||
}
|
|
||||||
ast_channel_unlock(bridge_channel->chan);
|
ast_channel_unlock(bridge_channel->chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user