[asterisk-commits] kharwell: branch 12 r403749 - in /branches/12: include/asterisk/ res/ res/ari...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Dec 13 10:32:55 CST 2013


Author: kharwell
Date: Fri Dec 13 10:32:53 2013
New Revision: 403749

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=403749
Log:
ARI: Adding a channel to a bridge while a live recording is active blocks

Added the ability to have rules that are checked when adding and/or removing
channels to/from a bridge.  In this case, if a channel is currently recording
and someone attempts to add it to a bridge an "is recording" rule is checked,
fails, and a 409 conflict is returned.

Also command functions now return an integer value that can be descriptive of
what kind of problems, if any, occurred before or during execution.

(closes issue ASTERISK-22624)
Reported by: Joshua Colp
Review: https://reviewboard.asterisk.org/r/2947/

Modified:
    branches/12/include/asterisk/stasis_app.h
    branches/12/include/asterisk/stasis_app_impl.h
    branches/12/res/ari/resource_bridges.c
    branches/12/res/res_ari_bridges.c
    branches/12/res/res_stasis_answer.c
    branches/12/res/res_stasis_playback.c
    branches/12/res/res_stasis_recording.c
    branches/12/res/stasis/command.c
    branches/12/res/stasis/command.h
    branches/12/res/stasis/control.c
    branches/12/rest-api/api-docs/bridges.json

Modified: branches/12/include/asterisk/stasis_app.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/stasis_app.h?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/include/asterisk/stasis_app.h (original)
+++ branches/12/include/asterisk/stasis_app.h Fri Dec 13 10:32:53 2013
@@ -277,6 +277,60 @@
 /*! \brief Handler for controlling a channel that's in a Stasis application */
 struct stasis_app_control;
 
+/*! \brief Rule to check to see if an operation is allowed */
+struct stasis_app_control_rule {
+	/*!
+	 * \brief Checks to see if an operation is allowed on the control
+	 *
+	 * \param control Control object to check
+	 * \return 0 on success, otherwise a failure code
+	 */
+	enum stasis_app_control_channel_result (*check_rule)(
+		const struct stasis_app_control *control);
+	/*! Next item in the list */
+	AST_LIST_ENTRY(stasis_app_control_rule) next;
+};
+
+/*!
+ * \brief Registers an add channel to bridge rule.
+ *
+ * \param control Control object
+ * \param rule The rule to register
+ */
+void stasis_app_control_register_add_rule(
+	struct stasis_app_control *control,
+	struct stasis_app_control_rule *rule);
+
+/*!
+ * \brief UnRegister an add channel to bridge rule.
+ *
+ * \param control Control object
+ * \param rule The rule to unregister
+ */
+void stasis_app_control_unregister_add_rule(
+	struct stasis_app_control *control,
+	struct stasis_app_control_rule *rule);
+
+/*!
+ * \brief Registers a remove channel from bridge rule.
+ *
+ * \param control Control object
+ * \param rule The rule to register
+ */
+void stasis_app_control_register_remove_rule(
+	struct stasis_app_control *control,
+	struct stasis_app_control_rule *rule);
+
+/*!
+ * \brief Unregisters a remove channel from bridge rule.
+ *
+ * \param control Control object
+ * \param rule The rule to unregister
+ */
+void stasis_app_control_unregister_remove_rule(
+	struct stasis_app_control *control,
+	struct stasis_app_control_rule *rule);
+
 /*!
  * \brief Returns the handler for the given channel.
  * \param chan Channel to handle.
@@ -582,6 +636,16 @@
 	struct ast_bridge *bridge);
 
 /*!
+ * \brief Result codes used when adding/removing channels to/from bridges.
+ */
+enum stasis_app_control_channel_result {
+	/*! The channel is okay to be added/removed */
+	STASIS_APP_CHANNEL_OKAY = 0,
+	/*! The channel is currently recording */
+	STASIS_APP_CHANNEL_RECORDING
+};
+
+/*!
  * \brief Add a channel to the bridge.
  *
  * \param control Control whose channel should be added to the bridge

Modified: branches/12/include/asterisk/stasis_app_impl.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/stasis_app_impl.h?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/include/asterisk/stasis_app_impl.h (original)
+++ branches/12/include/asterisk/stasis_app_impl.h Fri Dec 13 10:32:53 2013
@@ -49,7 +49,7 @@
 	char *argv[]);
 
 /*! Callback type for stasis app commands */
