tests: Test the case where ghost pads are removed while streaming
[platform/upstream/gstreamer.git] / tests / check / gst / gstghostpad.c
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
3  *
4  * gstghostpad.c: Unit test for GstGhostPad
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <gst/check/gstcheck.h>
23
24 /* test if removing a bin also cleans up the ghostpads
25  */
26 GST_START_TEST (test_remove1)
27 {
28   GstElement *b1, *b2, *src, *sink;
29   GstPad *srcpad, *sinkpad;
30   GstPadLinkReturn ret;
31
32   b1 = gst_element_factory_make ("pipeline", NULL);
33   b2 = gst_element_factory_make ("bin", NULL);
34   src = gst_element_factory_make ("fakesrc", NULL);
35   sink = gst_element_factory_make ("fakesink", NULL);
36   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
37   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
38
39   fail_unless (gst_bin_add (GST_BIN (b2), sink));
40   fail_unless (gst_bin_add (GST_BIN (b1), src));
41   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
42   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
43   fail_unless (gst_bin_add (GST_BIN (b1), b2));
44   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
45   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
46
47   sinkpad = gst_element_get_static_pad (sink, "sink");
48   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
49   gst_object_unref (sinkpad);
50
51   srcpad = gst_element_get_static_pad (src, "src");
52   /* get the ghostpad */
53   sinkpad = gst_element_get_static_pad (b2, "sink");
54
55   ret = gst_pad_link (srcpad, sinkpad);
56   fail_unless (ret == GST_PAD_LINK_OK);
57   gst_object_unref (srcpad);
58   gst_object_unref (sinkpad);
59
60   /* now remove the bin with the ghostpad, b2 is disposed now. */
61   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
62   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
63   gst_bin_remove (GST_BIN (b1), b2);
64
65   srcpad = gst_element_get_static_pad (src, "src");
66   /* pad cannot be linked now */
67   fail_if (gst_pad_is_linked (srcpad));
68   gst_object_unref (srcpad);
69
70   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
71   gst_object_unref (b1);
72 }
73
74 GST_END_TEST;
75
76 /* test if removing a bin also cleans up the ghostpads
77  */
78 GST_START_TEST (test_remove2)
79 {
80   GstElement *b1, *b2, *src, *sink;
81   GstPad *srcpad, *sinkpad;
82   GstPadLinkReturn ret;
83
84   b1 = gst_element_factory_make ("pipeline", NULL);
85   b2 = gst_element_factory_make ("bin", NULL);
86   src = gst_element_factory_make ("fakesrc", NULL);
87   sink = gst_element_factory_make ("fakesink", NULL);
88   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
89
90   fail_unless (gst_bin_add (GST_BIN (b2), sink));
91   fail_unless (gst_bin_add (GST_BIN (b1), src));
92   fail_unless (gst_bin_add (GST_BIN (b1), b2));
93   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
94
95   sinkpad = gst_element_get_static_pad (sink, "sink");
96   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
97   gst_object_unref (sinkpad);
98
99   srcpad = gst_element_get_static_pad (src, "src");
100   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); /* since we got one */
101   /* get the ghostpad */
102   sinkpad = gst_element_get_static_pad (b2, "sink");
103   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);       /* since we got one */
104
105   GST_DEBUG ("linking srcpad and sinkpad");
106   ret = gst_pad_link (srcpad, sinkpad);
107   GST_DEBUG ("linked srcpad and sinkpad");
108   fail_unless (ret == GST_PAD_LINK_OK);
109   /* Refcount should be unchanged, targets are now decuced using peer pad */
110   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
111   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
112   gst_object_unref (srcpad);
113   gst_object_unref (sinkpad);
114
115   /* now remove the sink from the bin */
116   gst_bin_remove (GST_BIN (b2), sink);
117
118   srcpad = gst_element_get_static_pad (src, "src");
119   /* pad is still linked to ghostpad */
120   fail_if (!gst_pad_is_linked (srcpad));
121   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
122   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
123   gst_object_unref (srcpad);
124   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
125
126   /* cleanup */
127   /* now unlink the pads */
128   gst_pad_unlink (srcpad, sinkpad);
129   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); /* we dropped our ref */
130   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
131
132   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
133   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
134   /* remove b2 from b1 */
135   gst_bin_remove (GST_BIN (b1), b2);
136
137   /* flush the message, dropping the b1 refcount to 1 */
138   gst_element_set_state (b1, GST_STATE_READY);
139   gst_element_set_state (b1, GST_STATE_NULL);
140   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
141   gst_object_unref (b1);
142 }
143
144 GST_END_TEST;
145
146
147
148 /* test if a ghost pad without a target can be linked and
149  * unlinked. An untargeted ghostpad has a default ANY caps unless there 
150  * is a padtemplate that says something else.
151  */
152 GST_START_TEST (test_ghost_pads_notarget)
153 {
154   GstElement *b1, *b2, *sink;
155   GstPad *srcpad, *sinkpad, *peer;
156   GstPadLinkReturn ret;
157   gboolean bret;
158   GstBus *bus;
159   GstCaps *caps;
160
161   b1 = gst_element_factory_make ("pipeline", NULL);
162
163   /* make sure all messages are discarded */
164   bus = gst_pipeline_get_bus (GST_PIPELINE (b1));
165   gst_bus_set_flushing (bus, TRUE);
166   gst_object_unref (bus);
167
168   b2 = gst_element_factory_make ("bin", NULL);
169   sink = gst_element_factory_make ("fakesink", NULL);
170
171   fail_unless (gst_bin_add (GST_BIN (b1), sink));
172   fail_unless (gst_bin_add (GST_BIN (b1), b2));
173
174   srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
175   fail_unless (srcpad != NULL);
176   sinkpad = gst_element_get_static_pad (sink, "sink");
177   fail_unless (sinkpad != NULL);
178
179   ret = gst_pad_link (srcpad, sinkpad);
180   fail_unless (ret == GST_PAD_LINK_OK);
181
182   /* check if the peers are ok */
183   peer = gst_pad_get_peer (srcpad);
184   fail_unless (peer == sinkpad);
185   gst_object_unref (peer);
186
187   peer = gst_pad_get_peer (sinkpad);
188   fail_unless (peer == srcpad);
189   gst_object_unref (peer);
190
191   /* check caps, untargetted pad should return ANY or the padtemplate caps 
192    * when it was created from a template */
193   caps = gst_pad_query_caps (srcpad, NULL);
194   fail_unless (gst_caps_is_any (caps));
195   gst_caps_unref (caps);
196
197   /* unlink */
198   bret = gst_pad_unlink (srcpad, sinkpad);
199   fail_unless (bret == TRUE);
200
201   /* cleanup */
202   gst_object_unref (srcpad);
203   gst_object_unref (sinkpad);
204   gst_object_unref (b1);
205 }
206
207 GST_END_TEST;
208
209 /* Test that removing the target of a ghostpad properly sets the target of the
210  * ghostpad to NULL */
211 GST_START_TEST (test_remove_target)
212 {
213   GstElement *b1, *b2, *src, *sink;
214   GstPad *sinkpad, *ghost, *target;
215
216   b1 = gst_element_factory_make ("pipeline", NULL);
217   b2 = gst_element_factory_make ("bin", NULL);
218   src = gst_element_factory_make ("fakesrc", NULL);
219   sink = gst_element_factory_make ("fakesink", NULL);
220   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
221
222   fail_unless (gst_bin_add (GST_BIN (b2), sink));
223   fail_unless (gst_bin_add (GST_BIN (b1), src));
224   fail_unless (gst_bin_add (GST_BIN (b1), b2));
225   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
226
227   sinkpad = gst_element_get_static_pad (sink, "sink");
228   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
229
230   ghost = gst_element_get_static_pad (b2, "sink");
231
232   target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
233   fail_unless (target == sinkpad);
234   gst_object_unref (target);
235   gst_object_unref (sinkpad);
236
237   gst_bin_remove (GST_BIN (b2), sink);
238
239   target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
240   fail_unless (target == NULL);
241
242   gst_object_unref (b1);
243   gst_object_unref (ghost);
244 }
245
246 GST_END_TEST;
247
248
249 /* test if linking fails over different bins using a pipeline
250  * like this:
251  *
252  * fakesrc num_buffers=10 ! ( fakesink )
253  *
254  */
255 GST_START_TEST (test_link)
256 {
257   GstElement *b1, *b2, *src, *sink;
258   GstPad *srcpad, *sinkpad, *gpad, *ppad, *tmp;
259   GstPadLinkReturn ret;
260
261   b1 = gst_element_factory_make ("pipeline", NULL);
262   b2 = gst_element_factory_make ("bin", NULL);
263   src = gst_element_factory_make ("fakesrc", NULL);
264   sink = gst_element_factory_make ("fakesink", NULL);
265
266   fail_unless (gst_bin_add (GST_BIN (b2), sink));
267   fail_unless (gst_bin_add (GST_BIN (b1), src));
268   fail_unless (gst_bin_add (GST_BIN (b1), b2));
269
270   srcpad = gst_element_get_static_pad (src, "src");
271   fail_unless (srcpad != NULL);
272   sinkpad = gst_element_get_static_pad (sink, "sink");
273   fail_unless (sinkpad != NULL);
274
275   /* linking in different hierarchies should fail */
276   ret = gst_pad_link (srcpad, sinkpad);
277   fail_unless (ret == GST_PAD_LINK_WRONG_HIERARCHY);
278
279   /* now setup a ghostpad */
280   gpad = gst_ghost_pad_new ("sink", sinkpad);
281
282   /* Check if the internal pads are set correctly */
283   ppad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (gpad)));
284   fail_unless (ppad == GST_PAD_PEER (sinkpad));
285   tmp = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ppad)));
286   fail_unless (tmp == gpad);
287   gst_object_unref (tmp);
288   gst_object_unref (ppad);
289   gst_object_unref (sinkpad);
290   /* need to ref as _add_pad takes ownership */
291   gst_object_ref (gpad);
292   gst_element_add_pad (b2, gpad);
293
294   /* our new sinkpad */
295   sinkpad = gpad;
296
297   /* and linking should work now */
298   ret = gst_pad_link (srcpad, sinkpad);
299   fail_unless (ret == GST_PAD_LINK_OK);
300
301   /* flush the message, dropping the b1 refcount to 1 */
302   gst_element_set_state (b1, GST_STATE_READY);
303   gst_element_set_state (b1, GST_STATE_NULL);
304   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
305
306   gst_object_unref (srcpad);
307   gst_object_unref (sinkpad);
308   gst_object_unref (b1);
309 }
310
311 GST_END_TEST;
312
313 /* test if ghostpads are created automagically when using
314  * gst_element_link_pads.
315  *
316  * fakesrc num_buffers=10 ! ( identity ) ! fakesink
317  */
318 GST_START_TEST (test_ghost_pads)
319 {
320   GstElement *b1, *b2, *src, *i1, *sink;
321   GstPad *gsink, *gsrc, *gisrc, *gisink, *isink, *isrc, *fsrc, *fsink;
322   GstStateChangeReturn ret;
323
324   b1 = gst_element_factory_make ("pipeline", NULL);
325   b2 = gst_element_factory_make ("bin", NULL);
326   src = gst_element_factory_make ("fakesrc", NULL);
327   g_object_set (src, "num-buffers", (int) 10, NULL);
328   i1 = gst_element_factory_make ("identity", NULL);
329   sink = gst_element_factory_make ("fakesink", NULL);
330
331   fail_unless (gst_bin_add (GST_BIN (b2), i1));
332   fail_unless (gst_bin_add (GST_BIN (b1), src));
333   fail_unless (gst_bin_add (GST_BIN (b1), b2));
334   fail_unless (gst_bin_add (GST_BIN (b1), sink));
335   fail_unless (gst_element_link_pads (src, NULL, i1, NULL));
336   fail_unless (gst_element_link_pads (i1, NULL, sink, NULL));
337   GST_OBJECT_LOCK (b2);
338   fail_unless (b2->numsinkpads == 1);
339   fail_unless (GST_IS_GHOST_PAD (b2->sinkpads->data));
340   fail_unless (b2->numsrcpads == 1);
341   fail_unless (GST_IS_GHOST_PAD (b2->srcpads->data));
342   GST_OBJECT_UNLOCK (b2);
343
344   fsrc = gst_element_get_static_pad (src, "src");
345   fail_unless (fsrc != NULL);
346   gsink = GST_PAD (gst_object_ref (b2->sinkpads->data));
347   fail_unless (gsink != NULL);
348   gsrc = GST_PAD (gst_object_ref (b2->srcpads->data));
349   fail_unless (gsrc != NULL);
350   fsink = gst_element_get_static_pad (sink, "sink");
351   fail_unless (fsink != NULL);
352
353   isink = gst_element_get_static_pad (i1, "sink");
354   fail_unless (isink != NULL);
355   isrc = gst_element_get_static_pad (i1, "src");
356   fail_unless (isrc != NULL);
357   gisrc = gst_pad_get_peer (isink);
358   fail_unless (gisrc != NULL);
359   gisink = gst_pad_get_peer (isrc);
360   fail_unless (gisink != NULL);
361
362   /* all objects above have one refcount owned by us as well */
363
364   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 2);     /* parent */
365   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 2);   /* parent */
366   ASSERT_OBJECT_REFCOUNT (gsrc, "gsrc", 2);     /* parent */
367   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 2);   /* parent */
368
369   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* parent */
370   ASSERT_OBJECT_REFCOUNT (isink, "isink", 2);   /* parent */
371   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* parent */
372   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 2);     /* parent */
373
374   ret = gst_element_set_state (b1, GST_STATE_PLAYING);
375   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
376   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
377
378   ret = gst_element_set_state (b1, GST_STATE_NULL);
379   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
380   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
381
382   gst_object_unref (b1);
383   /* unreffing the bin will unref all elements, which will unlink and unparent
384    * all pads */
385
386   /* wait for thread to settle down */
387   while (GST_OBJECT_REFCOUNT_VALUE (fsrc) > 1)
388     THREAD_SWITCH ();
389
390   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
391   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 1);
392   ASSERT_OBJECT_REFCOUNT (gsrc, "gsink", 1);
393   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
394
395   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* gsink */
396   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);   /* gsink */
397   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* gsrc */
398   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);     /* gsrc */
399
400   gst_object_unref (gsink);
401   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);
402   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 1);
403   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
404   gst_object_unref (gisrc);
405   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
406
407   gst_object_unref (gsrc);
408   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);
409   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 1);
410   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
411   gst_object_unref (gisink);
412   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
413
414   gst_object_unref (fsrc);
415   gst_object_unref (isrc);
416   gst_object_unref (isink);
417   gst_object_unref (fsink);
418 }
419
420 GST_END_TEST;
421
422 GST_START_TEST (test_ghost_pads_bin)
423 {
424   GstBin *pipeline;
425   GstBin *srcbin;
426   GstBin *sinkbin;
427   GstElement *src;
428   GstElement *sink;
429   GstPad *srcpad, *srcghost, *target;
430   GstPad *sinkpad, *sinkghost;
431
432   pipeline = GST_BIN (gst_pipeline_new ("pipe"));
433   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
434
435   srcbin = GST_BIN (gst_bin_new ("srcbin"));
436   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
437   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
438
439   sinkbin = GST_BIN (gst_bin_new ("sinkbin"));
440   gst_bin_add (pipeline, GST_ELEMENT (sinkbin));
441   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
442
443   src = gst_element_factory_make ("fakesrc", "src");
444   gst_bin_add (srcbin, src);
445   srcpad = gst_element_get_static_pad (src, "src");
446   srcghost = gst_ghost_pad_new ("src", srcpad);
447   gst_object_unref (srcpad);
448   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
449
450   sink = gst_element_factory_make ("fakesink", "sink");
451   gst_bin_add (sinkbin, sink);
452   sinkpad = gst_element_get_static_pad (sink, "sink");
453   sinkghost = gst_ghost_pad_new ("sink", sinkpad);
454   gst_object_unref (sinkpad);
455   gst_element_add_pad (GST_ELEMENT (sinkbin), sinkghost);
456
457   gst_element_link (GST_ELEMENT (srcbin), GST_ELEMENT (sinkbin));
458
459   fail_unless (GST_PAD_PEER (srcghost) != NULL);
460   fail_unless (GST_PAD_PEER (sinkghost) != NULL);
461   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcghost));
462   fail_unless (GST_PAD_PEER (target) != NULL);
463   gst_object_unref (target);
464   target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkghost));
465   fail_unless (GST_PAD_PEER (target) != NULL);
466   gst_object_unref (target);
467
468   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
469
470   gst_object_unref (pipeline);
471 }
472
473 GST_END_TEST;
474
475 typedef struct
476 {
477   GMutex mutex;
478   GCond cond;
479 } BlockData;
480
481 static GstPadProbeReturn
482 block_callback (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
483 {
484   BlockData *block_data = (BlockData *) user_data;
485
486   g_mutex_lock (&block_data->mutex);
487   GST_DEBUG ("blocked\n");
488   g_cond_signal (&block_data->cond);
489   g_mutex_unlock (&block_data->mutex);
490
491   return GST_PAD_PROBE_OK;
492 }
493
494 GST_START_TEST (test_ghost_pads_block)
495 {
496   GstBin *pipeline;
497   GstBin *srcbin;
498   GstElement *src;
499   GstPad *srcpad;
500   GstPad *srcghost;
501   BlockData block_data;
502
503   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
504
505   srcbin = GST_BIN (gst_bin_new ("srcbin"));
506   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
507
508   src = gst_element_factory_make ("fakesrc", "src");
509   gst_bin_add (srcbin, src);
510   srcpad = gst_element_get_static_pad (src, "src");
511   srcghost = gst_ghost_pad_new ("src", srcpad);
512   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
513   gst_object_unref (srcpad);
514
515   g_mutex_init (&block_data.mutex);
516   g_cond_init (&block_data.cond);
517
518   g_mutex_lock (&block_data.mutex);
519   gst_pad_add_probe (srcghost, GST_PAD_PROBE_TYPE_BLOCK, block_callback,
520       &block_data, NULL);
521   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
522   /* and wait now */
523   g_cond_wait (&block_data.cond, &block_data.mutex);
524   g_mutex_unlock (&block_data.mutex);
525   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
526
527   g_mutex_clear (&block_data.mutex);
528   g_cond_clear (&block_data.cond);
529
530   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
531   gst_object_unref (pipeline);
532 }
533
534 GST_END_TEST;
535
536 GST_START_TEST (test_ghost_pads_probes)
537 {
538   GstBin *pipeline;
539   GstBin *srcbin;
540   GstElement *src;
541   GstPad *srcpad;
542   GstPad *srcghost;
543   BlockData block_data;
544
545   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
546
547   srcbin = GST_BIN (gst_bin_new ("srcbin"));
548   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
549
550   src = gst_element_factory_make ("fakesrc", "src");
551   gst_bin_add (srcbin, src);
552   srcpad = gst_element_get_static_pad (src, "src");
553   srcghost = gst_ghost_pad_new ("src", srcpad);
554   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
555   gst_object_unref (srcpad);
556
557   g_mutex_init (&block_data.mutex);
558   g_cond_init (&block_data.cond);
559
560   g_mutex_lock (&block_data.mutex);
561   gst_pad_add_probe (srcghost, GST_PAD_PROBE_TYPE_BLOCK, block_callback,
562       &block_data, NULL);
563   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
564   /* and wait now */
565   g_cond_wait (&block_data.cond, &block_data.mutex);
566   g_mutex_unlock (&block_data.mutex);
567   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
568
569   g_mutex_clear (&block_data.mutex);
570   g_cond_clear (&block_data.cond);
571
572   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
573   gst_object_unref (pipeline);
574 }
575
576 GST_END_TEST;
577
578 GST_START_TEST (test_ghost_pads_new_from_template)
579 {
580   GstPad *sinkpad, *ghostpad;
581   GstPadTemplate *padtempl, *ghosttempl;
582   GstCaps *padcaps, *ghostcaps, *newcaps;
583
584   padcaps = gst_caps_from_string ("some/caps");
585   fail_unless (padcaps != NULL);
586   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
587   fail_unless (ghostcaps != NULL);
588
589   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
590       GST_PAD_ALWAYS, padcaps);
591   fail_unless (padtempl != NULL);
592   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
593       GST_PAD_ALWAYS, ghostcaps);
594
595   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
596   fail_unless (sinkpad != NULL);
597
598   ghostpad = gst_ghost_pad_new_from_template ("ghostpad", sinkpad, ghosttempl);
599   fail_unless (ghostpad != NULL);
600
601   /* check template is properly set */
602   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
603
604   /* check ghostpad caps are from the sinkpad */
605   newcaps = gst_pad_query_caps (ghostpad, NULL);
606   fail_unless (newcaps != NULL);
607   fail_unless (gst_caps_is_equal (newcaps, padcaps));
608   gst_caps_unref (newcaps);
609   gst_caps_unref (padcaps);
610   gst_caps_unref (ghostcaps);
611
612   gst_object_unref (sinkpad);
613   gst_object_unref (ghostpad);
614
615   gst_object_unref (padtempl);
616   gst_object_unref (ghosttempl);
617 }
618
619 GST_END_TEST;
620
621 GST_START_TEST (test_ghost_pads_new_no_target_from_template)
622 {
623   GstPad *sinkpad, *ghostpad;
624   GstPadTemplate *padtempl, *ghosttempl;
625   GstCaps *padcaps, *ghostcaps, *newcaps;
626
627   padcaps = gst_caps_from_string ("some/caps");
628   fail_unless (padcaps != NULL);
629   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
630   fail_unless (ghostcaps != NULL);
631
632   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
633       GST_PAD_ALWAYS, padcaps);
634   fail_unless (padtempl != NULL);
635   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
636       GST_PAD_ALWAYS, ghostcaps);
637
638   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
639   fail_unless (sinkpad != NULL);
640
641   ghostpad = gst_ghost_pad_new_no_target_from_template ("ghostpad", ghosttempl);
642   fail_unless (ghostpad != NULL);
643
644   /* check template is properly set */
645   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
646
647   /* check ghostpad caps are from the ghostpad template */
648   newcaps = gst_pad_query_caps (ghostpad, NULL);
649   fail_unless (newcaps != NULL);
650   fail_unless (gst_caps_is_equal (newcaps, ghostcaps));
651   gst_caps_unref (newcaps);
652
653   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
654
655   /* check ghostpad caps are now from the target pad */
656   newcaps = gst_pad_query_caps (ghostpad, NULL);
657   fail_unless (newcaps != NULL);
658   fail_unless (gst_caps_is_equal (newcaps, padcaps));
659   gst_caps_unref (newcaps);
660
661   gst_object_unref (sinkpad);
662   gst_object_unref (ghostpad);
663
664   gst_object_unref (padtempl);
665   gst_object_unref (ghosttempl);
666
667   gst_caps_unref (padcaps);
668   gst_caps_unref (ghostcaps);
669 }
670
671 GST_END_TEST;
672
673 static void
674 ghost_notify_caps (GObject * object, GParamSpec * pspec, gpointer * user_data)
675 {
676   GST_DEBUG ("caps notify called");
677   (*(gint *) user_data)++;
678 }
679
680 GST_START_TEST (test_ghost_pads_forward_setcaps)
681 {
682   GstCaps *templ_caps, *caps1, *caps2;
683   GstPadTemplate *src_template, *sink_template;
684   GstPad *src, *ghost, *sink;
685   gint notify_counter = 0;
686
687   templ_caps = gst_caps_from_string ("meh; muh");
688   src_template = gst_pad_template_new ("src", GST_PAD_SRC,
689       GST_PAD_ALWAYS, templ_caps);
690   gst_caps_unref (templ_caps);
691
692   templ_caps = gst_caps_from_string ("muh; meh");
693   sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
694       GST_PAD_ALWAYS, templ_caps);
695   gst_caps_unref (templ_caps);
696
697   src = gst_pad_new_from_template (src_template, "src");
698   sink = gst_pad_new_from_template (sink_template, "sink");
699
700   /* ghost source pad, setting caps on the source influences the caps of the
701    * ghostpad. */
702   ghost = gst_ghost_pad_new ("ghostsrc", src);
703   g_signal_connect (ghost, "notify::caps",
704       G_CALLBACK (ghost_notify_caps), &notify_counter);
705   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
706
707   /* Activate pads for caps forwarding/setting to work */
708   gst_pad_set_active (src, TRUE);
709   gst_pad_set_active (ghost, TRUE);
710
711   caps1 = gst_caps_from_string ("meh");
712   fail_unless (gst_pad_set_caps (src, caps1));
713   caps2 = gst_pad_get_current_caps (ghost);
714   fail_unless (gst_caps_is_equal (caps1, caps2));
715   fail_unless_equals_int (notify_counter, 1);
716
717   gst_object_unref (ghost);
718   gst_caps_unref (caps1);
719   gst_caps_unref (caps2);
720
721   /* source 2, setting the caps on the ghostpad does not influence the caps of
722    * the target */
723   notify_counter = 0;
724   ghost = gst_ghost_pad_new ("ghostsrc", src);
725   g_signal_connect (ghost, "notify::caps",
726       G_CALLBACK (ghost_notify_caps), &notify_counter);
727   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
728
729   gst_pad_set_active (ghost, TRUE);
730   gst_pad_set_active (sink, TRUE);
731
732   caps1 = gst_caps_from_string ("meh");
733   fail_unless (gst_pad_set_caps (ghost, caps1));
734 #if 0
735   caps2 = gst_pad_get_current_caps (src);
736   fail_unless (caps2 == NULL);
737 #endif
738   fail_unless_equals_int (notify_counter, 1);
739
740   gst_object_unref (ghost);
741   gst_caps_unref (caps1);
742
743
744   /* ghost sink pad. Setting caps on the ghostpad will also set those caps on
745    * the target pad. */
746   notify_counter = 0;
747   ghost = gst_ghost_pad_new ("ghostsink", sink);
748   g_signal_connect (ghost, "notify::caps",
749       G_CALLBACK (ghost_notify_caps), &notify_counter);
750   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
751
752   gst_pad_set_active (src, TRUE);
753   gst_pad_set_active (ghost, TRUE);
754
755   caps1 = gst_caps_from_string ("muh");
756   fail_unless (gst_pad_set_caps (ghost, caps1));
757   caps2 = gst_pad_get_current_caps (sink);
758   fail_unless (gst_caps_is_equal (caps1, caps2));
759   fail_unless_equals_int (notify_counter, 1);
760
761   gst_object_unref (ghost);
762   gst_caps_unref (caps1);
763   gst_caps_unref (caps2);
764
765   /* clear caps on pads */
766   gst_pad_set_active (src, FALSE);
767   gst_pad_set_active (src, TRUE);
768   gst_pad_set_active (sink, FALSE);
769   gst_pad_set_active (sink, TRUE);
770
771   /* sink pad 2, setting caps just on the target pad should not influence the caps
772    * on the ghostpad. */
773   notify_counter = 0;
774   ghost = gst_ghost_pad_new ("ghostsink", sink);
775   fail_unless (gst_pad_get_current_caps (ghost) == NULL);
776   g_signal_connect (ghost, "notify::caps",
777       G_CALLBACK (ghost_notify_caps), &notify_counter);
778   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
779
780   gst_pad_set_active (ghost, TRUE);
781
782   caps1 = gst_caps_from_string ("muh");
783   fail_unless (gst_pad_set_caps (sink, caps1));
784   caps2 = gst_pad_get_current_caps (ghost);
785   fail_unless (caps2 == NULL);
786   fail_unless_equals_int (notify_counter, 0);
787
788   gst_object_unref (ghost);
789   gst_caps_unref (caps1);
790
791   gst_object_unref (src);
792   gst_object_unref (sink);
793   gst_object_unref (src_template);
794   gst_object_unref (sink_template);
795 }
796
797 GST_END_TEST;
798
799 static gint linked_count1;
800 static gint unlinked_count1;
801 static gint linked_count2;
802 static gint unlinked_count2;
803
804 static GstPadLinkReturn
805 pad_linked1 (GstPad * pad, GstObject * parent, GstPad * peer)
806 {
807   linked_count1++;
808
809   return GST_PAD_LINK_OK;
810 }
811
812 static void
813 pad_unlinked1 (GstPad * pad, GstObject * parent)
814 {
815   unlinked_count1++;
816 }
817
818 static GstPadLinkReturn
819 pad_linked2 (GstPad * pad, GstObject * parent, GstPad * peer)
820 {
821   linked_count2++;
822
823   return GST_PAD_LINK_OK;
824 }
825
826 static void
827 pad_unlinked2 (GstPad * pad, GstObject * parent)
828 {
829   unlinked_count2++;
830 }
831
832 GST_START_TEST (test_ghost_pads_sink_link_unlink)
833 {
834   GstCaps *padcaps;
835   GstPad *srcpad, *sinkpad, *ghostpad;
836   GstPadTemplate *srctempl, *sinktempl;
837   GstPadLinkReturn ret;
838   gboolean res;
839
840   padcaps = gst_caps_from_string ("some/caps");
841   fail_unless (padcaps != NULL);
842   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
843       GST_PAD_ALWAYS, padcaps);
844   gst_caps_unref (padcaps);
845
846   padcaps = gst_caps_from_string ("some/caps");
847   fail_unless (padcaps != NULL);
848   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
849       GST_PAD_ALWAYS, padcaps);
850   gst_caps_unref (padcaps);
851
852   srcpad = gst_pad_new_from_template (srctempl, "src");
853   fail_unless (srcpad != NULL);
854   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
855   fail_unless (sinkpad != NULL);
856
857   /* set up link/unlink functions for the pad */
858   linked_count1 = unlinked_count1 = 0;
859   gst_pad_set_link_function (sinkpad, pad_linked1);
860   gst_pad_set_unlink_function (sinkpad, pad_unlinked1);
861   linked_count2 = unlinked_count2 = 0;
862   gst_pad_set_link_function (srcpad, pad_linked2);
863   gst_pad_set_unlink_function (srcpad, pad_unlinked2);
864
865   /* this should trigger a link from the internal pad to the sinkpad */
866   ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad);
867   fail_unless (ghostpad != NULL);
868   fail_unless (linked_count1 == 1);
869   fail_unless (unlinked_count1 == 0);
870   fail_unless (linked_count2 == 0);
871   fail_unless (unlinked_count2 == 0);
872
873   /* this should not trigger anything because we are not directly
874    * linking/unlinking the sink pad. */
875   ret = gst_pad_link (srcpad, ghostpad);
876   fail_unless (ret == GST_PAD_LINK_OK);
877   fail_unless (linked_count1 == 1);
878   fail_unless (unlinked_count1 == 0);
879   fail_unless (linked_count2 == 1);
880   fail_unless (unlinked_count2 == 0);
881
882   res = gst_pad_unlink (srcpad, ghostpad);
883   fail_unless (res == TRUE);
884   fail_unless (linked_count1 == 1);
885   fail_unless (unlinked_count1 == 0);
886   fail_unless (linked_count2 == 1);
887   fail_unless (unlinked_count2 == 1);
888
889   /* this should trigger the unlink */
890   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
891   fail_unless (res == TRUE);
892   fail_unless (linked_count1 == 1);
893   fail_unless (unlinked_count1 == 1);
894   fail_unless (linked_count2 == 1);
895   fail_unless (unlinked_count2 == 1);
896
897   gst_object_unref (ghostpad);
898   gst_object_unref (sinkpad);
899   gst_object_unref (srcpad);
900   gst_object_unref (srctempl);
901   gst_object_unref (sinktempl);
902 }
903
904 GST_END_TEST;
905
906 GST_START_TEST (test_ghost_pads_src_link_unlink)
907 {
908   GstCaps *padcaps;
909   GstPad *srcpad, *sinkpad, *ghostpad, *dummy;
910   GstPadTemplate *srctempl, *sinktempl;
911   GstPadLinkReturn ret;
912   gboolean res;
913
914   padcaps = gst_caps_from_string ("some/caps");
915   fail_unless (padcaps != NULL);
916   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
917       GST_PAD_ALWAYS, padcaps);
918   gst_caps_unref (padcaps);
919
920   padcaps = gst_caps_from_string ("some/caps");
921   fail_unless (padcaps != NULL);
922   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
923       GST_PAD_ALWAYS, padcaps);
924   gst_caps_unref (padcaps);
925
926   srcpad = gst_pad_new_from_template (srctempl, "src");
927   fail_unless (srcpad != NULL);
928   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
929   fail_unless (sinkpad != NULL);
930
931   /* set up link/unlink functions for the pad */
932   linked_count1 = unlinked_count1 = 0;
933   gst_pad_set_link_function (srcpad, pad_linked1);
934   gst_pad_set_unlink_function (srcpad, pad_unlinked1);
935   linked_count2 = unlinked_count2 = 0;
936   gst_pad_set_link_function (sinkpad, pad_linked2);
937   gst_pad_set_unlink_function (sinkpad, pad_unlinked2);
938
939   /* this should trigger a link from the internal pad to the srcpad */
940   ghostpad = gst_ghost_pad_new ("ghostpad", srcpad);
941   fail_unless (ghostpad != NULL);
942   fail_unless (linked_count1 == 1);
943   fail_unless (unlinked_count1 == 0);
944   fail_unless (linked_count2 == 0);
945   fail_unless (unlinked_count2 == 0);
946
947   /* this should fail with a critial */
948   ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad));
949   fail_unless (dummy == NULL);
950   fail_unless (linked_count1 == 1);
951   fail_unless (unlinked_count1 == 0);
952   fail_unless (linked_count2 == 0);
953   fail_unless (unlinked_count2 == 0);
954
955   /* this should not trigger anything because we are not directly
956    * linking/unlinking the src pad. */
957   ret = gst_pad_link (ghostpad, sinkpad);
958   fail_unless (ret == GST_PAD_LINK_OK);
959   fail_unless (linked_count1 == 1);
960   fail_unless (unlinked_count1 == 0);
961   fail_unless (linked_count2 == 1);
962   fail_unless (unlinked_count2 == 0);
963
964   /* this link should fail because we are already linked. Let's make sure the
965    * link functions are not called */
966   ret = gst_pad_link (ghostpad, sinkpad);
967   fail_unless (ret == GST_PAD_LINK_WAS_LINKED);
968   fail_unless (linked_count1 == 1);
969   fail_unless (unlinked_count1 == 0);
970   fail_unless (linked_count2 == 1);
971   fail_unless (unlinked_count2 == 0);
972
973   res = gst_pad_unlink (ghostpad, sinkpad);
974   fail_unless (res == TRUE);
975   fail_unless (linked_count1 == 1);
976   fail_unless (unlinked_count1 == 0);
977   fail_unless (linked_count2 == 1);
978   fail_unless (unlinked_count2 == 1);
979
980   res = gst_pad_unlink (ghostpad, sinkpad);
981   fail_unless (res == FALSE);
982   fail_unless (linked_count1 == 1);
983   fail_unless (unlinked_count1 == 0);
984   fail_unless (linked_count2 == 1);
985   fail_unless (unlinked_count2 == 1);
986
987   /* this should trigger the unlink function */
988   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
989   fail_unless (res == TRUE);
990   fail_unless (linked_count1 == 1);
991   fail_unless (unlinked_count1 == 1);
992   fail_unless (linked_count2 == 1);
993   fail_unless (unlinked_count2 == 1);
994
995   /* and this the link function again */
996   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad);
997   fail_unless (res == TRUE);
998   fail_unless (linked_count1 == 2);
999   fail_unless (unlinked_count1 == 1);
1000   fail_unless (linked_count2 == 1);
1001   fail_unless (unlinked_count2 == 1);
1002
1003   gst_object_unref (ghostpad);
1004   gst_object_unref (sinkpad);
1005   gst_object_unref (srcpad);
1006   gst_object_unref (srctempl);
1007   gst_object_unref (sinktempl);
1008 }
1009
1010 GST_END_TEST;
1011
1012 GST_START_TEST (test_ghost_pads_change_when_linked)
1013 {
1014   GstElement *b1, *b2, *src, *fmt, *sink1, *sink2;
1015   GstPad *sinkpad, *ghostpad;
1016   GstCaps *caps;
1017
1018   b1 = gst_element_factory_make ("pipeline", NULL);
1019   b2 = gst_element_factory_make ("bin", NULL);
1020   src = gst_element_factory_make ("fakesrc", NULL);
1021   fmt = gst_element_factory_make ("capsfilter", NULL);
1022   sink1 = gst_element_factory_make ("fakesink", NULL);
1023   sink2 = gst_element_factory_make ("fakesink", NULL);
1024
1025   gst_bin_add (GST_BIN (b2), sink1);
1026   gst_bin_add (GST_BIN (b2), sink2);
1027   gst_bin_add (GST_BIN (b1), src);
1028   gst_bin_add (GST_BIN (b1), fmt);
1029   gst_bin_add (GST_BIN (b1), b2);
1030
1031   caps = gst_caps_from_string ("audio/x-raw, format=S16LE, channels=1");
1032   g_object_set (fmt, "caps", caps, NULL);
1033   gst_caps_unref (caps);
1034
1035   /* create the ghostpad as a sink-pad for bin 2 */
1036   ghostpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1037   gst_element_add_pad (b2, ghostpad);
1038
1039   sinkpad = gst_element_get_static_pad (sink1, "sink");
1040   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1041   gst_object_unref (sinkpad);
1042
1043   fail_unless (gst_element_link_many (src, fmt, b2, NULL));
1044
1045   /* set different target after ghostpad is linked */
1046   sinkpad = gst_element_get_static_pad (sink2, "sink");
1047   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1048   gst_object_unref (sinkpad);
1049
1050   /* clean up */
1051   gst_object_unref (b1);
1052 }
1053
1054 GST_END_TEST;
1055
1056 /* test that setting a ghostpad proxy pad as ghostpad target automatically set
1057  * both ghostpad targets.
1058  *
1059  * fakesrc ! ( ) ! fakesink
1060  */
1061
1062 GST_START_TEST (test_ghost_pads_internal_link)
1063 {
1064   GstElement *pipeline, *src, *bin, *sink;
1065   GstPad *sinkpad, *srcpad, *target;
1066   GstProxyPad *proxypad;
1067
1068   pipeline = gst_element_factory_make ("pipeline", NULL);
1069   bin = gst_element_factory_make ("bin", NULL);
1070   src = gst_element_factory_make ("fakesrc", NULL);
1071   sink = gst_element_factory_make ("fakesink", NULL);
1072
1073   gst_bin_add (GST_BIN (pipeline), src);
1074   gst_bin_add (GST_BIN (pipeline), bin);
1075   gst_bin_add (GST_BIN (pipeline), sink);
1076
1077   /* create the sink ghostpad */
1078   sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1079   proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1080   gst_element_add_pad (bin, sinkpad);
1081
1082   /* create the src ghostpad and link it to sink proxypad */
1083   srcpad = gst_ghost_pad_new ("src", GST_PAD (proxypad));
1084   gst_object_unref (proxypad);
1085   gst_element_add_pad (bin, srcpad);
1086
1087   fail_unless (gst_element_link_many (src, bin, sink, NULL));
1088
1089   /* Check that both targets are set, and point to each other */
1090   target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkpad));
1091   fail_if (target == NULL);
1092   proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (srcpad));
1093   fail_unless (target == GST_PAD (proxypad));
1094   gst_object_unref (target);
1095   gst_object_unref (proxypad);
1096
1097   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcpad));
1098   fail_if (target == NULL);
1099   proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1100   fail_unless (target == GST_PAD (proxypad));
1101   gst_object_unref (target);
1102   gst_object_unref (proxypad);
1103
1104   /* clean up */
1105   gst_object_unref (pipeline);
1106 }
1107
1108 GST_END_TEST;
1109
1110 /* Test that remove a ghostpad that has something flowing through it does not
1111  * crash the program
1112  */
1113
1114 GstElement *bin;
1115 GstPad *ghostsink;
1116 GstPad *ghostsrc;
1117
1118 static GstPadProbeReturn
1119 remove_ghostpad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer data)
1120 {
1121   gst_pad_set_active (ghostsrc, FALSE);
1122   gst_pad_set_active (ghostsink, FALSE);
1123   gst_element_remove_pad (bin, ghostsrc);
1124   gst_element_remove_pad (bin, ghostsink);
1125
1126   return GST_PAD_PROBE_DROP;
1127 }
1128
1129 GST_START_TEST (test_ghost_pads_remove_while_playing)
1130 {
1131   GstPad *sinkpad;
1132   GstPad *srcpad;
1133
1134   bin = gst_bin_new (NULL);
1135   gst_element_set_state (bin, GST_STATE_PLAYING);
1136   sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
1137
1138   ghostsrc = gst_ghost_pad_new_no_target ("ghostsrc", GST_PAD_SRC);
1139   sinkpad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ghostsrc)));
1140   ghostsink = gst_ghost_pad_new ("ghostsink", sinkpad);
1141   gst_object_unref (sinkpad);
1142   gst_pad_set_active (ghostsrc, TRUE);
1143   gst_pad_set_active (ghostsink, TRUE);
1144   gst_element_add_pad (bin, ghostsrc);
1145   gst_element_add_pad (bin, ghostsink);
1146
1147   srcpad = gst_pad_new ("srcpad", GST_PAD_SRC);
1148   gst_pad_set_active (srcpad, TRUE);
1149   gst_pad_link (srcpad, ghostsink);
1150
1151   gst_pad_add_probe (ghostsrc, GST_PAD_PROBE_TYPE_BUFFER,
1152       remove_ghostpad_probe_cb, NULL, NULL);
1153
1154   g_assert (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK);
1155
1156   gst_pad_set_active (srcpad, FALSE);
1157   gst_element_set_state (bin, GST_STATE_NULL);
1158   gst_object_unref (bin);
1159   gst_object_unref (srcpad);
1160 }
1161
1162 GST_END_TEST;
1163
1164 static Suite *
1165 gst_ghost_pad_suite (void)
1166 {
1167   Suite *s = suite_create ("GstGhostPad");
1168
1169   TCase *tc_chain = tcase_create ("ghost pad tests");
1170
1171   suite_add_tcase (s, tc_chain);
1172   tcase_add_test (tc_chain, test_remove1);
1173   tcase_add_test (tc_chain, test_remove2);
1174   tcase_add_test (tc_chain, test_remove_target);
1175   tcase_add_test (tc_chain, test_link);
1176   tcase_add_test (tc_chain, test_ghost_pads);
1177   tcase_add_test (tc_chain, test_ghost_pads_bin);
1178   tcase_add_test (tc_chain, test_ghost_pads_notarget);
1179   tcase_add_test (tc_chain, test_ghost_pads_block);
1180   tcase_add_test (tc_chain, test_ghost_pads_probes);
1181   tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
1182   tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
1183   tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps);
1184   tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink);
1185   tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink);
1186   tcase_add_test (tc_chain, test_ghost_pads_change_when_linked);
1187   tcase_add_test (tc_chain, test_ghost_pads_internal_link);
1188   tcase_add_test (tc_chain, test_ghost_pads_remove_while_playing);
1189
1190   return s;
1191 }
1192
1193 GST_CHECK_MAIN (gst_ghost_pad);