[svn-commits] dlee: trunk r402928 - in /trunk: ./ include/asterisk/ res/ res/ari/ res/stasi...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Nov 21 09:56:36 CST 2013


Author: dlee
Date: Thu Nov 21 09:56:34 2013
New Revision: 402928

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=402928
Log:
ari: Add silence generator controls

This patch adds the ability to start a silence generator on a channel
via ARI. This generator will play silence on the channel (avoiding audio
timeouts on the peer) until it is stopped, or some other media operation
is started (like playing media, starting music on hold, etc.).

(closes issue ASTERISK-22514)
Review: https://reviewboard.asterisk.org/r/3019/
........

Merged revisions 402926 from http://svn.asterisk.org/svn/asterisk/branches/12

Modified:
    trunk/   (props changed)
    trunk/include/asterisk/stasis_app.h
    trunk/res/ari/resource_channels.c
    trunk/res/ari/resource_channels.h
    trunk/res/res_ari_channels.c
    trunk/res/stasis/control.c
    trunk/rest-api/api-docs/channels.json

Propchange: trunk/
------------------------------------------------------------------------------
--- branch-12-merged (original)
+++ branch-12-merged Thu Nov 21 09:56:34 2013
@@ -1,1 +1,1 @@
-/branches/12:1-398558,398560-398577,398579-399305,399307-401390,401392-402738,402755,402757,402767,402769,402787,402793,402804,402838,402864,402891
+/branches/12:1-398558,398560-398577,398579-399305,399307-401390,401392-402738,402755,402757,402767,402769,402787,402793,402804,402838,402864,402891,402926

Modified: trunk/include/asterisk/stasis_app.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/stasis_app.h?view=diff&rev=402928&r1=402927&r2=402928
==============================================================================
--- trunk/include/asterisk/stasis_app.h (original)
+++ trunk/include/asterisk/stasis_app.h Thu Nov 21 09:56:34 2013
@@ -386,6 +386,18 @@
 void stasis_app_control_moh_stop(struct stasis_app_control *control);
 
 /*!
+ * \brief Start playing silence to a channel.
+ * \param control Control for \c res_stasis.
+ */
+void stasis_app_control_silence_start(struct stasis_app_control *control);
+
+/*!
+ * \brief Stop playing silence to a channel.
+ * \param control Control for \c res_stasis.
+ */
+void stasis_app_control_silence_stop(struct stasis_app_control *control);
+
+/*!
  * \brief Returns the most recent snapshot for the associated channel.
  *
  * The returned pointer is AO2 managed, so ao2_cleanup() when you're done.

Modified: trunk/res/ari/resource_channels.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/ari/resource_channels.c?view=diff&rev=402928&r1=402927&r2=402928
==============================================================================
--- trunk/res/ari/resource_channels.c (original)
+++ trunk/res/ari/resource_channels.c Thu Nov 21 09:56:34 2013
@@ -318,6 +318,38 @@
 	}
 
 	stasis_app_control_moh_stop(control);
+	ast_ari_response_no_content(response);
+}
+
+void ast_ari_channels_start_silence(struct ast_variable *headers,
+	struct ast_ari_channels_start_silence_args *args,
+	struct ast_ari_response *response)
+{
+	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+	control = find_control(response, args->channel_id);
+	if (control == NULL) {
+		/* Response filled in by find_control */
+		return;
+	}
+
+	stasis_app_control_silence_start(control);
+	ast_ari_response_no_content(response);
+}
+
+void ast_ari_channels_stop_silence(struct ast_variable *headers,
+	struct ast_ari_channels_stop_silence_args *args,
+	struct ast_ari_response *response)
+{
+	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+	control = find_control(response, args->channel_id);
+	if (control == NULL) {
+		/* Response filled in by find_control */
+		return;
+	}
+
+	stasis_app_control_silence_stop(control);
 	ast_ari_response_no_content(response);
 }
 