-typedef void *(*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);
 
 /*!
@@ -63,10 +63,11 @@
  * \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.
- * \return Return value from \a command.
- * \return \c NULL on error.
+ *
+ * \return zero on success.
+ * \return error code otherwise.
  */
-void *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);
 
 /*!

Modified: branches/12/res/ari/resource_bridges.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/ari/resource_bridges.c?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/res/ari/resource_bridges.c (original)
+++ branches/12/res/ari/resource_bridges.c Fri Dec 13 10:32:53 2013
@@ -172,6 +172,22 @@
 	return list;
 }
 
+static int check_add_remove_channel(struct ast_ari_response *response,
+				    struct stasis_app_control *control,
+				    enum stasis_app_control_channel_result result)
+{
+	switch (result) {
+	case STASIS_APP_CHANNEL_RECORDING :
+		ast_ari_response_error(
+			response, 409, "Conflict", "Channel %s currently recording",
+			stasis_app_control_get_channel_id(control));
+		return -1;
+	case STASIS_APP_CHANNEL_OKAY:
+		return 0;
+	}
+	return 0;
+}
+
 void ast_ari_bridges_add_channel(struct ast_variable *headers,
 	struct ast_ari_bridges_add_channel_args *args,
 	struct ast_ari_response *response)
@@ -179,6 +195,7 @@
 	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
 	RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
 	size_t i;
+	int has_error = 0;
 
 	if (!bridge) {
 		/* Response filled in by find_bridge() */
