[asterisk-commits] dlee: branch dlee/ari-monitor2 r395935 - in /team/dlee/ari-monitor2: ./ apps/...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jul 31 23:05:23 CDT 2013


Author: dlee
Date: Wed Jul 31 23:05:21 2013
New Revision: 395935

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395935
Log:
Bringing in record-controls branch

Modified:
    team/dlee/ari-monitor2/   (props changed)
    team/dlee/ari-monitor2/apps/app_minivm.c
    team/dlee/ari-monitor2/apps/app_voicemail.c
    team/dlee/ari-monitor2/funcs/func_frame_trace.c
    team/dlee/ari-monitor2/include/asterisk/app.h
    team/dlee/ari-monitor2/include/asterisk/frame.h
    team/dlee/ari-monitor2/include/asterisk/stasis_app_recording.h
    team/dlee/ari-monitor2/main/app.c
    team/dlee/ari-monitor2/main/channel.c
    team/dlee/ari-monitor2/res/ari/resource_recordings.c
    team/dlee/ari-monitor2/res/ari/resource_recordings.h
    team/dlee/ari-monitor2/res/res_ari_recordings.c
    team/dlee/ari-monitor2/res/res_stasis_recording.c
    team/dlee/ari-monitor2/res/stasis_recording/recording.h
    team/dlee/ari-monitor2/rest-api/api-docs/recordings.json

Propchange: team/dlee/ari-monitor2/
------------------------------------------------------------------------------
    svn:mergeinfo = /team/dlee/record-controls:395156-395934

Modified: team/dlee/ari-monitor2/apps/app_minivm.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/apps/app_minivm.c?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/apps/app_minivm.c (original)
+++ team/dlee/ari-monitor2/apps/app_minivm.c Wed Jul 31 23:05:21 2013
@@ -1674,7 +1674,7 @@
 				ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
 			if (ast_test_flag(vmu, MVM_OPERATOR))
 				canceldtmf = "0";
-			cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
+			cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
 			if (record_gain)
 				ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
 			if (cmd == -1) /* User has hung up, no options to give */

Modified: team/dlee/ari-monitor2/apps/app_voicemail.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/apps/app_voicemail.c?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/apps/app_voicemail.c (original)
+++ team/dlee/ari-monitor2/apps/app_voicemail.c Wed Jul 31 23:05:21 2013
@@ -14682,7 +14682,7 @@
 				ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
 			if (ast_test_flag(vmu, VM_OPERATOR))
 				canceldtmf = "0";
