static GstPad *gst_adder_request_new_pad (GstElement * element,
GstPadTemplate * temp, const gchar * unused);
+static void gst_adder_release_pad (GstElement * element, GstPad * pad);
+
static GstStateChangeReturn gst_adder_change_state (GstElement * element,
GstStateChange transition);
parent_class = g_type_class_peek_parent (klass);
gstelement_class->request_new_pad = gst_adder_request_new_pad;
+ gstelement_class->release_pad = gst_adder_release_pad;
gstelement_class->change_state = gst_adder_change_state;
}
gst_element_add_pad (GST_ELEMENT (adder), adder->srcpad);
adder->format = GST_ADDER_FORMAT_UNSET;
- adder->numpads = 0;
+ adder->padcount = 0;
adder->func = NULL;
/* keep track of the sinkpads requested */
gchar *name;
GstAdder *adder;
GstPad *newpad;
-
- g_return_val_if_fail (GST_IS_ADDER (element), NULL);
+ gint padcount;
if (templ->direction != GST_PAD_SINK)
goto not_sink;
adder = GST_ADDER (element);
- name = g_strdup_printf ("sink%d", adder->numpads);
+ /* increment pad counter */
+ padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
+
+ name = g_strdup_printf ("sink%d", padcount);
newpad = gst_pad_new_from_template (templ, name);
+ GST_DEBUG_OBJECT (adder, "request new pad %s", name);
g_free (name);
gst_pad_set_getcaps_function (newpad,
adder->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_event));
+ /* takes ownership of the pad */
if (!gst_element_add_pad (GST_ELEMENT (adder), newpad))
goto could_not_add;
- adder->numpads++;
-
return newpad;
/* errors */
}
could_not_add:
{
+ GST_DEBUG_OBJECT (adder, "could not add pad");
gst_collect_pads_remove_pad (adder->collect, newpad);
gst_object_unref (newpad);
return NULL;
}
}
+static void
+gst_adder_release_pad (GstElement * element, GstPad * pad)
+{
+ GstAdder *adder;
+
+ adder = GST_ADDER (element);
+
+ GST_DEBUG_OBJECT (adder, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+
+ gst_collect_pads_remove_pad (adder->collect, pad);
+ gst_element_remove_pad (element, pad);
+}
+
static GstFlowReturn
gst_adder_collected (GstCollectPads * pads, gpointer user_data)
{
GST_END_TEST;
-/* check if adding and removing pads work as expected */
+/* check if adding pads work as expected */
GST_START_TEST (test_add_pad)
{
GstElement *bin, *src1, *src2, *adder, *sink;
GST_END_TEST;
+/* check if removing pads work as expected */
+GST_START_TEST (test_remove_pad)
+{
+ GstElement *bin, *src, *adder, *sink;
+ GstBus *bus;
+ GstPad *pad;
+ gboolean res;
+
+ GST_INFO ("preparing test");
+
+ /* build pipeline */
+ bin = gst_pipeline_new ("pipeline");
+ bus = gst_element_get_bus (bin);
+ gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+ src = gst_element_factory_make ("audiotestsrc", "src");
+ g_object_set (src, "num-buffers", 4, NULL);
+ g_object_set (src, "wave", 4, NULL);
+ adder = gst_element_factory_make ("adder", "adder");
+ sink = gst_element_factory_make ("fakesink", "sink");
+ gst_bin_add_many (GST_BIN (bin), src, adder, sink, NULL);
+
+ res = gst_element_link (src, adder);
+ fail_unless (res == TRUE, NULL);
+ res = gst_element_link (adder, sink);
+ fail_unless (res == TRUE, NULL);
+
+ /* create an unconnected sinkpad in adder */
+ pad = gst_element_get_request_pad (adder, "sink%d");
+ fail_if (pad == NULL, NULL);
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+ g_signal_connect (bus, "message::segment-done", (GCallback) message_received,
+ bin);
+ g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+ g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+ g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+ GST_INFO ("starting test");
+
+ /* prepare playing, this will not preroll as adder is waiting
+ * on the unconnected sinkpad. */
+ res = gst_element_set_state (bin, GST_STATE_PAUSED);
+ fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL);
+
+ /* wait for completion for one second, will return ASYNC */
+ res = gst_element_get_state (GST_ELEMENT (bin), NULL, NULL, GST_SECOND);
+ fail_unless (res == GST_STATE_CHANGE_ASYNC, NULL);
+
+ /* get rid of the pad now, adder should stop waiting on it and
+ * continue the preroll */
+ gst_element_release_request_pad (adder, pad);
+ gst_object_unref (pad);
+
+ /* wait for completion, should work now */
+ res =
+ gst_element_get_state (GST_ELEMENT (bin), NULL, NULL,
+ GST_CLOCK_TIME_NONE);
+ fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL);
+
+ /* now play all */
+ res = gst_element_set_state (bin, GST_STATE_PLAYING);
+ fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL);
+
+ g_main_loop_run (main_loop);
+
+ res = gst_element_set_state (bin, GST_STATE_NULL);
+ fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL);
+
+ /* cleanup */
+ g_main_loop_unref (main_loop);
+ gst_object_unref (G_OBJECT (bus));
+ gst_object_unref (G_OBJECT (bin));
+}
+
+GST_END_TEST;
+
+
Suite *
adder_suite (void)
{
tcase_add_test (tc_chain, test_event);
tcase_add_test (tc_chain, test_play_twice);
tcase_add_test (tc_chain, test_add_pad);
+ tcase_add_test (tc_chain, test_remove_pad);
/* Use a longer timeout */
tcase_set_timeout (tc_chain, 6);