@@ -202,10 +219,16 @@
 	}
 
 	for (i = 0; i < list->count; ++i) {
-		stasis_app_control_add_channel_to_bridge(list->controls[i], bridge);
-	}
-
-	ast_ari_response_no_content(response);
+		if ((has_error = check_add_remove_channel(response, list->controls[i],
+			     stasis_app_control_add_channel_to_bridge(
+				    list->controls[i], bridge)))) {
+			break;
+		}
+	}
+
+	if (!has_error) {
+		ast_ari_response_no_content(response);
+	}
 }
 
 void ast_ari_bridges_remove_channel(struct ast_variable *headers,

Modified: branches/12/res/res_ari_bridges.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_ari_bridges.c?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/res/res_ari_bridges.c (original)
+++ branches/12/res/res_ari_bridges.c Fri Dec 13 10:32:53 2013
@@ -438,7 +438,7 @@
 	case 501: /* Not Implemented */
 	case 400: /* Channel not found */
 	case 404: /* Bridge not found */
-	case 409: /* Bridge not in Stasis application */
+	case 409: /* Bridge not in Stasis application; Channel currently recording */
 	case 422: /* Channel not in Stasis application */
 		is_valid = 1;
 		break;

Modified: branches/12/res/res_stasis_answer.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_stasis_answer.c?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/res/res_stasis_answer.c (original)
+++ branches/12/res/res_stasis_answer.c Fri Dec 13 10:32:53 2013
@@ -35,28 +35,25 @@
 #include "asterisk/module.h"
 #include "asterisk/stasis_app_impl.h"
 
-static int OK = 0;
-static int FAIL = -1;
-
-static void *app_control_answer(struct stasis_app_control *control,
+static int app_control_answer(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	const int delay = 0;
 	ast_debug(3, "%s: Answering",
 		stasis_app_control_get_channel_id(control));
-	return __ast_answer(chan, delay) == 0 ? &OK : &FAIL;
+	return __ast_answer(chan, delay);
 }
 
 int stasis_app_control_answer(struct stasis_app_control *control)
 {
-	int *retval;
+	int retval;
 
 	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);
 
-	if (retval == NULL || *retval != 0) {
+	if (retval != 0) {
 		ast_log(LOG_WARNING, "%s: Failed to answer channel",
 			stasis_app_control_get_channel_id(control));
 		return -1;

Modified: branches/12/res/res_stasis_playback.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_stasis_playback.c?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/res/res_stasis_playback.c (original)
+++ branches/12/res/res_stasis_playback.c Fri Dec 13 10:32:53 2013
@@ -389,7 +389,7 @@
 		OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
 }
 
-static void *play_uri(struct stasis_app_control *control,
+static int play_uri(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	RAII_VAR(struct stasis_app_playback *, playback, NULL,
@@ -400,7 +400,7 @@
 	playback = data;
 
 	if (!control) {
-		return NULL;
+		return -1;
 	}
 
 	bridge = stasis_app_get_bridge(control);
@@ -435,7 +435,7 @@
 		play_on_channel(playback, chan);
 	}
 
-	return NULL;
+	return 0;
 }
 
 static void set_target_uri(

Modified: branches/12/res/res_stasis_recording.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_stasis_recording.c?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/res/res_stasis_recording.c (original)
+++ branches/12/res/res_stasis_recording.c Fri Dec 13 10:32:53 2013
@@ -244,11 +244,34 @@
 	stasis_app_control_publish(recording->control, message);
 }
 
-static void recording_fail(struct stasis_app_recording *recording, const char *cause)
+
+static void recording_set_state(struct stasis_app_recording *recording,
+				enum stasis_app_recording_state state,
+				const char *cause)
 {
 	SCOPED_AO2LOCK(lock, recording);
-	recording->state = STASIS_APP_RECORDING_STATE_FAILED;
+	recording->state = state;
 	recording_publish(recording, cause);
+}
+
+static enum stasis_app_control_channel_result check_rule_recording(
+	const struct stasis_app_control *control)
+{
+	return STASIS_APP_CHANNEL_RECORDING;
+}
+
+struct stasis_app_control_rule rule_recording = {
+	.check_rule = check_rule_recording
+};
+
+static void recording_fail(struct stasis_app_control *control,
+			   struct stasis_app_recording *recording,
+			   const char *cause)
+{
+	stasis_app_control_unregister_add_rule(control, &rule_recording);
+
+	recording_set_state(
+		recording, STASIS_APP_RECORDING_STATE_FAILED, cause);
 }
 
 static void recording_cleanup(struct stasis_app_recording *recording)
@@ -257,7 +280,7 @@
 		OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
 }
 
-static void *record_file(struct stasis_app_control *control,
+static int record_file(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	RAII_VAR(struct stasis_app_recording *, recording,
@@ -271,8 +294,8 @@
 
 	if (stasis_app_get_bridge(control)) {
 		ast_log(LOG_ERROR, "Cannot record channel while in bridge\n");
-		recording_fail(recording, "Cannot record channel while in bridge");
-		return NULL;
+		recording_fail(control, recording, "Cannot record channel while in bridge");
+		return -1;
 	}
 
 	switch (recording->options->terminate_on) {
@@ -293,15 +316,12 @@
 	if (res != 0) {
 		ast_debug(3, "%s: Failed to answer\n",
 			ast_channel_uniqueid(chan));
-		recording_fail(recording, "Failed to answer channel");
-		return NULL;
-	}
-
-	ao2_lock(recording);
-	recording->state = STASIS_APP_RECORDING_STATE_RECORDING;
-	recording_publish(recording, NULL);
-	ao2_unlock(recording);
-
+		recording_fail(control, recording, "Failed to answer channel");
+		return -1;
+	}
+
+	recording_set_state(
+		recording, STASIS_APP_RECORDING_STATE_RECORDING, NULL);
 	ast_play_and_record_full(chan,
 		NULL, /* playfile */
 		recording->absolute_name,
@@ -320,12 +340,12 @@
 
 	ast_debug(3, "%s: Recording complete\n", ast_channel_uniqueid(chan));
 
-	ao2_lock(recording);
-	recording->state = STASIS_APP_RECORDING_STATE_COMPLETE;
-	recording_publish(recording, NULL);
-	ao2_unlock(recording);
-
-	return NULL;
+	recording_set_state(
+		recording, STASIS_APP_RECORDING_STATE_COMPLETE, NULL);
+
+	stasis_app_control_unregister_add_rule(control, &rule_recording);
+
+	return 0;
 }
 
 static void recording_dtor(void *obj)
@@ -411,6 +431,8 @@
 		}
 		ao2_link(recordings, 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, recording);

Modified: branches/12/res/stasis/command.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/stasis/command.c?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/res/stasis/command.c (original)
+++ branches/12/res/stasis/command.c Fri Dec 13 10:32:53 2013
@@ -37,7 +37,7 @@
 	ast_cond_t condition;
 	stasis_app_command_cb callback;
 	void *data;
-	void *retval;
+	int retval;
 	int is_done:1;
 };
 
@@ -67,7 +67,7 @@
 	return command;
 }
 
-static void command_complete(struct stasis_app_command *command, void *retval)
+void command_complete(struct stasis_app_command *command, int retval)
 {
 	SCOPED_MUTEX(lock, &command->lock);
 
@@ -76,7 +76,7 @@
 	ast_cond_signal(&command->condition);
 }
 
-void *command_join(struct stasis_app_command *command)
+int command_join(struct stasis_app_command *command)
 {
 	SCOPED_MUTEX(lock, &command->lock);
 	while (!command->is_done) {
@@ -89,7 +89,7 @@
 void command_invoke(struct stasis_app_command *command,
 	struct stasis_app_control *control, struct ast_channel *chan)
 {
-	void *retval = command->callback(control, chan, command->data);
+	int retval = command->callback(control, chan, command->data);
 	command_complete(command, retval);
 }
 

Modified: branches/12/res/stasis/command.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/stasis/command.h?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/res/stasis/command.h (original)
+++ branches/12/res/stasis/command.h Fri Dec 13 10:32:53 2013
@@ -34,9 +34,11 @@
 struct stasis_app_command *command_create(
 	stasis_app_command_cb callback, void *data);
 
+void command_complete(struct stasis_app_command *command, int retval);
+
 void command_invoke(struct stasis_app_command *command,
 	struct stasis_app_control *control, struct ast_channel *chan);
 
-void *command_join(struct stasis_app_command *command);
+int command_join(struct stasis_app_command *command);
 
 #endif /* _ASTERISK_RES_STASIS_CONTROL_H */

Modified: branches/12/res/stasis/control.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/stasis/control.c?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/res/stasis/control.c (original)
+++ branches/12/res/stasis/control.c Fri Dec 13 10:32:53 2013
@@ -39,6 +39,8 @@
 #include "asterisk/pbx.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/app.h"
+
+AST_LIST_HEAD(app_control_rules, stasis_app_control_rule);
 
 struct stasis_app_control {
 	ast_cond_t wait_cond;
@@ -59,6 +61,14 @@
 	 */
 	struct ast_pbx *pbx;
 	/*!
+	 * A list of rules to check before adding a channel to a bridge.
+	 */
+	struct app_control_rules add_rules;
+	/*!
+	 * A list of rules to check before removing a channel from a bridge.
+	 */
+	struct app_control_rules remove_rules;
+	/*!
 	 * Silence generator, when silence is being generated.
 	 */
 	struct ast_silence_generator *silgen;
@@ -72,6 +82,9 @@
 {
 	struct stasis_app_control *control = obj;
 
+	AST_LIST_HEAD_DESTROY(&control->add_rules);
+	AST_LIST_HEAD_DESTROY(&control->remove_rules);
+
 	/* We may have a lingering silence generator; free it */
 	ast_channel_stop_silence_generator(control->channel, control->silgen);
 	control->silgen = NULL;
@@ -106,37 +119,148 @@
 
 	control->channel = channel;
 
+	AST_LIST_HEAD_INIT(&control->add_rules);
+	AST_LIST_HEAD_INIT(&control->remove_rules);
+
 	ao2_ref(control, +1);
 	return control;
 }
 
-static void *noop_cb(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	return NULL;
-}
-
+static void app_control_register_rule(
+	const struct stasis_app_control *control,
+	struct app_control_rules *list, struct stasis_app_control_rule *obj)
+{
+	SCOPED_AO2LOCK(lock, control->command_queue);
+	AST_LIST_INSERT_TAIL(list, obj, next);
+}
+
+static void app_control_unregister_rule(
+	const struct stasis_app_control *control,
+	struct app_control_rules *list, struct stasis_app_control_rule *obj)
+{
+	struct stasis_app_control_rule *rule;
+	SCOPED_AO2LOCK(lock, control->command_queue);
+	AST_RWLIST_TRAVERSE_SAFE_BEGIN(list, rule, next) {
+		if (rule == obj) {
+			AST_RWLIST_REMOVE_CURRENT(next);
+			break;
+		}
+	}
+	AST_RWLIST_TRAVERSE_SAFE_END;
+}
+
+/*!
+ * \internal
+ * \brief Checks to make sure each rule in the given list passes.
+ *
+ * \details Loops over a list of rules checking for rejections or failures.
+ *          If one rule fails its resulting error code is returned.
+ *
+ * \note Command queue should be locked before calling this function.
+ *
+ * \param control The stasis application control
+ * \param list The list of rules to check
+ *
+ * \retval 0 if all rules pass
+ * \retval non-zero error code if a rule fails
+ */
+static enum stasis_app_control_channel_result app_control_check_rules(
+	const struct stasis_app_control *control,
+	struct app_control_rules *list)
+{
+	int res = 0;
+	struct stasis_app_control_rule *rule;
+	AST_LIST_TRAVERSE(list, rule, next) {
+		if ((res = rule->check_rule(control))) {
+			return res;
+		}
+	}
+	return res;
+}
+
+void stasis_app_control_register_add_rule(
+	struct stasis_app_control *control,
+	struct stasis_app_control_rule *rule)
+{
+	return app_control_register_rule(control, &control->add_rules, rule);
+}
+
+void stasis_app_control_unregister_add_rule(
+	struct stasis_app_control *control,
+	struct stasis_app_control_rule *rule)
+{
+	app_control_unregister_rule(control, &control->add_rules, rule);
+}
+
+void stasis_app_control_register_remove_rule(
+	struct stasis_app_control *control,
+	struct stasis_app_control_rule *rule)
+{
+	return app_control_register_rule(control, &control->remove_rules, rule);
+}
+
+void stasis_app_control_unregister_remove_rule(
+	struct stasis_app_control *control,
+	struct stasis_app_control_rule *rule)
+{
+	app_control_unregister_rule(control, &control->remove_rules, rule);
+}
+
+static int app_control_can_add_channel_to_bridge(
+	struct stasis_app_control *control)
+{
+	return app_control_check_rules(control, &control->add_rules);
+}
+
+static int app_control_can_remove_channel_from_bridge(
+	struct stasis_app_control *control)
+{
+	return app_control_check_rules(control, &control->remove_rules);
+}
+
+static int noop_cb(struct stasis_app_control *control,
+	struct ast_channel *chan, void *data)
+{
+	return 0;
+}
+
+/*! Callback type to see if the command can execute
+    note: command_queue is locked during callback */
+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)
+{
+	int retval;
+	struct stasis_app_command *command;
+
+	command_fn = command_fn ? : noop_cb;
+
+	command = command_create(command_fn, data);
+	if (!command) {
+		return NULL;
+	}
+
+	ao2_lock(control->command_queue);
+	if (can_exec_fn && (retval = can_exec_fn(control))) {
+		ao2_unlock(control->command_queue);
+		command_complete(command, retval);
+		return command;
+	}
+
+	ao2_link_flags(control->command_queue, command, OBJ_NOLOCK);
+	ast_cond_signal(&control->wait_cond);
+	ao2_unlock(control->command_queue);
+
+	return command;
+}
 
 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_fn = command_fn ? : noop_cb;
-
-	command = command_create(command_fn, data);
-	if (!command) {
-		return NULL;
-	}
-
-	ao2_lock(control->command_queue);
-	ao2_link_flags(control->command_queue, command, OBJ_NOLOCK);
-	ast_cond_signal(&control->wait_cond);
-	ao2_unlock(control->command_queue);
-
-	ao2_ref(command, +1);
-	return command;
+	return exec_command_on_condition(control, command_fn, data, NULL);
 }
 
 struct stasis_app_control_dial_data {
@@ -144,11 +268,11 @@
 	int timeout;
 };
 
-static void *app_control_add_channel_to_bridge(
+static int app_control_add_channel_to_bridge(
         struct stasis_app_control *control,
         struct ast_channel *chan, void *data);
 
-static void *app_control_dial(struct stasis_app_control *control,
+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);
@@ -160,30 +284,30 @@
 
 	tech = dial_data->endpoint;
 	if (!(resource = strchr(tech, '/'))) {
-		return NULL;
+		return -1;
 	}
 	*resource++ = '\0';
 
 	if (!dial) {
 		ast_log(LOG_ERROR, "Failed to create dialing structure.\n");
-		return NULL;
+		return -1;
 	}
 
 	if (ast_dial_append(dial, tech, resource) < 0) {
 		ast_log(LOG_ERROR, "Failed to add %s/%s to dialing structure.\n", tech, resource);
-		return NULL;
+		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 NULL;
+		return -1;
 	}
 
 	if (!(bridge = ast_bridge_basic_new())) {
 		ast_log(LOG_ERROR, "Failed to create basic bridge.\n");
-		return NULL;
+		return -1;
 	}
 
 	if (ast_bridge_impart(bridge, new_chan, NULL, NULL,
@@ -193,7 +317,7 @@
 		app_control_add_channel_to_bridge(control, chan, bridge);
 	}
 
-	return NULL;
+	return 0;
 }
 
 int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, const char *exten, const char *context,
@@ -248,7 +372,7 @@
 	int priority;
 };
 
-static void *app_control_continue(struct stasis_app_control *control,
+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);
@@ -266,7 +390,7 @@
 
 	control->is_done = 1;
 
-	return NULL;
+	return 0;
 }
 
 int stasis_app_control_continue(struct stasis_app_control *control, const char *context, const char *extension, int priority)
@@ -297,7 +421,7 @@
 	char dtmf[];
 };
 
-static void *app_control_dtmf(struct stasis_app_control *control,
+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);
@@ -312,7 +436,7 @@
 		ast_safe_sleep(chan, dtmf_data->after);
 	}
 
-	return NULL;
+	return 0;
 }
 
 int stasis_app_control_dtmf(struct stasis_app_control *control, const char *dtmf, int before, int between, unsigned int duration, int after)