-			cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
+			cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
 			if (strchr(canceldtmf, cmd)) {
 			/* need this flag here to distinguish between pressing '0' during message recording or after */
 				canceleddtmf = 1;

Modified: team/dlee/ari-monitor2/funcs/func_frame_trace.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/funcs/func_frame_trace.c?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/funcs/func_frame_trace.c (original)
+++ team/dlee/ari-monitor2/funcs/func_frame_trace.c Wed Jul 31 23:05:21 2013
@@ -343,6 +343,18 @@
 		case AST_CONTROL_STREAM_FORWARD:
 			ast_verbose("SubClass: STREAM_FORWARD\n");
 			break;
+		case AST_CONTROL_RECORD_CANCEL:
+			ast_verbose("SubClass: RECORD_CANCEL\n");
+			break;
+		case AST_CONTROL_RECORD_STOP:
+			ast_verbose("SubClass: RECORD_STOP\n");
+			break;
+		case AST_CONTROL_RECORD_SUSPEND:
+			ast_verbose("SubClass: RECORD_SUSPEND\n");
+			break;
+		case AST_CONTROL_RECORD_MUTE:
+			ast_verbose("SubClass: RECORD_MUTE\n");
+			break;
 		}
 
 		if (frame->subclass.integer == -1) {

Modified: team/dlee/ari-monitor2/include/asterisk/app.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/include/asterisk/app.h?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/include/asterisk/app.h (original)
+++ team/dlee/ari-monitor2/include/asterisk/app.h Wed Jul 31 23:05:21 2013
@@ -709,11 +709,12 @@
  *        skip_confirmation_sound is false.
  *
  * \param chan the channel being recorded
- * \param playfile Filename of sound to play before recording begins
+ * \param playfile Filename of sound to play before recording begins. Implies beep.
  * \param recordfile Filename to save the recording
  * \param maxtime_sec Longest possible message length in seconds
  * \param fmt string containing all formats to be recorded delimited by '|'
  * \param duration pointer to integer for storing length of the recording
+ * \param beep If true, play a beep before recording begins (and doesn't play \a playfile)
  * \param sound_duration pointer to integer for storing length of the recording minus all silence
  * \param silencethreshold tolerance of noise levels that can be considered silence for the purpose of silence timeout, -1 for default
  * \param maxsilence_ms Length of time in milliseconds which will trigger a timeout from silence, -1 for default
@@ -728,7 +729,7 @@
  * \retval 't' Recording ended from the message exceeding the maximum duration
  * \retval dtmfchar Recording ended via the return value's DTMF character for either cancel or accept.
  */
-int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists);
+int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists);
 
 /*!
  * \brief Record a file based on input from a channel. Use default accept and cancel DTMF.

Modified: team/dlee/ari-monitor2/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/include/asterisk/frame.h?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/include/asterisk/frame.h (original)
+++ team/dlee/ari-monitor2/include/asterisk/frame.h Wed Jul 31 23:05:21 2013
@@ -278,7 +278,11 @@
 	AST_CONTROL_STREAM_RESTART = 1002,	/*!< Indicate to a channel in playback to restart the stream */
 	AST_CONTROL_STREAM_REVERSE = 1003,	/*!< Indicate to a channel in playback to rewind */
 	AST_CONTROL_STREAM_FORWARD = 1004,	/*!< Indicate to a channel in playback to fast forward */
-
+	/* Control frames to manipulate recording on a channel. */
+	AST_CONTROL_RECORD_CANCEL = 1100,	/*!< Indicated to a channel in record to stop recording and discard the file */
+	AST_CONTROL_RECORD_STOP = 1101,	/*!< Indicated to a channel in record to stop recording */
+	AST_CONTROL_RECORD_SUSPEND = 1102,	/*!< Indicated to a channel in record to suspend/unsuspend recording */
+	AST_CONTROL_RECORD_MUTE = 1103,	/*!< Indicated to a channel in record to mute/unmute (i.e. write silence) recording */
 };
 
 enum ast_frame_read_action {

Modified: team/dlee/ari-monitor2/include/asterisk/stasis_app_recording.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/include/asterisk/stasis_app_recording.h?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/include/asterisk/stasis_app_recording.h (original)
+++ team/dlee/ari-monitor2/include/asterisk/stasis_app_recording.h Wed Jul 31 23:05:21 2013
@@ -44,14 +44,30 @@
 	STASIS_APP_RECORDING_STATE_PAUSED,
 	/*! The media has stopped recording */
 	STASIS_APP_RECORDING_STATE_COMPLETE,
-	/*! The media has stopped playing */
+	/*! The media has stopped recording, with error */
 	STASIS_APP_RECORDING_STATE_FAILED,
+	/*! The media has stopped recording, discard the recording file */
+	STASIS_APP_RECORDING_STATE_CANCELED,
+	/*! Sentinel */
+	STASIS_APP_RECORDING_STATE_MAX,
 };
 
 /*! Valid operation for controlling a recording. */
 enum stasis_app_recording_media_operation {
-	/*! Stop the recording operation. */
+	/*! Stop the recording, deleting the media file(s) */
+	STASIS_APP_RECORDING_CANCEL,
+	/*! Stop the recording. */
 	STASIS_APP_RECORDING_STOP,
+	/*! Pause the recording */
+	STASIS_APP_RECORDING_PAUSE,
+	/*! Unpause the recording */
+	STASIS_APP_RECORDING_UNPAUSE,
+	/*! Mute the recording (record silence) */
+	STASIS_APP_RECORDING_MUTE,
+	/*! Unmute the recording */
+	STASIS_APP_RECORDING_UNMUTE,
+	/*! Sentinel */
+	STASIS_APP_RECORDING_OPER_MAX,
 };
 
 #define STASIS_APP_RECORDING_TERMINATE_INVALID 0

