Merging origin/master
[platform/upstream/gstreamer.git] / tests / check / gst / gstevent.c
1 /* GStreamer
2  * Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
3  *
4  * gstevent.c: Unit test for event handling
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
23 #include <gst/check/gstcheck.h>
24
25 GST_START_TEST (create_events)
26 {
27   GstEvent *event, *event2;
28   GstStructure *structure;
29
30   /* FLUSH_START */
31   {
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);
39   }
40   /* FLUSH_STOP */
41   {
42     gboolean reset_time;
43
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));
50
51     gst_event_parse_flush_stop (event, &reset_time);
52     fail_unless (reset_time == TRUE);
53     gst_event_unref (event);
54   }
55   /* EOS */
56   {
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);
64   }
65   /* SEGMENT */
66   {
67     GstSegment segment, parsed;
68
69     gst_segment_init (&segment, GST_FORMAT_TIME);
70     segment.rate = 0.5;
71     segment.applied_rate = 1.0;
72     segment.start = 1;
73     segment.stop = G_MAXINT64;
74     segment.time = 0xdeadbeef;
75
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));
82
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);
90
91     gst_event_unref (event);
92   }
93
94   /* TAGS */
95   {
96     GstTagList *taglist = gst_tag_list_new ();
97     GstTagList *tl2 = NULL;
98
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));
106
107     gst_event_parse_tag (event, &tl2);
108     fail_unless (taglist == tl2);
109     gst_event_unref (event);
110   }
111
112   /* QOS */
113   {
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;
118
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));
125
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);
136
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);
142
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);
150   }
151
152   /* SEEK */
153   {
154     gdouble rate;
155     GstFormat format;
156     GstSeekFlags flags;
157     GstSeekType cur_type, stop_type;
158     gint64 cur, stop;
159
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);
163
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));
169
170     gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
171         &stop_type, &stop);
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);
179
180     gst_event_unref (event);
181   }
182
183   /* NAVIGATION */
184   {
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));
194
195     fail_unless (gst_event_get_structure (event) == structure);
196     gst_event_unref (event);
197   }
198
199   /* Custom event types */
200   {
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);
212
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
215      */
216   }
217
218   /* Event copying */
219   {
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);
223
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"));
229
230     /* The structure should have been duplicated */
231     fail_if (gst_event_get_structure (event) ==
232         gst_event_get_structure (event2));
233
234     gst_event_unref (event);
235     gst_event_unref (event2);
236   }
237
238   /* Make events writable */
239   {
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"));
250
251     /* now make writable */
252     event2 =
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"));
259
260     gst_event_unref (event);
261     gst_event_unref (event);
262     gst_event_unref (event2);
263   }
264 }
265
266 GST_END_TEST;
267
268 static GTimeVal sent_event_time;
269 static GstEvent *got_event_before_q, *got_event_after_q;
270 static GTimeVal got_event_time;
271
272 static GstProbeReturn
273 event_probe (GstPad * pad, GstProbeType type, gpointer type_data,
274     gpointer user_data)
275 {
276   GstMiniObject *data = type_data;
277   gboolean before_q = (gboolean) GPOINTER_TO_INT (user_data);
278
279   GST_DEBUG ("event probe called %p", data);
280
281   fail_unless (GST_IS_EVENT (data));
282
283   if (before_q) {
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)
289           break;
290         gst_event_ref ((GstEvent *) data);
291         g_get_current_time (&got_event_time);
292         got_event_before_q = GST_EVENT (data);
293         break;
294       default:
295         break;
296     }
297   } else {
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)
304           break;
305         gst_event_ref ((GstEvent *) data);
306         g_get_current_time (&got_event_time);
307         got_event_after_q = GST_EVENT (data);
308         break;
309       default:
310         break;
311     }
312   }
313
314   return GST_PROBE_OK;
315 }
316
317
318 typedef struct
319 {
320   GMutex *lock;
321   GCond *cond;
322   gboolean signaled;
323 } SignalData;
324
325 static void
326 signal_data_init (SignalData * data)
327 {
328   GST_DEBUG ("init %p", data);
329   data->lock = g_mutex_new ();
330   data->cond = g_cond_new ();
331   data->signaled = FALSE;
332 }
333
334 static void
335 signal_data_cleanup (SignalData * data)
336 {
337   GST_DEBUG ("free %p", data);
338   g_mutex_free (data->lock);
339   g_cond_free (data->cond);
340 }
341
342 static void
343 signal_data_signal (SignalData * data)
344 {
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);
350 }
351
352 static void
353 signal_data_wait (SignalData * data)
354 {
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);
361 }
362
363 static GstProbeReturn
364 signal_blocked (GstPad * pad, GstProbeType type, gpointer type_data,
365     gpointer user_data)
366 {
367   SignalData *data = (SignalData *) user_data;
368
369   GST_DEBUG ("signal called %p", data);
370   signal_data_signal (data);
371   GST_DEBUG ("signal done %p", data);
372
373   return GST_PROBE_OK;
374 }
375
376 static void test_event
377     (GstBin * pipeline, GstEventType type, GstPad * pad,
378     gboolean expect_before_q, GstPad * fake_srcpad)
379 {
380   GstEvent *event;
381   GstPad *peer;
382   gint i;
383   SignalData data;
384   gulong id;
385
386   got_event_before_q = got_event_after_q = NULL;
387
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);
391
392   GST_DEBUG ("test event called");
393
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;
399
400   signal_data_init (&data);
401
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);
406
407   signal_data_wait (&data);
408
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);
414
415   gst_pad_remove_probe (fake_srcpad, id);
416
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)
422         break;
423     }
424     fail_if (got_event_before_q == NULL,
425         "Expected event failed to appear upstream of the queue "
426         "within 5 seconds");
427     fail_unless (GST_EVENT_TYPE (got_event_before_q) == type);
428   } else {
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)
433         break;
434     }
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);
438   }
439
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);
443
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);
448
449   got_event_before_q = got_event_after_q = NULL;
450
451   signal_data_cleanup (&data);
452 }
453
454 static gint64
455 timediff (GTimeVal * end, GTimeVal * start)
456 {
457   return (end->tv_sec - start->tv_sec) * G_USEC_PER_SEC +
458       (end->tv_usec - start->tv_usec);
459 }
460
461 GST_START_TEST (send_custom_events)
462 {
463   /* Run some tests on custom events. Checking for serialisation and whatnot.
464    * pipeline is fakesrc ! queue ! fakesink */
465   GstBin *pipeline;
466   GstElement *fakesrc, *fakesink, *queue;
467   GstPad *srcpad, *sinkpad;
468
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);
473
474   gst_bin_add_many (pipeline, fakesrc, queue, fakesink, NULL);
475   fail_unless (gst_element_link_many (fakesrc, queue, fakesink, NULL));
476
477   g_object_set (G_OBJECT (fakesink), "sync", FALSE, NULL);
478
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);
485
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);
490
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);
494
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));
501
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));
507
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));
513
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));
520
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));
526
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));
534
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));
540
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);
544
545   gst_object_unref (sinkpad);
546   gst_object_unref (srcpad);
547   gst_object_unref (pipeline);
548 }
549
550 GST_END_TEST;
551
552 static Suite *
553 gst_event_suite (void)
554 {
555   Suite *s = suite_create ("GstEvent");
556   TCase *tc_chain = tcase_create ("events");
557
558   tcase_set_timeout (tc_chain, 20);
559
560   suite_add_tcase (s, tc_chain);
561   tcase_add_test (tc_chain, create_events);
562   tcase_add_test (tc_chain, send_custom_events);
563   return s;
564 }
565
566 GST_CHECK_MAIN (gst_event);