Make code safe for -Wredundant-decls
[platform/upstream/gstreamer.git] / tests / check / elements / fakesink.c
1 /* GStreamer
2  *
3  * unit test for fakesink
4  *
5  * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
6  *               <2007> Wim Taymans <wim@fluendo.com>
7  *               <2009> Tim-Philipp Müller <tim centricular net>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include <unistd.h>
26
27 #include <gst/base/gstpushsrc.h>
28 #include <gst/check/gstcheck.h>
29
30 typedef struct
31 {
32   GstPad *pad;
33   GstBuffer *buffer;
34   GThread *thread;
35   GstFlowReturn ret;
36 } ChainData;
37
38 static gpointer
39 chain_async_buffer (gpointer data)
40 {
41   ChainData *chain_data = (ChainData *) data;
42
43   chain_data->ret = gst_pad_chain (chain_data->pad, chain_data->buffer);
44
45   return chain_data;
46 }
47
48 static ChainData *
49 chain_async (GstPad * pad, GstBuffer * buffer)
50 {
51   GThread *thread;
52   ChainData *chain_data;
53   GError *error = NULL;
54
55   chain_data = g_new (ChainData, 1);
56   chain_data->pad = pad;
57   chain_data->buffer = buffer;
58   chain_data->ret = GST_FLOW_ERROR;
59
60   thread = g_thread_create (chain_async_buffer, chain_data, TRUE, &error);
61   if (error != NULL) {
62     g_warning ("could not create thread reason: %s", error->message);
63     g_free (chain_data);
64     return NULL;
65   }
66   chain_data->thread = thread;
67
68   return chain_data;
69 }
70
71 static GstFlowReturn
72 chain_async_return (ChainData * data)
73 {
74   GstFlowReturn ret;
75
76   g_thread_join (data->thread);
77   ret = data->ret;
78   g_free (data);
79
80   return ret;
81 }
82
83 GST_START_TEST (test_clipping)
84 {
85   GstElement *sink;
86   GstPad *sinkpad;
87   GstStateChangeReturn ret;
88
89   /* create sink */
90   sink = gst_element_factory_make ("fakesink", "sink");
91   fail_if (sink == NULL);
92
93   sinkpad = gst_element_get_static_pad (sink, "sink");
94   fail_if (sinkpad == NULL);
95
96   /* make element ready to accept data */
97   ret = gst_element_set_state (sink, GST_STATE_PAUSED);
98   fail_unless (ret == GST_STATE_CHANGE_ASYNC);
99
100   /* send segment */
101   {
102     GstEvent *segment;
103     gboolean eret;
104
105     GST_DEBUG ("sending segment");
106     segment = gst_event_new_new_segment (FALSE,
107         1.0, GST_FORMAT_TIME, 1 * GST_SECOND, 5 * GST_SECOND, 1 * GST_SECOND);
108
109     eret = gst_pad_send_event (sinkpad, segment);
110     fail_if (eret == FALSE);
111   }
112
113   /* new segment should not have finished preroll */
114   ret = gst_element_get_state (sink, NULL, NULL, 0);
115   fail_unless (ret == GST_STATE_CHANGE_ASYNC);
116
117   /* send buffer that should be dropped */
118   {
119     GstBuffer *buffer;
120     GstFlowReturn fret;
121
122     buffer = gst_buffer_new ();
123     GST_BUFFER_TIMESTAMP (buffer) = 0;
124     GST_BUFFER_DURATION (buffer) = 1 * GST_MSECOND;
125
126     GST_DEBUG ("sending buffer to be dropped");
127     fret = gst_pad_chain (sinkpad, buffer);
128     fail_if (fret != GST_FLOW_OK);
129   }
130   /* dropped buffer should not have finished preroll */
131   ret = gst_element_get_state (sink, NULL, NULL, 0);
132   fail_unless (ret == GST_STATE_CHANGE_ASYNC);
133
134   /* send buffer that should be dropped */
135   {
136     GstBuffer *buffer;
137     GstFlowReturn fret;
138
139     buffer = gst_buffer_new ();
140     GST_BUFFER_TIMESTAMP (buffer) = 5 * GST_SECOND;
141     GST_BUFFER_DURATION (buffer) = 1 * GST_MSECOND;
142
143     GST_DEBUG ("sending buffer to be dropped");
144     fret = gst_pad_chain (sinkpad, buffer);
145     fail_if (fret != GST_FLOW_OK);
146   }
147   /* dropped buffer should not have finished preroll */
148   ret = gst_element_get_state (sink, NULL, NULL, 0);
149   fail_unless (ret == GST_STATE_CHANGE_ASYNC);
150
151   /* send buffer that should block and finish preroll */
152   {
153     GstBuffer *buffer;
154     GstFlowReturn fret;
155     ChainData *data;
156     GstState current, pending;
157
158     buffer = gst_buffer_new ();
159     GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
160     GST_BUFFER_DURATION (buffer) = 1 * GST_MSECOND;
161
162     GST_DEBUG ("sending buffer to finish preroll");
163     data = chain_async (sinkpad, buffer);
164     fail_if (data == NULL);
165
166     /* state should now eventually change to PAUSED */
167     ret = gst_element_get_state (sink, &current, &pending, GST_CLOCK_TIME_NONE);
168     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
169     fail_unless (current == GST_STATE_PAUSED);
170     fail_unless (pending == GST_STATE_VOID_PENDING);
171
172     /* playing should render the buffer */
173     ret = gst_element_set_state (sink, GST_STATE_PLAYING);
174     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
175
176     /* and we should get a success return value */
177     fret = chain_async_return (data);
178     fail_if (fret != GST_FLOW_OK);
179   }
180
181   /* send some buffer that will be dropped or clipped, this can 
182    * only be observed in the debug log. */
183   {
184     GstBuffer *buffer;
185     GstFlowReturn fret;
186
187     buffer = gst_buffer_new ();
188     GST_BUFFER_TIMESTAMP (buffer) = 6 * GST_SECOND;
189     GST_BUFFER_DURATION (buffer) = 1 * GST_MSECOND;
190
191     /* should be dropped */
192     GST_DEBUG ("sending buffer to drop");
193     fret = gst_pad_chain (sinkpad, buffer);
194     fail_if (fret != GST_FLOW_OK);
195
196     buffer = gst_buffer_new ();
197     GST_BUFFER_TIMESTAMP (buffer) = 0 * GST_SECOND;
198     GST_BUFFER_DURATION (buffer) = 2 * GST_SECOND;
199
200     /* should be clipped */
201     GST_DEBUG ("sending buffer to clip");
202     fret = gst_pad_chain (sinkpad, buffer);
203     fail_if (fret != GST_FLOW_OK);
204
205     buffer = gst_buffer_new ();
206     GST_BUFFER_TIMESTAMP (buffer) = 4 * GST_SECOND;
207     GST_BUFFER_DURATION (buffer) = 2 * GST_SECOND;
208
209     /* should be clipped */
210     GST_DEBUG ("sending buffer to clip");
211     fret = gst_pad_chain (sinkpad, buffer);
212     fail_if (fret != GST_FLOW_OK);
213   }
214
215   gst_element_set_state (sink, GST_STATE_NULL);
216   gst_element_get_state (sink, NULL, NULL, GST_CLOCK_TIME_NONE);
217   gst_object_unref (sinkpad);
218   gst_object_unref (sink);
219 }
220
221 GST_END_TEST;
222
223 static gint num_preroll = 0;
224
225 static void
226 preroll_count (GstElement * sink)
227 {
228   num_preroll++;
229   GST_DEBUG ("got preroll handoff %d", num_preroll);
230 }
231
232 GST_START_TEST (test_preroll_sync)
233 {
234   GstElement *pipeline, *sink;
235   GstPad *sinkpad;
236   GstStateChangeReturn ret;
237
238   /* create sink */
239   pipeline = gst_pipeline_new ("pipeline");
240   fail_if (pipeline == NULL);
241
242   sink = gst_element_factory_make ("fakesink", "sink");
243   fail_if (sink == NULL);
244   g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
245   g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL);
246   g_signal_connect (sink, "preroll-handoff", G_CALLBACK (preroll_count), NULL);
247
248   fail_unless (num_preroll == 0);
249
250   gst_bin_add (GST_BIN (pipeline), sink);
251
252   sinkpad = gst_element_get_static_pad (sink, "sink");
253   fail_if (sinkpad == NULL);
254
255   /* make pipeline and element ready to accept data */
256   ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
257   fail_unless (ret == GST_STATE_CHANGE_ASYNC);
258
259   /* send segment */
260   {
261     GstEvent *segment;
262     gboolean eret;
263
264     GST_DEBUG ("sending segment");
265     segment = gst_event_new_new_segment (FALSE,
266         1.0, GST_FORMAT_TIME, 0 * GST_SECOND, 102 * GST_SECOND, 0 * GST_SECOND);
267
268     eret = gst_pad_send_event (sinkpad, segment);
269     fail_if (eret == FALSE);
270   }
271
272   /* send buffer that should block and finish preroll */
273   {
274     GstBuffer *buffer;
275     GstFlowReturn fret;
276     ChainData *data;
277     GstState current, pending;
278
279     buffer = gst_buffer_new ();
280     GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
281     GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
282
283     GST_DEBUG ("sending buffer to finish preroll");
284     data = chain_async (sinkpad, buffer);
285     fail_if (data == NULL);
286
287     /* state should now eventually change to PAUSED */
288     ret =
289         gst_element_get_state (pipeline, &current, &pending,
290         GST_CLOCK_TIME_NONE);
291     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
292     fail_unless (current == GST_STATE_PAUSED);
293     fail_unless (pending == GST_STATE_VOID_PENDING);
294
295     fail_unless (num_preroll == 1);
296
297     /* playing should render the buffer */
298     ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
299     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
300
301     /* and we should get a success return value */
302     fret = chain_async_return (data);
303     fail_if (fret != GST_FLOW_OK);
304
305     /* now we are playing no new preroll was done */
306     fail_unless (num_preroll == 1);
307
308     buffer = gst_buffer_new ();
309     /* far in the future to make sure we block */
310     GST_BUFFER_TIMESTAMP (buffer) = 100 * GST_SECOND;
311     GST_BUFFER_DURATION (buffer) = 100 * GST_SECOND;
312     data = chain_async (sinkpad, buffer);
313     fail_if (data == NULL);
314
315     g_usleep (1000000);
316
317     /* pause again. Since the buffer has a humongous timestamp we likely
318      * interrupt the clock_wait and we should preroll on this buffer again */
319     ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
320     fail_unless (ret == GST_STATE_CHANGE_ASYNC);
321
322     ret =
323         gst_element_get_state (pipeline, &current, &pending,
324         GST_CLOCK_TIME_NONE);
325     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
326     fail_unless (current == GST_STATE_PAUSED);
327     fail_unless (pending == GST_STATE_VOID_PENDING);
328
329     fail_unless (num_preroll == 2);
330
331     /* shutdown */
332     ret = gst_element_set_state (pipeline, GST_STATE_READY);
333     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
334
335     /* should be wrong state now */
336     fret = chain_async_return (data);
337     fail_if (fret != GST_FLOW_WRONG_STATE);
338   }
339   gst_element_set_state (pipeline, GST_STATE_NULL);
340   gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
341   gst_object_unref (sinkpad);
342   gst_object_unref (pipeline);
343 }
344
345 GST_END_TEST;
346
347 /* after EOS, we refuse everything */
348 GST_START_TEST (test_eos)
349 {
350   GstElement *pipeline, *sink;
351   GstPad *sinkpad;
352   GstStateChangeReturn ret;
353   GstMessage *message;
354   GstBus *bus;
355
356   /* create sink */
357   pipeline = gst_pipeline_new ("pipeline");
358   fail_if (pipeline == NULL);
359
360   bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (pipeline));
361   fail_if (bus == NULL);
362
363   sink = gst_element_factory_make ("fakesink", "sink");
364   fail_if (sink == NULL);
365   g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
366
367   gst_bin_add (GST_BIN (pipeline), sink);
368
369   sinkpad = gst_element_get_static_pad (sink, "sink");
370   fail_if (sinkpad == NULL);
371
372   /* make pipeline and element ready to accept data */
373   ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
374   fail_unless (ret == GST_STATE_CHANGE_ASYNC);
375
376   /* send EOS, this should work fine */
377   {
378     GstEvent *eos;
379     gboolean eret;
380
381     GST_DEBUG ("sending EOS");
382     eos = gst_event_new_eos ();
383
384     eret = gst_pad_send_event (sinkpad, eos);
385     fail_if (eret == FALSE);
386   }
387
388   /* wait for preroll */
389   gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
390
391   /* EOS should be on the bus at some point */
392   while (TRUE) {
393     GstMessageType type;
394
395     /* blocking wait for messages */
396     message = gst_bus_timed_pop (bus, GST_CLOCK_TIME_NONE);
397     type = GST_MESSAGE_TYPE (message);
398     gst_message_unref (message);
399
400     GST_DEBUG ("got message %s", gst_message_type_get_name (type));
401
402     if (type == GST_MESSAGE_EOS)
403       break;
404   }
405   gst_object_unref (bus);
406
407   /* send another EOS, this should fail */
408   {
409     GstEvent *eos;
410     gboolean eret;
411
412     GST_DEBUG ("sending second EOS");
413     eos = gst_event_new_eos ();
414
415     eret = gst_pad_send_event (sinkpad, eos);
416     fail_if (eret == TRUE);
417   }
418
419   /* send segment, this should fail */
420   {
421     GstEvent *segment;
422     gboolean eret;
423
424     GST_DEBUG ("sending segment");
425     segment = gst_event_new_new_segment (FALSE,
426         1.0, GST_FORMAT_TIME, 0 * GST_SECOND, 2 * GST_SECOND, 0 * GST_SECOND);
427
428     eret = gst_pad_send_event (sinkpad, segment);
429     fail_if (eret == TRUE);
430   }
431
432   /* send buffer that should fail after EOS */
433   {
434     GstBuffer *buffer;
435     GstFlowReturn fret;
436
437     buffer = gst_buffer_new ();
438     GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
439     GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
440
441     GST_DEBUG ("sending buffer");
442
443     /* buffer after EOS is not UNEXPECTED */
444     fret = gst_pad_chain (sinkpad, buffer);
445     fail_unless (fret == GST_FLOW_UNEXPECTED);
446   }
447
448   /* flush, EOS state is flushed again. */
449   {
450     GstEvent *event;
451     gboolean eret;
452
453     GST_DEBUG ("sending FLUSH_START");
454     event = gst_event_new_flush_start ();
455     eret = gst_pad_send_event (sinkpad, event);
456     fail_unless (eret == TRUE);
457
458     GST_DEBUG ("sending FLUSH_STOP");
459     event = gst_event_new_flush_stop ();
460     eret = gst_pad_send_event (sinkpad, event);
461     fail_unless (eret == TRUE);
462   }
463
464   /* send segment, this should now work again */
465   {
466     GstEvent *segment;
467     gboolean eret;
468
469     GST_DEBUG ("sending segment");
470     segment = gst_event_new_new_segment (FALSE,
471         1.0, GST_FORMAT_TIME, 0 * GST_SECOND, 2 * GST_SECOND, 0 * GST_SECOND);
472
473     eret = gst_pad_send_event (sinkpad, segment);
474     fail_unless (eret == TRUE);
475   }
476
477   /* send buffer that should work and block */
478   {
479     GstBuffer *buffer;
480     GstFlowReturn fret;
481
482     buffer = gst_buffer_new ();
483     GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
484     GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
485
486     GST_DEBUG ("sending buffer");
487
488     fret = gst_pad_chain (sinkpad, buffer);
489     fail_unless (fret == GST_FLOW_OK);
490   }
491
492   gst_element_set_state (pipeline, GST_STATE_NULL);
493   gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
494   gst_object_unref (sinkpad);
495   gst_object_unref (pipeline);
496 }
497
498 GST_END_TEST;
499
500 /* test EOS triggered by the element */
501 GST_START_TEST (test_eos2)
502 {
503   GstElement *pipeline, *sink;
504   GstPad *sinkpad;
505   GstStateChangeReturn ret;
506
507   /* create sink */
508   pipeline = gst_pipeline_new ("pipeline");
509   fail_if (pipeline == NULL);
510
511   sink = gst_element_factory_make ("fakesink", "sink");
512   fail_if (sink == NULL);
513   g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
514   g_object_set (G_OBJECT (sink), "num-buffers", 1, NULL);
515
516   gst_bin_add (GST_BIN (pipeline), sink);
517
518   sinkpad = gst_element_get_static_pad (sink, "sink");
519   fail_if (sinkpad == NULL);
520
521   /* make pipeline and element ready to accept data */
522   ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
523   fail_unless (ret == GST_STATE_CHANGE_ASYNC);
524
525   /* send segment, this should work */
526   {
527     GstEvent *segment;
528     gboolean eret;
529
530     GST_DEBUG ("sending segment");
531     segment = gst_event_new_new_segment (FALSE,
532         1.0, GST_FORMAT_TIME, 0 * GST_SECOND, 2 * GST_SECOND, 0 * GST_SECOND);
533
534     eret = gst_pad_send_event (sinkpad, segment);
535     fail_if (eret == FALSE);
536   }
537
538   /* send buffer that should return UNEXPECTED */
539   {
540     GstBuffer *buffer;
541     GstFlowReturn fret;
542
543     buffer = gst_buffer_new ();
544     GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
545     GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
546
547     GST_DEBUG ("sending buffer");
548
549     /* this buffer will generate UNEXPECTED */
550     fret = gst_pad_chain (sinkpad, buffer);
551     fail_unless (fret == GST_FLOW_UNEXPECTED);
552   }
553
554   /* send buffer that should return UNEXPECTED */
555   {
556     GstBuffer *buffer;
557     GstFlowReturn fret;
558
559     buffer = gst_buffer_new ();
560     GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
561     GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
562
563     GST_DEBUG ("sending buffer");
564
565     fret = gst_pad_chain (sinkpad, buffer);
566     fail_unless (fret == GST_FLOW_UNEXPECTED);
567   }
568
569   gst_element_set_state (pipeline, GST_STATE_NULL);
570   gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
571   gst_object_unref (sinkpad);
572   gst_object_unref (pipeline);
573 }
574
575 GST_END_TEST;
576
577 /* test position reporting before, during and after flush 
578  * in PAUSED and PLAYING */
579 GST_START_TEST (test_position)
580 {
581   GstElement *pipeline, *sink;
582   GstPad *sinkpad;
583   GstStateChangeReturn ret;
584   gboolean qret;
585   GstFormat qformat;
586   gint64 qcur;
587   GstBuffer *buffer;
588   GstFlowReturn fret;
589   ChainData *data;
590   GstEvent *event;
591   gboolean eret;
592   gint i;
593
594   /* create sink */
595   pipeline = gst_pipeline_new ("pipeline");
596   fail_if (pipeline == NULL);
597
598   sink = gst_element_factory_make ("fakesink", "sink");
599   fail_if (sink == NULL);
600   g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
601   g_object_set (G_OBJECT (sink), "num-buffers", 2, NULL);
602
603   gst_bin_add (GST_BIN (pipeline), sink);
604
605   sinkpad = gst_element_get_static_pad (sink, "sink");
606   fail_if (sinkpad == NULL);
607
608   /* do position query, this should fail, we have nothing received yet */
609   qformat = GST_FORMAT_TIME;
610   qret = gst_element_query_position (sink, &qformat, &qcur);
611   fail_unless (qret == FALSE);
612
613   ret = gst_element_set_state (pipeline, GST_STATE_READY);
614   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
615
616   /* do position query, this should fail, we have nothing received yet */
617   qformat = GST_FORMAT_TIME;
618   qret = gst_element_query_position (sink, &qformat, &qcur);
619   fail_unless (qret == FALSE);
620
621   /* make pipeline and element ready to accept data */
622   ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
623   fail_unless (ret == GST_STATE_CHANGE_ASYNC);
624
625   /* do position query, this should fail, we have nothing received yet */
626   qformat = GST_FORMAT_TIME;
627   qret = gst_element_query_position (sink, &qformat, &qcur);
628   fail_unless (qret == FALSE);
629
630   /* send segment, this should work */
631   {
632     GST_DEBUG ("sending segment");
633     event = gst_event_new_new_segment (FALSE,
634         1.0, GST_FORMAT_TIME, 1 * GST_SECOND, 3 * GST_SECOND, 1 * GST_SECOND);
635
636     eret = gst_pad_send_event (sinkpad, event);
637     fail_if (eret == FALSE);
638   }
639
640   /* FIXME, do position query, this should succeed with the time value from the
641    * segment. */
642   qformat = GST_FORMAT_TIME;
643   qret = gst_element_query_position (sink, &qformat, &qcur);
644   fail_unless (qret == TRUE);
645   fail_unless (qcur == 1 * GST_SECOND);
646
647   /* send buffer that we will flush out */
648   buffer = gst_buffer_new ();
649   GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND;
650   GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
651
652   GST_DEBUG ("sending buffer");
653
654   /* this buffer causes the sink to preroll */
655   data = chain_async (sinkpad, buffer);
656   fail_if (data == NULL);
657
658   /* wait for preroll */
659   ret = gst_element_get_state (pipeline, NULL, NULL, -1);
660
661   /* do position query, this should succeed with the time value from the
662    * segment. */
663   qformat = GST_FORMAT_TIME;
664   qret = gst_element_query_position (sink, &qformat, &qcur);
665   fail_unless (qret == TRUE);
666   fail_unless (qcur == 1 * GST_SECOND);
667
668   /* start flushing, no timing is affected yet */
669   {
670     GST_DEBUG ("sending flush_start");
671     event = gst_event_new_flush_start ();
672
673     eret = gst_pad_send_event (sinkpad, event);
674     fail_if (eret == FALSE);
675   }
676
677   /* preroll buffer is flushed out */
678   fret = chain_async_return (data);
679   fail_unless (fret == GST_FLOW_WRONG_STATE);
680
681   /* do position query, this should succeed with the time value from the
682    * segment before the flush. */
683   qformat = GST_FORMAT_TIME;
684   qret = gst_element_query_position (sink, &qformat, &qcur);
685   fail_unless (qret == TRUE);
686   fail_unless (qcur == 1 * GST_SECOND);
687
688   /* stop flushing, timing is affected now */
689   {
690     GST_DEBUG ("sending flush_stop");
691     event = gst_event_new_flush_stop ();
692
693     eret = gst_pad_send_event (sinkpad, event);
694     fail_if (eret == FALSE);
695   }
696
697   /* do position query, this should fail, the segment is flushed */
698   qformat = GST_FORMAT_TIME;
699   qret = gst_element_query_position (sink, &qformat, &qcur);
700   fail_unless (qret == FALSE);
701
702   /* send segment, this should work */
703   {
704     GST_DEBUG ("sending segment");
705     event = gst_event_new_new_segment (FALSE,
706         1.0, GST_FORMAT_TIME, 2 * GST_SECOND, 4 * GST_SECOND, 1 * GST_SECOND);
707
708     eret = gst_pad_send_event (sinkpad, event);
709     fail_if (eret == FALSE);
710   }
711
712   /* send buffer that should return OK */
713   buffer = gst_buffer_new ();
714   GST_BUFFER_TIMESTAMP (buffer) = 3 * GST_SECOND;
715   GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
716
717   GST_DEBUG ("sending buffer");
718
719   /* this buffer causes the sink to preroll */
720   data = chain_async (sinkpad, buffer);
721   fail_if (data == NULL);
722
723   /* wait for preroll */
724   ret = gst_element_get_state (pipeline, NULL, NULL, -1);
725
726   /* do position query, this should succeed with the time value from the
727    * segment. */
728   qformat = GST_FORMAT_TIME;
729   qret = gst_element_query_position (sink, &qformat, &qcur);
730   fail_unless (qret == TRUE);
731   fail_unless (qcur == 1 * GST_SECOND);
732
733   ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
734   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
735
736   /* position now is increasing but never exceeds the boundaries of the segment */
737   for (i = 0; i < 5; i++) {
738     qformat = GST_FORMAT_TIME;
739     qret = gst_element_query_position (sink, &qformat, &qcur);
740     GST_DEBUG ("position %" GST_TIME_FORMAT, GST_TIME_ARGS (qcur));
741     fail_unless (qret == TRUE);
742     fail_unless (qcur >= 1 * GST_SECOND && qcur <= 3 * GST_SECOND);
743     g_usleep (1000 * 250);
744   }
745
746   /* preroll buffer is rendered, we expect one more buffer after this one */
747   fret = chain_async_return (data);
748   fail_unless (fret == GST_FLOW_OK);
749
750   /* after rendering the position must be bigger then the stream_time of the
751    * buffer */
752   qformat = GST_FORMAT_TIME;
753   qret = gst_element_query_position (sink, &qformat, &qcur);
754   fail_unless (qret == TRUE);
755   fail_unless (qcur >= 2 * GST_SECOND && qcur <= 3 * GST_SECOND);
756
757   /* start flushing in PLAYING */
758   {
759     GST_DEBUG ("sending flush_start");
760     event = gst_event_new_flush_start ();
761
762     eret = gst_pad_send_event (sinkpad, event);
763     fail_if (eret == FALSE);
764   }
765
766   /* this should now just report the stream time of the last buffer */
767   qformat = GST_FORMAT_TIME;
768   qret = gst_element_query_position (sink, &qformat, &qcur);
769   fail_unless (qret == TRUE);
770   fail_unless (qcur == 2 * GST_SECOND);
771
772   {
773     GST_DEBUG ("sending flush_stop");
774     event = gst_event_new_flush_stop ();
775
776     eret = gst_pad_send_event (sinkpad, event);
777     fail_if (eret == FALSE);
778   }
779
780   /* do position query, this should fail, the segment is flushed */
781   qformat = GST_FORMAT_TIME;
782   qret = gst_element_query_position (sink, &qformat, &qcur);
783   fail_unless (qret == FALSE);
784
785   /* send segment, this should work */
786   {
787     GST_DEBUG ("sending segment");
788     event = gst_event_new_new_segment (FALSE,
789         1.0, GST_FORMAT_TIME, 2 * GST_SECOND, 4 * GST_SECOND, 1 * GST_SECOND);
790
791     eret = gst_pad_send_event (sinkpad, event);
792     fail_if (eret == FALSE);
793   }
794
795   /* send buffer that should return UNEXPECTED */
796   buffer = gst_buffer_new ();
797   GST_BUFFER_TIMESTAMP (buffer) = 3 * GST_SECOND;
798   GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
799
800   GST_DEBUG ("sending buffer");
801
802   /* this buffer causes the sink to preroll */
803   data = chain_async (sinkpad, buffer);
804   fail_if (data == NULL);
805
806   /* wait for preroll */
807   ret = gst_element_get_state (pipeline, NULL, NULL, -1);
808
809   /* preroll buffer is rendered, we expect no more buffer after this one */
810   fret = chain_async_return (data);
811   fail_unless (fret == GST_FLOW_UNEXPECTED);
812
813   /* do position query, this should succeed with the stream time of the buffer
814    * against the clock. Since the buffer is synced against the clock, the time
815    * should be at least the stream time of the buffer. */
816   qformat = GST_FORMAT_TIME;
817   qret = gst_element_query_position (sink, &qformat, &qcur);
818   fail_unless (qret == TRUE);
819   fail_unless (qcur >= 2 * GST_SECOND && qcur <= 3 * GST_SECOND);
820
821   /* wait 2 more seconds, enough to test if the position was clipped correctly
822    * against the segment */
823   g_usleep (2 * G_USEC_PER_SEC);
824
825   qformat = GST_FORMAT_TIME;
826   qret = gst_element_query_position (sink, &qformat, &qcur);
827   fail_unless (qret == TRUE);
828   fail_unless (qcur == 3 * GST_SECOND);
829
830   GST_DEBUG ("going to PAUSED");
831
832   ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
833   fail_unless (ret == GST_STATE_CHANGE_ASYNC);
834
835   /* we report the time of the last start of the buffer. This is slightly
836    * incorrect, we should report the exact time when we paused but there is no
837    * record of that anywhere */
838   qformat = GST_FORMAT_TIME;
839   qret = gst_element_query_position (sink, &qformat, &qcur);
840   fail_unless (qret == TRUE);
841   fail_unless (qcur == 2 * GST_SECOND);
842
843   ret = gst_element_set_state (pipeline, GST_STATE_READY);
844   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
845
846   /* fails again because we are in the wrong state */
847   qformat = GST_FORMAT_TIME;
848   qret = gst_element_query_position (sink, &qformat, &qcur);
849   fail_unless (qret == FALSE);
850
851   gst_element_set_state (pipeline, GST_STATE_NULL);
852
853   qformat = GST_FORMAT_TIME;
854   qret = gst_element_query_position (sink, &qformat, &qcur);
855   fail_unless (qret == FALSE);
856
857   gst_object_unref (sinkpad);
858   gst_object_unref (pipeline);
859 }
860
861 GST_END_TEST;
862
863 /* like fakesrc, but also pushes an OOB event after each buffer */
864 typedef GstPushSrc OOBSource;
865 typedef GstPushSrcClass OOBSourceClass;
866
867 GType oob_source_get_type (void);
868 GST_BOILERPLATE (OOBSource, oob_source, GstPushSrc, GST_TYPE_PUSH_SRC);
869
870 static void
871 oob_source_base_init (gpointer g_class)
872 {
873   static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("src",
874       GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
875
876   gst_element_class_add_pad_template (GST_ELEMENT_CLASS (g_class),
877       gst_static_pad_template_get (&sinktemplate));
878 }
879
880 static GstFlowReturn
881 oob_source_create (GstPushSrc * src, GstBuffer ** p_buf)
882 {
883   *p_buf = gst_buffer_new ();
884
885   gst_pad_push_event (GST_BASE_SRC_PAD (src),
886       gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, NULL));
887
888   return GST_FLOW_OK;
889 }
890
891 static void
892 oob_source_class_init (OOBSourceClass * klass)
893 {
894   GstPushSrcClass *pushsrc_class = GST_PUSH_SRC_CLASS (klass);
895
896   pushsrc_class->create = GST_DEBUG_FUNCPTR (oob_source_create);
897 }
898
899 static void
900 oob_source_init (OOBSource * src, OOBSourceClass * g_class)
901 {
902   /* nothing to do */
903 }
904
905 #define NOTIFY_RACE_NUM_PIPELINES 10
906
907 typedef struct
908 {
909   GstElement *src;
910   GstElement *queue;
911   GstElement *sink;
912   GstElement *pipe;
913 } NotifyRacePipeline;
914
915 static void
916 test_notify_race_setup_pipeline (NotifyRacePipeline * p)
917 {
918   GST_DEBUG ("Creating pipeline");
919   p->pipe = gst_pipeline_new ("pipeline");
920   p->src = g_object_new (oob_source_get_type (), NULL);
921
922   p->queue = gst_element_factory_make ("queue", NULL);
923   g_object_set (p->queue, "max-size-buffers", 2, NULL);
924
925   p->sink = gst_element_factory_make ("fakesink", NULL);
926   gst_bin_add (GST_BIN (p->pipe), p->src);
927   gst_bin_add (GST_BIN (p->pipe), p->queue);
928   gst_bin_add (GST_BIN (p->pipe), p->sink);
929   gst_element_link_many (p->src, p->queue, p->sink, NULL);
930
931   GST_DEBUG ("Setting pipeline to PLAYING");
932   fail_unless_equals_int (gst_element_set_state (p->pipe, GST_STATE_PLAYING),
933       GST_STATE_CHANGE_ASYNC);
934   GST_DEBUG ("Getting state");
935   fail_unless_equals_int (gst_element_get_state (p->pipe, NULL, NULL, -1),
936       GST_STATE_CHANGE_SUCCESS);
937 }
938
939 static void
940 test_notify_race_cleanup_pipeline (NotifyRacePipeline * p)
941 {
942   gst_element_set_state (p->pipe, GST_STATE_NULL);
943   gst_object_unref (p->pipe);
944   memset (p, 0, sizeof (NotifyRacePipeline));
945 }
946
947 /* we create N pipelines to make sure the notify race isn't per-class, but
948  * only per instance */
949 GST_START_TEST (test_notify_race)
950 {
951   NotifyRacePipeline pipelines[NOTIFY_RACE_NUM_PIPELINES];
952   int i;
953
954   for (i = 0; i < G_N_ELEMENTS (pipelines); ++i) {
955     GST_DEBUG ("Starting up pipeline %d", i);
956     test_notify_race_setup_pipeline (&pipelines[i]);
957   }
958
959   g_usleep (2 * G_USEC_PER_SEC);
960
961   for (i = 0; i < G_N_ELEMENTS (pipelines); ++i) {
962     GST_DEBUG ("Cleaning up pipeline %d", i);
963     test_notify_race_cleanup_pipeline (&pipelines[i]);
964   }
965 }
966
967 GST_END_TEST;
968
969 static Suite *
970 fakesink_suite (void)
971 {
972   Suite *s = suite_create ("fakesink");
973   TCase *tc_chain = tcase_create ("general");
974
975   tcase_set_timeout (tc_chain, 20);
976
977   suite_add_tcase (s, tc_chain);
978   tcase_add_test (tc_chain, test_clipping);
979   tcase_add_test (tc_chain, test_preroll_sync);
980   tcase_add_test (tc_chain, test_eos);
981   tcase_add_test (tc_chain, test_eos2);
982   tcase_add_test (tc_chain, test_position);
983   tcase_add_test (tc_chain, test_notify_race);
984
985   return s;
986 }
987
988 GST_CHECK_MAIN (fakesink);