diff --git a/docs/design/part-messages.txt b/docs/design/part-messages.txt index aa5f21876a..cd53e106e6 100644 --- a/docs/design/part-messages.txt +++ b/docs/design/part-messages.txt @@ -128,4 +128,8 @@ Message types Posted by elements when the latency in a pipeline changed and a new global latency should be calculated by the pipeline or application. + GST_MESSAGE_REQUEST_STATE: + Posted by elements when they want to change the state of the pipeline they + are in. A typical use case would be an audio sink that requests the pipeline + to pause in order to play a higher priority stream. diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index b07d371a66..751d8e94a2 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -1089,6 +1089,8 @@ gst_message_parse_async_start gst_message_new_async_done gst_message_new_structure_change gst_message_parse_structure_change +gst_message_new_request_state +gst_message_parse_request_state GstMessageClass GST_MESSAGE diff --git a/gst/gstmessage.c b/gst/gstmessage.c index df9b5e1e75..78305bddac 100644 --- a/gst/gstmessage.c +++ b/gst/gstmessage.c @@ -111,6 +111,7 @@ static GstMessageQuarks message_quarks[] = { {GST_MESSAGE_LATENCY, "latency", 0}, {GST_MESSAGE_ASYNC_START, "async-start", 0}, {GST_MESSAGE_ASYNC_DONE, "async-done", 0}, + {GST_MESSAGE_REQUEST_STATE, "request-state", 0}, {0, NULL, 0} }; @@ -932,6 +933,35 @@ gst_message_new_latency (GstObject * src) return message; } +/** + * gst_message_new_request_state: + * @src: The object originating the message. + * @state: The new requested state + * + * This message can be posted by elements when they want to have their state + * changed. A typical use case would be an audio server that wants to pause the + * pipeline because a higher priority stream is being played. + * + * Returns: The new requst state message. + * + * MT safe. + * + * Since: 0.10.23 + */ +GstMessage * +gst_message_new_request_state (GstObject * src, GstState state) +{ + GstMessage *message; + GstStructure *structure; + + structure = gst_structure_empty_new ("GstMessageRequestState"); + gst_structure_id_set (structure, + GST_QUARK (NEW_STATE), GST_TYPE_STATE, (gint) state, NULL); + message = gst_message_new_custom (GST_MESSAGE_REQUEST_STATE, src, structure); + + return message; +} + /** * gst_message_get_structure: * @message: The #GstMessage. @@ -1431,3 +1461,25 @@ gst_message_parse_async_start (GstMessage * message, gboolean * new_base_time) g_value_get_boolean (gst_structure_id_get_value (message->structure, GST_QUARK (NEW_BASE_TIME))); } + +/** + * gst_message_parse_request_state: + * @message: A valid #GstMessage of type GST_MESSAGE_REQUEST_STATE. + * @state: Result location for the requested state or NULL + * + * Extract the requested state from the request_state message. + * + * MT safe. + * + * Since: 0.10.23 + */ +void +gst_message_parse_request_state (GstMessage * message, GstState * state) +{ + g_return_if_fail (GST_IS_MESSAGE (message)); + g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_REQUEST_STATE); + + if (state) + *state = g_value_get_enum (gst_structure_id_get_value (message->structure, + GST_QUARK (NEW_STATE))); +} diff --git a/gst/gstmessage.h b/gst/gstmessage.h index ad13ac001b..b1b5b5ca91 100644 --- a/gst/gstmessage.h +++ b/gst/gstmessage.h @@ -81,6 +81,9 @@ typedef struct _GstMessageClass GstMessageClass; * pipeline. Since: 0.10.13 * @GST_MESSAGE_LATENCY: Posted by elements when their latency changes. The * pipeline will calculate and distribute a new latency. Since: 0.10.12 + * @GST_MESSAGE_REQUEST_STATE: Posted by elements when they want the pipeline to + * change state. This message is a suggestion to the application which can + * decide to perform the state change on (part of) the pipeline. Since: 0.10.23. * @GST_MESSAGE_ANY: mask for all of the above messages. * * The different message types that are available. @@ -113,6 +116,7 @@ typedef enum GST_MESSAGE_LATENCY = (1 << 19), GST_MESSAGE_ASYNC_START = (1 << 20), GST_MESSAGE_ASYNC_DONE = (1 << 21), + GST_MESSAGE_REQUEST_STATE = (1 << 22), GST_MESSAGE_ANY = ~0 } GstMessageType; @@ -383,6 +387,10 @@ GstMessage * gst_message_new_structure_change (GstObject * src, GstStructureCh void gst_message_parse_structure_change (GstMessage *message, GstStructureChangeType *type, GstElement **owner, gboolean *busy); +/* REQUEST_STATE */ +GstMessage * gst_message_new_request_state (GstObject * src, GstState state); +void gst_message_parse_request_state (GstMessage * message, GstState *state); + /* custom messages */ GstMessage * gst_message_new_custom (GstMessageType type, GstObject * src, diff --git a/tests/check/gst/gstmessage.c b/tests/check/gst/gstmessage.c index b2a03f2a16..39bae402de 100644 --- a/tests/check/gst/gstmessage.c +++ b/tests/check/gst/gstmessage.c @@ -186,8 +186,25 @@ GST_START_TEST (test_parsing) void gst_message_parse_warning (GstMessage *message, GError **gerror, gchar **debug); */ + /* GST_MESSAGE_REQUEST_STATE */ + { + GstState state; + state = GST_STATE_PAUSED; + message = gst_message_new_request_state (NULL, state); + fail_if (message == NULL); + fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_REQUEST_STATE); + fail_unless (GST_MESSAGE_SRC (message) == NULL); + + /* set some wrong values to check if the parse method overwrites them + * with the good values */ + state = GST_STATE_READY; + gst_message_parse_request_state (message, &state); + fail_unless (state == GST_STATE_PAUSED); + + gst_message_unref (message); + } } GST_END_TEST; diff --git a/tools/gst-launch.c b/tools/gst-launch.c index d23f1c7c12..3930eaee87 100644 --- a/tools/gst-launch.c +++ b/tools/gst-launch.c @@ -523,7 +523,7 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state) gint percent; gst_message_parse_buffering (message, &percent); - if(!quiet) + if (!quiet) fprintf (stderr, "%s %d%% \r", _("buffering..."), percent); /* no state management needed for live pipelines */ @@ -535,7 +535,7 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state) buffering = FALSE; /* if the desired state is playing, go back */ if (target_state == GST_STATE_PLAYING) { - if(!quiet) + if (!quiet) fprintf (stderr, _("Done buffering, setting pipeline to PLAYING ...\n")); gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -545,8 +545,9 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state) /* buffering busy */ if (buffering == FALSE && target_state == GST_STATE_PLAYING) { /* we were not buffering but PLAYING, PAUSE the pipeline. */ - if(!quiet) - fprintf (stderr, _("Buffering, setting pipeline to PAUSED ...\n")); + if (!quiet) + fprintf (stderr, + _("Buffering, setting pipeline to PAUSED ...\n")); gst_element_set_state (pipeline, GST_STATE_PAUSED); } buffering = TRUE; @@ -559,6 +560,21 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state) gst_bin_recalculate_latency (GST_BIN (pipeline)); break; } + case GST_MESSAGE_REQUEST_STATE: + { + GstState state; + gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message)); + + gst_message_parse_request_state (message, &state); + + fprintf (stderr, _("Setting state to %s as requested by %s...\n"), + gst_element_state_get_name (state), name); + + gst_element_set_state (pipeline, state); + + g_free (name); + break; + } case GST_MESSAGE_APPLICATION:{ const GstStructure *s; @@ -567,7 +583,7 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state) if (gst_structure_has_name (s, "GstLaunchInterrupt")) { /* this application message is posted when we caught an interrupt and * we need to stop the pipeline. */ - if(!quiet) + if (!quiet) fprintf (stderr, _("Interrupt: Stopping pipeline ...\n")); /* return TRUE when we caught an interrupt */ res = TRUE; @@ -728,7 +744,7 @@ main (int argc, char *argv[]) gst_bin_add (GST_BIN (real_pipeline), pipeline); pipeline = real_pipeline; } - if(!quiet) + if (!quiet) fprintf (stderr, _("Setting pipeline to PAUSED ...\n")); ret = gst_element_set_state (pipeline, GST_STATE_PAUSED); @@ -739,12 +755,13 @@ main (int argc, char *argv[]) event_loop (pipeline, FALSE, GST_STATE_VOID_PENDING); goto end; case GST_STATE_CHANGE_NO_PREROLL: - if(!quiet) - fprintf (stderr, _("Pipeline is live and does not need PREROLL ...\n")); + if (!quiet) + fprintf (stderr, + _("Pipeline is live and does not need PREROLL ...\n")); is_live = TRUE; break; case GST_STATE_CHANGE_ASYNC: - if(!quiet) + if (!quiet) fprintf (stderr, _("Pipeline is PREROLLING ...\n")); caught_error = event_loop (pipeline, TRUE, GST_STATE_PAUSED); if (caught_error) { @@ -754,7 +771,7 @@ main (int argc, char *argv[]) state = GST_STATE_PAUSED; /* fallthrough */ case GST_STATE_CHANGE_SUCCESS: - if(!quiet) + if (!quiet) fprintf (stderr, _("Pipeline is PREROLLED ...\n")); break; } @@ -767,7 +784,7 @@ main (int argc, char *argv[]) GstClockTime tfthen, tfnow; GstClockTimeDiff diff; - if(!quiet) + if (!quiet) fprintf (stderr, _("Setting pipeline to PLAYING ...\n")); if (gst_element_set_state (pipeline, @@ -804,24 +821,24 @@ main (int argc, char *argv[]) /* iterate mainloop to process pending stuff */ while (g_main_context_iteration (NULL, FALSE)); - if(!quiet) + if (!quiet) fprintf (stderr, _("Setting pipeline to PAUSED ...\n")); gst_element_set_state (pipeline, GST_STATE_PAUSED); if (!caught_error) gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE); - if(!quiet) + if (!quiet) fprintf (stderr, _("Setting pipeline to READY ...\n")); gst_element_set_state (pipeline, GST_STATE_READY); gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE); end: - if(!quiet) + if (!quiet) fprintf (stderr, _("Setting pipeline to NULL ...\n")); gst_element_set_state (pipeline, GST_STATE_NULL); gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE); } - if(!quiet) + if (!quiet) fprintf (stderr, _("Freeing pipeline ...\n")); gst_object_unref (pipeline);