@@ -334,12 +458,12 @@
 	return 0;
 }
 
-static void *app_control_ring(struct stasis_app_control *control,
+static int app_control_ring(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	ast_indicate(control->channel, AST_CONTROL_RINGING);
 
-	return NULL;
+	return 0;
 }
 
 int stasis_app_control_ring(struct stasis_app_control *control)
@@ -349,12 +473,12 @@
 	return 0;
 }
 
-static void *app_control_ring_stop(struct stasis_app_control *control,
+static int app_control_ring_stop(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	ast_indicate(control->channel, -1);
 
-	return NULL;
+	return 0;
 }
 
 int stasis_app_control_ring_stop(struct stasis_app_control *control)
@@ -369,7 +493,7 @@
 	unsigned int direction;
 };
 
-static void *app_control_mute(struct stasis_app_control *control,
+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);
@@ -377,7 +501,7 @@
 
 	ast_channel_suppress(control->channel, mute_data->direction, mute_data->frametype);
 
-	return NULL;
+	return 0;
 }
 
 int stasis_app_control_mute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
@@ -396,7 +520,7 @@
 	return 0;
 }
 
-static void *app_control_unmute(struct stasis_app_control *control,
+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);
@@ -404,7 +528,7 @@
 
 	ast_channel_unsuppress(control->channel, mute_data->direction, mute_data->frametype);
 
