[asterisk-commits] dlee: branch dlee/record r390021 - in /team/dlee/record: include/asterisk/ ma...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed May 29 09:51:06 CDT 2013


Author: dlee
Date: Wed May 29 09:51:02 2013
New Revision: 390021

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=390021
Log:
Recording work

Modified:
    team/dlee/record/include/asterisk/channel.h
    team/dlee/record/include/asterisk/stasis_app_recording.h
    team/dlee/record/main/channel.c
    team/dlee/record/res/res_stasis_http_channels.c
    team/dlee/record/res/res_stasis_recording.c
    team/dlee/record/res/stasis_http/resource_channels.c
    team/dlee/record/res/stasis_http/resource_channels.h
    team/dlee/record/rest-api/api-docs/channels.json

Modified: team/dlee/record/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/include/asterisk/channel.h?view=diff&rev=390021&r1=390020&r2=390021
==============================================================================
--- team/dlee/record/include/asterisk/channel.h (original)
+++ team/dlee/record/include/asterisk/channel.h Wed May 29 09:51:02 2013
@@ -1834,6 +1834,31 @@
 
 /*! \brief Send empty audio to prime a channel driver */
 int ast_prod(struct ast_channel *chan);
+
+/*! \brief An object which resets a channel's formats on cleanup */
+struct ast_format_janitor;
+
+/*!
+ * \brief Creates a janitor object which resets a channel's format specifiers
+ * when the janitor is cleaned up. Meant for use with RAII_VAR().
+ *
+ * \code
+ * RAII_VAR(struct ast_format_janitor *, janitor,
+ * 	ast_format_janitor_create(chan), ast_format_janitor_dtor);
+ * \endocde
+ *
+ * \param chan Channel to reset at destruction.
+ * \return Janitor object.
+ * \return \c NULL on error.
+ */
+struct ast_format_janitor *ast_format_janitor_create(struct ast_channel *chan);
+
+/*!
+ * \brief Destroy a janitor object, created with ast_format_janitor_create().
+ *
+ * \param janitor Janitor object to destroy. May be \c NULL.
+ */
+void ast_format_janitor_dtor(struct ast_format_janitor *janitor);
 
 /*!
  * \brief Sets read format on channel chan from capabilities

Modified: team/dlee/record/include/asterisk/stasis_app_recording.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/include/asterisk/stasis_app_recording.h?view=diff&rev=390021&r1=390020&r2=390021
==============================================================================
--- team/dlee/record/include/asterisk/stasis_app_recording.h (original)
+++ team/dlee/record/include/asterisk/stasis_app_recording.h Wed May 29 09:51:02 2013
@@ -51,6 +51,16 @@
 enum stasis_app_recording_media_operation {
 	/*! Stop the recording operation. */
 	STASIS_APP_RECORDING_STOP,
+};
+
+/*! Possible actions to take if a recording already exists */
+enum stasis_app_recording_if_exists {
+	/*! Fail the recording. */
+	STASIS_APP_RECORDING_IF_EXISTS_FAIL,
+	/*! Overwrite the existing recording. */
+	STASIS_APP_RECORDING_IF_EXISTS_OVERWRITE,
+	/*! Append to the existing recording. */
+	STASIS_APP_RECORDING_IF_EXISTS_APPEND,
 };
 
 #define STASIS_APP_RECORDING_TERMINATE_INVALID 0
@@ -71,6 +81,7 @@
 	 *  \c STASIS_APP_RECORDING_TERMINATE_ANY to terminate on any DTMF
 	 */
 	char terminate_on;
+	enum stasis_app_recording_if_exists if_exists;
 	/*! If true, file is appended to instead of overwriting. */
 	int append:1;
 	/*! If true, a beep is played at the start of recording */
