And correct even more valid sparse warnings.
[platform/upstream/gstreamer.git] / tests / check / gst / gstsystemclock.c
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
3  *
4  * gstsystemclock.c: Unit test for GstSystemClock
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <gst/check/gstcheck.h>
23
24 /* see if the defines make sense */
25 GST_START_TEST (test_range)
26 {
27   GstClockTime time, time2;
28
29   time = GST_SECOND;
30   fail_unless (time == G_GUINT64_CONSTANT (1000000000));
31
32   time2 = time / 1000;
33   fail_unless (time2 == 1000000);
34   fail_unless (time2 == GST_MSECOND);
35   fail_unless (time2 == GST_TIME_AS_USECONDS (time));
36
37   time2 = time / 1000000;
38   fail_unless (time2 == 1000);
39   fail_unless (time2 == GST_USECOND);
40   fail_unless (time2 == GST_TIME_AS_MSECONDS (time));
41 }
42
43 GST_END_TEST;
44
45 GST_START_TEST (test_signedness)
46 {
47   GstClockTime time[] = { 0, 1, G_MAXUINT64 / GST_SECOND };
48   GstClockTimeDiff diff[] =
49       { 0, 1, -1, G_MAXINT64 / GST_SECOND, G_MININT64 / GST_SECOND };
50   guint i;
51
52   for (i = 0; i < G_N_ELEMENTS (time); i++) {
53     fail_if (time[i] != (time[i] * GST_SECOND / GST_SECOND));
54   }
55   for (i = 0; i < G_N_ELEMENTS (diff); i++) {
56     fail_if (diff[i] != (diff[i] * GST_SECOND / GST_SECOND));
57   }
58 }
59
60 GST_END_TEST;
61
62 #define TIME_UNIT (GST_SECOND / 5)
63 static void
64 gst_clock_debug (GstClock * clock)
65 {
66   GstClockTime time;
67
68   time = gst_clock_get_time (clock);
69   GST_DEBUG ("Clock info: time %" GST_TIME_FORMAT, GST_TIME_ARGS (time));
70 }
71
72 static gboolean
73 ok_callback (GstClock * clock, GstClockTime time,
74     GstClockID id, gpointer user_data)
75 {
76   GST_LOG ("unlocked async id %p", id);
77   return FALSE;
78 }
79
80 static gboolean
81 error_callback (GstClock * clock, GstClockTime time,
82     GstClockID id, gpointer user_data)
83 {
84   GST_WARNING ("unlocked unscheduled async id %p, this is wrong", id);
85   fail_if (TRUE);
86
87   return FALSE;
88 }
89
90 static gboolean
91 store_callback (GstClock * clock, GstClockTime time,
92     GstClockID id, gpointer user_data)
93 {
94   GList **list = user_data;
95
96   GST_DEBUG ("unlocked async id %p", id);
97   *list = g_list_append (*list, id);
98   return FALSE;
99 }
100
101 static gboolean
102 notify_callback (GstClock * clock, GstClockTime time,
103     GstClockID id, gpointer user_data)
104 {
105   gboolean *ret = (gboolean *) user_data;
106
107   if (ret != NULL)
108     *ret = TRUE;
109
110   return FALSE;
111 }
112
113 GST_START_TEST (test_single_shot)
114 {
115   GstClock *clock;
116   GstClockID id, id2;
117   GstClockTime base;
118   GstClockReturn result;
119
120   clock = gst_system_clock_obtain ();
121   fail_unless (clock != NULL, "Could not create instance of GstSystemClock");
122
123   gst_clock_debug (clock);
124   base = gst_clock_get_time (clock);
125
126   id = gst_clock_new_single_shot_id (clock, base + TIME_UNIT);
127   fail_unless (id != NULL, "Could not create single shot id");
128
129   GST_DEBUG ("waiting one time unit");
130   result = gst_clock_id_wait (id, NULL);
131   gst_clock_debug (clock);
132   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK (result=%d)",
133       result);
134   fail_unless (gst_clock_get_time (clock) > (base + TIME_UNIT),
135       "target time has not been reached");
136
137   GST_DEBUG ("waiting in the past");
138   result = gst_clock_id_wait (id, NULL);
139   gst_clock_debug (clock);
140   fail_unless (result == GST_CLOCK_EARLY,
141       "Waiting did not return EARLY(result=%d)", result);
142   gst_clock_id_unref (id);
143
144   id = gst_clock_new_single_shot_id (clock, base + 2 * TIME_UNIT);
145   GST_DEBUG ("waiting one second async id %p", id);
146   result = gst_clock_id_wait_async (id, ok_callback, NULL);
147   gst_clock_id_unref (id);
148   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
149   g_usleep (TIME_UNIT / (2 * 1000));
150
151   id = gst_clock_new_single_shot_id (clock, base + 5 * TIME_UNIT);
152   GST_DEBUG ("waiting one second async, with cancel on id %p", id);
153   result = gst_clock_id_wait_async (id, error_callback, NULL);
154   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
155   g_usleep (TIME_UNIT / (2 * 1000));
156   GST_DEBUG ("cancel id %p after half a time unit", id);
157   gst_clock_id_unschedule (id);
158   gst_clock_id_unref (id);
159   GST_DEBUG ("canceled id %p", id);
160
161   GST_DEBUG ("waiting multiple one second async, with cancel");
162   id = gst_clock_new_single_shot_id (clock, base + 5 * TIME_UNIT);
163   id2 = gst_clock_new_single_shot_id (clock, base + 6 * TIME_UNIT);
164   GST_DEBUG ("waiting id %p", id);
165   result = gst_clock_id_wait_async (id, ok_callback, NULL);
166   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
167   gst_clock_id_unref (id);
168   GST_DEBUG ("waiting id %p", id2);
169   result = gst_clock_id_wait_async (id2, error_callback, NULL);
170   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
171   g_usleep (TIME_UNIT / (2 * 1000));
172   GST_DEBUG ("cancel id %p after half a time unit", id2);
173   gst_clock_id_unschedule (id2);
174   GST_DEBUG ("canceled id %p", id2);
175   gst_clock_id_unref (id2);
176   g_usleep (TIME_UNIT / (2 * 1000));
177 }
178
179 GST_END_TEST;
180
181 GST_START_TEST (test_periodic_shot)
182 {
183   GstClock *clock;
184   GstClockID id, id2;
185   GstClockTime base;
186   GstClockReturn result;
187
188   clock = gst_system_clock_obtain ();
189   fail_unless (clock != NULL, "Could not create instance of GstSystemClock");
190
191   gst_clock_debug (clock);
192   base = gst_clock_get_time (clock);
193
194   /* signal every half a time unit */
195   id = gst_clock_new_periodic_id (clock, base + TIME_UNIT, TIME_UNIT / 2);
196   fail_unless (id != NULL, "Could not create periodic id");
197
198   GST_DEBUG ("waiting one time unit");
199   result = gst_clock_id_wait (id, NULL);
200   gst_clock_debug (clock);
201   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
202
203   GST_DEBUG ("waiting for the next");
204   result = gst_clock_id_wait (id, NULL);
205   gst_clock_debug (clock);
206   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
207
208   GST_DEBUG ("waiting for the next async %p", id);
209   result = gst_clock_id_wait_async (id, ok_callback, NULL);
210   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
211   g_usleep (TIME_UNIT / (2 * 1000));
212
213   GST_DEBUG ("waiting some more for the next async %p", id);
214   result = gst_clock_id_wait_async (id, ok_callback, NULL);
215   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
216   g_usleep (TIME_UNIT / (2 * 1000));
217
218   id2 = gst_clock_new_periodic_id (clock, base + TIME_UNIT, TIME_UNIT / 2);
219   fail_unless (id2 != NULL, "Could not create second periodic id");
220
221   GST_DEBUG ("waiting some more for another async %p", id2);
222   result = gst_clock_id_wait_async (id2, ok_callback, NULL);
223   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
224   g_usleep (TIME_UNIT / (2 * 1000));
225
226   GST_DEBUG ("unschedule %p", id);
227   gst_clock_id_unschedule (id);
228
229   /* entry cannot be used again */
230   result = gst_clock_id_wait_async (id, error_callback, NULL);
231   fail_unless (result == GST_CLOCK_UNSCHEDULED,
232       "Waiting did not return UNSCHEDULED");
233   result = gst_clock_id_wait (id, NULL);
234   fail_unless (result == GST_CLOCK_UNSCHEDULED,
235       "Waiting did not return UNSCHEDULED");
236   g_usleep (TIME_UNIT / (2 * 1000));
237
238   /* clean up */
239   gst_clock_id_unref (id);
240 }
241
242 GST_END_TEST;
243
244 GST_START_TEST (test_async_order)
245 {
246   GstClock *clock;
247   GstClockID id1, id2;
248   GList *cb_list = NULL, *next;
249   GstClockTime base;
250   GstClockReturn result;
251
252   clock = gst_system_clock_obtain ();
253   fail_unless (clock != NULL, "Could not create instance of GstSystemClock");
254
255   gst_clock_debug (clock);
256   base = gst_clock_get_time (clock);
257
258   id1 = gst_clock_new_single_shot_id (clock, base + 2 * TIME_UNIT);
259   id2 = gst_clock_new_single_shot_id (clock, base + 1 * TIME_UNIT);
260   result = gst_clock_id_wait_async (id1, store_callback, &cb_list);
261   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
262   g_usleep (TIME_UNIT / (2 * 1000));
263   result = gst_clock_id_wait_async (id2, store_callback, &cb_list);
264   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
265   g_usleep (TIME_UNIT / 1000);
266   /* at this point at least one of the timers should have timed out */
267   fail_unless (cb_list != NULL, "expected notification");
268   fail_unless (cb_list->data == id2,
269       "Expected notification for id2 to come first");
270   g_usleep (TIME_UNIT / 1000);
271   /* now both should have timed out */
272   next = g_list_next (cb_list);
273   fail_unless (next != NULL, "expected second notification");
274   fail_unless (next->data == id1, "Missing notification for id1");
275   gst_clock_id_unref (id1);
276   gst_clock_id_unref (id2);
277   g_list_free (cb_list);
278 }
279
280 GST_END_TEST;
281
282 GST_START_TEST (test_periodic_multi)
283 {
284   GstClock *clock;
285   GstClockID clock_id;
286   GstClockTime base;
287   GstClockReturn result;
288   gboolean got_callback = FALSE;
289
290   clock = gst_system_clock_obtain ();
291   fail_unless (clock != NULL, "Could not create instance of GstSystemClock");
292
293   gst_clock_debug (clock);
294   base = gst_clock_get_time (clock);
295
296   clock_id = gst_clock_new_periodic_id (clock, base + TIME_UNIT, TIME_UNIT);
297   gst_clock_id_wait (clock_id, NULL);
298   fail_unless (gst_clock_get_time (clock) >= base + TIME_UNIT);
299   fail_unless (gst_clock_get_time (clock) < base + 2 * TIME_UNIT);
300
301   /* now perform a concurrent wait and wait_async */
302
303   result = gst_clock_id_wait_async (clock_id, notify_callback, &got_callback);
304   fail_unless (result == GST_CLOCK_OK, "Async waiting did not return OK");
305   fail_unless (got_callback == FALSE);
306   result = gst_clock_id_wait (clock_id, NULL);
307   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
308   fail_unless (gst_clock_get_time (clock) >= base + 2 * TIME_UNIT);
309   /* give the async thread some time to call our callback: */
310   g_usleep (TIME_UNIT / (10 * 1000));
311   fail_unless (got_callback == TRUE, "got no async callback (1)");
312   fail_unless (gst_clock_get_time (clock) < base + 3 * TIME_UNIT);
313   got_callback = FALSE;
314
315   result = gst_clock_id_wait (clock_id, NULL);
316   fail_unless (result == GST_CLOCK_OK, "Waiting did not return OK");
317   fail_unless (gst_clock_get_time (clock) >= base + 3 * TIME_UNIT);
318   /* give the async thread some time to call our callback: */
319   g_usleep (TIME_UNIT / (10 * 1000));
320   fail_unless (got_callback == TRUE, "got no async callback (2)");
321   fail_unless (gst_clock_get_time (clock) < base + 4 * TIME_UNIT);
322 }
323
324 GST_END_TEST;
325
326 GST_START_TEST (test_diff)
327 {
328   GstClockTime time1[] = { 0, (GstClockTime) - 1, 0, 1, 2 * GST_SECOND,
329     (GstClockTime) - GST_SECOND, (GstClockTime) - GST_SECOND
330   };
331   GstClockTime time2[] =
332       { 0, 1, 1, 0, 1 * GST_SECOND, (GstClockTime) - GST_SECOND, GST_SECOND };
333   GstClockTimeDiff d[] = { 0, 2, 1, -1, -GST_SECOND, 0, 2 * GST_SECOND };
334   guint i;
335
336   for (i = 0; i < G_N_ELEMENTS (d); i++) {
337     fail_if (d[i] != GST_CLOCK_DIFF (time1[i], time2[i]));
338   }
339 }
340
341 GST_END_TEST;
342
343 /* test if a blocking wait, unblocked by an async entry continues to be
344  * scheduled */
345 typedef struct
346 {
347   GstClock *clock;
348   GstClockID id;
349   GstClockTimeDiff jitter;
350   GstClockReturn ret;
351 } MixedInfo;
352
353 static gpointer
354 mixed_thread (MixedInfo * info)
355 {
356   info->ret = gst_clock_id_wait (info->id, &info->jitter);
357   return NULL;
358 }
359
360 static gboolean
361 mixed_async_cb (GstClock * clock, GstClockTime time,
362     GstClockID id, gpointer user_data)
363 {
364   return TRUE;
365 }
366
367 GST_START_TEST (test_mixed)
368 {
369   GThread *thread;
370   GError *error = NULL;
371   MixedInfo info;
372   GstClockTime base;
373   GstClockID id;
374
375   info.clock = gst_system_clock_obtain ();
376   fail_unless (info.clock != NULL,
377       "Could not create instance of GstSystemClock");
378
379   /* get current time of the clock as base time */
380   base = gst_clock_get_time (info.clock);
381
382   /* create entry to wait for 1 second */
383   info.id = gst_clock_new_single_shot_id (info.clock, base + GST_SECOND);
384
385   /* make and start an entry that is scheduled every 10ms */
386   id = gst_clock_new_periodic_id (info.clock, base, 10 * GST_MSECOND);
387
388   /* start waiting for the entry */
389   thread = g_thread_create ((GThreadFunc) mixed_thread, &info, TRUE, &error);
390   fail_unless (error == NULL, "error creating thread");
391   fail_unless (thread != NULL, "Could not create thread");
392
393   /* wait half a second so we are sure to be in the thread */
394   g_usleep (G_USEC_PER_SEC / 2);
395
396   /* start scheduling the entry */
397   gst_clock_id_wait_async (id, mixed_async_cb, NULL);
398
399   /* wait for thread to finish */
400   g_thread_join (thread);
401   /* entry must have timed out correctly */
402   fail_unless (info.ret == GST_CLOCK_OK, "clock return was %d", info.ret);
403
404   gst_clock_id_unschedule (id);
405   gst_clock_id_unref (id);
406   gst_clock_id_unref (info.id);
407   gst_object_unref (info.clock);
408 }
409
410 GST_END_TEST;
411
412 static Suite *
413 gst_systemclock_suite (void)
414 {
415   Suite *s = suite_create ("GstSystemClock");
416   TCase *tc_chain = tcase_create ("waiting");
417
418   suite_add_tcase (s, tc_chain);
419   tcase_add_test (tc_chain, test_range);
420   tcase_add_test (tc_chain, test_signedness);
421   tcase_add_test (tc_chain, test_single_shot);
422   tcase_add_test (tc_chain, test_periodic_shot);
423   tcase_add_test (tc_chain, test_periodic_multi);
424   tcase_add_test (tc_chain, test_async_order);
425   tcase_add_test (tc_chain, test_diff);
426   tcase_add_test (tc_chain, test_mixed);
427
428   return s;
429 }
430
431 GST_CHECK_MAIN (gst_systemclock);