-	return NULL;
+	return 0;
 }
 
 int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
@@ -456,12 +580,12 @@
 	return pbx_builtin_setvar_helper(control->channel, variable, value);
 }
 
-static void *app_control_hold(struct stasis_app_control *control,
+static int app_control_hold(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	ast_indicate(control->channel, AST_CONTROL_HOLD);
 
-	return NULL;
+	return 0;
 }
 
 void stasis_app_control_hold(struct stasis_app_control *control)
@@ -469,12 +593,12 @@
 	stasis_app_send_command_async(control, app_control_hold, NULL);
 }
 
-static void *app_control_unhold(struct stasis_app_control *control,
+static int app_control_unhold(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	ast_indicate(control->channel, AST_CONTROL_UNHOLD);
 
-	return NULL;
+	return 0;
 }
 
 void stasis_app_control_unhold(struct stasis_app_control *control)
@@ -482,7 +606,7 @@
 	stasis_app_send_command_async(control, app_control_unhold, NULL);
 }
 
-static void *app_control_moh_start(struct stasis_app_control *control,
+static int app_control_moh_start(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	char *moh_class = data;
@@ -490,7 +614,7 @@
 	ast_moh_start(chan, moh_class, NULL);
 
 	ast_free(moh_class);
-	return NULL;
+	return 0;
 }
 
 void stasis_app_control_moh_start(struct stasis_app_control *control, const char *moh_class)
@@ -504,11 +628,11 @@
 	stasis_app_send_command_async(control, app_control_moh_start, data);
 }
 