@@ -102,6 +113,16 @@
 char stasis_app_recording_termination_parse(const char *str);
 
 /*!
+ * \brief Parse a string into the if_exists enum.
+ *
+ * \param str String to parse.
+ * \return How to handle an existing file.
+ * \return -1 on error.
+ */
+enum stasis_app_recording_if_exists stasis_app_recording_if_exists_parse(
+	const char *str);
+
+/*!
  * \brief Record media from a channel.
  *
  * A reference to the \a options object may be kept, so it MUST NOT be modified

Modified: team/dlee/record/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/main/channel.c?view=diff&rev=390021&r1=390020&r2=390021
==============================================================================
--- team/dlee/record/main/channel.c (original)
+++ team/dlee/record/main/channel.c Wed May 29 09:51:02 2013
@@ -5308,6 +5308,62 @@
 	}
 	ast_channel_unlock(chan);
 	return res;
+}
+
+struct ast_format_janitor {
+	struct ast_channel *channel;
+	struct ast_format rfmt;
+	struct ast_format wfmt;
+};
+
+struct ast_format_janitor *ast_format_janitor_create(struct ast_channel *chan)
+{
+	struct ast_format_janitor *janitor;
+
+	if (chan == NULL) {
+		return NULL;
+	}
+
+	janitor = ast_calloc(1, sizeof(*janitor));
+	if (janitor == NULL) {
+		return NULL;
+	}
+
+	janitor->channel = ast_channel_ref(chan);
+	ast_format_clear(&janitor->rfmt);
+	ast_format_copy(&janitor->rfmt, ast_channel_readformat(chan));
+	ast_format_clear(&janitor->wfmt);
+	ast_format_copy(&janitor->wfmt, ast_channel_writeformat(chan));
+
+	return janitor;
+}
+
+void ast_format_janitor_dtor(struct ast_format_janitor *janitor)
+{
+	int res;
+
+	if (janitor == NULL) {
+		return;
+	}
+
+	if (janitor->rfmt.id != ast_channel_readformat(janitor->channel)->id) {
+		res = ast_set_read_format(janitor->channel, &janitor->rfmt);
+		if (res != 0) {
+			ast_log(LOG_WARNING,
+				"Failed to reset channel read format");
+		}
+	}
+
+	if (janitor->wfmt.id != ast_channel_writeformat(janitor->channel)->id) {
+		res = ast_set_write_format(janitor->channel, &janitor->wfmt);
+		if (res != 0) {
+			ast_log(LOG_WARNING,
+				"Failed to reset channel write format");
+		}
+	}
+
+	janitor->channel = ast_channel_unref(janitor->channel);
+	ast_free(janitor);
 }
 
 struct set_format_trans_access {

Modified: team/dlee/record/res/res_stasis_http_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/res/res_stasis_http_channels.c?view=diff&rev=390021&r1=390020&r2=390021
==============================================================================
--- team/dlee/record/res/res_stasis_http_channels.c (original)
+++ team/dlee/record/res/res_stasis_http_channels.c Wed May 29 09:51:02 2013
@@ -373,8 +373,8 @@
 		if (strcmp(i->name, "maxSilenceSeconds") == 0) {
 			args.max_silence_seconds = atoi(i->value);
 		} else
-		if (strcmp(i->name, "append") == 0) {
-			args.append = ast_true(i->value);
+		if (strcmp(i->name, "ifExists") == 0) {
+			args.if_exists = (i->value);
 		} else
 		if (strcmp(i->name, "beep") == 0) {
 			args.beep = ast_true(i->value);

Modified: team/dlee/record/res/res_stasis_recording.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/res/res_stasis_recording.c?view=diff&rev=390021&r1=390020&r2=390021
==============================================================================
--- team/dlee/record/res/res_stasis_recording.c (original)
+++ team/dlee/record/res/res_stasis_recording.c Wed May 29 09:51:02 2013
@@ -32,6 +32,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/dsp.h"
 #include "asterisk/file.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app_impl.h"
@@ -40,6 +41,9 @@
 
 /*! Number of hash buckets for recording container. Keep it prime! */
 #define RECORDING_BUCKETS 127
+
+/*! Comment is ignored by most formats, so we will ignore it, too. */
+#define RECORDING_COMMENT NULL
 
 STASIS_MESSAGE_TYPE_DEFN(stasis_app_recording_snapshot_type);
 
@@ -144,6 +148,29 @@
 	return STASIS_APP_RECORDING_TERMINATE_INVALID;
 }
 
+enum stasis_app_recording_if_exists stasis_app_recording_if_exists_parse(
+	const char *str)
+{
+	if (ast_strlen_zero(str)) {
+		/* Default value */
+		return STASIS_APP_RECORDING_IF_EXISTS_FAIL;
+	}
+
+	if (strcmp(str, "fail") == 0) {
+		return STASIS_APP_RECORDING_IF_EXISTS_FAIL;
+	}
+
+	if (strcmp(str, "overwrite") == 0) {
+		return STASIS_APP_RECORDING_IF_EXISTS_OVERWRITE;
+	}
+
+	if (strcmp(str, "append") == 0) {
+		return STASIS_APP_RECORDING_IF_EXISTS_APPEND;
+	}
+
+	return -1;
+}
+
 static void recording_publish(struct stasis_app_recording *recording)
 {
 	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
@@ -206,13 +233,19 @@
 	RAII_VAR(struct stasis_app_recording *, recording,
 		NULL, recording_cleanup);
 	RAII_VAR(struct ast_filestream *, s, NULL, ast_closestream);
-	int res;
-	struct timeval start;
-	int ms;
-	long maxms;
-	int ioflags;
-	const char *comment = "Stasis recording";
-	int check = 0;
+	RAII_VAR(struct ast_format_janitor *, janitor,
+		NULL, ast_format_janitor_dtor);
+	RAII_VAR(struct ast_dsp *, sildet, NULL, ast_dsp_free);
+
+	int check;	/* Whether to check file existence before writing. */
+	int dtmf_term = 0;	/* Flag to indicate termination via DTMF */
+	int ioflags;	/* IO flags for writing output file */
+	int ms;	/* Time remaining/waited, in milliseconds */
+	int res;	/* Result variable */
+	int total_silence_ms = 0;	/* Total silence currently recorded */
+	long max_silence_ms = 0;	/* Max silence for termination */
+	long maxms;	/* Max milliseconds to record */
+	struct timeval start;	/* Start of recording */
 
 	recording = data;
 	ast_assert(recording != NULL);
@@ -222,15 +255,48 @@
 	recording_publish(recording);
 	ao2_unlock(recording);
 
+	check = 1;
 	ioflags = O_CREAT|O_WRONLY;
-	if (recording->options->append) {
+
+	switch (recording->options->if_exists) {
+	case STASIS_APP_RECORDING_IF_EXISTS_FAIL:
+		break;
+	case STASIS_APP_RECORDING_IF_EXISTS_OVERWRITE:
+		check = 0;
 		ioflags |= O_APPEND;
-	} else {
+		break;
+	case STASIS_APP_RECORDING_IF_EXISTS_APPEND:
+		check = 0;
 		ioflags |= O_TRUNC;
+		break;
+	}
+
+	if (recording->options->max_silence_seconds > 0) {
+		max_silence_ms = recording->options->max_silence_seconds * 1000;
+
+		janitor = ast_format_janitor_create(chan);
+		if (janitor == NULL) {
+			recording_fail(recording);
+			return NULL;
+		}
+
+		res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
+		if (res != 0) {
+			recording_fail(recording);
+			return NULL;
+		}
+
+		sildet = ast_dsp_new();
+		if (!sildet) {
+			recording_fail(recording);
+			return NULL;
+		}
+		ast_dsp_set_threshold(sildet,
+			ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
 	}
 
 	s = ast_writefile(recording->options->name,recording->options->format,
-		comment, ioflags, check, AST_FILE_MODE);
+		RECORDING_COMMENT, ioflags, check, AST_FILE_MODE);
 	if (s == NULL) {
 		ast_log(LOG_WARNING, "Could not create file %s.%s\n",
 			recording->options->name, recording->options->format);
@@ -240,6 +306,8 @@
 
 	res = ast_auto_answer(chan);
 	if (res != 0) {
+		ast_debug(3, "%s: Failed to answer\n",
+			ast_channel_uniqueid(chan));
 		recording_fail(recording);
 		return NULL;
 	}
@@ -248,6 +316,8 @@
 		res = ast_play_sound(chan, "beep");
 	}
 	if (res != 0) {
+		ast_debug(3, "%s: Failed to play beep\n",
+			ast_channel_uniqueid(chan));
 		recording_fail(recording);
 		return NULL;
 	}
@@ -255,7 +325,6 @@
 	maxms = recording->options->max_duration_seconds * 1000;
 	start = ast_tvnow();
 	while ((ms = ast_remaining_ms(start, maxms))) {
-		int terminated = 0;
 		RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
 
 		ms = ast_waitfor(chan, ms);
@@ -281,12 +350,16 @@
 		switch (f->frametype) {
 		case AST_FRAME_VOICE:
 			res = ast_writestream(s, f);
+
+			if (res == 0 && sildet) {
+				ast_dsp_silence(sildet, f, &total_silence_ms);
+			}
 			break;
 		case AST_FRAME_VIDEO:
 			res = ast_writestream(s, f);
 			break;
 		case AST_FRAME_DTMF:
-			terminated = recording_should_terminate(recording,
+			dtmf_term = recording_should_terminate(recording,
 				f->subclass.integer);
 			break;
 		default:
@@ -294,8 +367,20 @@
 			break;
 		}
 
-		if (terminated) {
-			ast_debug(3, "%s: Terminating recording\n",
+		if (dtmf_term) {
+			ast_debug(3,
+				"%s: DTMF detected. Terminating recording\n",
+				ast_channel_uniqueid(chan));
+			break;
+		}
+
+		if (total_silence_ms > max_silence_ms) {
+			/* Strip off the detected silence. Leave a second of it,
+			 * for a smooth transition at the end. */
+			ast_stream_rewind(s, total_silence_ms - 1000);
+			ast_truncstream(s);
+			ast_debug(3,
+				"%s: Silence detected. Terminating recording\n",
 				ast_channel_uniqueid(chan));
 			break;
 		}

Modified: team/dlee/record/res/stasis_http/resource_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/res/stasis_http/resource_channels.c?view=diff&rev=390021&r1=390020&r2=390021
==============================================================================
--- team/dlee/record/res/stasis_http/resource_channels.c (original)
+++ team/dlee/record/res/stasis_http/resource_channels.c Wed May 29 09:51:02 2013
@@ -256,13 +256,21 @@
 	options->max_duration_seconds = args->max_duration_seconds;
 	options->terminate_on =
 		stasis_app_recording_termination_parse(args->terminate_on);
-	options->append = args->append;
+	options->if_exists =
+		stasis_app_recording_if_exists_parse(args->if_exists);
 	options->beep = args->beep;
 
 	if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
 		stasis_http_response_error(
 			response, 400, "Bad Request",
 			"terminateOn invalid");
+		return;
+	}
+
+	if (options->if_exists == -1) {
+		stasis_http_response_error(
+			response, 400, "Bad Request",
+			"ifExists invalid");
 		return;
 	}
 

Modified: team/dlee/record/res/stasis_http/resource_channels.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/res/stasis_http/resource_channels.h?view=diff&rev=390021&r1=390020&r2=390021
==============================================================================
--- team/dlee/record/res/stasis_http/resource_channels.h (original)
+++ team/dlee/record/res/stasis_http/resource_channels.h Wed May 29 09:51:02 2013
@@ -229,8 +229,8 @@
 	int max_duration_seconds;
 	/*! \brief Maximum duration of silence, in seconds. 0 for no limit */
 	int max_silence_seconds;
-	/*! \brief If true, and recording already exists, append to recording */
-	int append;
+	/*! \brief Action to take if a recording with the same name already exists. */
+	const char *if_exists;
 	/*! \brief Play beep when recording begins */
 	int beep;
 	/*! \brief DTMF input to terminate recording */

Modified: team/dlee/record/rest-api/api-docs/channels.json
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/rest-api/api-docs/channels.json?view=diff&rev=390021&r1=390020&r2=390021
==============================================================================
--- team/dlee/record/rest-api/api-docs/channels.json (original)
+++ team/dlee/record/rest-api/api-docs/channels.json Wed May 29 09:51:02 2013
@@ -507,13 +507,21 @@
 							}
 						},
 						{
-							"name": "append",
-							"description": "If true, and recording already exists, append to recording",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "boolean",
-							"defaultValue": false
+							"name": "ifExists",
+							"description": "Action to take if a recording with the same name already exists.",
+							"paramType": "query",
+							"required": false,
+							"allowMultiple": false,
+							"dataType": "string",
+							"defaultValue": "fail",
+							"allowableValues": {
+								"valueType": "LIST",
+								"values": [
+									"fail",
+									"overwrite",
+									"append"
+								]
+							}
 						},
 						{
 							"name": "beep",




More information about the asterisk-commits mailing list