Modified: trunk/res/ari/resource_channels.h
URL: http://svnview.digium.com/svn/asterisk/trunk/res/ari/resource_channels.h?view=diff&rev=402928&r1=402927&r2=402928
==============================================================================
--- trunk/res/ari/resource_channels.h (original)
+++ trunk/res/ari/resource_channels.h Thu Nov 21 09:56:34 2013
@@ -254,7 +254,7 @@
 /*!
  * \brief Play music on hold to a channel.
  *
- * Using media operations such as playOnChannel on a channel playing MOH in this manner will suspend MOH without resuming automatically. If continuing music on hold is desired, the stasis application must reinitiate music on hold.
+ * Using media operations such as /play on a channel playing MOH in this manner will suspend MOH without resuming automatically. If continuing music on hold is desired, the stasis application must reinitiate music on hold.
  *
  * \param headers HTTP headers
  * \param args Swagger parameters
@@ -274,6 +274,34 @@
  * \param[out] response HTTP response
  */
 void ast_ari_channels_stop_moh(struct ast_variable *headers, struct ast_ari_channels_stop_moh_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_channels_start_silence() */
+struct ast_ari_channels_start_silence_args {
+	/*! \brief Channel's id */
+	const char *channel_id;
+};
+/*!
+ * \brief Play silence to a channel.
+ *
+ * Using media operations such as /play on a channel playing silence in this manner will suspend silence without resuming automatically.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_channels_start_silence(struct ast_variable *headers, struct ast_ari_channels_start_silence_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_channels_stop_silence() */
+struct ast_ari_channels_stop_silence_args {
+	/*! \brief Channel's id */
+	const char *channel_id;
+};
+/*!
+ * \brief Stop playing silence to a channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_channels_stop_silence(struct ast_variable *headers, struct ast_ari_channels_stop_silence_args *args, struct ast_ari_response *response);
 /*! \brief Argument struct for ast_ari_channels_play() */
 struct ast_ari_channels_play_args {
 	/*! \brief Channel's id */

Modified: trunk/res/res_ari_channels.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_ari_channels.c?view=diff&rev=402928&r1=402927&r2=402928
==============================================================================
--- trunk/res/res_ari_channels.c (original)
+++ trunk/res/res_ari_channels.c Thu Nov 21 09:56:34 2013
@@ -978,6 +978,122 @@
 
 	if (!is_valid) {
 		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/moh\n");
+		ast_ari_response_error(response, 500,
+			"Internal Server Error", "Response validation failed");
+	}
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
+}
+/*!
+ * \brief Parameter parsing callback for /channels/{channelId}/silence.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_channels_start_silence_cb(
+	struct ast_variable *get_params, struct ast_variable *path_vars,
+	struct ast_variable *headers, struct ast_ari_response *response)
+{
+	struct ast_ari_channels_start_silence_args args = {};
+	struct ast_variable *i;
+#if defined(AST_DEVMODE)
+	int is_valid;
+	int code;
+#endif /* AST_DEVMODE */
+
+	for (i = path_vars; i; i = i->next) {
+		if (strcmp(i->name, "channelId") == 0) {
+			args.channel_id = (i->value);
+		} else
+		{}
+	}
+	ast_ari_channels_start_silence(headers, &args, response);
+#if defined(AST_DEVMODE)
+	code = response->response_code;
+
+	switch (code) {
+	case 0: /* Implementation is still a stub, or the code wasn't set */
+		is_valid = response->message == NULL;
+		break;
+	case 500: /* Internal Server Error */
+	case 501: /* Not Implemented */
+	case 404: /* Channel not found */
+	case 409: /* Channel not in a Stasis application */
+		is_valid = 1;
+		break;
+	default:
+		if (200 <= code && code <= 299) {
+			is_valid = ast_ari_validate_void(
+				response->message);
+		} else {
+			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/silence\n", code);
+			is_valid = 0;
+		}
+	}
+
+	if (!is_valid) {
+		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/silence\n");
+		ast_ari_response_error(response, 500,
+			"Internal Server Error", "Response validation failed");
+	}
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
+}
+/*!
+ * \brief Parameter parsing callback for /channels/{channelId}/silence.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_channels_stop_silence_cb(
+	struct ast_variable *get_params, struct ast_variable *path_vars,
+	struct ast_variable *headers, struct ast_ari_response *response)
+{
+	struct ast_ari_channels_stop_silence_args args = {};
+	struct ast_variable *i;
+#if defined(AST_DEVMODE)
+	int is_valid;
+	int code;
+#endif /* AST_DEVMODE */
+
+	for (i = path_vars; i; i = i->next) {
+		if (strcmp(i->name, "channelId") == 0) {
+			args.channel_id = (i->value);
+		} else
+		{}
+	}
+	ast_ari_channels_stop_silence(headers, &args, response);
+#if defined(AST_DEVMODE)
+	code = response->response_code;
+
+	switch (code) {
+	case 0: /* Implementation is still a stub, or the code wasn't set */
+		is_valid = response->message == NULL;
+		break;
+	case 500: /* Internal Server Error */
+	case 501: /* Not Implemented */
+	case 404: /* Channel not found */
+	case 409: /* Channel not in a Stasis application */
+		is_valid = 1;
+		break;
+	default:
+		if (200 <= code && code <= 299) {
+			is_valid = ast_ari_validate_void(
+				response->message);
+		} else {
+			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/silence\n", code);
+			is_valid = 0;
+		}
+	}
+
+	if (!is_valid) {
+		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/silence\n");
 		ast_ari_response_error(response, 500,
 			"Internal Server Error", "Response validation failed");
 	}