-static void *app_control_moh_stop(struct stasis_app_control *control,
+static int app_control_moh_stop(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	ast_moh_stop(chan);
-	return NULL;
+	return 0;
 }
 
 void stasis_app_control_moh_stop(struct stasis_app_control *control)
@@ -516,7 +640,7 @@
 	stasis_app_send_command_async(control, app_control_moh_stop, NULL);
 }
 
-static void *app_control_silence_start(struct stasis_app_control *control,
+static int app_control_silence_start(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	if (control->silgen) {
@@ -538,7 +662,7 @@
 			stasis_app_control_get_channel_id(control));
 	}
 
-	return NULL;
+	return 0;
 }
 
 void stasis_app_control_silence_start(struct stasis_app_control *control)
@@ -546,7 +670,7 @@
 	stasis_app_send_command_async(control, app_control_silence_start, NULL);
 }
 
-static void *app_control_silence_stop(struct stasis_app_control *control,
+static int app_control_silence_stop(struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	if (control->silgen) {
@@ -557,7 +681,7 @@
 		control->silgen = NULL;
 	}
 
-	return NULL;
+	return 0;
 }
 
 void stasis_app_control_silence_stop(struct stasis_app_control *control)
@@ -584,21 +708,29 @@
 	return snapshot;
 }
 
