+2005-10-12 Wim Taymans <wim@fluendo.com>
+
+ * check/Makefile.am:
+ * check/states/sinks.c: (GST_START_TEST), (gst_object_suite):
+ * check/states/sinks2.c:
+ Moved sinks2 testcode in sinks check.
+
+ * gst/gstbin.c: (gst_bin_provide_clock_func), (gst_bin_add_func),
+ (gst_bin_remove_func), (gst_bin_recalc_state),
+ (gst_bin_change_state_func), (bin_bus_handler):
+ Fix potential race condition when _get_state() iterated over an
+ ASYNC element right before it posted a state completion.
+
+ * gst/gstclock.h:
+ Do proper cast here.
+
+ * gst/gstevent.c: (gst_event_new_newsegment),
+ (gst_event_parse_newsegment):
+ A playback rate of 0.0 is not allowed.
+
2005-10-11 Thomas Vander Stichele <thomas at apestaart dot org>
* win32/common/config.h:
pipelines/simple_launch_lines \
pipelines/cleanup \
states/sinks \
- states/sinks2 \
gst-libs/controller \
gst-libs/gdp
}
GST_END_TEST
+/* a sink should go ASYNC to PAUSE and PLAYING, when linking a src, it
+ * should complete the state change. */
+GST_START_TEST (test_sink_completion)
+{
+ GstElement *sink, *src;
+ GstStateChangeReturn ret;
+ GstState current, pending;
+ GTimeVal tv;
+
+ sink = gst_element_factory_make ("fakesink", "sink");
+
+ ret = gst_element_set_state (sink, GST_STATE_PLAYING);
+ fail_unless (ret == GST_STATE_CHANGE_ASYNC, "no async state return");
+
+ GST_TIME_TO_TIMEVAL ((GstClockTime) 0, tv);
+
+ ret = gst_element_get_state (sink, ¤t, &pending, &tv);
+ fail_unless (ret == GST_STATE_CHANGE_ASYNC, "not changing state async");
+ fail_unless (current == GST_STATE_READY, "bad current state");
+ fail_unless (pending == GST_STATE_PLAYING, "bad pending state");
+
+ src = gst_element_factory_make ("fakesrc", "src");
+ gst_element_link (src, sink);
+
+ ret = gst_element_set_state (src, GST_STATE_PLAYING);
+ fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "no success state return");
+
+ /* now wait for final state */
+ ret = gst_element_get_state (sink, ¤t, &pending, NULL);
+ fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "failed to change state");
+ fail_unless (current == GST_STATE_PLAYING, "bad current state");
+ fail_unless (pending == GST_STATE_VOID_PENDING, "bad pending state");
+
+ ret = gst_element_set_state (sink, GST_STATE_NULL);
+ fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "failed to go to null");
+
+ ret = gst_element_set_state (src, GST_STATE_NULL);
+ fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "failed to go to null");
+
+ gst_object_unref (sink);
+ gst_object_unref (src);
+}
+
+GST_END_TEST
/* a sink should go ASYNC to PAUSE. PAUSE should complete when
* prerolled. */
GST_START_TEST (test_src_sink)
GstStateChangeReturn ret;
GstState current, pending;
GstPad *srcpad, *sinkpad;
+ GTimeVal tv;
pipeline = gst_pipeline_new ("pipeline");
src = gst_element_factory_make ("fakesrc", "src");
fail_unless (current == GST_STATE_PAUSED, "not paused");
fail_unless (pending == GST_STATE_VOID_PENDING, "not playing");
+ /* don't block here */
+ GST_TIME_TO_TIMEVAL (0, tv);
+ ret = gst_element_get_state (sink, ¤t, &pending, &tv);
+ fail_unless (ret == GST_STATE_CHANGE_ASYNC, "not async");
+ fail_unless (current == GST_STATE_READY, "not ready");
+ fail_unless (pending == GST_STATE_PAUSED, "not paused");
+
ret = gst_element_get_state (pipeline, ¤t, &pending, NULL);
fail_unless (ret == GST_STATE_CHANGE_NO_PREROLL, "not paused");
fail_unless (current == GST_STATE_PAUSED, "not paused");
fail_unless (pending == GST_STATE_VOID_PENDING, "not playing");
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
- ret = gst_element_get_state (pipeline, NULL, NULL, NULL);
- fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "cannot force play got %d",
- ret);
-
+ fail_unless (ret == GST_STATE_CHANGE_ASYNC, "not async");
ret = gst_element_get_state (pipeline, ¤t, &pending, NULL);
fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "not playing");
fail_unless (current == GST_STATE_PLAYING, "not playing");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_sink);
+ tcase_add_test (tc_chain, test_sink_completion);
tcase_add_test (tc_chain, test_src_sink);
tcase_add_test (tc_chain, test_livesrc_remove);
tcase_add_test (tc_chain, test_livesrc_sink);
+++ /dev/null
-/* GStreamer
- *
- * unit test for sinks
- *
- * Copyright (C) <2005> Wim Taymans <wim at fluendo dot com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <gst/check/gstcheck.h>
-
-/* a sink should go ASYNC to PAUSE and PLAYING. */
-GST_START_TEST (test_sink)
-{
- GstElement *sink, *src;
- GstStateChangeReturn ret;
- GstState current, pending;
- GTimeVal tv;
-
- sink = gst_element_factory_make ("fakesink", "sink");
-
- ret = gst_element_set_state (sink, GST_STATE_PLAYING);
- fail_unless (ret == GST_STATE_CHANGE_ASYNC, "no async state return");
-
- GST_TIME_TO_TIMEVAL ((GstClockTime) 0, tv);
-
- ret = gst_element_get_state (sink, ¤t, &pending, &tv);
- fail_unless (ret == GST_STATE_CHANGE_ASYNC, "not changing state async");
- fail_unless (current == GST_STATE_READY, "bad current state");
- fail_unless (pending == GST_STATE_PLAYING, "bad pending state");
-
- src = gst_element_factory_make ("fakesrc", "src");
- gst_element_link (src, sink);
-
- ret = gst_element_set_state (src, GST_STATE_PLAYING);
- fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "no success state return");
-
- /* now wait for final state */
- ret = gst_element_get_state (sink, ¤t, &pending, NULL);
- fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "failed to change state");
- fail_unless (current == GST_STATE_PLAYING, "bad current state");
- fail_unless (pending == GST_STATE_VOID_PENDING, "bad pending state");
-
- ret = gst_element_set_state (sink, GST_STATE_NULL);
- fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "failed to go to null");
-
- ret = gst_element_set_state (src, GST_STATE_NULL);
- fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "failed to go to null");
-
- gst_object_unref (sink);
- gst_object_unref (src);
-}
-
-GST_END_TEST
-/* test: try changing state of sinks */
- Suite * gst_object_suite (void)
-{
- Suite *s = suite_create ("Sinks");
- TCase *tc_chain = tcase_create ("general");
-
- suite_add_tcase (s, tc_chain);
- tcase_add_test (tc_chain, test_sink);
-
- return s;
-}
-
-int
-main (int argc, char **argv)
-{
- int nf;
-
- Suite *s = gst_object_suite ();
- SRunner *sr = srunner_create (s);
-
- gst_check_init (&argc, &argv);
-
- srunner_run_all (sr, CK_NORMAL);
- nf = srunner_ntests_failed (sr);
- srunner_free (sr);
-
- return nf;
-}
-Subproject commit 615cf4d4506ef1ffb1f600c434fced1fa26b0f44
+Subproject commit 37ed26e33bae9a6ab256c62ebbb9d711374a0abb
/* lock bin, no element can be added or removed while we have this lock */
GST_LOCK (bin);
+ /* forced recalc, make state dirty again */
+ if (force)
+ bin->state_dirty = TRUE;
+
/* no point in scanning if nothing changed and it's no forced recalc */
- if (!force && !bin->state_dirty)
+ if (!bin->state_dirty)
goto not_dirty;
/* no point in having two scans run concurrently */
GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin, "recalc state");
restart:
+ /* when we leave this function, the state must not be dirty, whenever
+ * we are scanning and the state bemoces dirty again, we restart. */
+ bin->state_dirty = FALSE;
+
have_no_preroll = FALSE;
have_async = FALSE;
/* child added/removed during state change, restart. We need
* to restart with the quick check as a no-preroll element could
* have been added here and we don't want to block on sinks then.*/
+ GST_DEBUG_OBJECT (bin, "children added or removed, restarting recalc");
+ goto restart;
+ }
+ if (bin->state_dirty) {
+ GST_DEBUG_OBJECT (bin, "state dirty again, restarting recalc");
goto restart;
}
}
done:
- bin->state_dirty = FALSE;
bin->polling = FALSE;
GST_UNLOCK (bin);
*/
#define GST_TIME_TO_TIMEVAL(t,tv) \
G_STMT_START { \
- (tv).tv_sec = (t) / GST_SECOND; \
- (tv).tv_usec = ((t) - (tv).tv_sec * GST_SECOND) / GST_USECOND; \
+ (tv).tv_sec = ((GstClockTime)(t)) / GST_SECOND; \
+ (tv).tv_usec = (((GstClockTime)(t)) - (tv).tv_sec * GST_SECOND) / GST_USECOND; \
} G_STMT_END
/**
gst_event_new_newsegment (gboolean update, gdouble rate, GstFormat format,
gint64 start_value, gint64 stop_value, gint64 stream_time)
{
+ g_return_val_if_fail (rate != 0.0, NULL);
+
if (format == GST_FORMAT_TIME) {
GST_CAT_INFO (GST_CAT_EVENT,
"creating newsegment update %d, rate %lf, format GST_FORMAT_TIME, "
pipelines/simple_launch_lines \
pipelines/cleanup \
states/sinks \
- states/sinks2 \
gst-libs/controller \
gst-libs/gdp
}
GST_END_TEST
+/* a sink should go ASYNC to PAUSE and PLAYING, when linking a src, it
+ * should complete the state change. */
+GST_START_TEST (test_sink_completion)
+{
+ GstElement *sink, *src;
+ GstStateChangeReturn ret;
+ GstState current, pending;
+ GTimeVal tv;
+
+ sink = gst_element_factory_make ("fakesink", "sink");
+
+ ret = gst_element_set_state (sink, GST_STATE_PLAYING);
+ fail_unless (ret == GST_STATE_CHANGE_ASYNC, "no async state return");
+
+ GST_TIME_TO_TIMEVAL ((GstClockTime) 0, tv);
+
+ ret = gst_element_get_state (sink, ¤t, &pending, &tv);
+ fail_unless (ret == GST_STATE_CHANGE_ASYNC, "not changing state async");
+ fail_unless (current == GST_STATE_READY, "bad current state");
+ fail_unless (pending == GST_STATE_PLAYING, "bad pending state");
+
+ src = gst_element_factory_make ("fakesrc", "src");
+ gst_element_link (src, sink);
+
+ ret = gst_element_set_state (src, GST_STATE_PLAYING);
+ fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "no success state return");
+
+ /* now wait for final state */
+ ret = gst_element_get_state (sink, ¤t, &pending, NULL);
+ fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "failed to change state");
+ fail_unless (current == GST_STATE_PLAYING, "bad current state");
+ fail_unless (pending == GST_STATE_VOID_PENDING, "bad pending state");
+
+ ret = gst_element_set_state (sink, GST_STATE_NULL);
+ fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "failed to go to null");
+
+ ret = gst_element_set_state (src, GST_STATE_NULL);
+ fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "failed to go to null");
+
+ gst_object_unref (sink);
+ gst_object_unref (src);
+}
+
+GST_END_TEST
/* a sink should go ASYNC to PAUSE. PAUSE should complete when
* prerolled. */
GST_START_TEST (test_src_sink)
GstStateChangeReturn ret;
GstState current, pending;
GstPad *srcpad, *sinkpad;
+ GTimeVal tv;
pipeline = gst_pipeline_new ("pipeline");
src = gst_element_factory_make ("fakesrc", "src");
fail_unless (current == GST_STATE_PAUSED, "not paused");
fail_unless (pending == GST_STATE_VOID_PENDING, "not playing");
+ /* don't block here */
+ GST_TIME_TO_TIMEVAL (0, tv);
+ ret = gst_element_get_state (sink, ¤t, &pending, &tv);
+ fail_unless (ret == GST_STATE_CHANGE_ASYNC, "not async");
+ fail_unless (current == GST_STATE_READY, "not ready");
+ fail_unless (pending == GST_STATE_PAUSED, "not paused");
+
ret = gst_element_get_state (pipeline, ¤t, &pending, NULL);
fail_unless (ret == GST_STATE_CHANGE_NO_PREROLL, "not paused");
fail_unless (current == GST_STATE_PAUSED, "not paused");
fail_unless (pending == GST_STATE_VOID_PENDING, "not playing");
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
- ret = gst_element_get_state (pipeline, NULL, NULL, NULL);
- fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "cannot force play got %d",
- ret);
-
+ fail_unless (ret == GST_STATE_CHANGE_ASYNC, "not async");
ret = gst_element_get_state (pipeline, ¤t, &pending, NULL);
fail_unless (ret == GST_STATE_CHANGE_SUCCESS, "not playing");
fail_unless (current == GST_STATE_PLAYING, "not playing");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_sink);
+ tcase_add_test (tc_chain, test_sink_completion);
tcase_add_test (tc_chain, test_src_sink);
tcase_add_test (tc_chain, test_livesrc_remove);
tcase_add_test (tc_chain, test_livesrc_sink);