Modified: team/dlee/ari-monitor2/main/app.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/main/app.c?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/main/app.c (original)
+++ team/dlee/ari-monitor2/main/app.c Wed Jul 31 23:05:21 2013
@@ -1144,6 +1144,78 @@
 	return d;
 }
 
+/*!
+ * \brief Construct a silence frame of the same duration as \a orig.
+ *
+ * The \a orig frame must be \ref AST_FORMAT_SLINEAR.
+ *
+ * \param orig Frame as basis for silence to generate.
+ * \return New frame of silence; free with ast_frfree().
+ * \return \c NULL on error.
+ */
+static struct ast_frame *make_silence(const struct ast_frame *orig)
+{
+	struct ast_frame *silence;
+	size_t size;
+	size_t datalen;
+	size_t samples = 0;
+	struct ast_frame *next;
+
+	if (!orig) {
+		return NULL;
+	}
+
+	if (orig->subclass.format.id != AST_FORMAT_SLINEAR) {
+		ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n");
+		return NULL;
+	}
+
+	for (next = AST_LIST_NEXT(orig, frame_list);
+		 orig;
+		 orig = next, next = orig ? AST_LIST_NEXT(orig, frame_list) : NULL) {
+		samples += orig->samples;
+	}
+
+	ast_verb(4, "Silencing %zd samples\n", samples);
+
+
+	datalen = sizeof(short) * samples;
+	size = sizeof(*silence) + datalen;
+	silence = ast_calloc(1, size);
+	if (!silence) {
+		return NULL;
+	}
+
+	silence->mallocd = AST_MALLOCD_HDR;
+	silence->frametype = AST_FRAME_VOICE;
+	silence->data.ptr = (void *)(silence + 1);
+	silence->samples = samples;
+	silence->datalen = datalen;
+
+	ast_format_set(&silence->subclass.format, AST_FORMAT_SLINEAR, 0);
+
+	return silence;
+}
+
+/*!
+ * \brief Sets a channel's read format to \ref AST_FORMAT_SLINEAR, recording
+ * its original format.
+ *
+ * \param chan Channel to modify.
+ * \param[out] orig_format Output variable to store channel's original read
+ *                         format.
+ * \return 0 on success.
+ * \return -1 on error.
+ */
+static int set_read_to_slin(struct ast_channel *chan, struct ast_format *orig_format)
+{
+	if (!chan || !orig_format) {
+		return -1;
+	}
+	ast_format_copy(orig_format, ast_channel_readformat(chan));
+	return ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
+}
+
 static int global_silence_threshold = 128;
 static int global_maxsilence = 0;
 
@@ -1273,8 +1345,7 @@
 			return -1;
 		}
 		ast_dsp_set_threshold(sildet, silencethreshold);
-		ast_format_copy(&rfmt, ast_channel_readformat(chan));
-		res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
+		res = set_read_to_slin(chan, &rfmt);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
 			ast_dsp_free(sildet);
