[asterisk-commits] dlee: branch dlee/playback-controls r388577 - in /team/dlee/playback-controls...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon May 13 14:24:02 CDT 2013


Author: dlee
Date: Mon May 13 14:24:00 2013
New Revision: 388577

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=388577
Log:
Playback control operations

Modified:
    team/dlee/playback-controls/include/asterisk/channel.h
    team/dlee/playback-controls/include/asterisk/stasis_app.h
    team/dlee/playback-controls/include/asterisk/stasis_app_playback.h
    team/dlee/playback-controls/res/res_stasis_playback.c
    team/dlee/playback-controls/res/stasis/control.c
    team/dlee/playback-controls/res/stasis_http/resource_playback.c
    team/dlee/playback-controls/rest-api/api-docs/playback.json

Modified: team/dlee/playback-controls/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/playback-controls/include/asterisk/channel.h?view=diff&rev=388577&r1=388576&r2=388577
==============================================================================
--- team/dlee/playback-controls/include/asterisk/channel.h (original)
+++ team/dlee/playback-controls/include/asterisk/channel.h Mon May 13 14:24:00 2013
@@ -1205,7 +1205,7 @@
 int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause);
 
 /*!
- * \brief Queue a control frame with payload
+ * \brief Queue a control frame without payload
  *
  * \param chan channel to queue frame onto
  * \param control type of control frame

Modified: team/dlee/playback-controls/include/asterisk/stasis_app.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/playback-controls/include/asterisk/stasis_app.h?view=diff&rev=388577&r1=388576&r2=388577
==============================================================================
--- team/dlee/playback-controls/include/asterisk/stasis_app.h (original)
+++ team/dlee/playback-controls/include/asterisk/stasis_app.h Mon May 13 14:24:00 2013
@@ -170,6 +170,18 @@
 void stasis_app_control_publish(
 	struct stasis_app_control *control, struct stasis_message *message);
 
+/*!
+ * \brief Queue a control frame without payload.
+ *
+ * \param control Control to publish to.
+ * \param frame_type type of control frame.
+ *
+ * \return zero on success
+ * \return non-zero on failure
+ */
+int stasis_app_control_queue_control(struct stasis_app_control *control,
+	enum ast_control_frame_type frame_type);
+
 /*! @} */
 
 #endif /* _ASTERISK_STASIS_APP_H */

Modified: team/dlee/playback-controls/include/asterisk/stasis_app_playback.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/playback-controls/include/asterisk/stasis_app_playback.h?view=diff&rev=388577&r1=388576&r2=388577
==============================================================================
--- team/dlee/playback-controls/include/asterisk/stasis_app_playback.h (original)
+++ team/dlee/playback-controls/include/asterisk/stasis_app_playback.h Mon May 13 14:24:00 2013
@@ -41,16 +41,16 @@
 	STASIS_PLAYBACK_STATE_PLAYING,
 	/*! The media has stopped playing */
 	STASIS_PLAYBACK_STATE_COMPLETE,
+	/*! The media was cancelled before playback could start */
+	STASIS_PLAYBACK_STATE_CANCELLED,
 };
 