@@ -1345,6 +1461,16 @@
 	.children = {  }
 };
 /*! \brief REST handler for /api-docs/channels.{format} */
+static struct stasis_rest_handlers channels_channelId_silence = {
+	.path_segment = "silence",
+	.callbacks = {
+		[AST_HTTP_POST] = ast_ari_channels_start_silence_cb,
+		[AST_HTTP_DELETE] = ast_ari_channels_stop_silence_cb,
+	},
+	.num_children = 0,
+	.children = {  }
+};
+/*! \brief REST handler for /api-docs/channels.{format} */
 static struct stasis_rest_handlers channels_channelId_play = {
 	.path_segment = "play",
 	.callbacks = {
@@ -1380,8 +1506,8 @@
 		[AST_HTTP_GET] = ast_ari_channels_get_cb,
 		[AST_HTTP_DELETE] = ast_ari_channels_hangup_cb,
 	},
-	.num_children = 10,
-	.children = { &channels_channelId_continue,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable, }
+	.num_children = 11,
+	.children = { &channels_channelId_continue,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable, }
 };
 /*! \brief REST handler for /api-docs/channels.{format} */
 static struct stasis_rest_handlers channels = {

Modified: trunk/res/stasis/control.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/stasis/control.c?view=diff&rev=402928&r1=402927&r2=402928
==============================================================================
--- trunk/res/stasis/control.c (original)
+++ trunk/res/stasis/control.c Thu Nov 21 09:56:34 2013
@@ -59,6 +59,10 @@
 	 */
 	struct ast_pbx *pbx;
 	/*!
+	 * Silence generator, when silence is being generated.
+	 */
+	struct ast_silence_generator *silgen;
+	/*!
 	 * When set, /c app_stasis should exit and continue in the dialplan.
 	 */
 	int is_done:1;
@@ -67,6 +71,10 @@
 static void control_dtor(void *obj)
 {
 	struct stasis_app_control *control = obj;
+
+	/* We may have a lingering silence generator; free it */
+	ast_channel_stop_silence_generator(control->channel, control->silgen);
+	control->silgen = NULL;
 
 	ao2_cleanup(control->command_queue);
 	ast_cond_destroy(&control->wait_cond);
@@ -500,6 +508,55 @@
 void stasis_app_control_moh_stop(struct stasis_app_control *control)
 {
 	stasis_app_send_command_async(control, app_control_moh_stop, NULL);
+}
+
+static void *app_control_silence_start(struct stasis_app_control *control,
+	struct ast_channel *chan, void *data)
+{
+	if (control->silgen) {
+		/* We have a silence generator, but it may have been implicitly
+		 * disabled by media actions (music on hold, playing media,
+		 * etc.) Just stop it and restart a new one.
+		 */
+		ast_channel_stop_silence_generator(
+			control->channel, control->silgen);
+	}
+
+	ast_debug(3, "%s: Starting silence generator\n",
+		stasis_app_control_get_channel_id(control));
+	control->silgen = ast_channel_start_silence_generator(control->channel);
+
+	if (!control->silgen) {
+		ast_log(LOG_WARNING,
+			"%s: Failed to start silence generator.\n",
+			stasis_app_control_get_channel_id(control));
+	}
+
+	return NULL;
+}
+
+void stasis_app_control_silence_start(struct stasis_app_control *control)
+{
+	stasis_app_send_command_async(control, app_control_silence_start, NULL);
+}
+
+static void *app_control_silence_stop(struct stasis_app_control *control,
+	struct ast_channel *chan, void *data)
+{
+	if (control->silgen) {
+		ast_debug(3, "%s: Stopping silence generator\n",
+			stasis_app_control_get_channel_id(control));
+		ast_channel_stop_silence_generator(
+			control->channel, control->silgen);
+		control->silgen = NULL;
+	}
+
+	return NULL;
+}
+
+void stasis_app_control_silence_stop(struct stasis_app_control *control)
+{
+	stasis_app_send_command_async(control, app_control_silence_stop, NULL);
 }
 
 struct ast_channel_snapshot *stasis_app_control_get_snapshot(

Modified: trunk/rest-api/api-docs/channels.json
URL: http://svnview.digium.com/svn/asterisk/trunk/rest-api/api-docs/channels.json?view=diff&rev=402928&r1=402927&r2=402928
==============================================================================
--- trunk/rest-api/api-docs/channels.json (original)
+++ trunk/rest-api/api-docs/channels.json Thu Nov 21 09:56:34 2013
@@ -553,7 +553,7 @@
 				{
 					"httpMethod": "POST",
 					"summary": "Play music on hold to a channel.",
-					"notes": "Using media operations such as playOnChannel on a channel playing MOH in this manner will suspend MOH without resuming automatically. If continuing music on hold is desired, the stasis application must reinitiate music on hold.",
+					"notes": "Using media operations such as /play on a channel playing MOH in this manner will suspend MOH without resuming automatically. If continuing music on hold is desired, the stasis application must reinitiate music on hold.",
 					"nickname": "startMoh",
 					"responseClass": "void",
 					"parameters": [
@@ -589,6 +589,65 @@
 					"httpMethod": "DELETE",
 					"summary": "Stop playing music on hold to a channel.",
 					"nickname": "stopMoh",
+					"responseClass": "void",
+					"parameters": [
+						{
+							"name": "channelId",
+							"description": "Channel's id",
+							"paramType": "path",
+							"required": true,
+							"allowMultiple": false,
+							"dataType": "string"
+						}
+					],
+					"errorResponses": [
+						{
+							"code": 404,
+							"reason": "Channel not found"
+						},
+						{
+							"code": 409,
+							"reason": "Channel not in a Stasis application"
+						}
+					]
+				}
+			]
+		},
+		{
+			"path": "/channels/{channelId}/silence",
+			"description": "Play silence to a channel",
+			"operations": [
+				{
+					"httpMethod": "POST",
+					"summary": "Play silence to a channel.",
+					"notes": "Using media operations such as /play on a channel playing silence in this manner will suspend silence without resuming automatically.",
+					"nickname": "startSilence",
+					"responseClass": "void",
+					"parameters": [
+						{
+							"name": "channelId",
+							"description": "Channel's id",
+							"paramType": "path",
+							"required": true,
+							"allowMultiple": false,
+							"dataType": "string"
+						}
+					],
+					"errorResponses": [
+						{
+							"code": 404,
+							"reason": "Channel not found"
+						},
+						{
+							"code": 409,
+							"reason": "Channel not in a Stasis application"
+						}
+					]
+				},
+				{
+					"httpMethod": "DELETE",
+					"summary": "Stop playing silence to a channel.",
+					"nickname": "stopSilence",
 					"responseClass": "void",
 					"parameters": [
 						{




More information about the svn-commits mailing list