diff --git a/include/asterisk/stasis_app_impl.h b/include/asterisk/stasis_app_impl.h index a8c8c05866c1e42e27f9eab83470c48849d73722..ce60804a8a8f9554bf0cbdcbc41b6b85de324209 100644 --- a/include/asterisk/stasis_app_impl.h +++ b/include/asterisk/stasis_app_impl.h @@ -48,6 +48,19 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, 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 */ typedef int (*stasis_app_command_cb)(struct stasis_app_control *control, 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 command Command function to execute. * \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 error code otherwise. */ 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 - * \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 * 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 command Command function to execute. * \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 Non-zero on error. */ 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 */ diff --git a/res/res_stasis.c b/res/res_stasis.c index 7e7904caedcfb7d43354851dc0d2f66e53dfecb2..f2abaf7703942a04c2f4c8d86138d0148f1cd214 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -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); struct ast_bridge *bridge = NULL; int res = 0; + int needs_depart; 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)); ao2_cleanup(bridge); diff --git a/res/res_stasis_answer.c b/res/res_stasis_answer.c index 4a4670dcefb0c334b855ee9b0bd9a12e494ca3b5..05d5302fdffec75cbe32d9c1a67381b9f6caef39 100644 --- a/res/res_stasis_answer.c +++ b/res/res_stasis_answer.c @@ -50,7 +50,7 @@ int stasis_app_control_answer(struct stasis_app_control *control) ast_debug(3, "%s: Sending answer command\n", 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) { ast_log(LOG_WARNING, "%s: Failed to answer channel\n", diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index 832d6fc1b797c55426a82363bcedc6d18359ef8e..1de774ff5edba814915691e4cb70a099f5056a8f 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -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 * 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, OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA); + ao2_ref(playback, -1); } static int play_uri(struct stasis_app_control *control, struct ast_channel *chan, void *data) { - RAII_VAR(struct stasis_app_playback *, playback, NULL, - remove_from_playbacks); + struct stasis_app_playback *playback = data; struct ast_bridge *bridge; - playback = data; - if (!control) { return -1; } @@ -434,7 +434,7 @@ struct stasis_app_playback *stasis_app_control_play_uri( enum stasis_app_playback_target_type target_type, 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) { return NULL; @@ -444,6 +444,9 @@ struct stasis_app_playback *stasis_app_control_play_uri( stasis_app_control_get_channel_id(control), uri); playback = playback_create(control, id); + if (!playback) { + return NULL; + } if (skipms == 0) { skipms = PLAYBACK_DEFAULT_SKIPMS; @@ -459,11 +462,8 @@ struct stasis_app_playback *stasis_app_control_play_uri( playback->state = STASIS_PLAYBACK_STATE_QUEUED; playback_publish(playback); - /* A ref is kept in the playbacks container; no need to bump */ - stasis_app_send_command_async(control, play_uri, playback); + stasis_app_send_command_async(control, play_uri, ao2_bump(playback), remove_from_playbacks); - /* Although this should be bumped for the caller */ - ao2_ref(playback, +1); return playback; } diff --git a/res/res_stasis_recording.c b/res/res_stasis_recording.c index d9e9599cd4441c8ddd0f414300893566d5fe2235..433adb3d5018f7d5b3be4fe915ec846a4d714392 100644 --- a/res/res_stasis_recording.c +++ b/res/res_stasis_recording.c @@ -279,21 +279,22 @@ static void recording_fail(struct stasis_app_control *control, 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, OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA); + ao2_ref(recording, -1); } static int record_file(struct stasis_app_control *control, struct ast_channel *chan, void *data) { - RAII_VAR(struct stasis_app_recording *, recording, - NULL, recording_cleanup); + struct stasis_app_recording *recording = data; char *acceptdtmf; int res; - recording = data; ast_assert(recording != NULL); 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_recording_options *options) { - RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup); + struct stasis_app_recording *recording; char *last_slash; errno = 0; @@ -395,6 +396,7 @@ struct stasis_app_recording *stasis_app_control_record( if (recording->absolute_name == NULL) { errno = ENOMEM; + ao2_ref(recording, -1); return NULL; } @@ -403,6 +405,7 @@ struct stasis_app_recording *stasis_app_control_record( if (ast_safe_mkdir(ast_config_AST_RECORDING_DIR, recording->absolute_name, 0777) != 0) { /* errno set by ast_mkdir */ + ao2_ref(recording, -1); return NULL; } *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", recording->absolute_name); errno = EEXIST; + ao2_ref(recording, -1); return NULL; } @@ -434,6 +438,7 @@ struct stasis_app_recording *stasis_app_control_record( "Recording %s already in progress\n", recording->options->name); errno = EEXIST; + ao2_ref(recording, -1); return NULL; } 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); - /* A ref is kept in the recordings container; no need to bump */ - stasis_app_send_command_async(control, record_file, recording); + stasis_app_send_command_async(control, record_file, ao2_bump(recording), recording_cleanup); - /* Although this should be bumped for the caller */ - ao2_ref(recording, +1); return recording; } diff --git a/res/stasis/command.c b/res/stasis/command.c index 75a5c5aff76811b074c60f5bce579334c207271a..534e434ecfe2f7fa7a5e452c493841054061b6d9 100644 --- a/res/stasis/command.c +++ b/res/stasis/command.c @@ -37,6 +37,7 @@ struct stasis_app_command { ast_cond_t condition; stasis_app_command_cb callback; void *data; + command_data_destructor_fn data_destructor; int retval; int is_done:1; }; @@ -44,17 +45,25 @@ struct stasis_app_command { static void command_dtor(void *obj) { struct stasis_app_command *command = obj; + + if (command->data_destructor) { + command->data_destructor(command->data); + } + ast_mutex_destroy(&command->lock); ast_cond_destroy(&command->condition); } 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); if (!command) { + if (data_destructor) { + data_destructor(data); + } return NULL; } @@ -62,8 +71,8 @@ struct stasis_app_command *command_create( ast_cond_init(&command->condition, 0); command->callback = callback; command->data = data; + command->data_destructor = data_destructor; - ao2_ref(command, +1); return command; } @@ -90,6 +99,10 @@ void command_invoke(struct stasis_app_command *command, struct stasis_app_control *control, struct ast_channel *chan) { 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); } @@ -105,12 +118,12 @@ static const struct ast_datastore_info command_queue_prestart = { }; 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 ao2_container *command_queue; 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) { return -1; diff --git a/res/stasis/command.h b/res/stasis/command.h index 7f12ab36fa9f5c15c25ca0973fd322c218bf97f1..16f2a0a4138cc9c2087a3c22b3458030eeaa50af 100644 --- a/res/stasis/command.h +++ b/res/stasis/command.h @@ -32,7 +32,8 @@ struct stasis_app_command; 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); @@ -49,12 +50,16 @@ int command_join(struct stasis_app_command *command); * \param chan The channel on which to queue the prestart command * \param command_fn The callback to call for the command * \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 non-zero on failure */ 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 diff --git a/res/stasis/control.c b/res/stasis/control.c index 5c85b9ba1a4c151fab37fc4d69ed00d97ff107ee..7dc1220cf60dd804b1f90c41ade7439beb356138 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -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( 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; struct stasis_app_command *command; command_fn = command_fn ? : noop_cb; - command = command_create(command_fn, data); + command = command_create(command_fn, data, data_destructor); if (!command) { return NULL; } @@ -266,9 +267,9 @@ static struct stasis_app_command *exec_command_on_condition( static struct stasis_app_command *exec_command( 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 { @@ -280,7 +281,7 @@ 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); - 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; char *tech, *resource; 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; } - 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; } @@ -389,7 +390,7 @@ struct stasis_app_control_continue_data { static int app_control_continue(struct stasis_app_control *control, 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); @@ -422,7 +423,7 @@ int stasis_app_control_continue(struct stasis_app_control *control, const char * 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; } @@ -438,7 +439,7 @@ struct stasis_app_control_dtmf_data { static int app_control_dtmf(struct stasis_app_control *control, 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) { 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; 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; } @@ -486,7 +487,7 @@ static int 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; } @@ -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) { - 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; } @@ -514,7 +515,7 @@ struct stasis_app_control_mute_data { static int app_control_mute(struct stasis_app_control *control, 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); 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->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; } @@ -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, 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); 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->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; } @@ -580,7 +581,7 @@ static int 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, @@ -593,7 +594,7 @@ static int 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, @@ -607,7 +608,6 @@ static int app_control_moh_start(struct stasis_app_control *control, ast_moh_start(chan, moh_class, NULL); - ast_free(moh_class); return 0; } @@ -619,7 +619,7 @@ void stasis_app_control_moh_start(struct stasis_app_control *control, const char 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, @@ -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) { - 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, @@ -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) { - 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, @@ -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) { - 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( @@ -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, stasis_app_command_cb command_fn, void *data, + command_data_destructor_fn data_destructor, app_command_can_exec_cb can_exec_fn) { 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( - control, command_fn, data, can_exec_fn); + control, command_fn, data, data_destructor, can_exec_fn); if (!command) { 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, - 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, - 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); @@ -740,7 +742,7 @@ int stasis_app_send_command_async(struct stasis_app_control *control, return -1; } - command = exec_command(control, command_fn, data); + command = exec_command(control, command_fn, data, data_destructor); if (!command) { 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, 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); @@ -807,9 +809,7 @@ static void bridge_after_cb(struct ast_channel *chan, void *data) ast_channel_unlock(chan); /* Depart this channel from the bridge using the command queue if possible */ - if (stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel)) { - ao2_cleanup(bridge_channel); - } + stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup); 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 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)); 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); } @@ -954,7 +954,7 @@ int stasis_app_control_remove_channel_from_bridge( ast_debug(3, "%s: Sending channel remove_from_bridge command\n", stasis_app_control_get_channel_id(control)); 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); } diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index 93542812f321993d5dfa8fc8328963b329588588..9aef40353838b71310d6ca7ae87989cfdc1b3533 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -85,7 +85,6 @@ static int add_channel_to_bridge( res = control_add_channel_to_bridge(control, chan, bridge); - ao2_cleanup(bridge); return res; } @@ -93,9 +92,8 @@ static void bridge_stasis_queue_join_action(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel) { ast_channel_lock(bridge_channel->chan); - if (command_prestart_queue_command(bridge_channel->chan, add_channel_to_bridge, ao2_bump(self))) { - ao2_cleanup(self); - } + command_prestart_queue_command(bridge_channel->chan, add_channel_to_bridge, + ao2_bump(self), __ao2_cleanup); ast_channel_unlock(bridge_channel->chan); }