-enum stasis_app_playback_media_control {
+enum stasis_app_playback_media_operation {
 	STASIS_PLAYBACK_STOP,
 	STASIS_PLAYBACK_PAUSE,
 	STASIS_PLAYBACK_PLAY,
 	STASIS_PLAYBACK_REWIND,
 	STASIS_PLAYBACK_FAST_FORWARD,
-	STASIS_PLAYBACK_SPEED_UP,
-	STASIS_PLAYBACK_SLOW_DOWN,
 };
 
 /*!
@@ -95,18 +95,27 @@
  * \return Associated \ref stasis_app_playback object.
  * \return \c NULL if \a id not found.
  */
-struct ast_json *stasis_app_playback_find_by_id(const char *id);
+struct stasis_app_playback *stasis_app_playback_find_by_id(const char *id);
 
+struct ast_json *stasis_app_playback_to_json(
+	const struct stasis_app_playback *playback);
+
+enum stasis_playback_oper_results {
+	STASIS_PLAYBACK_OPER_OK,
+	STASIS_PLAYBACK_OPER_FAILED,
+	STASIS_PLAYBACK_OPER_NOT_PLAYING,
+};
 /*!
  * \brief Controls the media for a given playback operation.
  *
  * \param playback Playback control object.
  * \param control Media control operation.
- * \return 0 on success
- * \return non-zero on error.
+ * \return 0 on success.
+ * \return -1 Playback isn't in a valid state for the operation.
+ * \return -2 Operation failed.
  */
-int stasis_app_playback_control(struct stasis_app_playback *playback,
-	enum stasis_app_playback_media_control control);
+int stasis_app_playback_operation(struct stasis_app_playback *playback,
+	enum stasis_app_playback_media_operation operation);
 
 /*!
  * \brief Message type for playback updates. The data is an

Modified: team/dlee/playback-controls/res/res_stasis_playback.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/playback-controls/res/res_stasis_playback.c?view=diff&rev=388577&r1=388576&r2=388577
==============================================================================
--- team/dlee/playback-controls/res/res_stasis_playback.c (original)
+++ team/dlee/playback-controls/res/res_stasis_playback.c Mon May 13 14:24:00 2013
@@ -86,36 +86,6 @@
 	}
 }
 
-static struct ast_json *playback_to_json(struct stasis_app_playback *playback)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	char *state = "?";
-
-	if (playback == NULL) {
-		return NULL;
-	}
-
-	switch (playback->state) {
-	case STASIS_PLAYBACK_STATE_QUEUED:
-		state = "queued";
-		break;
-	case STASIS_PLAYBACK_STATE_PLAYING:
-		state = "playing";
-		break;
-	case STASIS_PLAYBACK_STATE_COMPLETE:
-		state = "complete";
-		break;
-	}
-
-	json = ast_json_pack("{s: s, s: s, s: s, s: s}",
-		"id", playback->id,
-		"media_uri", playback->media,
-		"language", playback->language,
-		"state", state);
-
-	return ast_json_ref(json);
-}
-
 static void playback_publish(struct stasis_app_playback *playback)
 {
 	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
@@ -124,7 +94,7 @@
 
 	ast_assert(playback != NULL);
 
-	json = playback_to_json(playback);
+	json = stasis_app_playback_to_json(playback);
 	if (json == NULL) {
 		return;
 	}
@@ -168,7 +138,13 @@
 	playback = data;
 	ast_assert(playback != NULL);
 
+	ao2_lock(playback);
+	if (playback->state == STASIS_PLAYBACK_STATE_CANCELLED) {
+		ao2_unlock(playback);
+		return NULL;
+	}
 	playback_set_state(playback, STASIS_PLAYBACK_STATE_PLAYING);
+	ao2_unlock(playback);
 
 	if (ast_channel_state(chan) != AST_STATE_UP) {
 		ast_answer(chan);
@@ -246,26 +222,111 @@
 	return control->id;
 }
 
-struct ast_json *stasis_app_playback_find_by_id(const char *id)
+struct stasis_app_playback *stasis_app_playback_find_by_id(const char *id)
 {
 	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
 
 	playback = ao2_find(playbacks, id, OBJ_KEY);
 	if (playback == NULL) {
 		return NULL;
 	}
 
-	json = playback_to_json(playback);
+	ao2_ref(playback, +1);
+	return playback;
+}
+
+struct ast_json *stasis_app_playback_to_json(
+	const struct stasis_app_playback *playback)
+{
+	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+	char *state = "?";
+
+	if (playback == NULL) {
+		return NULL;
+	}
+
+	switch (playback->state) {
+	case STASIS_PLAYBACK_STATE_QUEUED:
+		state = "queued";
+		break;
+	case STASIS_PLAYBACK_STATE_PLAYING:
+		state = "playing";
+		break;
+	case STASIS_PLAYBACK_STATE_COMPLETE:
+	case STASIS_PLAYBACK_STATE_CANCELLED:
+		/* Treat cancelled as complete */
+		state = "complete";
+		break;
+	}
+
+	json = ast_json_pack("{s: s, s: s, s: s, s: s}",
+		"id", playback->id,
+		"media_uri", playback->media,
+		"language", playback->language,
+		"state", state);
+
 	return ast_json_ref(json);
 }
 
