diff --git a/ChangeLog b/ChangeLog index 537cf3f2ff..06834da237 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2005-09-23 Tim-Philipp Müller + + * check/gst/gstbin.c: (test_children_state_change_order_flagged_sink), + (test_children_state_change_order_semi_sink), (gst_bin_suite): + Added test to check state change order in bins (can still be made + to fail here under heavy disk load; bails out with 'Push on pad + fakesink:sink0, but it was not activated in push mode'). + + * gst/gstbin.c: (gst_bin_class_init), (gst_bin_change_state): + Fix state change order when there is only a semi sink (#316856) + + * gst/gstbus.c: (gst_bus_class_init): + Use _class_peek_parent(), not _class_ref(); fix docs to say + 'default main context' instead of 'mainloop' where that is + what's meant. + + * gst/gstelement.c: (gst_element_commit_state), + (gst_element_set_state): + Fix typos in debug messages + 2005-09-23 Thomas Vander Stichele * docs/README: diff --git a/check/gst/gstbin.c b/check/gst/gstbin.c index 16c6f620de..f205bb025a 100644 --- a/check/gst/gstbin.c +++ b/check/gst/gstbin.c @@ -392,7 +392,7 @@ GST_START_TEST (test_add_linked) src = gst_element_factory_make ("fakesrc", NULL); fail_if (src == NULL, "Could not create fakesrc"); sink = gst_element_factory_make ("fakesink", NULL); - fail_if (src == NULL, "Could not create fakesink"); + fail_if (sink == NULL, "Could not create fakesink"); srcpad = gst_element_get_pad (src, "src"); fail_unless (srcpad != NULL); @@ -432,6 +432,183 @@ GST_START_TEST (test_add_linked) GST_END_TEST; +/* g_print ("%10s: %4d => %4d\n", GST_OBJECT_NAME (msg->src), old, new); */ + +#define ASSERT_STATE_CHANGE_MSG(bus,element,old_state,new_state,num) \ + { \ + GstMessage *msg; \ + GstState old = 0, new = 0; \ + msg = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, GST_SECOND); \ + fail_if (msg == NULL, "No state change message within 1 second (#" \ + G_STRINGIFY (num) ")"); \ + gst_message_parse_state_changed (msg, &old, &new); \ + fail_if (msg->src != GST_OBJECT (element), G_STRINGIFY(element) \ + " should have changed state next (#" G_STRINGIFY (num) ")"); \ + fail_if (old != old_state || new != new_state, "state change is not " \ + G_STRINGIFY (old_state) " => " G_STRINGIFY (new_state)); \ + gst_message_unref (msg); \ + } + +GST_START_TEST (test_children_state_change_order_flagged_sink) +{ + GstElement *src, *identity, *sink, *pipeline; + GstStateChangeReturn ret; + GstBus *bus; + + pipeline = gst_pipeline_new (NULL); + fail_unless (pipeline != NULL, "Could not create pipeline"); + + bus = GST_ELEMENT_BUS (pipeline); + fail_unless (bus != NULL, "Pipeline has no bus?!"); + + src = gst_element_factory_make ("fakesrc", NULL); + fail_if (src == NULL, "Could not create fakesrc"); + + identity = gst_element_factory_make ("identity", NULL); + fail_if (identity == NULL, "Could not create identity"); + + sink = gst_element_factory_make ("fakesink", NULL); + fail_if (sink == NULL, "Could not create fakesink"); + + gst_bin_add_many (GST_BIN (pipeline), src, identity, sink, NULL); + + fail_unless (gst_element_link (src, identity) == TRUE); + fail_unless (gst_element_link (identity, sink) == TRUE); + + /* (1) Test state change with fakesink being a regular sink */ + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to PLAYING failed"); + + /* NULL => READY */ + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_NULL, GST_STATE_READY, 101); + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_NULL, GST_STATE_READY, 102); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_NULL, GST_STATE_READY, 103); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_NULL, GST_STATE_READY, 104); + + /* READY => PAUSED */ + /* because of pre-rolling, sink will return ASYNC on state + * change and change state later when it has a buffer */ + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_READY, GST_STATE_PAUSED, + 105); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_READY, GST_STATE_PAUSED, 106); + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_READY, GST_STATE_PAUSED, 107); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_READY, GST_STATE_PAUSED, + 108); + + /* PAUSED => PLAYING */ + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_PAUSED, GST_STATE_PLAYING, 109); + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_PAUSED, GST_STATE_PLAYING, + 110); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_PAUSED, GST_STATE_PLAYING, 111); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_PAUSED, GST_STATE_PLAYING, + 112); + + /* don't set to NULL that will set the bus flushing and kill our messages */ + ret = gst_element_set_state (pipeline, GST_STATE_READY); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to READY failed"); + + /* TODO: do we need to check downwards state change order as well? */ + pop_messages (bus, 4); /* pop playing => paused messages off the bus */ + pop_messages (bus, 4); /* pop paused => ready messages off the bus */ + + ASSERT_OBJECT_REFCOUNT (src, "src", 1); + ASSERT_OBJECT_REFCOUNT (sink, "sink", 1); + ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); + + ret = gst_element_set_state (pipeline, GST_STATE_NULL); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to NULL failed"); + + ASSERT_OBJECT_REFCOUNT (src, "src", 1); + ASSERT_OBJECT_REFCOUNT (sink, "sink", 1); + ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); + + gst_object_unref (pipeline); +} + +GST_END_TEST; + + +GST_START_TEST (test_children_state_change_order_semi_sink) +{ + GstElement *src, *identity, *sink, *pipeline; + GstStateChangeReturn ret; + GstBus *bus; + + /* (2) Now again, but check other code path where we don't have + * a proper sink correctly flagged as such, but a 'semi-sink' */ + pipeline = gst_pipeline_new (NULL); + fail_unless (pipeline != NULL, "Could not create pipeline"); + + bus = GST_ELEMENT_BUS (pipeline); + fail_unless (bus != NULL, "Pipeline has no bus?!"); + + src = gst_element_factory_make ("fakesrc", NULL); + fail_if (src == NULL, "Could not create fakesrc"); + + identity = gst_element_factory_make ("identity", NULL); + fail_if (identity == NULL, "Could not create identity"); + + sink = gst_element_factory_make ("fakesink", NULL); + fail_if (sink == NULL, "Could not create fakesink"); + + gst_bin_add_many (GST_BIN (pipeline), src, identity, sink, NULL); + + fail_unless (gst_element_link (src, identity) == TRUE); + fail_unless (gst_element_link (identity, sink) == TRUE); + + GST_FLAG_UNSET (sink, GST_ELEMENT_IS_SINK); /* <======== */ + + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to PLAYING failed"); + + /* NULL => READY */ + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_NULL, GST_STATE_READY, 201); + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_NULL, GST_STATE_READY, 202); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_NULL, GST_STATE_READY, 203); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_NULL, GST_STATE_READY, 204); + + /* READY => PAUSED */ + /* because of pre-rolling, sink will return ASYNC on state + * change and change state later when it has a buffer */ + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_READY, GST_STATE_PAUSED, + 205); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_READY, GST_STATE_PAUSED, 206); + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_READY, GST_STATE_PAUSED, 207); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_READY, GST_STATE_PAUSED, + 208); + + /* PAUSED => PLAYING */ + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_PAUSED, GST_STATE_PLAYING, 209); + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_PAUSED, GST_STATE_PLAYING, + 210); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_PAUSED, GST_STATE_PLAYING, 211); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_PAUSED, GST_STATE_PLAYING, + 212); + + /* don't set to NULL that will set the bus flushing and kill our messages */ + ret = gst_element_set_state (pipeline, GST_STATE_READY); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to READY failed"); + + /* TODO: do we need to check downwards state change order as well? */ + pop_messages (bus, 4); /* pop playing => paused messages off the bus */ + pop_messages (bus, 4); /* pop paused => ready messages off the bus */ + + ASSERT_OBJECT_REFCOUNT (src, "src", 1); + ASSERT_OBJECT_REFCOUNT (sink, "sink", 1); + ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); + + ret = gst_element_set_state (pipeline, GST_STATE_NULL); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to NULL failed"); + + ASSERT_OBJECT_REFCOUNT (src, "src", 1); + ASSERT_OBJECT_REFCOUNT (sink, "sink", 1); + ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); + + gst_object_unref (pipeline); +} + +GST_END_TEST; + Suite * gst_bin_suite (void) { @@ -440,6 +617,8 @@ gst_bin_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_interface); + tcase_add_test (tc_chain, test_children_state_change_order_flagged_sink); + tcase_add_test (tc_chain, test_children_state_change_order_semi_sink); tcase_add_test (tc_chain, test_message_state_changed); tcase_add_test (tc_chain, test_message_state_changed_child); tcase_add_test (tc_chain, test_message_state_changed_children); diff --git a/gst/gstbin.c b/gst/gstbin.c index 74b34a08b2..98181047aa 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -223,7 +223,7 @@ gst_bin_class_init (GstBinClass * klass) gstobject_class = (GstObjectClass *) klass; gstelement_class = (GstElementClass *) klass; - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + parent_class = g_type_class_peek_parent (klass); /** * GstBin::element-added: @@ -1359,7 +1359,7 @@ restart: /* was reffed before pushing on the queue by the * gst_object_get_parent() call we used to get the element. */ - g_queue_push_tail (elem_queue, peer_parent); + g_queue_push_head (elem_queue, peer_parent); /* so that we don't unref it */ peer_parent = NULL; } else { diff --git a/gst/gstbus.c b/gst/gstbus.c index cb4c59f28f..da464a6f4a 100644 --- a/gst/gstbus.c +++ b/gst/gstbus.c @@ -43,7 +43,7 @@ * is posted on the bus. The application can then _pop() the messages from the * bus to handle them. * Alternatively the application can register an asynchronous bus function using - * gst_bus_add_watch_full() orgst_bus_add_watch(). This function will receive + * gst_bus_add_watch_full() or gst_bus_add_watch(). This function will receive * messages a short while after they have been posted. * * It is also possible to get messages from the bus without any thread @@ -65,10 +65,6 @@ #include "gstbus.h" -enum -{ - ARG_0, -}; static void gst_bus_class_init (GstBusClass * klass); static void gst_bus_init (GstBus * bus); @@ -116,7 +112,7 @@ gst_bus_class_init (GstBusClass * klass) gobject_class = (GObjectClass *) klass; gstobject_class = (GstObjectClass *) klass; - parent_class = g_type_class_ref (GST_TYPE_OBJECT); + parent_class = g_type_class_peek_parent (klass); if (!g_thread_supported ()) g_thread_init (NULL); @@ -590,11 +586,11 @@ gst_bus_create_watch (GstBus * bus, GstMessageType events) * @user_data: user data passed to @func. * @notify: the function to call when the source is removed. * - * Adds the bus to the mainloop with the given priority. If the func returns - * FALSE, the func will be removed. + * Adds a bus watch to the default main context with the given priority. + * If the func returns FALSE, the source will be removed. * * When the func is called, the message belongs to the caller; if you want to - * keep a copy of it, call gst_message_ref before leaving the func. + * keep a copy of it, call gst_message_ref() before leaving the func. * * Returns: The event source id. * @@ -631,7 +627,7 @@ gst_bus_add_watch_full (GstBus * bus, gint priority, GstMessageType events, * @func: A function to call when a message is received. * @user_data: user data passed to @func. * - * Adds the bus to the mainloop with the default priority. + * Adds a bus watch to the default main context with the default priority. * * Returns: The event source id. * diff --git a/gst/gstelement.c b/gst/gstelement.c index 0f64186a0b..a478a7d8ba 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -1737,7 +1737,8 @@ gst_element_commit_state (GstElement * element) GstState old_state = GST_STATE (element); GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, - "commiting state from %s to %s", gst_element_state_get_name (old_state), + "committing state from %s to %s", + gst_element_state_get_name (old_state), gst_element_state_get_name (pending)); GST_STATE (element) = pending; @@ -1892,7 +1893,7 @@ gst_element_set_state (GstElement * element, GstState state) "element changed state successfully"); /* we can commit the state now and proceed to the next state */ gst_element_commit_state (element); - GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "commited state"); + GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "committed state"); break; case GST_STATE_CHANGE_NO_PREROLL: GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, @@ -1900,7 +1901,7 @@ gst_element_set_state (GstElement * element, GstState state) /* we can commit the state now and proceed to the next state */ gst_element_commit_state (element); GST_STATE_NO_PREROLL (element) = TRUE; - GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "commited state"); + GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "committed state"); break; default: goto invalid_return; diff --git a/tests/check/gst/gstbin.c b/tests/check/gst/gstbin.c index 16c6f620de..f205bb025a 100644 --- a/tests/check/gst/gstbin.c +++ b/tests/check/gst/gstbin.c @@ -392,7 +392,7 @@ GST_START_TEST (test_add_linked) src = gst_element_factory_make ("fakesrc", NULL); fail_if (src == NULL, "Could not create fakesrc"); sink = gst_element_factory_make ("fakesink", NULL); - fail_if (src == NULL, "Could not create fakesink"); + fail_if (sink == NULL, "Could not create fakesink"); srcpad = gst_element_get_pad (src, "src"); fail_unless (srcpad != NULL); @@ -432,6 +432,183 @@ GST_START_TEST (test_add_linked) GST_END_TEST; +/* g_print ("%10s: %4d => %4d\n", GST_OBJECT_NAME (msg->src), old, new); */ + +#define ASSERT_STATE_CHANGE_MSG(bus,element,old_state,new_state,num) \ + { \ + GstMessage *msg; \ + GstState old = 0, new = 0; \ + msg = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, GST_SECOND); \ + fail_if (msg == NULL, "No state change message within 1 second (#" \ + G_STRINGIFY (num) ")"); \ + gst_message_parse_state_changed (msg, &old, &new); \ + fail_if (msg->src != GST_OBJECT (element), G_STRINGIFY(element) \ + " should have changed state next (#" G_STRINGIFY (num) ")"); \ + fail_if (old != old_state || new != new_state, "state change is not " \ + G_STRINGIFY (old_state) " => " G_STRINGIFY (new_state)); \ + gst_message_unref (msg); \ + } + +GST_START_TEST (test_children_state_change_order_flagged_sink) +{ + GstElement *src, *identity, *sink, *pipeline; + GstStateChangeReturn ret; + GstBus *bus; + + pipeline = gst_pipeline_new (NULL); + fail_unless (pipeline != NULL, "Could not create pipeline"); + + bus = GST_ELEMENT_BUS (pipeline); + fail_unless (bus != NULL, "Pipeline has no bus?!"); + + src = gst_element_factory_make ("fakesrc", NULL); + fail_if (src == NULL, "Could not create fakesrc"); + + identity = gst_element_factory_make ("identity", NULL); + fail_if (identity == NULL, "Could not create identity"); + + sink = gst_element_factory_make ("fakesink", NULL); + fail_if (sink == NULL, "Could not create fakesink"); + + gst_bin_add_many (GST_BIN (pipeline), src, identity, sink, NULL); + + fail_unless (gst_element_link (src, identity) == TRUE); + fail_unless (gst_element_link (identity, sink) == TRUE); + + /* (1) Test state change with fakesink being a regular sink */ + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to PLAYING failed"); + + /* NULL => READY */ + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_NULL, GST_STATE_READY, 101); + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_NULL, GST_STATE_READY, 102); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_NULL, GST_STATE_READY, 103); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_NULL, GST_STATE_READY, 104); + + /* READY => PAUSED */ + /* because of pre-rolling, sink will return ASYNC on state + * change and change state later when it has a buffer */ + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_READY, GST_STATE_PAUSED, + 105); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_READY, GST_STATE_PAUSED, 106); + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_READY, GST_STATE_PAUSED, 107); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_READY, GST_STATE_PAUSED, + 108); + + /* PAUSED => PLAYING */ + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_PAUSED, GST_STATE_PLAYING, 109); + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_PAUSED, GST_STATE_PLAYING, + 110); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_PAUSED, GST_STATE_PLAYING, 111); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_PAUSED, GST_STATE_PLAYING, + 112); + + /* don't set to NULL that will set the bus flushing and kill our messages */ + ret = gst_element_set_state (pipeline, GST_STATE_READY); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to READY failed"); + + /* TODO: do we need to check downwards state change order as well? */ + pop_messages (bus, 4); /* pop playing => paused messages off the bus */ + pop_messages (bus, 4); /* pop paused => ready messages off the bus */ + + ASSERT_OBJECT_REFCOUNT (src, "src", 1); + ASSERT_OBJECT_REFCOUNT (sink, "sink", 1); + ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); + + ret = gst_element_set_state (pipeline, GST_STATE_NULL); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to NULL failed"); + + ASSERT_OBJECT_REFCOUNT (src, "src", 1); + ASSERT_OBJECT_REFCOUNT (sink, "sink", 1); + ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); + + gst_object_unref (pipeline); +} + +GST_END_TEST; + + +GST_START_TEST (test_children_state_change_order_semi_sink) +{ + GstElement *src, *identity, *sink, *pipeline; + GstStateChangeReturn ret; + GstBus *bus; + + /* (2) Now again, but check other code path where we don't have + * a proper sink correctly flagged as such, but a 'semi-sink' */ + pipeline = gst_pipeline_new (NULL); + fail_unless (pipeline != NULL, "Could not create pipeline"); + + bus = GST_ELEMENT_BUS (pipeline); + fail_unless (bus != NULL, "Pipeline has no bus?!"); + + src = gst_element_factory_make ("fakesrc", NULL); + fail_if (src == NULL, "Could not create fakesrc"); + + identity = gst_element_factory_make ("identity", NULL); + fail_if (identity == NULL, "Could not create identity"); + + sink = gst_element_factory_make ("fakesink", NULL); + fail_if (sink == NULL, "Could not create fakesink"); + + gst_bin_add_many (GST_BIN (pipeline), src, identity, sink, NULL); + + fail_unless (gst_element_link (src, identity) == TRUE); + fail_unless (gst_element_link (identity, sink) == TRUE); + + GST_FLAG_UNSET (sink, GST_ELEMENT_IS_SINK); /* <======== */ + + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to PLAYING failed"); + + /* NULL => READY */ + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_NULL, GST_STATE_READY, 201); + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_NULL, GST_STATE_READY, 202); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_NULL, GST_STATE_READY, 203); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_NULL, GST_STATE_READY, 204); + + /* READY => PAUSED */ + /* because of pre-rolling, sink will return ASYNC on state + * change and change state later when it has a buffer */ + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_READY, GST_STATE_PAUSED, + 205); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_READY, GST_STATE_PAUSED, 206); + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_READY, GST_STATE_PAUSED, 207); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_READY, GST_STATE_PAUSED, + 208); + + /* PAUSED => PLAYING */ + ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_PAUSED, GST_STATE_PLAYING, 209); + ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_PAUSED, GST_STATE_PLAYING, + 210); + ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_PAUSED, GST_STATE_PLAYING, 211); + ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_PAUSED, GST_STATE_PLAYING, + 212); + + /* don't set to NULL that will set the bus flushing and kill our messages */ + ret = gst_element_set_state (pipeline, GST_STATE_READY); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to READY failed"); + + /* TODO: do we need to check downwards state change order as well? */ + pop_messages (bus, 4); /* pop playing => paused messages off the bus */ + pop_messages (bus, 4); /* pop paused => ready messages off the bus */ + + ASSERT_OBJECT_REFCOUNT (src, "src", 1); + ASSERT_OBJECT_REFCOUNT (sink, "sink", 1); + ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); + + ret = gst_element_set_state (pipeline, GST_STATE_NULL); + fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to NULL failed"); + + ASSERT_OBJECT_REFCOUNT (src, "src", 1); + ASSERT_OBJECT_REFCOUNT (sink, "sink", 1); + ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); + + gst_object_unref (pipeline); +} + +GST_END_TEST; + Suite * gst_bin_suite (void) { @@ -440,6 +617,8 @@ gst_bin_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_interface); + tcase_add_test (tc_chain, test_children_state_change_order_flagged_sink); + tcase_add_test (tc_chain, test_children_state_change_order_semi_sink); tcase_add_test (tc_chain, test_message_state_changed); tcase_add_test (tc_chain, test_message_state_changed_child); tcase_add_test (tc_chain, test_message_state_changed_children);