@@ -1292,9 +1363,15 @@
 	}
 
 	if (x == fmtcnt) {
-		/* Loop forever, writing the packets we read to the writer(s), until
-		   we read a digit or get a hangup */
+		/* Loop, writing the packets we read to the writer(s), until
+		 * we have reason to stop. */
 		struct ast_frame *f;
+		int paused = 0;
+		int muted = 0;
+		time_t pause_start = 0;
+		int paused_secs = 0;
+		int pausedsilence = 0;
+
 		for (;;) {
 			if (!(res = ast_waitfor(chan, 2000))) {
 				ast_debug(1, "One waitfor failed, trying another\n");
@@ -1314,11 +1391,29 @@
 			}
 			if (f->frametype == AST_FRAME_VOICE) {
 				/* write each format */
-				for (x = 0; x < fmtcnt; x++) {
-					if (prepend && !others[x]) {
-						break;
+				if (paused) {
+					/* It's all good */
+					res = 0;
+				} else {
+					RAII_VAR(struct ast_frame *, silence, NULL, ast_frame_dtor);
+					struct ast_frame *orig = f;
+
+					if (muted) {
+						silence = make_silence(orig);
+						if (!silence) {
+							ast_log(LOG_WARNING,
+								"Error creating silence\n");
+							break;
+						}
+						f = silence;
 					}
-					res = ast_writestream(others[x], f);
+					for (x = 0; x < fmtcnt; x++) {
+						if (prepend && !others[x]) {
+							break;
+						}
+						res = ast_writestream(others[x], f);
+					}
+					f = orig;
 				}
 
 				/* Silence Detection */
@@ -1329,6 +1424,17 @@
 						totalsilence += olddspsilence;
 					}
 					olddspsilence = dspsilence;
+
+					if (paused) {
+						/* record how much silence there was while we are paused */
+						pausedsilence = dspsilence;
+					} else if (dspsilence > pausedsilence) {
+						/* ignore the paused silence */
+						dspsilence -= pausedsilence;
+					} else {
+						/* dspsilence has reset, reset pausedsilence */
+						pausedsilence = 0;
+					}
 
 					if (dspsilence > maxsilence) {
 						/* Ended happily with silence */
@@ -1361,15 +1467,51 @@
 					break;
 				}
 				if (strchr(canceldtmf, f->subclass.integer)) {
-					ast_verb(3, "User cancelled message by pressing %c\n", f->subclass.integer);
+					ast_verb(3, "User canceled message by pressing %c\n", f->subclass.integer);
 					res = f->subclass.integer;
 					outmsg = 0;
 					break;
 				}
-			}
-			if (maxtime) {
+			} else if (f->frametype == AST_FRAME_CONTROL) {
+				if (f->subclass.integer == AST_CONTROL_RECORD_CANCEL) {
+					ast_verb(3, "Message canceled by control\n");
+					outmsg = 0; /* cancels the recording */
+					res = 0;
+					break;
+				} else if (f->subclass.integer == AST_CONTROL_RECORD_STOP) {
+					ast_verb(3, "Message ended by control\n");
+					res = 0;
+					break;
+				} else if (f->subclass.integer == AST_CONTROL_RECORD_SUSPEND) {
+					paused = !paused;
+					ast_verb(3, "Message %spaused by control\n",
+						paused ? "" : "un");
+					if (paused) {
+						pause_start = time(NULL);
+					} else {
+						paused_secs += time(NULL) - pause_start;
+					}
+				} else if (f->subclass.integer == AST_CONTROL_RECORD_MUTE) {
+					muted = !muted;
+					ast_verb(3, "Message %smuted by control\n",
+						muted ? "" : "un");
+					/* We can only silence slin frames, so
+					 * set the mode, if we haven't already
+					 * for sildet
+					 */
+					if (muted && !rfmt.id) {
+						ast_verb(3, "Setting read format to linear mode\n");
+						res = set_read_to_slin(chan, &rfmt);
+						if (res < 0) {
+							ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
+							break;
+						}
+					}
+				}
+			}
+			if (maxtime && !paused) {
 				end = time(NULL);
-				if (maxtime < (end - start)) {
+				if (maxtime < (end - start - paused_secs)) {
 					ast_verb(3, "Took too long, cutting it short...\n");
 					res = 't';
 					outmsg = 2;
@@ -1492,9 +1634,9 @@
 static const char default_acceptdtmf[] = "#";
 static const char default_canceldtmf[] = "";
 
-int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
-{
-	return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf), skip_confirmation_sound, if_exists);
+int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
+{
+	return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf), skip_confirmation_sound, if_exists);
 }
 
 int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path)

Modified: team/dlee/ari-monitor2/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/main/channel.c?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/main/channel.c (original)
+++ team/dlee/ari-monitor2/main/channel.c Wed Jul 31 23:05:21 2013
@@ -4308,6 +4308,10 @@
 	case AST_CONTROL_STREAM_REVERSE:
 	case AST_CONTROL_STREAM_FORWARD:
 	case AST_CONTROL_STREAM_RESTART:
+	case AST_CONTROL_RECORD_CANCEL:
+	case AST_CONTROL_RECORD_STOP:
+	case AST_CONTROL_RECORD_SUSPEND:
+	case AST_CONTROL_RECORD_MUTE:
 		break;
 
 	case AST_CONTROL_INCOMPLETE:
@@ -4566,6 +4570,10 @@
 	case AST_CONTROL_STREAM_REVERSE:
 	case AST_CONTROL_STREAM_FORWARD:
 	case AST_CONTROL_STREAM_RESTART:
+	case AST_CONTROL_RECORD_CANCEL:
+	case AST_CONTROL_RECORD_STOP:
+	case AST_CONTROL_RECORD_SUSPEND:
+	case AST_CONTROL_RECORD_MUTE:
 		/* Nothing left to do for these. */
 		res = 0;
 		break;

Modified: team/dlee/ari-monitor2/res/ari/resource_recordings.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/res/ari/resource_recordings.c?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/res/ari/resource_recordings.c (original)
+++ team/dlee/ari-monitor2/res/ari/resource_recordings.c Wed Jul 31 23:05:21 2013
@@ -71,27 +71,81 @@
 	ast_ari_response_ok(response, ast_json_ref(json));
 }
 
-void ast_ari_cancel_recording(struct ast_variable *headers, struct ast_cancel_recording_args *args, struct ast_ari_response *response)
+static void control_recording(const char *name,
+	enum stasis_app_recording_media_operation operation,
+	struct ast_ari_response *response)
 {
-	ast_log(LOG_ERROR, "TODO: ast_ari_cancel_recording\n");
+	RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+	enum stasis_app_recording_oper_results res;
+
+	recording = stasis_app_recording_find_by_name(name);
+	if (recording == NULL) {
+		ast_ari_response_error(response, 404, "Not Found",
+			"Recording not found");
+		return;
+	}
+
+	res = stasis_app_recording_operation(recording, operation);
+
+	switch (res) {
+	case STASIS_APP_RECORDING_OPER_OK:
+		ast_ari_response_no_content(response);
+		return;
+	case STASIS_APP_RECORDING_OPER_FAILED:
+		ast_ari_response_error(response, 500,
+			"Internal Server Error", "Recording operation failed");
+		return;
+	case STASIS_APP_RECORDING_OPER_NOT_RECORDING:
+		ast_ari_response_error(response, 409,
+			"Conflict", "Recording not in session");
+	}
 }
-void ast_ari_stop_recording(struct ast_variable *headers, struct ast_stop_recording_args *args, struct ast_ari_response *response)
+
+void ast_ari_cancel_recording(struct ast_variable *headers,
+	struct ast_cancel_recording_args *args,
+	struct ast_ari_response *response)
 {
-	ast_log(LOG_ERROR, "TODO: ast_ari_stop_recording\n");
+	control_recording(args->recording_name, STASIS_APP_RECORDING_CANCEL,
+		response);
 }
-void ast_ari_pause_recording(struct ast_variable *headers, struct ast_pause_recording_args *args, struct ast_ari_response *response)
+
+void ast_ari_stop_recording(struct ast_variable *headers,
+	struct ast_stop_recording_args *args,
+	struct ast_ari_response *response)
 {
-	ast_log(LOG_ERROR, "TODO: ast_ari_pause_recording\n");
+	control_recording(args->recording_name, STASIS_APP_RECORDING_STOP,
+		response);
 }
-void ast_ari_unpause_recording(struct ast_variable *headers, struct ast_unpause_recording_args *args, struct ast_ari_response *response)
+
+void ast_ari_pause_recording(struct ast_variable *headers,
+	struct ast_pause_recording_args *args,
+	struct ast_ari_response *response)
 {
-	ast_log(LOG_ERROR, "TODO: ast_ari_unpause_recording\n");
+	control_recording(args->recording_name, STASIS_APP_RECORDING_PAUSE,
+		response);
 }
-void ast_ari_mute_recording(struct ast_variable *headers, struct ast_mute_recording_args *args, struct ast_ari_response *response)
+
+void ast_ari_unpause_recording(struct ast_variable *headers,
+	struct ast_unpause_recording_args *args,
+	struct ast_ari_response *response)
 {
-	ast_log(LOG_ERROR, "TODO: ast_ari_mute_recording\n");
+	control_recording(args->recording_name, STASIS_APP_RECORDING_UNPAUSE,
+		response);
 }
-void ast_ari_unmute_recording(struct ast_variable *headers, struct ast_unmute_recording_args *args, struct ast_ari_response *response)
+
+void ast_ari_mute_recording(struct ast_variable *headers,
+	struct ast_mute_recording_args *args,
+	struct ast_ari_response *response)
 {
-	ast_log(LOG_ERROR, "TODO: ast_ari_unmute_recording\n");
+	control_recording(args->recording_name, STASIS_APP_RECORDING_MUTE,
+		response);
 }
+
+void ast_ari_unmute_recording(struct ast_variable *headers,
+	struct ast_unmute_recording_args *args,
+	struct ast_ari_response *response)
+{
+	control_recording(args->recording_name, STASIS_APP_RECORDING_UNMUTE,
+		response);
+}

Modified: team/dlee/ari-monitor2/res/ari/resource_recordings.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/res/ari/resource_recordings.h?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/res/ari/resource_recordings.h (original)
+++ team/dlee/ari-monitor2/res/ari/resource_recordings.h Wed Jul 31 23:05:21 2013
@@ -134,7 +134,7 @@
 /*!
  * \brief Pause a live recording.
  *
- * Pausing a recording suspends silence detection, which will be restarted when the recording is unpaused.
+ * Pausing a recording suspends silence detection, which will be restarted when the recording is unpaused. Paused time is not included in the accounting for maxDurationSeconds.
  *
  * \param headers HTTP headers
  * \param args Swagger parameters

Modified: team/dlee/ari-monitor2/res/res_ari_recordings.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/res/res_ari_recordings.c?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/res/res_ari_recordings.c (original)
+++ team/dlee/ari-monitor2/res/res_ari_recordings.c Wed Jul 31 23:05:21 2013
@@ -451,6 +451,7 @@
 	case 500: /* Internal Server Error */
 	case 501: /* Not Implemented */
 	case 404: /* Recording not found */
+	case 409: /* Recording not in session */
 		is_valid = 1;
 		break;
 	default:
@@ -506,6 +507,7 @@
 	case 500: /* Internal Server Error */
 	case 501: /* Not Implemented */
 	case 404: /* Recording not found */
+	case 409: /* Recording not in session */
 		is_valid = 1;
 		break;
 	default:
@@ -561,6 +563,7 @@
 	case 500: /* Internal Server Error */
 	case 501: /* Not Implemented */
 	case 404: /* Recording not found */
+	case 409: /* Recording not in session */
 		is_valid = 1;
 		break;
 	default:
@@ -616,6 +619,7 @@
 	case 500: /* Internal Server Error */
 	case 501: /* Not Implemented */
 	case 404: /* Recording not found */
+	case 409: /* Recording not in session */
 		is_valid = 1;
 		break;
 	default:

Modified: team/dlee/ari-monitor2/res/res_stasis_recording.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/res/res_stasis_recording.c?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/res/res_stasis_recording.c (original)
+++ team/dlee/ari-monitor2/res/res_stasis_recording.c Wed Jul 31 23:05:21 2013
@@ -88,6 +88,10 @@
 		return "done";
 	case STASIS_APP_RECORDING_STATE_FAILED:
 		return "failed";
+	case STASIS_APP_RECORDING_STATE_CANCELED:
+		return "canceled";
+	case STASIS_APP_RECORDING_STATE_MAX:
+		return "?";
 	}
 
 	return "?";
