GST_END_TEST;
+guint nb_stream_start_event = 0;
+guint nb_caps_event = 0;
+guint nb_segment_event = 0;
+guint nb_gap_event = 0;
+
+static GstPadProbeReturn
+event_counter (GstObject * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+ GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
+
+ fail_unless (event != NULL);
+ fail_unless (GST_IS_EVENT (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_STREAM_START:
+ ++nb_stream_start_event;
+ break;
+ case GST_EVENT_CAPS:
+ ++nb_caps_event;
+ break;
+ case GST_EVENT_SEGMENT:
+ ++nb_segment_event;
+ break;
+ case GST_EVENT_GAP:
+ ++nb_gap_event;
+ break;
+ default:
+ break;
+ }
+
+ return GST_PAD_PROBE_OK;
+}
+
+/*
+ * Push GAP events into funnel to forward sticky events.
+ * Funnel element shoud also treat GAP events likes buffers.
+ * For example, funnel can be used for internal subtitle with streamiddemux.
+ * +--------------------------------------------------------------------------+
+ * | playbin +--------------------------------+ |
+ * | +--------------+ +----------------+ | +------------+ playsink | |
+ * | | uridecodebin | | input-selector | | | video-sink | | |
+ * | | | +----------------+ | +------------+ | |
+ * | | | | | |
+ * | | | +----------------+ | +------------+ | |
+ * | | | | input-selector | | | audio-sink | | |
+ * | | | +----------------+ | +------------+ | |
+ * | | | | | |
+ * | | | +----------------+ | +---------------+ +----------+ | |
+ * | | | | funnel | | | streamiddemux | | appsink0 | | |
+ * | +--------------+ +----------------+ | +---------------+ +----------+ | |
+ * | | +----------+ | |
+ * | | | appsinkn | | |
+ * | | +----------+ | |
+ * | +--------------------------------+ |
+ * +--------------------------------------------------------------------------+
+ * If no data was received in funnel and then sticky events can be pending continuously.
+ * And streamiddemux only receive gap events continuously.
+ * Thus, pipeline can not be constructed completely.
+ * For support it, need to handle GAP events likes buffers.
+ */
+GST_START_TEST (test_funnel_gap_event)
+{
+ struct TestData td;
+ guint probe = 0;
+
+ setup_test_objects (&td, chain_ok);
+
+ nb_stream_start_event = 0;
+ nb_caps_event = 0;
+ nb_segment_event = 0;
+ nb_gap_event = 0;
+ bufcount = 0;
+
+ probe = gst_pad_add_probe (td.mysink, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+ (GstPadProbeCallback) event_counter, NULL, NULL);
+
+ /* push a gap event to srcpad1 to push sticky events */
+ fail_unless (gst_pad_push_event (td.mysrc1, gst_event_new_gap (0,
+ GST_SECOND)));
+
+ fail_unless (nb_stream_start_event == 1);
+ fail_unless (nb_caps_event == 1);
+ fail_unless (nb_segment_event == 1);
+ fail_unless (nb_gap_event == 1);
+
+ /* push a gap event to srcpad2 to push sticky events */
+ fail_unless (gst_pad_push_event (td.mysrc2, gst_event_new_gap (0,
+ GST_SECOND)));
+
+ fail_unless (nb_stream_start_event == 2);
+ fail_unless (nb_caps_event == 2);
+ fail_unless (nb_segment_event == 2);
+ fail_unless (nb_gap_event == 2);
+
+ /* push a gap event to srcpad2 */
+ fail_unless (gst_pad_push_event (td.mysrc2, gst_event_new_gap (0,
+ GST_SECOND)));
+
+ fail_unless (nb_stream_start_event == 2);
+ fail_unless (nb_caps_event == 2);
+ fail_unless (nb_segment_event == 2);
+ fail_unless (nb_gap_event == 3);
+
+ /* push a gap event to srcpad1 */
+ fail_unless (gst_pad_push_event (td.mysrc1, gst_event_new_gap (0,
+ GST_SECOND)));
+
+ fail_unless (nb_stream_start_event == 3);
+ fail_unless (nb_caps_event == 3);
+ fail_unless (nb_segment_event == 3);
+ fail_unless (nb_gap_event == 4);
+
+ /* push buffer */
+ fail_unless (gst_pad_push (td.mysrc1, gst_buffer_new ()) == GST_FLOW_OK);
+ fail_unless (gst_pad_push (td.mysrc2, gst_buffer_new ()) == GST_FLOW_OK);
+
+ fail_unless (nb_stream_start_event == 4);
+ fail_unless (nb_caps_event == 4);
+ fail_unless (nb_segment_event == 4);
+ fail_unless (nb_gap_event == 4);
+ fail_unless (bufcount == 2);
+
+ gst_pad_remove_probe (td.mysink, probe);
+
+ release_test_objects (&td);
+}
+
+GST_END_TEST;
+
static Suite *
funnel_suite (void)
{
tc_chain = tcase_create ("funnel simple");
tcase_add_test (tc_chain, test_funnel_simple);
tcase_add_test (tc_chain, test_funnel_eos);
+ tcase_add_test (tc_chain, test_funnel_gap_event);
suite_add_tcase (s, tc_chain);
return s;