Rework GstSegment handling
[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     event = gst_event_new_flush_stop ();
43     fail_if (event == NULL);
44     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP);
45     fail_unless (GST_EVENT_IS_UPSTREAM (event));
46     fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
47     fail_unless (GST_EVENT_IS_SERIALIZED (event));
48     gst_event_unref (event);
49   }
50   /* EOS */
51   {
52     event = gst_event_new_eos ();
53     fail_if (event == NULL);
54     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_EOS);
55     fail_if (GST_EVENT_IS_UPSTREAM (event));
56     fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
57     fail_unless (GST_EVENT_IS_SERIALIZED (event));
58     gst_event_unref (event);
59   }
60   /* SEGMENT */
61   {
62     GstSegment segment, parsed;
63
64     gst_segment_init (&segment, GST_FORMAT_TIME);
65     segment.rate = 0.5;
66     segment.applied_rate = 1.0;
67     segment.start = 1;
68     segment.stop = G_MAXINT64;
69     segment.time = 0xdeadbeef;
70
71     event = gst_event_new_segment (&segment);
72     fail_if (event == NULL);
73     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT);
74     fail_if (GST_EVENT_IS_UPSTREAM (event));
75     fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
76     fail_unless (GST_EVENT_IS_SERIALIZED (event));
77
78     gst_event_parse_segment (event, &parsed);
79     fail_unless (parsed.rate == 0.5);
80     fail_unless (parsed.applied_rate == 1.0);
81     fail_unless (parsed.format == GST_FORMAT_TIME);
82     fail_unless (parsed.start == 1);
83     fail_unless (parsed.stop == G_MAXINT64);
84     fail_unless (parsed.time == 0xdeadbeef);
85
86     gst_event_unref (event);
87   }
88
89   /* TAGS */
90   {
91     GstTagList *taglist = gst_tag_list_new ();
92     GstTagList *tl2 = NULL;
93
94     event = gst_event_new_tag (taglist);
95     fail_if (taglist == NULL);
96     fail_if (event == NULL);
97     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_TAG);
98     fail_if (GST_EVENT_IS_UPSTREAM (event));
99     fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
100     fail_unless (GST_EVENT_IS_SERIALIZED (event));
101
102     gst_event_parse_tag (event, &tl2);
103     fail_unless (taglist == tl2);
104     gst_event_unref (event);
105   }
106
107   /* QOS */
108   {
109     GstQOSType t1 = GST_QOS_TYPE_THROTTLE, t2;
110     gdouble p1 = 1.0, p2;
111     GstClockTimeDiff ctd1 = G_GINT64_CONSTANT (10), ctd2;
112     GstClockTime ct1 = G_GUINT64_CONSTANT (20), ct2;
113
114     event = gst_event_new_qos (t1, p1, ctd1, ct1);
115     fail_if (event == NULL);
116     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_QOS);
117     fail_unless (GST_EVENT_IS_UPSTREAM (event));
118     fail_if (GST_EVENT_IS_DOWNSTREAM (event));
119     fail_if (GST_EVENT_IS_SERIALIZED (event));
120
121     gst_event_parse_qos (event, &t2, &p2, &ctd2, &ct2);
122     fail_unless (p1 == p2);
123     fail_unless (ctd1 == ctd2);
124     fail_unless (ct1 == ct2);
125     gst_event_parse_qos (event, &t2, &p2, &ctd2, &ct2);
126     fail_unless (t2 == GST_QOS_TYPE_THROTTLE);
127     fail_unless (p1 == p2);
128     fail_unless (ctd1 == ctd2);
129     fail_unless (ct1 == ct2);
130     gst_event_unref (event);
131
132     ctd1 = G_GINT64_CONSTANT (-10);
133     event = gst_event_new_qos (t1, p1, ctd1, ct1);
134     gst_event_parse_qos (event, &t2, &p2, &ctd2, &ct2);
135     fail_unless (t2 == GST_QOS_TYPE_THROTTLE);
136     gst_event_unref (event);
137
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     fail_unless (p1 == p2);
142     fail_unless (ctd1 == ctd2);
143     fail_unless (ct1 == ct2);
144     gst_event_unref (event);
145   }
146
147   /* SEEK */
148   {
149     gdouble rate;
150     GstFormat format;
151     GstSeekFlags flags;
152     GstSeekType cur_type, stop_type;
153     gint64 cur, stop;
154
155     event = gst_event_new_seek (0.5, GST_FORMAT_BYTES,
156         GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
157         GST_SEEK_TYPE_SET, 1, GST_SEEK_TYPE_NONE, 0xdeadbeef);
158
159     fail_if (event == NULL);
160     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_SEEK);
161     fail_unless (GST_EVENT_IS_UPSTREAM (event));
162     fail_if (GST_EVENT_IS_DOWNSTREAM (event));
163     fail_if (GST_EVENT_IS_SERIALIZED (event));
164
165     gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
166         &stop_type, &stop);
167     fail_unless (rate == 0.5);
168     fail_unless (format == GST_FORMAT_BYTES);
169     fail_unless (flags == (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE));
170     fail_unless (cur_type == GST_SEEK_TYPE_SET);
171     fail_unless (cur == 1);
172     fail_unless (stop_type == GST_SEEK_TYPE_NONE);
173     fail_unless (stop == 0xdeadbeef);
174
175     gst_event_unref (event);
176   }
177
178   /* NAVIGATION */
179   {
180     structure = gst_structure_new ("application/x-gst-navigation", "event",
181         G_TYPE_STRING, "key-press", "key", G_TYPE_STRING, "mon", NULL);
182     fail_if (structure == NULL);
183     event = gst_event_new_navigation (structure);
184     fail_if (event == NULL);
185     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION);
186     fail_unless (GST_EVENT_IS_UPSTREAM (event));
187     fail_if (GST_EVENT_IS_DOWNSTREAM (event));
188     fail_if (GST_EVENT_IS_SERIALIZED (event));
189
190     fail_unless (gst_event_get_structure (event) == structure);
191     gst_event_unref (event);
192   }
193
194   /* Custom event types */
195   {
196     structure = gst_structure_empty_new ("application/x-custom");
197     fail_if (structure == NULL);
198     event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure);
199     fail_if (event == NULL);
200     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM);
201     fail_unless (GST_EVENT_IS_UPSTREAM (event));
202     fail_if (GST_EVENT_IS_DOWNSTREAM (event));
203     fail_if (GST_EVENT_IS_SERIALIZED (event));
204     fail_unless (gst_event_get_structure (event) == structure);
205     fail_unless (gst_event_has_name (event, "application/x-custom"));
206     gst_event_unref (event);
207
208     /* Decided not to test the other custom enum types, as they
209      * only differ by the value of the enum passed to gst_event_new_custom
210      */
211   }
212
213   /* Event copying */
214   {
215     structure = gst_structure_empty_new ("application/x-custom");
216     fail_if (structure == NULL);
217     event = gst_event_new_custom (GST_EVENT_CUSTOM_BOTH, structure);
218
219     fail_if (event == NULL);
220     event2 = gst_event_copy (event);
221     fail_if (event2 == NULL);
222     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_TYPE (event2));
223     fail_unless (gst_event_has_name (event, "application/x-custom"));
224
225     /* The structure should have been duplicated */
226     fail_if (gst_event_get_structure (event) ==
227         gst_event_get_structure (event2));
228
229     gst_event_unref (event);
230     gst_event_unref (event2);
231   }
232
233   /* Make events writable */
234   {
235     structure = gst_structure_empty_new ("application/x-custom");
236     fail_if (structure == NULL);
237     event = gst_event_new_custom (GST_EVENT_CUSTOM_BOTH, structure);
238     /* ref the event so that it becomes non-writable */
239     gst_event_ref (event);
240     gst_event_ref (event);
241     /* this should fail if the structure isn't writable */
242     ASSERT_CRITICAL (gst_structure_remove_all_fields ((GstStructure *)
243             gst_event_get_structure (event)));
244     fail_unless (gst_event_has_name (event, "application/x-custom"));
245
246     /* now make writable */
247     event2 =
248         GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
249     fail_unless (event != event2);
250     /* this fail if the structure isn't writable */
251     gst_structure_remove_all_fields ((GstStructure *)
252         gst_event_get_structure (event2));
253     fail_unless (gst_event_has_name (event2, "application/x-custom"));
254
255     gst_event_unref (event);
256     gst_event_unref (event);
257     gst_event_unref (event2);
258   }
259 }
260
261 GST_END_TEST;
262
263 static GTimeVal sent_event_time;
264 static GstEvent *got_event_before_q, *got_event_after_q;
265 static GTimeVal got_event_time;
266
267 static gboolean
268 event_probe (GstPad * pad, GstMiniObject ** data, gpointer user_data)
269 {
270   gboolean before_q = (gboolean) GPOINTER_TO_INT (user_data);
271
272   fail_unless (GST_IS_EVENT (data));
273
274   GST_DEBUG ("event probe called");
275
276   if (before_q) {
277     switch (GST_EVENT_TYPE (GST_EVENT (data))) {
278       case GST_EVENT_CUSTOM_UPSTREAM:
279       case GST_EVENT_CUSTOM_BOTH:
280       case GST_EVENT_CUSTOM_BOTH_OOB:
281         if (got_event_before_q != NULL)
282           break;
283         gst_event_ref ((GstEvent *) data);
284         g_get_current_time (&got_event_time);
285         got_event_before_q = GST_EVENT (data);
286         break;
287       default:
288         break;
289     }
290   } else {
291     switch (GST_EVENT_TYPE (GST_EVENT (data))) {
292       case GST_EVENT_CUSTOM_DOWNSTREAM:
293       case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
294       case GST_EVENT_CUSTOM_BOTH:
295       case GST_EVENT_CUSTOM_BOTH_OOB:
296         if (got_event_after_q != NULL)
297           break;
298         gst_event_ref ((GstEvent *) data);
299         g_get_current_time (&got_event_time);
300         got_event_after_q = GST_EVENT (data);
301         break;
302       default:
303         break;
304     }
305   }
306
307   return TRUE;
308 }
309
310 static void test_event
311     (GstBin * pipeline, GstEventType type, GstPad * pad,
312     gboolean expect_before_q, GstPad * fake_srcpad)
313 {
314   GstEvent *event;
315   GstPad *peer;
316   gint i;
317
318   got_event_before_q = got_event_after_q = NULL;
319
320   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
321   gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL,
322       GST_CLOCK_TIME_NONE);
323
324   GST_DEBUG ("test event called");
325
326   event = gst_event_new_custom (type,
327       gst_structure_empty_new ("application/x-custom"));
328   g_get_current_time (&sent_event_time);
329   got_event_time.tv_sec = 0;
330   got_event_time.tv_usec = 0;
331
332   /* We block the pad so the stream lock is released and we can send the event */
333   fail_unless (gst_pad_set_blocked (fake_srcpad, TRUE) == TRUE);
334
335   /* We send on the peer pad, since the pad is blocked */
336   fail_unless ((peer = gst_pad_get_peer (pad)) != NULL);
337   gst_pad_send_event (peer, event);
338   gst_object_unref (peer);
339
340   fail_unless (gst_pad_set_blocked (fake_srcpad, FALSE) == TRUE);
341
342   if (expect_before_q) {
343     /* Wait up to 5 seconds for the event to appear */
344     for (i = 0; i < 500; i++) {
345       g_usleep (G_USEC_PER_SEC / 100);
346       if (got_event_before_q != NULL)
347         break;
348     }
349     fail_if (got_event_before_q == NULL,
350         "Expected event failed to appear upstream of the queue "
351         "within 5 seconds");
352     fail_unless (GST_EVENT_TYPE (got_event_before_q) == type);
353   } else {
354     /* Wait up to 10 seconds for the event to appear */
355     for (i = 0; i < 1000; i++) {
356       g_usleep (G_USEC_PER_SEC / 100);
357       if (got_event_after_q != NULL)
358         break;
359     }
360     fail_if (got_event_after_q == NULL,
361         "Expected event failed to appear after the queue within 10 seconds");
362     fail_unless (GST_EVENT_TYPE (got_event_after_q) == type);
363   }
364
365   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED);
366   gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL,
367       GST_CLOCK_TIME_NONE);
368
369   if (got_event_before_q)
370     gst_event_unref (got_event_before_q);
371   if (got_event_after_q)
372     gst_event_unref (got_event_after_q);
373
374   got_event_before_q = got_event_after_q = NULL;
375 }
376
377 static gint64
378 timediff (GTimeVal * end, GTimeVal * start)
379 {
380   return (end->tv_sec - start->tv_sec) * G_USEC_PER_SEC +
381       (end->tv_usec - start->tv_usec);
382 }
383
384 GST_START_TEST (send_custom_events)
385 {
386   /* Run some tests on custom events. Checking for serialisation and whatnot.
387    * pipeline is fakesrc ! queue ! fakesink */
388   GstBin *pipeline;
389   GstElement *fakesrc, *fakesink, *queue;
390   GstPad *srcpad, *sinkpad;
391
392   fail_if ((pipeline = (GstBin *) gst_pipeline_new ("testpipe")) == NULL);
393   fail_if ((fakesrc = gst_element_factory_make ("fakesrc", NULL)) == NULL);
394   fail_if ((fakesink = gst_element_factory_make ("fakesink", NULL)) == NULL);
395   fail_if ((queue = gst_element_factory_make ("queue", NULL)) == NULL);
396
397   gst_bin_add_many (pipeline, fakesrc, queue, fakesink, NULL);
398   fail_unless (gst_element_link_many (fakesrc, queue, fakesink, NULL));
399
400   g_object_set (G_OBJECT (fakesink), "sync", FALSE, NULL);
401
402   /* Send 100 buffers per sec */
403   g_object_set (G_OBJECT (fakesrc), "silent", TRUE, "datarate", 100,
404       "sizemax", 1, "sizetype", 2, NULL);
405   g_object_set (G_OBJECT (queue), "max-size-buffers", 0, "max-size-time",
406       (guint64) GST_SECOND, "max-size-bytes", 0, NULL);
407   g_object_set (G_OBJECT (fakesink), "silent", TRUE, "sync", TRUE, NULL);
408
409   /* add pad-probes to faksrc.src and fakesink.sink */
410   fail_if ((srcpad = gst_element_get_static_pad (fakesrc, "src")) == NULL);
411   gst_pad_add_event_probe (srcpad, (GCallback) event_probe,
412       GINT_TO_POINTER (TRUE));
413
414   fail_if ((sinkpad = gst_element_get_static_pad (fakesink, "sink")) == NULL);
415   gst_pad_add_event_probe (sinkpad, (GCallback) event_probe,
416       GINT_TO_POINTER (FALSE));
417
418   /* Upstream events */
419   test_event (pipeline, GST_EVENT_CUSTOM_UPSTREAM, sinkpad, TRUE, srcpad);
420   fail_unless (timediff (&got_event_time,
421           &sent_event_time) < G_USEC_PER_SEC / 2,
422       "GST_EVENT_CUSTOM_UP took too long to reach source: %"
423       G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
424
425   test_event (pipeline, GST_EVENT_CUSTOM_BOTH, sinkpad, TRUE, srcpad);
426   fail_unless (timediff (&got_event_time,
427           &sent_event_time) < G_USEC_PER_SEC / 2,
428       "GST_EVENT_CUSTOM_BOTH took too long to reach source: %"
429       G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
430
431   test_event (pipeline, GST_EVENT_CUSTOM_BOTH_OOB, sinkpad, TRUE, srcpad);
432   fail_unless (timediff (&got_event_time,
433           &sent_event_time) < G_USEC_PER_SEC / 2,
434       "GST_EVENT_CUSTOM_BOTH_OOB took too long to reach source: %"
435       G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
436
437   /* Out of band downstream events */
438   test_event (pipeline, GST_EVENT_CUSTOM_DOWNSTREAM_OOB, srcpad, FALSE, srcpad);
439   fail_unless (timediff (&got_event_time,
440           &sent_event_time) < G_USEC_PER_SEC / 2,
441       "GST_EVENT_CUSTOM_DS_OOB took too long to reach source: %"
442       G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
443
444   test_event (pipeline, GST_EVENT_CUSTOM_BOTH_OOB, srcpad, FALSE, srcpad);
445   fail_unless (timediff (&got_event_time,
446           &sent_event_time) < G_USEC_PER_SEC / 2,
447       "GST_EVENT_CUSTOM_BOTH_OOB took too long to reach source: %"
448       G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
449
450   /* In-band downstream events are expected to take at least 1 second
451    * to traverse the the queue */
452   test_event (pipeline, GST_EVENT_CUSTOM_DOWNSTREAM, srcpad, FALSE, srcpad);
453   fail_unless (timediff (&got_event_time,
454           &sent_event_time) >= G_USEC_PER_SEC / 2,
455       "GST_EVENT_CUSTOM_DS arrived too quickly for an in-band event: %"
456       G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
457
458   test_event (pipeline, GST_EVENT_CUSTOM_BOTH, srcpad, FALSE, srcpad);
459   fail_unless (timediff (&got_event_time,
460           &sent_event_time) >= G_USEC_PER_SEC / 2,
461       "GST_EVENT_CUSTOM_BOTH arrived too quickly for an in-band event: %"
462       G_GINT64_FORMAT " us", timediff (&got_event_time, &sent_event_time));
463
464   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
465   gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL,
466       GST_CLOCK_TIME_NONE);
467
468   gst_object_unref (pipeline);
469 }
470
471 GST_END_TEST;
472
473 static Suite *
474 gst_event_suite (void)
475 {
476   Suite *s = suite_create ("GstEvent");
477   TCase *tc_chain = tcase_create ("events");
478
479   tcase_set_timeout (tc_chain, 20);
480
481   suite_add_tcase (s, tc_chain);
482   tcase_add_test (tc_chain, create_events);
483   tcase_add_test (tc_chain, send_custom_events);
484   return s;
485 }
486
487 GST_CHECK_MAIN (gst_event);