@@ -248,12 +252,13 @@
 	ao2_unlock(recording);
 
 	ast_play_and_record_full(chan,
-		recording->options->beep ? "beep" : NULL,
+		NULL, /* playfile */
 		recording->absolute_name,
 		recording->options->max_duration_seconds,
 		recording->options->format,
 		&duration,
 		NULL, /* sound_duration */
+		recording->options->beep,
 		-1, /* silencethreshold */
 		recording->options->max_silence_seconds * 1000,
 		NULL, /* path */
@@ -417,12 +422,127 @@
 	return ast_json_ref(json);
 }
 
+typedef int (*recording_operation_cb)(struct stasis_app_recording *recording);
+
+static int recording_noop(struct stasis_app_recording *recording)
+{
+	return 0;
+}
+
+static int recording_disregard(struct stasis_app_recording *recording)
+{
+	recording->state = STASIS_APP_RECORDING_STATE_CANCELED;
+	return 0;
+}
+
+static int recording_cancel(struct stasis_app_recording *recording)
+{
+	int res = 0;
+	recording->state = STASIS_APP_RECORDING_STATE_CANCELED;
+	res |= stasis_app_control_queue_control(recording->control,
+		AST_CONTROL_RECORD_CANCEL);
+	res |= ast_filedelete(recording->absolute_name, NULL);
+	return res;
+}
+
+static int recording_stop(struct stasis_app_recording *recording)
+{
+	recording->state = STASIS_APP_RECORDING_STATE_COMPLETE;
+	return stasis_app_control_queue_control(recording->control,
+		AST_CONTROL_RECORD_STOP);
+}
+
+static int recording_pause(struct stasis_app_recording *recording)
+{
+	recording->state = STASIS_APP_RECORDING_STATE_PAUSED;
+	return stasis_app_control_queue_control(recording->control,
+		AST_CONTROL_RECORD_SUSPEND);
+}
+
+static int recording_unpause(struct stasis_app_recording *recording)
+{
+	recording->state = STASIS_APP_RECORDING_STATE_RECORDING;
+	return stasis_app_control_queue_control(recording->control,
+		AST_CONTROL_RECORD_SUSPEND);
+}
+
+static int recording_mute(struct stasis_app_recording *recording)
+{
+	if (recording->muted) {
+		/* already muted */
+		return 0;
+	}
+
+	recording->muted = 1;
+	return stasis_app_control_queue_control(recording->control,
+		AST_CONTROL_RECORD_MUTE);
+}
+
+static int recording_unmute(struct stasis_app_recording *recording)
+{
+	if (!recording->muted) {
+		/* already unmuted */
+		return 0;
+	}
+
+	return stasis_app_control_queue_control(recording->control,
+		AST_CONTROL_RECORD_MUTE);
+}
+
+recording_operation_cb operations[STASIS_APP_RECORDING_STATE_MAX][STASIS_APP_RECORDING_OPER_MAX] = {
+	[STASIS_APP_RECORDING_STATE_QUEUED][STASIS_APP_RECORDING_CANCEL] = recording_disregard,
+	[STASIS_APP_RECORDING_STATE_QUEUED][STASIS_APP_RECORDING_STOP] = recording_disregard,
+	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_CANCEL] = recording_cancel,
+	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_STOP] = recording_stop,
+	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_PAUSE] = recording_pause,
+	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_UNPAUSE] = recording_noop,
+	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_MUTE] = recording_mute,
+	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_UNMUTE] = recording_unmute,
+	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_CANCEL] = recording_cancel,
+	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_STOP] = recording_stop,
+	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_PAUSE] = recording_noop,
+	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_UNPAUSE] = recording_unpause,
+	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_MUTE] = recording_mute,
+	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_UNMUTE] = recording_unmute,
+};
+
 enum stasis_app_recording_oper_results stasis_app_recording_operation(
 	struct stasis_app_recording *recording,
 	enum stasis_app_recording_media_operation operation)
 {
-	ast_assert(0); // TODO
-	return STASIS_APP_RECORDING_OPER_FAILED;
+	recording_operation_cb cb;
+	SCOPED_AO2LOCK(lock, recording);
+
+	if (recording->state < 0 || recording->state >= STASIS_APP_RECORDING_STATE_MAX) {
+		ast_log(LOG_WARNING, "Invalid recording state %d\n",
+			recording->state);
+		return -1;
+	}
+
+	if (operation < 0 || operation >= STASIS_APP_RECORDING_OPER_MAX) {
+		ast_log(LOG_WARNING, "Invalid recording operation %d\n",
+			operation);
+		return -1;
+	}
+
+	cb = operations[recording->state][operation];
+
+	if (!cb) {
+		if (recording->state != STASIS_APP_RECORDING_STATE_RECORDING) {
+			/* So we can be specific in our error message. */
+			return STASIS_APP_RECORDING_OPER_NOT_RECORDING;
+		} else {
+			/* And, really, all operations should be valid during
+			 * recording */
+			ast_log(LOG_ERROR,
+				"Unhandled operation during recording: %d\n",
+				operation);
+			return STASIS_APP_RECORDING_OPER_FAILED;
+		}
+	}
+
+	return cb(recording) ?
+		STASIS_APP_RECORDING_OPER_FAILED : STASIS_APP_RECORDING_OPER_OK;
 }
 
 static int load_module(void)

