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