-void *stasis_app_send_command(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,
+					 app_command_can_exec_cb can_exec_fn)
+{
+	RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
+
+	if (control == NULL) {
+		return -1;
+	}
+
+	command = exec_command_on_condition(
+		control, command_fn, data, can_exec_fn);
+	if (!command) {
+		return -1;
+	}
+
+	return command_join(command);
+}
+
+int 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);
+	return app_send_command_on_condition(control, command_fn, data, NULL);
 }
 
 int stasis_app_send_command_async(struct stasis_app_control *control,
@@ -628,7 +760,7 @@
 	}
 }
 
-static void *bridge_channel_depart(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);
@@ -639,7 +771,7 @@
 		if (bridge_channel != ast_channel_internal_bridge_channel(chan)) {
 			ast_debug(3, "%s: Channel is no longer in departable state\n",
 				ast_channel_uniqueid(chan));
-			return NULL;
+			return -1;
 		}
 	}
 
@@ -648,7 +780,7 @@
 
 	ast_bridge_depart(chan);
 
-	return NULL;
+	return 0;
 }
 
 static void bridge_after_cb(struct ast_channel *chan, void *data)
@@ -691,10 +823,7 @@
 		ast_bridge_after_cb_reason_string(reason));
 }
 
-static int OK = 0;
-static int FAIL = -1;
-
-static void *app_control_add_channel_to_bridge(
+static int app_control_add_channel_to_bridge(
 	struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
@@ -702,7 +831,7 @@
 	int res;
 
 	if (!control || !bridge) {
-		return NULL;
+		return -1;
 	}
 
 	ast_debug(3, "%s: Adding to bridge %s\n",
@@ -726,7 +855,7 @@
 		bridge_after_cb_failed, control);
 	if (res != 0) {
 		ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
-		return &FAIL;
+		return -1;
 	}
 
 	{
@@ -752,34 +881,34 @@
 			ast_log(LOG_ERROR, "Error adding channel to bridge\n");
 			ast_channel_pbx_set(chan, control->pbx);
 			control->pbx = NULL;
-			return &FAIL;
+			return -1;
 		}
 
 		ast_assert(stasis_app_get_bridge(control) == NULL);
 		control->bridge = bridge;
 	}
-	return &OK;
+	return 0;
 }
 
 int stasis_app_control_add_channel_to_bridge(
 	struct stasis_app_control *control, struct ast_bridge *bridge)
 {
-	int *res;
 	ast_debug(3, "%s: Sending channel add_to_bridge command\n",
 			stasis_app_control_get_channel_id(control));
-	res = stasis_app_send_command(control,
-		app_control_add_channel_to_bridge, bridge);
-	return *res;
-}
-
-static void *app_control_remove_channel_from_bridge(
+
+	return app_send_command_on_condition(
+		control, app_control_add_channel_to_bridge, bridge,
+		app_control_can_add_channel_to_bridge);
+}
+
+static int app_control_remove_channel_from_bridge(
 	struct stasis_app_control *control,
 	struct ast_channel *chan, void *data)
 {
 	struct ast_bridge *bridge = data;
 
 	if (!control) {
-		return &FAIL;
+		return -1;
 	}
 
 	/* We should only depart from our own bridge */
@@ -791,22 +920,21 @@
 		ast_log(LOG_WARNING, "%s: Not in bridge %s; not removing\n",
 			stasis_app_control_get_channel_id(control),
 			bridge->uniqueid);
-		return &FAIL;
+		return -1;
 	}
 
 	ast_bridge_depart(chan);