-int stasis_app_playback_control(struct stasis_app_playback *playback,
-	enum stasis_app_playback_media_control control)
-{
+int stasis_app_playback_operation(struct stasis_app_playback *playback,
+	enum stasis_app_playback_media_operation operation)
+{
+	enum ast_control_frame_type frame_type = -1;
+	int res;
+
 	SCOPED_AO2LOCK(lock, playback);
-	ast_assert(0); /* TODO */
-	return -1;
+
+	switch (playback->state) {
+	case STASIS_PLAYBACK_STATE_COMPLETE:
+	case STASIS_PLAYBACK_STATE_CANCELLED:
+		if (operation == STASIS_PLAYBACK_STOP) {
+			/* Already stopped. */
+			return 0;
+		} else {
+			/* Invalid state for operation */
+			return STASIS_PLAYBACK_OPER_NOT_PLAYING;
+		}
+		break;
+	case STASIS_PLAYBACK_STATE_QUEUED:
+		if (operation == STASIS_PLAYBACK_STOP) {
+			/* Cancel a playback before it starts */
+			playback_set_state(playback,
+				STASIS_PLAYBACK_STATE_CANCELLED);
+		} else {
+			/* None of the other ops make sense for queued media */
+			return STASIS_PLAYBACK_OPER_NOT_PLAYING;
+		}
+		break;
+	case STASIS_PLAYBACK_STATE_PLAYING:
+		/* Media control makes sense. Carry on, then. */
+		break;
+	}
+
+	switch (operation) {
+	case STASIS_PLAYBACK_STOP:
+		frame_type = AST_CONTROL_STREAM_STOP;
+		break;
+	case STASIS_PLAYBACK_PAUSE:
+		frame_type = AST_CONTROL_STREAM_SUSPEND;
+		break;
+	case STASIS_PLAYBACK_PLAY:
+		frame_type = AST_CONTROL_STREAM_RESTART;
+		break;
+	case STASIS_PLAYBACK_REWIND:
+		frame_type = AST_CONTROL_STREAM_REVERSE;
+		break;
+	case STASIS_PLAYBACK_FAST_FORWARD:
+		frame_type = AST_CONTROL_STREAM_FORWARD;
+		break;
+	}
+
+	if (frame_type == -1) {
+		/* Invalid operation. Tsk, tsk. */
+		return STASIS_PLAYBACK_OPER_FAILED;
+	}
+
+	res = stasis_app_control_queue_control(playback->control, frame_type);
+	return res ? STASIS_PLAYBACK_OPER_FAILED : STASIS_PLAYBACK_OPER_OK;
 }
 
 static int load_module(void)

Modified: team/dlee/playback-controls/res/stasis/control.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/playback-controls/res/stasis/control.c?view=diff&rev=388577&r1=388576&r2=388577
==============================================================================
--- team/dlee/playback-controls/res/stasis/control.c (original)
+++ team/dlee/playback-controls/res/stasis/control.c Mon May 13 14:24:00 2013
@@ -175,6 +175,12 @@
 	stasis_publish(ast_channel_topic(control->channel), message);
 }
 
