gstreamer/tests/check/libs/gsttestclock.c
Havard Graff 3892cc4c2d testclock: add support for waiting and releasing multiple GstClockIDs
In order to be deterministic, multiple waiting GstClockIDs needs to be
released at the same time, or else one can get into the situation that
the one being released first can add itself back again before the next
one waiting is released.

Test added for new API and old tests rewritten to comply.
2014-04-12 15:33:31 +01:00

1038 lines
33 KiB
C

/*
* 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;
gboolean wait_complete = FALSE;
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);
/* any wait should timeout immediately */
g_assert (gst_clock_id_wait_async (clock_id, test_async_wait_cb,
&wait_complete, NULL) == GST_CLOCK_UNSCHEDULED);
g_assert (gst_clock_id_wait (clock_id, NULL) == GST_CLOCK_UNSCHEDULED);
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_multiple_pending_ids (test_clock, 0, NULL);
worker_thread_b =
g_thread_new ("worker_thread_b",
test_wait_pending_single_shot_id_sync_worker, &context_b);
gst_test_clock_wait_for_multiple_pending_ids (test_clock, 1, NULL);
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_multiple_pending_ids (test_clock, 2, NULL);
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_multiple_pending_ids (test_clock, 1, NULL);
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_multiple_pending_ids (test_clock, 0, NULL);
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_processing_multiple_ids)
{
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;
GstTestClockIDList * pending_list;
clock = gst_test_clock_new_with_start_time (GST_SECOND);
test_clock = GST_TEST_CLOCK (clock);
/* register a wait for 5 seconds */
clock_id_a = gst_clock_new_single_shot_id (clock, 5 * GST_SECOND);
context_a.clock_id = gst_clock_id_ref (clock_id_a);
context_a.jitter = 0;
worker_thread_a =
g_thread_new ("worker_thread_a",
test_wait_pending_single_shot_id_sync_worker, &context_a);
/* register another wait for 6 seconds */
clock_id_b = gst_clock_new_single_shot_id (clock, 6 * GST_SECOND);
context_b.clock_id = gst_clock_id_ref (clock_id_b);
context_b.jitter = 0;
worker_thread_b =
g_thread_new ("worker_thread_b",
test_wait_pending_single_shot_id_sync_worker, &context_b);
/* wait for two waits */
gst_test_clock_wait_for_multiple_pending_ids (test_clock, 2, &pending_list);
/* assert they are correct */
assert_pending_id (pending_list->cur->data, clock_id_a, GST_CLOCK_ENTRY_SINGLE,
5 * GST_SECOND);
assert_pending_id (pending_list->cur->next->data, clock_id_b, GST_CLOCK_ENTRY_SINGLE,
6 * GST_SECOND);
/* verify we are waiting for 6 seconds as the latest time */
fail_unless_equals_int64 (6 * GST_SECOND,
gst_test_clock_id_list_get_latest_time (pending_list));
/* process both ID's at the same time */
gst_test_clock_process_id_list (test_clock, pending_list);
gst_test_clock_id_list_free (pending_list);
g_thread_join (worker_thread_a);
g_thread_join (worker_thread_b);
fail_unless_equals_int64 (-4 * GST_SECOND, context_a.jitter);
fail_unless_equals_int64 (-5 * GST_SECOND, context_b.jitter);
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_processing_multiple_ids);
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);