2 * Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
4 * gstevent.c: Unit test for event handling
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.
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.
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.
23 #include <gst/check/gstcheck.h>
25 GST_START_TEST (create_events)
27 GstEvent *event, *event2;
28 GstStructure *structure;
32 event = gst_event_new_flush_start ();
33 fail_if (event == NULL);
34 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START);
35 fail_unless (GST_EVENT_IS_UPSTREAM (event));
36 fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
37 fail_if (GST_EVENT_IS_SERIALIZED (event));
38 gst_event_unref (event);
44 event = gst_event_new_flush_stop (TRUE);
45 fail_if (event == NULL);
46 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP);
47 fail_unless (GST_EVENT_IS_UPSTREAM (event));
48 fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
49 fail_unless (GST_EVENT_IS_SERIALIZED (event));
51 gst_event_parse_flush_stop (event, &reset_time);
52 fail_unless (reset_time == TRUE);
53 gst_event_unref (event);
57 event = gst_event_new_eos ();
58 fail_if (event == NULL);
59 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_EOS);
60 fail_if (GST_EVENT_IS_UPSTREAM (event));
61 fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
62 fail_unless (GST_EVENT_IS_SERIALIZED (event));
63 gst_event_unref (event);
67 GstSegment segment, parsed;
69 gst_segment_init (&segment, GST_FORMAT_TIME);
71 segment.applied_rate = 1.0;
73 segment.stop = G_MAXINT64;
74 segment.time = 0xdeadbeef;
76 event = gst_event_new_segment (&segment);
77 fail_if (event == NULL);
78 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT);
79 fail_if (GST_EVENT_IS_UPSTREAM (event));
80 fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
81 fail_unless (GST_EVENT_IS_SERIALIZED (event));
83 gst_event_copy_segment (event, &parsed);
84 fail_unless (parsed.rate == 0.5);
85 fail_unless (parsed.applied_rate == 1.0);
86 fail_unless (parsed.format == GST_FORMAT_TIME);
87 fail_unless (parsed.start == 1);
88 fail_unless (parsed.stop == G_MAXINT64);
89 fail_unless (parsed.time == 0xdeadbeef);
91 gst_event_unref (event);
96 GstTagList *taglist = gst_tag_list_new ();
97 GstTagList *tl2 = NULL;
99 event = gst_event_new_tag (taglist);
100 fail_if (taglist == NULL);
101 fail_if (event == NULL);
102 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_TAG);
103 fail_if (GST_EVENT_IS_UPSTREAM (event));
104 fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
105 fail_unless (GST_EVENT_IS_SERIALIZED (event));
107 gst_event_parse_tag (event, &tl2);
108 fail_unless (taglist == tl2);
109 gst_event_unref (event);
114 GstQOSType t1 = GST_QOS_TYPE_THROTTLE, t2;
115 gdouble p1 = 1.0, p2;
116 GstClockTimeDiff ctd1 = G_GINT64_CONSTANT (10), ctd2;
117 GstClockTime ct1 = G_GUINT64_CONSTANT (20), ct2;
119 event = gst_event_new_qos (t1, p1, ctd1, ct1);
120 fail_if (event == NULL);
121 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_QOS);
122 fail_unless (GST_EVENT_IS_UPSTREAM (event));
123 fail_if (GST_EVENT_IS_DOWNSTREAM (event));
124 fail_if (GST_EVENT_IS_SERIALIZED (event));
126 gst_event_parse_qos (event, &t2, &p2, &ctd2, &ct2);
127 fail_unless (p1 == p2);
128 fail_unless (ctd1 == ctd2);
129 fail_unless (ct1 == ct2);
130 gst_event_parse_qos (event, &t2, &p2, &ctd2, &ct2);
131 fail_unless (t2 == GST_QOS_TYPE_THROTTLE);
132 fail_unless (p1 == p2);
133 fail_unless (ctd1 == ctd2);
134 fail_unless (ct1 == ct2);
135 gst_event_unref (event);
137 ctd1 = G_GINT64_CONSTANT (-10);
138 event = gst_event_new_qos (t1, p1, ctd1, ct1);
139 gst_event_parse_qos (event, &t2, &p2, &ctd2, &ct2);
140 fail_unless (t2 == GST_QOS_TYPE_THROTTLE);
141 gst_event_unref (event);
143 event = gst_event_new_qos (t1, p1, ctd1, ct1);
144 gst_event_parse_qos (event, &t2, &p2, &ctd2, &ct2);
145 fail_unless (t2 == GST_QOS_TYPE_THROTTLE);
146 fail_unless (p1 == p2);
147 fail_unless (ctd1 == ctd2);
148 fail_unless (ct1 == ct2);
149 gst_event_unref (event);
157 GstSeekType cur_type, stop_type;
160 event = gst_event_new_seek (0.5, GST_FORMAT_BYTES,
161 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
162 GST_SEEK_TYPE_SET, 1, GST_SEEK_TYPE_NONE, 0xdeadbeef);
164 fail_if (event == NULL);
165 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_SEEK);
166 fail_unless (GST_EVENT_IS_UPSTREAM (event));
167 fail_if (GST_EVENT_IS_DOWNSTREAM (event));
168 fail_if (GST_EVENT_IS_SERIALIZED (event));
170 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
172 fail_unless (rate == 0.5);
173 fail_unless (format == GST_FORMAT_BYTES);
174 fail_unless (flags == (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE));
175 fail_unless (cur_type == GST_SEEK_TYPE_SET);
176 fail_unless (cur == 1);
177 fail_unless (stop_type == GST_SEEK_TYPE_NONE);
178 fail_unless (stop == 0xdeadbeef);
180 gst_event_unref (event);
185 structure = gst_structure_new ("application/x-gst-navigation", "event",
186 G_TYPE_STRING, "key-press", "key", G_TYPE_STRING, "mon", NULL);
187 fail_if (structure == NULL);
188 event = gst_event_new_navigation (structure);
189 fail_if (event == NULL);
190 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION);
191 fail_unless (GST_EVENT_IS_UPSTREAM (event));
192 fail_if (GST_EVENT_IS_DOWNSTREAM (event));
193 fail_if (GST_EVENT_IS_SERIALIZED (event));
195 fail_unless (gst_event_get_structure (event) == structure);
196 gst_event_unref (event);
199 /* Custom event types */
201 structure = gst_structure_empty_new ("application/x-custom");
202 fail_if (structure == NULL);
203 event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure);
204 fail_if (event == NULL);
205 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM);
206 fail_unless (GST_EVENT_IS_UPSTREAM (event));
207 fail_if (GST_EVENT_IS_DOWNSTREAM (event));
208 fail_if (GST_EVENT_IS_SERIALIZED (event));
209 fail_unless (gst_event_get_structure (event) == structure);
210 fail_unless (gst_event_has_name (event, "application/x-custom"));
211 gst_event_unref (event);
213 /* Decided not to test the other custom enum types, as they
214 * only differ by the value of the enum passed to gst_event_new_custom
220 structure = gst_structure_empty_new ("application/x-custom");
221 fail_if (structure == NULL);
222 event = gst_event_new_custom (GST_EVENT_CUSTOM_BOTH, structure);
224 fail_if (event == NULL);
225 event2 = gst_event_copy (event);
226 fail_if (event2 == NULL);
227 fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_TYPE (event2));
228 fail_unless (gst_event_has_name (event, "application/x-custom"));
230 /* The structure should have been duplicated */
231 fail_if (gst_event_get_structure (event) ==
232 gst_event_get_structure (event2));
234 gst_event_unref (event);
235 gst_event_unref (event2);
238 /* Make events writable */
240 structure = gst_structure_empty_new ("application/x-custom");
241 fail_if (structure == NULL);
242 event = gst_event_new_custom (GST_EVENT_CUSTOM_BOTH, structure);
243 /* ref the event so that it becomes non-writable */
244 gst_event_ref (event);
245 gst_event_ref (event);
246 /* this should fail if the structure isn't writable */
247 ASSERT_CRITICAL (gst_structure_remove_all_fields ((GstStructure *)
248 gst_event_get_structure (event)));
249 fail_unless (gst_event_has_name (event, "application/x-custom"));
251 /* now make writable */
253 GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
254 fail_unless (event != event2);
255 /* this fail if the structure isn't writable */
256 gst_structure_remove_all_fields ((GstStructure *)
257 gst_event_get_structure (event2));
258 fail_unless (gst_event_has_name (event2, "application/x-custom"));
260 gst_event_unref (event);
261 gst_event_unref (event);
262 gst_event_unref (event2);
268 static GTimeVal sent_event_time;
269 static GstEvent *got_event_before_q, *got_event_after_q;
270 static GTimeVal got_event_time;
272 static GstProbeReturn
273 event_probe (GstPad * pad, GstProbeType type, gpointer type_data,
276 GstMiniObject *data = type_data;
277 gboolean before_q = (gboolean) GPOINTER_TO_INT (user_data);
279 GST_DEBUG ("event probe called %p", data);
281 fail_unless (GST_IS_EVENT (data));
284 switch (GST_EVENT_TYPE (GST_EVENT (data))) {
285 case GST_EVENT_CUSTOM_UPSTREAM:
286 case GST_EVENT_CUSTOM_BOTH:
287 case GST_EVENT_CUSTOM_BOTH_OOB:
288 if (got_event_before_q != NULL)
290 gst_event_ref ((GstEvent *) data);
291 g_get_current_time (&got_event_time);
292 got_event_before_q = GST_EVENT (data);
298 switch (GST_EVENT_TYPE (GST_EVENT (data))) {
299 case GST_EVENT_CUSTOM_DOWNSTREAM:
300 case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
301 case GST_EVENT_CUSTOM_BOTH:
302 case GST_EVENT_CUSTOM_BOTH_OOB:
303 if (got_event_after_q != NULL)
305 gst_event_ref ((GstEvent *) data);
306 g_get_current_time (&got_event_time);
307 got_event_after_q = GST_EVENT (data);
326 signal_data_init (SignalData * data)
328 GST_DEBUG ("init %p", data);
329 data->lock = g_mutex_new ();
330 data->cond = g_cond_new ();
331 data->signaled = FALSE;
335 signal_data_cleanup (SignalData * data)
337 GST_DEBUG ("free %p", data);
338 g_mutex_free (data->lock);
339 g_cond_free (data->cond);
343 signal_data_signal (SignalData * data)
345 g_mutex_lock (data->lock);
346 data->signaled = TRUE;
347 g_cond_broadcast (data->cond);
348 GST_DEBUG ("signaling %p", data);
349 g_mutex_unlock (data->lock);
353 signal_data_wait (SignalData * data)
355 g_mutex_lock (data->lock);
356 GST_DEBUG ("signal wait %p", data);
357 while (!data->signaled)
358 g_cond_wait (data->cond, data->lock);
359 GST_DEBUG ("signal wait done %p", data);
360 g_mutex_unlock (data->lock);
363 static GstProbeReturn
364 signal_blocked (GstPad * pad, GstProbeType type, gpointer type_data,
367 SignalData *data = (SignalData *) user_data;
369 GST_DEBUG ("signal called %p", data);
370 signal_data_signal (data);
371 GST_DEBUG ("signal done %p", data);
376 static void test_event
377 (GstBin * pipeline, GstEventType type, GstPad * pad,
378 gboolean expect_before_q, GstPad * fake_srcpad)
386 got_event_before_q = got_event_after_q = NULL;
388 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
389 gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL,
390 GST_CLOCK_TIME_NONE);
392 GST_DEBUG ("test event called");
394 event = gst_event_new_custom (type,
395 gst_structure_empty_new ("application/x-custom"));
396 g_get_current_time (&sent_event_time);
397 got_event_time.tv_sec = 0;
398 got_event_time.tv_usec = 0;
400 signal_data_init (&data);
402 /* We block the pad so the stream lock is released and we can send the event */
403 id = gst_pad_add_probe (fake_srcpad, GST_PROBE_TYPE_BLOCK,
404 signal_blocked, &data, NULL);
405 fail_unless (id != 0);
407 signal_data_wait (&data);
409 /* We send on the peer pad, since the pad is blocked */
410 GST_DEBUG ("sending event %p", event);
411 fail_unless ((peer = gst_pad_get_peer (pad)) != NULL);
412 gst_pad_send_event (peer, event);
413 gst_object_unref (peer);
415 gst_pad_remove_probe (fake_srcpad, id);
417 if (expect_before_q) {
418 /* Wait up to 5 seconds for the event to appear */
419 for (i = 0; i < 500; i++) {
420 g_usleep (G_USEC_PER_SEC / 100);
421 if (got_event_before_q != NULL)
424 fail_if (got_event_before_q == NULL,
425 "Expected event failed to appear upstream of the queue "
427 fail_unless (GST_EVENT_TYPE (got_event_before_q) == type);
429 /* Wait up to 10 seconds for the event to appear */
430 for (i = 0; i < 1000; i++) {
431 g_usleep (G_USEC_PER_SEC / 100);
432 if (got_event_after_q != NULL)
435 fail_if (got_event_after_q == NULL,
436 "Expected event failed to appear after the queue within 10 seconds");
437 fail_unless (GST_EVENT_TYPE (got_event_after_q) == type);
440 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED);
441 gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL,
442 GST_CLOCK_TIME_NONE);
444 if (got_event_before_q)
445 gst_event_unref (got_event_before_q);
446 if (got_event_after_q)
447 gst_event_unref (got_event_after_q);
449 got_event_before_q = got_event_after_q = NULL;
451 signal_data_cleanup (&data);
455 timediff (GTimeVal * end, GTimeVal * start)
457 return (end->tv_sec - start->tv_sec) * G_USEC_PER_SEC +
458 (end->tv_usec - start->tv_usec);
461 GST_START_TEST (send_custom_events)
463 /* Run some tests on custom events. Checking for serialisation and whatnot.
464 * pipeline is fakesrc ! queue ! fakesink */
466 GstElement *fakesrc, *fakesink, *queue;
467 GstPad *srcpad, *sinkpad;
469 fail_if ((pipeline = (GstBin *) gst_pipeline_new ("testpipe")) == NULL);
470 fail_if ((fakesrc = gst_element_factory_make ("fakesrc", NULL)) == NULL);
471 fail_if ((fakesink = gst_element_factory_make ("fakesink", NULL)) == NULL);
472 fail_if ((queue = gst_element_factory_make ("queue", NULL)) == NULL);
474 gst_bin_add_many (pipeline, fakesrc, queue, fakesink, NULL);
475 fail_unless (gst_element_link_many (fakesrc, queue, fakesink, NULL));
477 g_object_set (G_OBJECT (fakesink), "sync", FALSE, NULL);
479 /* Send 100 buffers per sec */
480 g_object_set (G_OBJECT (fakesrc), "silent", TRUE, "datarate", 100,
481 "sizemax", 1, "sizetype", 2, NULL);
482 g_object_set (G_OBJECT (queue), "max-size-buffers", 0, "max-size-time",
483 (guint64) GST_SECOND, "max-size-bytes", 0, NULL);
484 g_object_set (G_OBJECT (fakesink), "silent", TRUE, "sync", TRUE, NULL);
486 /* add pad-probes to faksrc.src and fakesink.sink */
487 fail_if ((srcpad = gst_element_get_static_pad (fakesrc, "src")) == NULL);
488 gst_pad_add_probe (srcpad, GST_PROBE_TYPE_EVENT,
489 event_probe, GINT_TO_POINTER (TRUE), NULL);
491 fail_if ((sinkpad = gst_element_get_static_pad (fakesink, "sink")) == NULL);
492 gst_pad_add_probe (sinkpad, GST_PROBE_TYPE_EVENT,
493 event_probe, GINT_TO_POINTER (FALSE), NULL);
495 /* Upstream events */
496 test_event (pipeline, GST_EVENT_CUSTOM_UPSTREAM, sinkpad, TRUE, srcpad);
497 fail_unless (timediff (&got_event_time,
498 &sent_event_time) < G_USEC_PER_SEC / 2,
499 "GST_EVENT_CUSTOM_UP took too long to reach source: %"
500 G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
502 test_event (pipeline, GST_EVENT_CUSTOM_BOTH, sinkpad, TRUE, srcpad);
503 fail_unless (timediff (&got_event_time,
504 &sent_event_time) < G_USEC_PER_SEC / 2,
505 "GST_EVENT_CUSTOM_BOTH took too long to reach source: %"
506 G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
508 test_event (pipeline, GST_EVENT_CUSTOM_BOTH_OOB, sinkpad, TRUE, srcpad);
509 fail_unless (timediff (&got_event_time,
510 &sent_event_time) < G_USEC_PER_SEC / 2,
511 "GST_EVENT_CUSTOM_BOTH_OOB took too long to reach source: %"
512 G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
514 /* Out of band downstream events */
515 test_event (pipeline, GST_EVENT_CUSTOM_DOWNSTREAM_OOB, srcpad, FALSE, srcpad);
516 fail_unless (timediff (&got_event_time,
517 &sent_event_time) < G_USEC_PER_SEC / 2,
518 "GST_EVENT_CUSTOM_DS_OOB took too long to reach source: %"
519 G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
521 test_event (pipeline, GST_EVENT_CUSTOM_BOTH_OOB, srcpad, FALSE, srcpad);
522 fail_unless (timediff (&got_event_time,
523 &sent_event_time) < G_USEC_PER_SEC / 2,
524 "GST_EVENT_CUSTOM_BOTH_OOB took too long to reach source: %"
525 G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
527 /* In-band downstream events are expected to take at least 1 second
528 * to traverse the queue */
529 test_event (pipeline, GST_EVENT_CUSTOM_DOWNSTREAM, srcpad, FALSE, srcpad);
530 fail_unless (timediff (&got_event_time,
531 &sent_event_time) >= G_USEC_PER_SEC / 2,
532 "GST_EVENT_CUSTOM_DS arrived too quickly for an in-band event: %"
533 G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
535 test_event (pipeline, GST_EVENT_CUSTOM_BOTH, srcpad, FALSE, srcpad);
536 fail_unless (timediff (&got_event_time,
537 &sent_event_time) >= G_USEC_PER_SEC / 2,
538 "GST_EVENT_CUSTOM_BOTH arrived too quickly for an in-band event: %"
539 G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
541 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
542 gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL,
543 GST_CLOCK_TIME_NONE);
545 gst_object_unref (pipeline);
551 gst_event_suite (void)
553 Suite *s = suite_create ("GstEvent");
554 TCase *tc_chain = tcase_create ("events");
556 tcase_set_timeout (tc_chain, 20);
558 suite_add_tcase (s, tc_chain);
559 tcase_add_test (tc_chain, create_events);
560 tcase_add_test (tc_chain, send_custom_events);
564 GST_CHECK_MAIN (gst_event);