mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 22:36:33 +00:00
Add message to request a state change
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
This commit is contained in:
parent
26f368f7e7
commit
4b986a4a94
6 changed files with 115 additions and 15 deletions
|
@ -128,4 +128,8 @@ Message types
|
||||||
Posted by elements when the latency in a pipeline changed and a new global
|
Posted by elements when the latency in a pipeline changed and a new global
|
||||||
latency should be calculated by the pipeline or application.
|
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.
|
||||||
|
|
|
@ -1089,6 +1089,8 @@ gst_message_parse_async_start
|
||||||
gst_message_new_async_done
|
gst_message_new_async_done
|
||||||
gst_message_new_structure_change
|
gst_message_new_structure_change
|
||||||
gst_message_parse_structure_change
|
gst_message_parse_structure_change
|
||||||
|
gst_message_new_request_state
|
||||||
|
gst_message_parse_request_state
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GstMessageClass
|
GstMessageClass
|
||||||
GST_MESSAGE
|
GST_MESSAGE
|
||||||
|
|
|
@ -111,6 +111,7 @@ static GstMessageQuarks message_quarks[] = {
|
||||||
{GST_MESSAGE_LATENCY, "latency", 0},
|
{GST_MESSAGE_LATENCY, "latency", 0},
|
||||||
{GST_MESSAGE_ASYNC_START, "async-start", 0},
|
{GST_MESSAGE_ASYNC_START, "async-start", 0},
|
||||||
{GST_MESSAGE_ASYNC_DONE, "async-done", 0},
|
{GST_MESSAGE_ASYNC_DONE, "async-done", 0},
|
||||||
|
{GST_MESSAGE_REQUEST_STATE, "request-state", 0},
|
||||||
{0, NULL, 0}
|
{0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -932,6 +933,35 @@ gst_message_new_latency (GstObject * src)
|
||||||
return message;
|
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:
|
* gst_message_get_structure:
|
||||||
* @message: The #GstMessage.
|
* @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,
|
g_value_get_boolean (gst_structure_id_get_value (message->structure,
|
||||||
GST_QUARK (NEW_BASE_TIME)));
|
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)));
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,9 @@ typedef struct _GstMessageClass GstMessageClass;
|
||||||
* pipeline. Since: 0.10.13
|
* pipeline. Since: 0.10.13
|
||||||
* @GST_MESSAGE_LATENCY: Posted by elements when their latency changes. The
|
* @GST_MESSAGE_LATENCY: Posted by elements when their latency changes. The
|
||||||
* pipeline will calculate and distribute a new latency. Since: 0.10.12
|
* 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.
|
* @GST_MESSAGE_ANY: mask for all of the above messages.
|
||||||
*
|
*
|
||||||
* The different message types that are available.
|
* The different message types that are available.
|
||||||
|
@ -113,6 +116,7 @@ typedef enum
|
||||||
GST_MESSAGE_LATENCY = (1 << 19),
|
GST_MESSAGE_LATENCY = (1 << 19),
|
||||||
GST_MESSAGE_ASYNC_START = (1 << 20),
|
GST_MESSAGE_ASYNC_START = (1 << 20),
|
||||||
GST_MESSAGE_ASYNC_DONE = (1 << 21),
|
GST_MESSAGE_ASYNC_DONE = (1 << 21),
|
||||||
|
GST_MESSAGE_REQUEST_STATE = (1 << 22),
|
||||||
GST_MESSAGE_ANY = ~0
|
GST_MESSAGE_ANY = ~0
|
||||||
} GstMessageType;
|
} GstMessageType;
|
||||||
|
|
||||||
|
@ -383,6 +387,10 @@ GstMessage * gst_message_new_structure_change (GstObject * src, GstStructureCh
|
||||||
void gst_message_parse_structure_change (GstMessage *message, GstStructureChangeType *type,
|
void gst_message_parse_structure_change (GstMessage *message, GstStructureChangeType *type,
|
||||||
GstElement **owner, gboolean *busy);
|
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 */
|
/* custom messages */
|
||||||
GstMessage * gst_message_new_custom (GstMessageType type,
|
GstMessage * gst_message_new_custom (GstMessageType type,
|
||||||
GstObject * src,
|
GstObject * src,
|
||||||
|
|
|
@ -186,8 +186,25 @@ GST_START_TEST (test_parsing)
|
||||||
void gst_message_parse_warning (GstMessage *message, GError **gerror, gchar **debug);
|
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;
|
GST_END_TEST;
|
||||||
|
|
|
@ -523,7 +523,7 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
|
||||||
gint percent;
|
gint percent;
|
||||||
|
|
||||||
gst_message_parse_buffering (message, &percent);
|
gst_message_parse_buffering (message, &percent);
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, "%s %d%% \r", _("buffering..."), percent);
|
fprintf (stderr, "%s %d%% \r", _("buffering..."), percent);
|
||||||
|
|
||||||
/* no state management needed for live pipelines */
|
/* no state management needed for live pipelines */
|
||||||
|
@ -535,7 +535,7 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
|
||||||
buffering = FALSE;
|
buffering = FALSE;
|
||||||
/* if the desired state is playing, go back */
|
/* if the desired state is playing, go back */
|
||||||
if (target_state == GST_STATE_PLAYING) {
|
if (target_state == GST_STATE_PLAYING) {
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
_("Done buffering, setting pipeline to PLAYING ...\n"));
|
_("Done buffering, setting pipeline to PLAYING ...\n"));
|
||||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
|
@ -545,8 +545,9 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
|
||||||
/* buffering busy */
|
/* buffering busy */
|
||||||
if (buffering == FALSE && target_state == GST_STATE_PLAYING) {
|
if (buffering == FALSE && target_state == GST_STATE_PLAYING) {
|
||||||
/* we were not buffering but PLAYING, PAUSE the pipeline. */
|
/* we were not buffering but PLAYING, PAUSE the pipeline. */
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Buffering, setting pipeline to PAUSED ...\n"));
|
fprintf (stderr,
|
||||||
|
_("Buffering, setting pipeline to PAUSED ...\n"));
|
||||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||||
}
|
}
|
||||||
buffering = TRUE;
|
buffering = TRUE;
|
||||||
|
@ -559,6 +560,21 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
|
||||||
gst_bin_recalculate_latency (GST_BIN (pipeline));
|
gst_bin_recalculate_latency (GST_BIN (pipeline));
|
||||||
break;
|
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:{
|
case GST_MESSAGE_APPLICATION:{
|
||||||
const GstStructure *s;
|
const GstStructure *s;
|
||||||
|
|
||||||
|
@ -567,7 +583,7 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
|
||||||
if (gst_structure_has_name (s, "GstLaunchInterrupt")) {
|
if (gst_structure_has_name (s, "GstLaunchInterrupt")) {
|
||||||
/* this application message is posted when we caught an interrupt and
|
/* this application message is posted when we caught an interrupt and
|
||||||
* we need to stop the pipeline. */
|
* we need to stop the pipeline. */
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Interrupt: Stopping pipeline ...\n"));
|
fprintf (stderr, _("Interrupt: Stopping pipeline ...\n"));
|
||||||
/* return TRUE when we caught an interrupt */
|
/* return TRUE when we caught an interrupt */
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
|
@ -728,7 +744,7 @@ main (int argc, char *argv[])
|
||||||
gst_bin_add (GST_BIN (real_pipeline), pipeline);
|
gst_bin_add (GST_BIN (real_pipeline), pipeline);
|
||||||
pipeline = real_pipeline;
|
pipeline = real_pipeline;
|
||||||
}
|
}
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Setting pipeline to PAUSED ...\n"));
|
fprintf (stderr, _("Setting pipeline to PAUSED ...\n"));
|
||||||
ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
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);
|
event_loop (pipeline, FALSE, GST_STATE_VOID_PENDING);
|
||||||
goto end;
|
goto end;
|
||||||
case GST_STATE_CHANGE_NO_PREROLL:
|
case GST_STATE_CHANGE_NO_PREROLL:
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Pipeline is live and does not need PREROLL ...\n"));
|
fprintf (stderr,
|
||||||
|
_("Pipeline is live and does not need PREROLL ...\n"));
|
||||||
is_live = TRUE;
|
is_live = TRUE;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_ASYNC:
|
case GST_STATE_CHANGE_ASYNC:
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Pipeline is PREROLLING ...\n"));
|
fprintf (stderr, _("Pipeline is PREROLLING ...\n"));
|
||||||
caught_error = event_loop (pipeline, TRUE, GST_STATE_PAUSED);
|
caught_error = event_loop (pipeline, TRUE, GST_STATE_PAUSED);
|
||||||
if (caught_error) {
|
if (caught_error) {
|
||||||
|
@ -754,7 +771,7 @@ main (int argc, char *argv[])
|
||||||
state = GST_STATE_PAUSED;
|
state = GST_STATE_PAUSED;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case GST_STATE_CHANGE_SUCCESS:
|
case GST_STATE_CHANGE_SUCCESS:
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Pipeline is PREROLLED ...\n"));
|
fprintf (stderr, _("Pipeline is PREROLLED ...\n"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -767,7 +784,7 @@ main (int argc, char *argv[])
|
||||||
GstClockTime tfthen, tfnow;
|
GstClockTime tfthen, tfnow;
|
||||||
GstClockTimeDiff diff;
|
GstClockTimeDiff diff;
|
||||||
|
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Setting pipeline to PLAYING ...\n"));
|
fprintf (stderr, _("Setting pipeline to PLAYING ...\n"));
|
||||||
|
|
||||||
if (gst_element_set_state (pipeline,
|
if (gst_element_set_state (pipeline,
|
||||||
|
@ -804,24 +821,24 @@ main (int argc, char *argv[])
|
||||||
/* iterate mainloop to process pending stuff */
|
/* iterate mainloop to process pending stuff */
|
||||||
while (g_main_context_iteration (NULL, FALSE));
|
while (g_main_context_iteration (NULL, FALSE));
|
||||||
|
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Setting pipeline to PAUSED ...\n"));
|
fprintf (stderr, _("Setting pipeline to PAUSED ...\n"));
|
||||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||||
if (!caught_error)
|
if (!caught_error)
|
||||||
gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
|
gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Setting pipeline to READY ...\n"));
|
fprintf (stderr, _("Setting pipeline to READY ...\n"));
|
||||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||||
gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
|
gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Setting pipeline to NULL ...\n"));
|
fprintf (stderr, _("Setting pipeline to NULL ...\n"));
|
||||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
|
gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!quiet)
|
if (!quiet)
|
||||||
fprintf (stderr, _("Freeing pipeline ...\n"));
|
fprintf (stderr, _("Freeing pipeline ...\n"));
|
||||||
gst_object_unref (pipeline);
|
gst_object_unref (pipeline);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue