diff options
Diffstat (limited to 'tests/check/libs/gsttestclock.c')
-rw-r--r-- | tests/check/libs/gsttestclock.c | 969 |
1 files changed, 969 insertions, 0 deletions
diff --git a/tests/check/libs/gsttestclock.c b/tests/check/libs/gsttestclock.c new file mode 100644 index 0000000..de59031 --- /dev/null +++ b/tests/check/libs/gsttestclock.c @@ -0,0 +1,969 @@ +/* + * Unit test for a deterministic clock for Gstreamer unit tests + * + * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com> + * Copyright (C) 2012 Sebastian Rasmussen <sebastian.rasmussen@axis.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> +#include <gst/check/gsttestclock.h> + +typedef struct +{ + GstTestClock *test_clock; + GstClockID id; + GstClockTime reference; +} GtuClockWaitContext; + +typedef struct +{ + GstClockID clock_id; + GstClockTimeDiff jitter; +} SyncClockWaitContext; + +#define assert_pending_id(pending_id, id, type, time) \ +G_STMT_START { \ + GstClockEntry *entry = GST_CLOCK_ENTRY (pending_id); \ + g_assert (entry == (id)); \ + g_assert (GST_CLOCK_ENTRY_TYPE (entry) == (type)); \ + g_assert_cmpuint (GST_CLOCK_ENTRY_TIME (entry), ==, (time)); \ +} G_STMT_END + +#define assert_processed_id(processed_id, id, type, time) \ +G_STMT_START { \ + GstClockEntry *entry = GST_CLOCK_ENTRY (processed_id); \ + g_assert (entry == (id)); \ + g_assert (GST_CLOCK_ENTRY_TYPE (entry) == (type)); \ + g_assert_cmpuint (GST_CLOCK_ENTRY_STATUS (entry), ==, (time)); \ +} G_STMT_END + +static gpointer test_wait_pending_single_shot_id_sync_worker (gpointer data); +static gpointer test_wait_pending_single_shot_id_async_worker (gpointer data); +static gpointer test_wait_pending_periodic_id_waiter_thread (gpointer data); +static gboolean test_async_wait_cb (GstClock * clock, GstClockTime time, + GstClockID id, gpointer user_data); + +static GtuClockWaitContext *gst_test_util_wait_for_clock_id_begin (GstTestClock + * clock, GstClockID id, GstClockTimeDiff * jitter); +static GstClockReturn gst_test_util_wait_for_clock_id_end (GtuClockWaitContext * + wait_ctx); +static gboolean +gst_test_util_clock_wait_context_has_completed (GtuClockWaitContext * wait_ctx); + +static gpointer +test_wait_pending_single_shot_id_sync_worker (gpointer data) +{ + SyncClockWaitContext *ctx = data; + + gst_clock_id_wait (ctx->clock_id, &ctx->jitter); + + return NULL; +} + +static gpointer +test_wait_pending_single_shot_id_async_worker (gpointer data) +{ + GstClockID clock_id = data; + + g_usleep (G_USEC_PER_SEC / 10); + gst_clock_id_wait_async (clock_id, test_async_wait_cb, NULL, NULL); + + return NULL; +} + +static gpointer +test_wait_pending_periodic_id_waiter_thread (gpointer data) +{ + GstClockID clock_id = data; + gst_clock_id_wait (clock_id, NULL); + return NULL; +} + +static gboolean +test_async_wait_cb (GstClock * clock, + GstClockTime time, GstClockID id, gpointer user_data) +{ + + gboolean *wait_complete = user_data; + + if (wait_complete != NULL) + *wait_complete = TRUE; + + return TRUE; +} + +static GtuClockWaitContext * +gst_test_util_wait_for_clock_id_begin (GstTestClock * test_clock, GstClockID id, + GstClockTimeDiff * jitter) +{ + GtuClockWaitContext *wait_ctx; + + wait_ctx = g_slice_new (GtuClockWaitContext); + wait_ctx->test_clock = gst_object_ref (test_clock); + wait_ctx->reference = gst_clock_get_time (GST_CLOCK (wait_ctx->test_clock)); + wait_ctx->id = gst_clock_id_ref (id); + + if (jitter) { + GstClockEntry *entry = GST_CLOCK_ENTRY (wait_ctx->id); + GstClockTime requested = GST_CLOCK_ENTRY_TIME (entry); + GstClockTime reference = wait_ctx->reference; + + *jitter = GST_CLOCK_DIFF (requested, reference); + } + + if (!gst_test_clock_has_id (wait_ctx->test_clock, wait_ctx->id)) { + GstClockClass *klass = GST_CLOCK_GET_CLASS (wait_ctx->test_clock); + GstClock *clock = GST_CLOCK (wait_ctx->test_clock); + g_assert (klass->wait_async (clock, wait_ctx->id) == GST_CLOCK_OK); + } + + g_assert (gst_test_clock_has_id (wait_ctx->test_clock, wait_ctx->id)); + g_assert_cmpint (gst_test_clock_peek_id_count (wait_ctx->test_clock), >, 0); + + return wait_ctx; +} + +static GstClockReturn +gst_test_util_wait_for_clock_id_end (GtuClockWaitContext * wait_ctx) +{ + GstClockReturn status = GST_CLOCK_ERROR; + GstClockEntry *entry = GST_CLOCK_ENTRY (wait_ctx->id); + + if (G_UNLIKELY (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED)) { + status = GST_CLOCK_UNSCHEDULED; + } else { + GstClockTime requested = GST_CLOCK_ENTRY_TIME (entry); + GstClockTimeDiff diff; + + g_assert (gst_test_clock_has_id (wait_ctx->test_clock, wait_ctx->id)); + + diff = GST_CLOCK_DIFF (requested, wait_ctx->reference); + + if (diff > 0) { + status = GST_CLOCK_EARLY; + } else { + status = GST_CLOCK_OK; + } + + g_atomic_int_set (&GST_CLOCK_ENTRY_STATUS (entry), status); + } + + if (GST_CLOCK_ENTRY_TYPE (entry) == GST_CLOCK_ENTRY_SINGLE) { + GstClockClass *klass = GST_CLOCK_GET_CLASS (wait_ctx->test_clock); + GstClock *clock = GST_CLOCK (wait_ctx->test_clock); + + klass->unschedule (clock, wait_ctx->id); + g_assert (!gst_test_clock_has_id (wait_ctx->test_clock, wait_ctx->id)); + } else { + GST_CLOCK_ENTRY_TIME (entry) += GST_CLOCK_ENTRY_INTERVAL (entry); + g_assert (gst_test_clock_has_id (wait_ctx->test_clock, wait_ctx->id)); + } + + gst_clock_id_unref (wait_ctx->id); + gst_object_unref (wait_ctx->test_clock); + g_slice_free (GtuClockWaitContext, wait_ctx); + + return status; +} + +static gboolean +gst_test_util_clock_wait_context_has_completed (GtuClockWaitContext * wait_ctx) +{ + GstClock *clock = GST_CLOCK (wait_ctx->test_clock); + GstClockEntry *entry = GST_CLOCK_ENTRY (wait_ctx->id); + GstClockTime requested = GST_CLOCK_ENTRY_TIME (entry); + GstClockTime now = gst_clock_get_time (clock); + + return requested < now; +} + +GST_START_TEST (test_object_flags) +{ + GstClock *clock = gst_test_clock_new (); + g_assert (GST_OBJECT_FLAG_IS_SET (clock, GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC)); + g_assert (GST_OBJECT_FLAG_IS_SET (clock, GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC)); + g_assert (GST_OBJECT_FLAG_IS_SET (clock, + GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC)); + g_assert (GST_OBJECT_FLAG_IS_SET (clock, + GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC)); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_resolution_query) +{ + GstClock *clock = gst_test_clock_new (); + g_assert_cmpuint (gst_clock_get_resolution (clock), ==, 1); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_start_time) +{ + GstClock *clock; + guint64 start_time; + + clock = gst_test_clock_new (); + g_assert_cmpuint (gst_clock_get_time (clock), ==, 0); + g_object_get (clock, "start-time", &start_time, NULL); + g_assert_cmpuint (start_time, ==, 0); + gst_object_unref (clock); + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + g_assert_cmpuint (gst_clock_get_time (clock), ==, GST_SECOND); + g_object_get (clock, "start-time", &start_time, NULL); + g_assert_cmpuint (start_time, ==, GST_SECOND); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_set_time) +{ + GstClock *clock = gst_test_clock_new_with_start_time (GST_SECOND); + gst_test_clock_set_time (GST_TEST_CLOCK (clock), GST_SECOND); + g_assert_cmpuint (gst_clock_get_time (clock), ==, GST_SECOND); + gst_test_clock_set_time (GST_TEST_CLOCK (clock), GST_SECOND + 1); + g_assert_cmpuint (gst_clock_get_time (clock), ==, GST_SECOND + 1); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_advance_time) +{ + GstClock *clock = gst_test_clock_new_with_start_time (GST_SECOND); + gst_test_clock_advance_time (GST_TEST_CLOCK (clock), 0); + g_assert_cmpuint (gst_clock_get_time (clock), ==, GST_SECOND); + gst_test_clock_advance_time (GST_TEST_CLOCK (clock), 42 * GST_MSECOND); + g_assert_cmpuint (gst_clock_get_time (clock), ==, + GST_SECOND + (42 * GST_MSECOND)); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_wait_synchronous_no_timeout) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id; + GThread *worker_thread; + GstClockID pending_id; + GstClockID processed_id; + SyncClockWaitContext context; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + + clock_id = gst_clock_new_single_shot_id (clock, GST_SECOND - 1); + context.clock_id = gst_clock_id_ref (clock_id); + context.jitter = 0; + worker_thread = + g_thread_new ("worker_thread", + test_wait_pending_single_shot_id_sync_worker, &context); + gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); + assert_pending_id (pending_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + GST_SECOND - 1); + gst_clock_id_unref (pending_id); + processed_id = gst_test_clock_process_next_clock_id (test_clock); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + GST_CLOCK_EARLY); + gst_clock_id_unref (processed_id); + g_thread_join (worker_thread); + g_assert_cmpuint (context.jitter, ==, 1); + gst_clock_id_unref (context.clock_id); + gst_clock_id_unref (clock_id); + + clock_id = gst_clock_new_single_shot_id (clock, GST_SECOND); + context.clock_id = gst_clock_id_ref (clock_id); + context.jitter = 0; + worker_thread = + g_thread_new ("worker_thread", + test_wait_pending_single_shot_id_sync_worker, &context); + gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); + assert_pending_id (pending_id, clock_id, GST_CLOCK_ENTRY_SINGLE, GST_SECOND); + gst_clock_id_unref (pending_id); + processed_id = gst_test_clock_process_next_clock_id (test_clock); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + g_thread_join (worker_thread); + g_assert_cmpuint (context.jitter, ==, 0); + gst_clock_id_unref (context.clock_id); + gst_clock_id_unref (clock_id); + + clock_id = gst_clock_new_single_shot_id (clock, GST_SECOND + 1); + context.clock_id = gst_clock_id_ref (clock_id); + context.jitter = 0; + worker_thread = + g_thread_new ("worker_thread", + test_wait_pending_single_shot_id_sync_worker, &context); + gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); + assert_pending_id (pending_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + GST_SECOND + 1); + gst_clock_id_unref (pending_id); + processed_id = gst_test_clock_process_next_clock_id (test_clock); + g_assert (processed_id == NULL); + gst_test_clock_advance_time (test_clock, 1); + processed_id = gst_test_clock_process_next_clock_id (test_clock); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + g_thread_join (worker_thread); + g_assert_cmpuint (context.jitter, ==, -1); + gst_clock_id_unref (context.clock_id); + gst_clock_id_unref (clock_id); + + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_wait_pending_single_shot_id) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id; + GstClockID processed_id; + GThread *worker_thread; + GstClockID pending_id; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + + clock_id = gst_clock_new_single_shot_id (clock, GST_SECOND); + gst_clock_id_wait_async (clock_id, test_async_wait_cb, NULL, NULL); + gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); + assert_pending_id (pending_id, clock_id, GST_CLOCK_ENTRY_SINGLE, GST_SECOND); + gst_clock_id_unref (pending_id); + processed_id = gst_test_clock_process_next_clock_id (test_clock); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + gst_clock_id_unref (clock_id); + + clock_id = gst_clock_new_single_shot_id (clock, 2 * GST_SECOND); + worker_thread = + g_thread_new ("worker_thread", + test_wait_pending_single_shot_id_async_worker, clock_id); + gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); + assert_pending_id (pending_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + 2 * GST_SECOND); + gst_clock_id_unref (pending_id); + g_thread_join (worker_thread); + gst_clock_id_unref (clock_id); + + clock_id = gst_clock_new_single_shot_id (clock, 3 * GST_SECOND); + worker_thread = + g_thread_new ("worker_thread", + test_wait_pending_single_shot_id_async_worker, clock_id); + gst_test_clock_wait_for_next_pending_id (test_clock, NULL); + g_thread_join (worker_thread); + gst_clock_id_unref (clock_id); + + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_wait_pending_periodic_id) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id; + GstClockID processed_id; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + clock_id = gst_clock_new_periodic_id (clock, GST_SECOND, GST_MSECOND); + + { + GThread *waiter_thread; + + waiter_thread = + g_thread_new ("waiter_thread", + test_wait_pending_periodic_id_waiter_thread, clock_id); + + gst_test_clock_wait_for_next_pending_id (test_clock, NULL); + gst_test_clock_set_time (test_clock, GST_SECOND); + processed_id = gst_test_clock_process_next_clock_id (test_clock); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_PERIODIC, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + + g_thread_join (waiter_thread); + } + + { + guint i; + GThread *waiter_thread; + + for (i = 0; i < 3; i++) { + g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL)); + g_usleep (G_USEC_PER_SEC / 10 / 10); + } + + waiter_thread = + g_thread_new ("waiter_thread", + test_wait_pending_periodic_id_waiter_thread, clock_id); + + gst_test_clock_wait_for_next_pending_id (test_clock, NULL); + gst_clock_id_unschedule (clock_id); + + g_thread_join (waiter_thread); + } + + gst_clock_id_unref (clock_id); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_sync_past) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id; + GstClockTimeDiff jitter; + GtuClockWaitContext *wait_ctx; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + + clock_id = gst_clock_new_single_shot_id (clock, GST_SECOND - 1); + wait_ctx = + gst_test_util_wait_for_clock_id_begin (test_clock, clock_id, &jitter); + g_assert (gst_test_util_wait_for_clock_id_end (wait_ctx) == GST_CLOCK_EARLY); + g_assert_cmpint (jitter, ==, 1); + gst_clock_id_unref (clock_id); + + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_sync_present) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id; + GstClockTimeDiff jitter; + GtuClockWaitContext *wait_ctx; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + + clock_id = gst_clock_new_single_shot_id (clock, GST_SECOND); + wait_ctx = + gst_test_util_wait_for_clock_id_begin (test_clock, clock_id, &jitter); + g_assert (gst_test_util_wait_for_clock_id_end (wait_ctx) == GST_CLOCK_OK); + g_assert_cmpint (jitter, ==, 0); + gst_clock_id_unref (clock_id); + + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_sync_future) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id; + GstClockTimeDiff jitter; + GtuClockWaitContext *wait_ctx; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + + clock_id = gst_clock_new_single_shot_id (clock, 2 * GST_SECOND); + wait_ctx = + gst_test_util_wait_for_clock_id_begin (test_clock, clock_id, &jitter); + gst_test_clock_advance_time (test_clock, GST_SECOND); + g_assert (gst_test_util_wait_for_clock_id_end (wait_ctx) == GST_CLOCK_OK); + g_assert_cmpint (jitter, ==, -GST_SECOND); + gst_clock_id_unref (clock_id); + + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_sync_unschedule) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id; + GtuClockWaitContext *wait_ctx; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + + clock_id = gst_clock_new_single_shot_id (clock, GST_SECOND); + gst_clock_id_unschedule (clock_id); + gst_clock_id_unref (clock_id); + + clock_id = gst_clock_new_single_shot_id (clock, 2 * GST_SECOND); + wait_ctx = gst_test_util_wait_for_clock_id_begin (test_clock, clock_id, NULL); + gst_clock_id_unschedule (clock_id); + g_assert (gst_test_util_wait_for_clock_id_end (wait_ctx) + == GST_CLOCK_UNSCHEDULED); + gst_clock_id_unref (clock_id); + + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_sync_ordering) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id_a, clock_id_b; + GtuClockWaitContext *wait_ctx_a, *wait_ctx_b; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + + clock_id_a = gst_clock_new_single_shot_id (clock, 3 * GST_SECOND); + wait_ctx_a = + gst_test_util_wait_for_clock_id_begin (test_clock, clock_id_a, NULL); + + gst_test_clock_advance_time (test_clock, GST_SECOND); + + clock_id_b = gst_clock_new_single_shot_id (clock, 2 * GST_SECOND); + wait_ctx_b = + gst_test_util_wait_for_clock_id_begin (test_clock, clock_id_b, NULL); + + gst_test_clock_advance_time (test_clock, GST_SECOND); + + g_assert (gst_test_util_wait_for_clock_id_end (wait_ctx_b) == GST_CLOCK_OK); + g_assert (gst_test_util_wait_for_clock_id_end (wait_ctx_a) == GST_CLOCK_OK); + + gst_clock_id_unref (clock_id_b); + gst_clock_id_unref (clock_id_a); + + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_sync_ordering_parallel) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id_a, clock_id_b; + GtuClockWaitContext *wait_ctx_a, *wait_ctx_b; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + + clock_id_a = gst_clock_new_single_shot_id (clock, 3 * GST_SECOND); + clock_id_b = gst_clock_new_single_shot_id (clock, 2 * GST_SECOND); + wait_ctx_a = gst_test_util_wait_for_clock_id_begin (test_clock, clock_id_a, + NULL); + wait_ctx_b = gst_test_util_wait_for_clock_id_begin (test_clock, clock_id_b, + NULL); + + g_assert_cmpuint (gst_test_clock_get_next_entry_time (test_clock), ==, + 2 * GST_SECOND); + gst_test_clock_advance_time (test_clock, GST_SECOND); + g_assert (gst_test_util_wait_for_clock_id_end (wait_ctx_b) == GST_CLOCK_OK); + + g_assert_cmpuint (gst_test_clock_get_next_entry_time (test_clock), ==, + 3 * GST_SECOND); + gst_test_clock_advance_time (test_clock, GST_SECOND); + g_assert (gst_test_util_wait_for_clock_id_end (wait_ctx_a) == GST_CLOCK_OK); + + gst_clock_id_unref (clock_id_b); + gst_clock_id_unref (clock_id_a); + + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_sync_simultaneous_no_timeout) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id_a; + GstClockID clock_id_b; + SyncClockWaitContext context_a; + SyncClockWaitContext context_b; + GThread *worker_thread_a; + GThread *worker_thread_b; + GstClockID processed_id; + GstClockID pending_id; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + test_clock = GST_TEST_CLOCK (clock); + + clock_id_a = gst_clock_new_single_shot_id (clock, 5 * GST_SECOND); + clock_id_b = gst_clock_new_single_shot_id (clock, 6 * GST_SECOND); + + context_a.clock_id = gst_clock_id_ref (clock_id_a); + context_a.jitter = 0; + context_b.clock_id = gst_clock_id_ref (clock_id_b); + context_b.jitter = 0; + + gst_test_clock_wait_for_pending_id_count (test_clock, 0); + + worker_thread_b = + g_thread_new ("worker_thread_b", + test_wait_pending_single_shot_id_sync_worker, &context_b); + + gst_test_clock_wait_for_pending_id_count (test_clock, 1); + gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); + assert_pending_id (pending_id, clock_id_b, GST_CLOCK_ENTRY_SINGLE, + 6 * GST_SECOND); + gst_clock_id_unref (pending_id); + + worker_thread_a = + g_thread_new ("worker_thread_a", + test_wait_pending_single_shot_id_sync_worker, &context_a); + + gst_test_clock_wait_for_pending_id_count (test_clock, 2); + gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); + assert_pending_id (pending_id, clock_id_a, GST_CLOCK_ENTRY_SINGLE, + 5 * GST_SECOND); + gst_clock_id_unref (pending_id); + + g_assert_cmpuint (gst_test_clock_get_next_entry_time (test_clock), ==, + 5 * GST_SECOND); + gst_test_clock_advance_time (test_clock, 5 * GST_SECOND); + processed_id = gst_test_clock_process_next_clock_id (test_clock); + assert_processed_id (processed_id, clock_id_a, GST_CLOCK_ENTRY_SINGLE, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + + gst_test_clock_wait_for_pending_id_count (test_clock, 1); + gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); + assert_pending_id (pending_id, clock_id_b, GST_CLOCK_ENTRY_SINGLE, + 6 * GST_SECOND); + gst_clock_id_unref (pending_id); + + g_assert_cmpuint (gst_test_clock_get_next_entry_time (test_clock), ==, + 6 * GST_SECOND); + gst_test_clock_advance_time (test_clock, 6 * GST_SECOND); + processed_id = gst_test_clock_process_next_clock_id (test_clock); + assert_processed_id (processed_id, clock_id_b, GST_CLOCK_ENTRY_SINGLE, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + + gst_test_clock_wait_for_pending_id_count (test_clock, 0); + + g_thread_join (worker_thread_a); + g_thread_join (worker_thread_b); + + g_assert_cmpuint (context_a.jitter, ==, -4 * GST_SECOND); + g_assert_cmpuint (context_b.jitter, ==, -5 * GST_SECOND); + + gst_clock_id_unref (context_a.clock_id); + gst_clock_id_unref (context_b.clock_id); + + gst_clock_id_unref (clock_id_a); + gst_clock_id_unref (clock_id_b); + + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_async_past) +{ + GstClock *clock; + GstClockID clock_id; + GstClockID processed_id; + gboolean wait_complete = FALSE; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + clock_id = gst_clock_new_single_shot_id (clock, GST_SECOND - 1); + g_assert (gst_clock_id_wait_async (clock_id, test_async_wait_cb, + &wait_complete, NULL) == GST_CLOCK_OK); + g_assert (!wait_complete); + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + g_assert (wait_complete); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + GST_CLOCK_EARLY); + gst_clock_id_unref (processed_id); + gst_clock_id_unref (clock_id); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_async_present) +{ + GstClock *clock; + GstClockID clock_id; + GstClockID processed_id; + gboolean wait_complete = FALSE; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + clock_id = gst_clock_new_single_shot_id (clock, GST_SECOND); + g_assert (gst_clock_id_wait_async (clock_id, test_async_wait_cb, + &wait_complete, NULL) == GST_CLOCK_OK); + g_assert (!wait_complete); + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + g_assert (wait_complete); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + gst_clock_id_unref (clock_id); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_async_future) +{ + GstClock *clock; + GstClockID clock_id; + GstClockID processed_id; + gboolean wait_complete = FALSE; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + clock_id = gst_clock_new_single_shot_id (clock, 2 * GST_SECOND); + g_assert (gst_clock_id_wait_async (clock_id, test_async_wait_cb, + &wait_complete, NULL) == GST_CLOCK_OK); + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + g_assert (processed_id == NULL); + g_assert (!wait_complete); + g_assert (GST_CLOCK_ENTRY_STATUS (GST_CLOCK_ENTRY (clock_id)) + == GST_CLOCK_OK); + + gst_test_clock_advance_time (GST_TEST_CLOCK (clock), GST_SECOND - 1); + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + g_assert (processed_id == NULL); + g_assert (!wait_complete); + g_assert (GST_CLOCK_ENTRY_STATUS (GST_CLOCK_ENTRY (clock_id)) + == GST_CLOCK_OK); + + gst_test_clock_advance_time (GST_TEST_CLOCK (clock), 1); + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + g_assert (wait_complete); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_SINGLE, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + g_assert (GST_CLOCK_ENTRY_STATUS (GST_CLOCK_ENTRY (clock_id)) + == GST_CLOCK_OK); + + gst_clock_id_unref (clock_id); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_single_shot_async_unschedule) +{ + GstClock *clock; + GstClockID clock_id; + gboolean wait_complete = FALSE; + + clock = gst_test_clock_new_with_start_time (GST_SECOND); + + clock_id = gst_clock_new_single_shot_id (clock, 3 * GST_SECOND); + g_assert (gst_clock_id_wait_async (clock_id, test_async_wait_cb, + &wait_complete, NULL) == GST_CLOCK_OK); + + gst_clock_id_unschedule (clock_id); + + gst_test_clock_advance_time (GST_TEST_CLOCK (clock), 2 * GST_SECOND); + g_assert (gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)) + == NULL); + g_assert (!wait_complete); + + gst_clock_id_unref (clock_id); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_periodic_sync) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id; + guint i; + const GstClockTime interval = 4 * GST_MSECOND; + + clock = gst_test_clock_new (); + test_clock = GST_TEST_CLOCK (clock); + + clock_id = gst_clock_new_periodic_id (clock, GST_SECOND, interval); + + for (i = 0; i < 3; i++) { + GtuClockWaitContext *wait_ctx; + GstClockID pending_id; + guint j; + + wait_ctx = + gst_test_util_wait_for_clock_id_begin (test_clock, clock_id, NULL); + + gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); + assert_pending_id (pending_id, clock_id, GST_CLOCK_ENTRY_PERIODIC, + GST_SECOND + (i * interval)); + gst_clock_id_unref (pending_id); + + for (j = 0; j < 10; j++) { + g_usleep (G_USEC_PER_SEC / 10 / 10); + g_assert (!gst_test_util_clock_wait_context_has_completed (wait_ctx)); + } + + if (i == 0) + gst_test_clock_advance_time (test_clock, GST_SECOND); + else + gst_test_clock_advance_time (test_clock, interval); + + gst_test_util_wait_for_clock_id_end (wait_ctx); + } + + gst_clock_id_unref (clock_id); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_periodic_async) +{ + GstClock *clock; + GstClockID clock_id; + GstClockID processed_id; + gboolean wait_complete = FALSE; + const GstClockTime interval = 4 * GST_MSECOND; + + clock = gst_test_clock_new (); + clock_id = gst_clock_new_periodic_id (clock, gst_clock_get_time (clock), + interval); + g_assert (gst_clock_id_wait_async (clock_id, test_async_wait_cb, + &wait_complete, NULL) == GST_CLOCK_OK); + + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_PERIODIC, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + + g_assert (wait_complete); + wait_complete = FALSE; + + gst_test_clock_advance_time (GST_TEST_CLOCK (clock), interval - 1); + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + g_assert (processed_id == NULL); + g_assert (!wait_complete); + + gst_test_clock_advance_time (GST_TEST_CLOCK (clock), 1); + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_PERIODIC, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + g_assert (wait_complete); + wait_complete = FALSE; + + gst_test_clock_advance_time (GST_TEST_CLOCK (clock), interval - 1); + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + g_assert (processed_id == NULL); + g_assert (!wait_complete); + + gst_test_clock_advance_time (GST_TEST_CLOCK (clock), 1); + processed_id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (clock)); + assert_processed_id (processed_id, clock_id, GST_CLOCK_ENTRY_PERIODIC, + GST_CLOCK_OK); + gst_clock_id_unref (processed_id); + g_assert (wait_complete); + wait_complete = FALSE; + + gst_clock_id_unref (clock_id); + gst_object_unref (clock); +} + +GST_END_TEST; + +GST_START_TEST (test_periodic_uniqueness) +{ + GstClock *clock; + GstTestClock *test_clock; + GstClockID clock_id; + guint i; + const GstClockTime interval = 4 * GST_MSECOND; + + clock = gst_test_clock_new (); + test_clock = GST_TEST_CLOCK (clock); + + clock_id = gst_clock_new_periodic_id (clock, 0, interval); + + for (i = 0; i < 3; i++) { + GtuClockWaitContext *wait_ctx; + guint j; + + wait_ctx = + gst_test_util_wait_for_clock_id_begin (test_clock, clock_id, NULL); + + for (j = 0; j < 10; j++) { + g_usleep (G_USEC_PER_SEC / 10 / 10); + g_assert_cmpuint (gst_test_clock_peek_id_count (test_clock), ==, 1); + } + + gst_test_clock_advance_time (test_clock, interval); + gst_test_util_wait_for_clock_id_end (wait_ctx); + } + + gst_clock_id_unref (clock_id); + gst_object_unref (clock); +} + +GST_END_TEST; + +static Suite * +gst_test_clock_suite (void) +{ + Suite *s = suite_create ("GstTestClock"); + TCase *tc_chain = tcase_create ("testclock"); + + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_object_flags); + tcase_add_test (tc_chain, test_resolution_query); + tcase_add_test (tc_chain, test_start_time); + tcase_add_test (tc_chain, test_set_time); + tcase_add_test (tc_chain, test_advance_time); + tcase_add_test (tc_chain, test_wait_synchronous_no_timeout); + tcase_add_test (tc_chain, test_wait_pending_single_shot_id); + tcase_add_test (tc_chain, test_wait_pending_periodic_id); + tcase_add_test (tc_chain, test_single_shot_sync_simultaneous_no_timeout); + tcase_add_test (tc_chain, test_single_shot_sync_past); + tcase_add_test (tc_chain, test_single_shot_sync_present); + tcase_add_test (tc_chain, test_single_shot_sync_future); + tcase_add_test (tc_chain, test_single_shot_sync_unschedule); + tcase_add_test (tc_chain, test_single_shot_sync_ordering); + tcase_add_test (tc_chain, test_single_shot_sync_ordering_parallel); + tcase_add_test (tc_chain, test_single_shot_async_past); + tcase_add_test (tc_chain, test_single_shot_async_present); + tcase_add_test (tc_chain, test_single_shot_async_future); + tcase_add_test (tc_chain, test_single_shot_async_unschedule); + tcase_add_test (tc_chain, test_periodic_sync); + tcase_add_test (tc_chain, test_periodic_async); + tcase_add_test (tc_chain, test_periodic_uniqueness); + + return s; +} + +GST_CHECK_MAIN (gst_test_clock); |