Modified: team/dlee/ari-monitor2/res/stasis_recording/recording.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/res/stasis_recording/recording.h?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/res/stasis_recording/recording.h (original)
+++ team/dlee/ari-monitor2/res/stasis_recording/recording.h Wed Jul 31 23:05:21 2013
@@ -40,6 +40,8 @@
 
 	/*! Current state of the recording. */
 	enum stasis_app_recording_state state;
+	/*! Indicates whether the recording is currently muted */
+	int muted:1;
 };
 
 /*!

Modified: team/dlee/ari-monitor2/rest-api/api-docs/recordings.json
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-monitor2/rest-api/api-docs/recordings.json?view=diff&rev=395935&r1=395934&r2=395935
==============================================================================
--- team/dlee/ari-monitor2/rest-api/api-docs/recordings.json (original)
+++ team/dlee/ari-monitor2/rest-api/api-docs/recordings.json Wed Jul 31 23:05:21 2013
@@ -168,7 +168,7 @@
 				{
 					"httpMethod": "POST",
 					"summary": "Pause a live recording.",
-					"notes": "Pausing a recording suspends silence detection, which will be restarted when the recording is unpaused.",
+					"notes": "Pausing a recording suspends silence detection, which will be restarted when the recording is unpaused. Paused time is not included in the accounting for maxDurationSeconds.",
 					"nickname": "pauseRecording",
 					"responseClass": "void",
 					"parameters": [
@@ -185,6 +185,10 @@
 						{
 							"code": 404,
 							"reason": "Recording not found"
+						},
+						{
+							"code": 409,
+							"reason": "Recording not in session"
 						}
 					]
 
@@ -213,6 +217,10 @@
 						{
 							"code": 404,
 							"reason": "Recording not found"
+						},
+						{
+							"code": 409,
+							"reason": "Recording not in session"
 						}
 					]
 
@@ -242,6 +250,10 @@
 						{
 							"code": 404,
 							"reason": "Recording not found"
+						},
+						{
+							"code": 409,
+							"reason": "Recording not in session"
 						}
 					]
 
@@ -270,6 +282,10 @@
 						{
 							"code": 404,
 							"reason": "Recording not found"
+						},
+						{
+							"code": 409,
+							"reason": "Recording not in session"
 						}
 					]
 




More information about the asterisk-commits mailing list