+int stasis_app_control_queue_control(struct stasis_app_control *control,
+	enum ast_control_frame_type frame_type)
+{
+	return ast_queue_control(control->channel, frame_type);
+}
+
 int control_dispatch_all(struct stasis_app_control *control,
 	struct ast_channel *chan)
 {

Modified: team/dlee/playback-controls/res/stasis_http/resource_playback.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/playback-controls/res/stasis_http/resource_playback.c?view=diff&rev=388577&r1=388576&r2=388577
==============================================================================
--- team/dlee/playback-controls/res/stasis_http/resource_playback.c (original)
+++ team/dlee/playback-controls/res/stasis_http/resource_playback.c Mon May 13 14:24:00 2013
@@ -34,7 +34,9 @@
 	struct ast_get_playback_args *args,
 	struct stasis_http_response *response)
 {
-	RAII_VAR(struct ast_json *, playback, NULL, ast_json_unref);
+	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+
 	playback = stasis_app_playback_find_by_id(args->playback_id);
 	if (playback == NULL) {
 		stasis_http_response_error(response, 404, "Not Found",
@@ -42,13 +44,94 @@
 		return;
 	}
 
-	stasis_http_response_ok(response, ast_json_ref(playback));
+	json = stasis_app_playback_to_json(playback);
+	if (json == NULL) {
+		stasis_http_response_error(response, 500,
+			"Internal Server Error", "Error building response");
+		return;
+	}
+
+	stasis_http_response_ok(response, ast_json_ref(json));
 }
-void stasis_http_stop_playback(struct ast_variable *headers, struct ast_stop_playback_args *args, struct stasis_http_response *response)
+void stasis_http_stop_playback(struct ast_variable *headers,
+	struct ast_stop_playback_args *args,
+	struct stasis_http_response *response)
 {
-	ast_log(LOG_ERROR, "TODO: stasis_http_stop_playback\n");
+	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
+	enum stasis_playback_oper_results res;
+
+	playback = stasis_app_playback_find_by_id(args->playback_id);
+	if (playback == NULL) {
+		stasis_http_response_error(response, 404, "Not Found",
+			"Playback not found");
+		return;
+	}
+
+	res = stasis_app_playback_operation(playback, STASIS_PLAYBACK_STOP);
+
+	switch (res) {
+	case STASIS_PLAYBACK_OPER_OK:
+		stasis_http_response_no_content(response);
+		return;
+	case STASIS_PLAYBACK_OPER_FAILED:
+		stasis_http_response_error(response, 500,
+			"Internal Server Error", "Could not stop playback");
+		return;
+	case STASIS_PLAYBACK_OPER_NOT_PLAYING:
+		/* Stop operation should be valid even when not playing */
+		ast_assert(0);
+		stasis_http_response_error(response, 500,
+			"Internal Server Error", "Could not stop playback");
+		return;
+	}
 }
-void stasis_http_control_playback(struct ast_variable *headers, struct ast_control_playback_args *args, struct stasis_http_response *response)
+void stasis_http_control_playback(struct ast_variable *headers,
+	struct ast_control_playback_args *args,
+	struct stasis_http_response *response)
 {
-	ast_log(LOG_ERROR, "TODO: stasis_http_control_playback\n");
+	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
+	enum stasis_app_playback_media_operation oper;
+	enum stasis_playback_oper_results res;
+
+	if (strcmp(args->operation, "play") == 0) {
+		oper = STASIS_PLAYBACK_PLAY;
+	} else if (strcmp(args->operation, "pause") == 0) {
+		oper = STASIS_PLAYBACK_PAUSE;
+	} else if (strcmp(args->operation, "rewind") == 0) {
+		oper = STASIS_PLAYBACK_REWIND;
+	} else if (strcmp(args->operation, "fast-forward") == 0) {
+		oper = STASIS_PLAYBACK_FAST_FORWARD;
+	} else {
+		stasis_http_response_error(response, 400,
+			"Bad Request", "Invalid operation %s",
+			args->operation);
+		return;
+
+	}
+
+	playback = stasis_app_playback_find_by_id(args->playback_id);
+	if (playback == NULL) {
+		stasis_http_response_error(response, 404, "Not Found",
+			"Playback not found");
+		return;
+	}
+
+	res = stasis_app_playback_operation(playback, oper);
+
+	switch (res) {
+	case STASIS_PLAYBACK_OPER_OK:
+		stasis_http_response_no_content(response);
+		return;
+	case STASIS_PLAYBACK_OPER_FAILED:
+		stasis_http_response_error(response, 500,
+			"Internal Server Error", "Could not %s playback",
+			args->operation);
+		return;
+	case STASIS_PLAYBACK_OPER_NOT_PLAYING:
+		/* Stop operation should be valid even when not playing */
+		ast_assert(0);
+		stasis_http_response_error(response, 409, "Conflict",
+			"Can only %s while media is playing", args->operation);
+		return;
+	}
 }

Modified: team/dlee/playback-controls/rest-api/api-docs/playback.json
URL: http://svnview.digium.com/svn/asterisk/team/dlee/playback-controls/rest-api/api-docs/playback.json?view=diff&rev=388577&r1=388576&r2=388577
==============================================================================
--- team/dlee/playback-controls/rest-api/api-docs/playback.json (original)
+++ team/dlee/playback-controls/rest-api/api-docs/playback.json Mon May 13 14:24:00 2013
@@ -76,13 +76,25 @@
 									"play",
 									"pause",
 									"rewind",
-									"fast-forward",
-									"speed-up",
-									"slow-down"
+									"fast-forward"
 								]
 							}
 						}
-					]
+					],
+					"errorResponses": [
+						{
+							"code": 400,
+							"reason": "The provided operation parameter was invalid"
+						},
+						{
+							"code": 404,
+							"reason": "The playback cannot be found"
+						},
+						{
+							"code": 409,
+							"reason": "The operation cannot be performed in the playback's current state"
+						}
+]
 				}
 			]
 		}




More information about the asterisk-commits mailing list