Add message to request a state change
authorWim Taymans <wim.taymans@collabora.co.uk>
Wed, 18 Feb 2009 14:31:55 +0000 (15:31 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 18 Feb 2009 14:31:55 +0000 (15:31 +0100)
Add a GST_MESSAGE_REQUEST_STATE that can be posted by element when they would
like to have the application change the state of the pipeline. the primary use
case is to pause the pipeline when an audio mixer is mixing a higher priority
stream but it can also be used for other purposes.

Add some docs and a unit test.

Implement the REQUEST_STATE message in gst-launch.

API: gst_message_new_request_state()
API: gst_message_parse_request_state()
API: GST_MESSAGE_REQUEST_STATE

docs/design/part-messages.txt
docs/gst/gstreamer-sections.txt
gst/gstmessage.c
gst/gstmessage.h
tests/check/gst/gstmessage.c
tools/gst-launch.c

index aa5f21876a3cbf1bf2e97bbf659d7f6ab9e2167b..cd53e106e625f283b6767160dc1071dc068a2928 100644 (file)
@@ -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.
index b07d371a665489f7af419738366daa2d007b7686..751d8e94a272e26ca121df1b45a3ab8aa22ed37c 100644 (file)
@@ -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
 <SUBSECTION Standard>
 GstMessageClass
 GST_MESSAGE
index df9b5e1e75847817a00f2ce7fac8328023f44d07..78305bddacaa798bf81ec7a1ac15d792750a8134 100644 (file)
@@ -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)));
+}
index ad13ac001bd72be6498036bab9ba20063517aa9e..b1b5b5ca91aa754cfd04c8e8a9761b5a180534ec 100644 (file)
@@ -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,
index b2a03f2a1670c79b474be2bea5328918f36e5945..39bae402defb5d7fdfa06b3c5a6f20814c9ef018 100644 (file)
@@ -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;
index d23f1c7c12a4acb7377a76da9f3b0afd905966ec..3930eaee8749259e80ba7864c5d14b7d8d066f5e 100644 (file)
@@ -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);