-	return &OK;
+	return 0;
 }
 
 int stasis_app_control_remove_channel_from_bridge(
 	struct stasis_app_control *control, struct ast_bridge *bridge)
 {
-	int *res;
 	ast_debug(3, "%s: Sending channel remove_from_bridge command\n",
 			stasis_app_control_get_channel_id(control));
-	res = stasis_app_send_command(control,
-		app_control_remove_channel_from_bridge, bridge);
-	return *res;
+	return app_send_command_on_condition(
+		control, app_control_remove_channel_from_bridge, bridge,
+		app_control_can_remove_channel_from_bridge);
 }
 
 const char *stasis_app_control_get_channel_id(

Modified: branches/12/rest-api/api-docs/bridges.json
URL: http://svnview.digium.com/svn/asterisk/branches/12/rest-api/api-docs/bridges.json?view=diff&rev=403749&r1=403748&r2=403749
==============================================================================
--- branches/12/rest-api/api-docs/bridges.json (original)
+++ branches/12/rest-api/api-docs/bridges.json Fri Dec 13 10:32:53 2013
@@ -140,7 +140,7 @@
 						},
 						{
 							"code": 409,
-							"reason": "Bridge not in Stasis application"
+							"reason": "Bridge not in Stasis application; Channel currently recording"
 						},
 						{
 							"code": 422,




More information about the asterisk-commits mailing list