5 * Copyright (C) <2006> Stefan Kost <ensonic@users.sf.net>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
25 #include <gst/check/gstcheck.h>
27 #define UNDERRUN_LOCK() (g_mutex_lock (underrun_mutex))
28 #define UNDERRUN_UNLOCK() (g_mutex_unlock (underrun_mutex))
29 #define UNDERRUN_SIGNAL() (g_cond_signal (underrun_cond))
30 #define UNDERRUN_WAIT() (g_cond_wait (underrun_cond, underrun_mutex))
32 static GstElement *queue;
34 /* For ease of programming we use globals to keep refs for our floating
35 * src and sink pads we create; otherwise we always have to do get_pad,
36 * get_peer, and then remove references in every test function */
37 static GstPad *mysrcpad;
38 static GstPad *mysinkpad;
40 static gint overrun_count;
42 static GMutex *underrun_mutex;
43 static GCond *underrun_cond;
44 static gint underrun_count;
48 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
52 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
58 queue_overrun (GstElement * queue, gpointer user_data)
60 GST_DEBUG ("queue overrun");
65 queue_underrun (GstElement * queue, gpointer user_data)
67 GST_DEBUG ("queue underrun");
75 event_func (GstPad * pad, GstEvent * event)
77 GST_DEBUG ("%s event", gst_event_type_get_name (GST_EVENT_TYPE (event)));
78 events = g_list_append (events, event);
86 while (events != NULL) {
87 gst_event_unref (GST_EVENT (events->data));
88 events = g_list_delete_link (events, events);
95 GST_DEBUG ("setup_queue");
97 queue = gst_check_setup_element ("queue");
98 g_signal_connect (queue, "underrun", G_CALLBACK (queue_underrun), NULL);
100 mysrcpad = gst_check_setup_src_pad (queue, &srctemplate, NULL);
101 gst_pad_set_active (mysrcpad, TRUE);
107 underrun_mutex = g_mutex_new ();
108 underrun_cond = g_cond_new ();
117 GST_DEBUG ("cleanup_queue");
119 gst_check_drop_buffers ();
123 g_cond_free (underrun_cond);
124 underrun_cond = NULL;
125 g_mutex_free (underrun_mutex);
126 underrun_mutex = NULL;
128 if (mysinkpad != NULL) {
129 gst_pad_set_active (mysinkpad, FALSE);
130 gst_check_teardown_sink_pad (queue);
133 gst_pad_set_active (mysrcpad, FALSE);
134 gst_check_teardown_src_pad (queue);
136 gst_check_teardown_element (queue);
140 /* setup the sinkpad on a playing queue element. gst_check_setup_sink_pad()
141 * does not work in this case since it does not activate the pad before linking
144 setup_sink_pad (GstElement * element, GstStaticPadTemplate * tmpl)
149 sinkpad = gst_pad_new_from_static_template (tmpl, "sink");
150 fail_if (sinkpad == NULL);
151 srcpad = gst_element_get_static_pad (element, "src");
152 fail_if (srcpad == NULL);
153 gst_pad_set_chain_function (sinkpad, gst_check_chain_func);
154 gst_pad_set_event_function (sinkpad, event_func);
155 gst_pad_set_active (sinkpad, TRUE);
156 fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK);
157 gst_object_unref (srcpad);
162 /* set queue size to 2 buffers
164 * check over/underuns
166 GST_START_TEST (test_non_leaky_underrun)
168 g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun), NULL);
169 g_object_set (G_OBJECT (queue), "max-size-buffers", 2, NULL);
170 mysinkpad = gst_check_setup_sink_pad (queue, &sinktemplate, NULL);
171 gst_pad_set_active (mysinkpad, TRUE);
173 GST_DEBUG ("starting");
176 fail_unless (gst_element_set_state (queue,
177 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
178 "could not set to playing");
182 fail_unless (overrun_count == 0);
183 fail_unless (underrun_count == 1);
185 GST_DEBUG ("stopping");
186 fail_unless (gst_element_set_state (queue,
187 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
193 queue_overrun_link_and_activate (GstElement * queue, gpointer user_data)
195 GST_DEBUG ("queue overrun");
198 /* link the src pad of the queue to make it dequeue buffers */
199 mysinkpad = setup_sink_pad (queue, &sinktemplate);
202 /* set queue size to 2 buffers
204 * check over/underuns
206 * check over/underuns again
208 GST_START_TEST (test_non_leaky_overrun)
215 g_signal_connect (queue, "overrun",
216 G_CALLBACK (queue_overrun_link_and_activate), NULL);
217 g_object_set (G_OBJECT (queue), "max-size-buffers", 2, NULL);
219 GST_DEBUG ("starting");
221 fail_unless (gst_element_set_state (queue,
222 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
223 "could not set to playing");
224 fail_unless (overrun_count == 0);
225 fail_unless (underrun_count == 0);
227 buffer1 = gst_buffer_new_and_alloc (4);
228 /* pushing gives away my reference */
229 gst_pad_push (mysrcpad, buffer1);
231 GST_DEBUG ("added 1st");
232 fail_unless (overrun_count == 0);
233 fail_unless (underrun_count == 0);
235 buffer2 = gst_buffer_new_and_alloc (4);
236 gst_pad_push (mysrcpad, buffer2);
238 GST_DEBUG ("added 2nd");
239 fail_unless (overrun_count == 0);
240 fail_unless (underrun_count == 0);
242 buffer3 = gst_buffer_new_and_alloc (4);
243 /* lock the check_mutex to block the first buffer pushed to mysinkpad */
244 g_mutex_lock (check_mutex);
245 /* the next call to gst_pad_push will emit the overrun signal. The signal
246 * handler queue_overrun_link_and_activate() (above) increases overrun_count,
247 * activates and links mysinkpad. The queue task then dequeues a buffer and
248 * gst_pad_push() will return. */
249 gst_pad_push (mysrcpad, buffer3);
251 GST_DEBUG ("added 3rd");
252 fail_unless (overrun_count == 1);
253 fail_unless (underrun_count == 0);
255 /* now let the queue push all buffers */
256 while (g_list_length (buffers) < 3) {
257 g_cond_wait (check_cond, check_mutex);
259 g_mutex_unlock (check_mutex);
261 fail_unless (overrun_count == 1);
262 /* make sure we get the underrun signal before we check underrun_count */
264 while (underrun_count < 1) {
268 fail_unless (underrun_count == 1);
270 buffer = g_list_nth (buffers, 0)->data;
271 fail_unless (buffer == buffer1);
273 buffer = g_list_nth (buffers, 1)->data;
274 fail_unless (buffer == buffer2);
276 buffer = g_list_nth (buffers, 2)->data;
277 fail_unless (buffer == buffer3);
279 GST_DEBUG ("stopping");
280 fail_unless (gst_element_set_state (queue,
281 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
286 /* set queue size to 2 buffers
288 * check over/underuns
290 * check over/underuns again
291 * check which buffer was leaked
293 GST_START_TEST (test_leaky_upstream)
300 g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun), NULL);
301 g_object_set (G_OBJECT (queue), "max-size-buffers", 2, "leaky", 1, NULL);
303 GST_DEBUG ("starting");
305 fail_unless (gst_element_set_state (queue,
306 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
307 "could not set to playing");
308 fail_unless (overrun_count == 0);
309 fail_unless (underrun_count == 0);
311 buffer1 = gst_buffer_new_and_alloc (4);
312 /* pushing gives away my reference */
313 gst_pad_push (mysrcpad, buffer1);
315 GST_DEBUG ("added 1st");
316 fail_unless (overrun_count == 0);
317 fail_unless (underrun_count == 0);
319 buffer2 = gst_buffer_new_and_alloc (4);
320 gst_pad_push (mysrcpad, buffer2);
322 GST_DEBUG ("added 2nd");
323 fail_unless (overrun_count == 0);
324 fail_unless (underrun_count == 0);
326 buffer3 = gst_buffer_new_and_alloc (4);
327 /* buffer3 will be leaked, keep a ref so refcount can be checked below */
328 gst_buffer_ref (buffer3);
329 gst_pad_push (mysrcpad, buffer3);
331 GST_DEBUG ("added 3rd");
332 /* it still triggers overrun when leaking */
333 fail_unless (overrun_count == 1);
334 fail_unless (underrun_count == 0);
336 /* wait for underrun and check that we got buffer1 and buffer2 only */
338 mysinkpad = setup_sink_pad (queue, &sinktemplate);
342 fail_unless (overrun_count == 1);
343 fail_unless (underrun_count == 1);
345 fail_unless (g_list_length (buffers) == 2);
347 buffer = g_list_nth (buffers, 0)->data;
348 fail_unless (buffer == buffer1);
350 buffer = g_list_nth (buffers, 1)->data;
351 fail_unless (buffer == buffer2);
353 ASSERT_BUFFER_REFCOUNT (buffer3, "buffer", 1);
354 gst_buffer_unref (buffer3);
356 GST_DEBUG ("stopping");
357 fail_unless (gst_element_set_state (queue,
358 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
363 /* set queue size to 2 buffers
365 * check over/underuns
367 * check over/underuns again
368 * check which buffer was leaked
370 GST_START_TEST (test_leaky_downstream)
377 g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun), NULL);
378 g_object_set (G_OBJECT (queue), "max-size-buffers", 2, "leaky", 2, NULL);
380 GST_DEBUG ("starting");
382 fail_unless (gst_element_set_state (queue,
383 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
384 "could not set to playing");
385 fail_unless (overrun_count == 0);
386 fail_unless (underrun_count == 0);
388 buffer1 = gst_buffer_new_and_alloc (4);
389 /* buffer1 will be leaked, keep a ref so refcount can be checked below */
390 gst_buffer_ref (buffer1);
391 /* pushing gives away one reference */
392 gst_pad_push (mysrcpad, buffer1);
394 GST_DEBUG ("added 1st");
395 fail_unless (overrun_count == 0);
396 fail_unless (underrun_count == 0);
398 buffer2 = gst_buffer_new_and_alloc (4);
399 gst_pad_push (mysrcpad, buffer2);
401 GST_DEBUG ("added 2nd");
402 fail_unless (overrun_count == 0);
403 fail_unless (underrun_count == 0);
405 buffer3 = gst_buffer_new_and_alloc (4);
406 gst_pad_push (mysrcpad, buffer3);
408 GST_DEBUG ("added 3rd");
409 /* it still triggers overrun when leaking */
410 fail_unless (overrun_count == 1);
411 fail_unless (underrun_count == 0);
413 /* wait for underrun and check that we got buffer1 and buffer2 only */
415 mysinkpad = setup_sink_pad (queue, &sinktemplate);
419 fail_unless (overrun_count == 1);
420 fail_unless (underrun_count == 1);
422 fail_unless (g_list_length (buffers) == 2);
424 ASSERT_BUFFER_REFCOUNT (buffer1, "buffer", 1);
425 gst_buffer_unref (buffer1);
427 buffer = g_list_nth (buffers, 0)->data;
428 fail_unless (buffer == buffer2);
430 buffer = g_list_nth (buffers, 1)->data;
431 fail_unless (buffer == buffer3);
433 GST_DEBUG ("stopping");
434 fail_unless (gst_element_set_state (queue,
435 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
440 /* set queue size to 6 buffers and 7 seconds
441 * push 7 buffers with and without duration
442 * check current-level-time
444 GST_START_TEST (test_time_level)
446 GstBuffer *buffer = NULL;
449 g_signal_connect (queue, "overrun",
450 G_CALLBACK (queue_overrun_link_and_activate), NULL);
451 g_object_set (G_OBJECT (queue), "max-size-buffers", 6, NULL);
452 g_object_set (G_OBJECT (queue), "max-size-time", 7 * GST_SECOND, NULL);
454 GST_DEBUG ("starting");
456 fail_unless (gst_element_set_state (queue,
457 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
458 "could not set to playing");
460 /* push buffer without duration */
461 buffer = gst_buffer_new_and_alloc (4);
462 GST_BUFFER_TIMESTAMP (buffer) = GST_SECOND;
463 /* pushing gives away my reference */
464 gst_pad_push (mysrcpad, buffer);
466 /* level should be 1 seconds because buffer has no duration and starts at 1
467 * SECOND (sparse stream). */
468 g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
469 fail_if (time != GST_SECOND);
471 /* second push should set the level to 2 second */
472 buffer = gst_buffer_new_and_alloc (4);
473 GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND;
474 gst_pad_push (mysrcpad, buffer);
476 g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
477 fail_if (time != 2 * GST_SECOND);
479 /* third push should set the level to 4 seconds, the 1 second diff with the
480 * previous buffer (without duration) and the 1 second duration of this
482 buffer = gst_buffer_new_and_alloc (4);
483 GST_BUFFER_TIMESTAMP (buffer) = 3 * GST_SECOND;
484 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
485 ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
486 gst_pad_push (mysrcpad, buffer);
488 g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
489 fail_if (time != 4 * GST_SECOND);
491 /* fourth push should set the level to 6 seconds, the 2 second diff with the
492 * previous buffer, same duration. */
493 buffer = gst_buffer_new_and_alloc (4);
494 GST_BUFFER_TIMESTAMP (buffer) = 5 * GST_SECOND;
495 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
496 ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
497 gst_pad_push (mysrcpad, buffer);
499 g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
500 fail_if (time != 6 * GST_SECOND);
502 /* fifth push should not adjust the level, the timestamp and duration are the
503 * same, meaning the previous buffer did not really have a duration. */
504 buffer = gst_buffer_new_and_alloc (4);
505 GST_BUFFER_TIMESTAMP (buffer) = 5 * GST_SECOND;
506 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
507 gst_pad_push (mysrcpad, buffer);
509 g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
510 fail_if (time != 6 * GST_SECOND);
512 /* sixth push should adjust the level with 1 second, we now know the
513 * previous buffer actually had a duration of 2 SECONDS */
514 buffer = gst_buffer_new_and_alloc (4);
515 GST_BUFFER_TIMESTAMP (buffer) = 7 * GST_SECOND;
516 gst_pad_push (mysrcpad, buffer);
518 g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
519 fail_if (time != 7 * GST_SECOND);
521 /* eighth push should cause overrun */
522 fail_unless (overrun_count == 0);
523 buffer = gst_buffer_new_and_alloc (4);
524 GST_BUFFER_TIMESTAMP (buffer) = 8 * GST_SECOND;
525 /* the next call to gst_pad_push will emit the overrun signal. The signal
526 * handler queue_overrun_link_and_activate() (above) increases overrun_count,
527 * activates and links mysinkpad. The queue task then dequeues a buffer and
528 * gst_pad_push() will return. */
529 gst_pad_push (mysrcpad, buffer);
531 fail_unless (overrun_count == 1);
533 GST_DEBUG ("stopping");
534 fail_unless (gst_element_set_state (queue,
535 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
540 GST_START_TEST (test_time_level_task_not_started)
546 GST_DEBUG ("starting");
548 fail_unless (gst_element_set_state (queue,
549 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
550 "could not set to playing");
552 gst_segment_init (&segment, GST_FORMAT_TIME);
553 segment.start = 1 * GST_SECOND;
554 segment.stop = 5 * GST_SECOND;
556 segment.position = 1 * GST_SECOND;
558 event = gst_event_new_segment (&segment);
559 gst_pad_push_event (mysrcpad, event);
561 g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
562 fail_if (time != 0 * GST_SECOND);
564 segment.base = 4 * GST_SECOND;
565 event = gst_event_new_segment (&segment);
566 gst_pad_push_event (mysrcpad, event);
568 g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
569 GST_DEBUG ("time now %" GST_TIME_FORMAT, GST_TIME_ARGS (time));
570 fail_if (time != 4 * GST_SECOND);
572 GST_DEBUG ("stopping");
573 fail_unless (gst_element_set_state (queue,
574 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
581 event_equals_newsegment (GstEvent * event, gboolean update, gdouble rate,
582 GstFormat format, gint64 start, gint64 stop, gint64 position)
585 gdouble ns_rate, ns_arate;
591 if (GST_EVENT_TYPE (event) != GST_EVENT_SEGMENT) {
595 gst_event_parse_new_segment (event, &ns_update, &ns_rate, &ns_arate,
596 &ns_format, &ns_start, &ns_stop, &ns_position);
598 GST_DEBUG ("update %d, rate %lf, format %s, start %" GST_TIME_FORMAT
599 ", stop %" GST_TIME_FORMAT ", position %" GST_TIME_FORMAT, ns_update,
600 ns_rate, gst_format_get_name (ns_format), GST_TIME_ARGS (ns_start),
601 GST_TIME_ARGS (ns_stop), GST_TIME_ARGS (ns_position));
603 return (ns_update == update && ns_rate == rate && ns_format == format &&
604 ns_start == start && ns_stop == stop && ns_position == position);
607 GST_START_TEST (test_newsegment)
614 g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun), NULL);
615 g_object_set (G_OBJECT (queue), "max-size-buffers", 1, "max-size-time",
616 (guint64) 0, "leaky", 2, NULL);
618 GST_DEBUG ("starting");
620 fail_unless (gst_element_set_state (queue,
621 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
622 "could not set to playing");
623 fail_unless (overrun_count == 0);
624 fail_unless (underrun_count == 0);
626 event = gst_event_new_new_segment (FALSE, 2.0, 1.0, GST_FORMAT_TIME, 0,
628 gst_pad_push_event (mysrcpad, event);
630 GST_DEBUG ("added 1st newsegment");
631 fail_unless (overrun_count == 0);
632 fail_unless (underrun_count == 0);
634 event = gst_event_new_new_segment (FALSE, 1.0, 1.0, GST_FORMAT_TIME, 0,
636 gst_pad_push_event (mysrcpad, event);
638 GST_DEBUG ("added 2nd newsegment");
639 fail_unless (overrun_count == 0);
640 fail_unless (underrun_count == 0);
642 event = gst_event_new_new_segment (FALSE, 1.0, 1.0, GST_FORMAT_TIME,
643 4 * GST_SECOND, 5 * GST_SECOND, 4 * GST_SECOND);
644 gst_pad_push_event (mysrcpad, event);
646 GST_DEBUG ("added 3rd newsegment");
647 fail_unless (overrun_count == 0);
648 fail_unless (underrun_count == 0);
650 buffer1 = gst_buffer_new_and_alloc (4);
651 /* buffer1 will be leaked, keep a ref so refcount can be checked below */
652 gst_buffer_ref (buffer1);
653 /* pushing gives away one reference */
654 gst_pad_push (mysrcpad, buffer1);
656 GST_DEBUG ("added 1st buffer");
657 fail_unless (overrun_count == 0);
658 fail_unless (underrun_count == 0);
660 buffer2 = gst_buffer_new_and_alloc (4);
661 /* next push will cause overrun and leak all newsegment events and buffer1 */
662 gst_pad_push (mysrcpad, buffer2);
664 GST_DEBUG ("added 2nd buffer");
665 /* it still triggers overrun when leaking */
666 fail_unless (overrun_count == 1);
667 fail_unless (underrun_count == 0);
669 /* wait for underrun and check that we got one accumulated newsegment event,
670 * one real newsegment event and buffer2 only */
672 mysinkpad = setup_sink_pad (queue, &sinktemplate);
676 fail_unless (overrun_count == 1);
677 fail_unless (underrun_count == 1);
679 fail_unless (g_list_length (events) == 2);
681 event = g_list_nth (events, 0)->data;
682 fail_unless (event_equals_newsegment (event, FALSE, 1.0, GST_FORMAT_TIME, 0,
685 event = g_list_nth (events, 1)->data;
686 fail_unless (event_equals_newsegment (event, FALSE, 1.0, GST_FORMAT_TIME,
687 4 * GST_SECOND, 5 * GST_SECOND, 4 * GST_SECOND));
689 fail_unless (g_list_length (buffers) == 1);
691 ASSERT_BUFFER_REFCOUNT (buffer1, "buffer", 1);
692 gst_buffer_unref (buffer1);
694 buffer = g_list_nth (buffers, 0)->data;
695 fail_unless (buffer == buffer2);
697 GST_DEBUG ("stopping");
698 fail_unless (gst_element_set_state (queue,
699 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
708 Suite *s = suite_create ("queue");
709 TCase *tc_chain = tcase_create ("general");
711 suite_add_tcase (s, tc_chain);
712 tcase_add_checked_fixture (tc_chain, setup, cleanup);
713 tcase_add_test (tc_chain, test_non_leaky_underrun);
714 tcase_add_test (tc_chain, test_non_leaky_overrun);
715 tcase_add_test (tc_chain, test_leaky_upstream);
716 tcase_add_test (tc_chain, test_leaky_downstream);
717 tcase_add_test (tc_chain, test_time_level);
718 tcase_add_test (tc_chain, test_time_level_task_not_started);
720 tcase_add_test (tc_chain, test_newsegment);
726 GST_CHECK_MAIN (queue);