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