6c6f51866c0b14ffbcdb3f4af60852f2f227d9c1
[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., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include <gst/check/gstcheck.h>
23 #include <gst/check/gstharness.h>
24
25 /* test if removing a bin also cleans up the ghostpads
26  */
27 GST_START_TEST (test_remove1)
28 {
29   GstElement *b1, *b2, *src, *sink;
30   GstPad *srcpad, *sinkpad;
31   GstPadLinkReturn ret;
32
33   b1 = gst_element_factory_make ("pipeline", NULL);
34   b2 = gst_element_factory_make ("bin", NULL);
35   src = gst_element_factory_make ("fakesrc", NULL);
36   sink = gst_element_factory_make ("fakesink", NULL);
37   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
38   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
39
40   fail_unless (gst_bin_add (GST_BIN (b2), sink));
41   fail_unless (gst_bin_add (GST_BIN (b1), src));
42   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
43   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
44   fail_unless (gst_bin_add (GST_BIN (b1), b2));
45   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
46   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
47
48   sinkpad = gst_element_get_static_pad (sink, "sink");
49   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
50   gst_object_unref (sinkpad);
51
52   srcpad = gst_element_get_static_pad (src, "src");
53   /* get the ghostpad */
54   sinkpad = gst_element_get_static_pad (b2, "sink");
55
56   ret = gst_pad_link (srcpad, sinkpad);
57   fail_unless (ret == GST_PAD_LINK_OK);
58   gst_object_unref (srcpad);
59   gst_object_unref (sinkpad);
60
61   /* now remove the bin with the ghostpad, b2 is disposed now. */
62   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
63   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
64   gst_bin_remove (GST_BIN (b1), b2);
65
66   srcpad = gst_element_get_static_pad (src, "src");
67   /* pad cannot be linked now */
68   fail_if (gst_pad_is_linked (srcpad));
69   gst_object_unref (srcpad);
70
71   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
72   gst_object_unref (b1);
73 }
74
75 GST_END_TEST;
76
77 /* test if removing a bin also cleans up the ghostpads
78  */
79 GST_START_TEST (test_remove2)
80 {
81   GstElement *b1, *b2, *src, *sink;
82   GstPad *srcpad, *sinkpad;
83   GstPadLinkReturn ret;
84
85   b1 = gst_element_factory_make ("pipeline", NULL);
86   b2 = gst_element_factory_make ("bin", NULL);
87   src = gst_element_factory_make ("fakesrc", NULL);
88   sink = gst_element_factory_make ("fakesink", NULL);
89   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
90
91   fail_unless (gst_bin_add (GST_BIN (b2), sink));
92   fail_unless (gst_bin_add (GST_BIN (b1), src));
93   fail_unless (gst_bin_add (GST_BIN (b1), b2));
94   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
95
96   sinkpad = gst_element_get_static_pad (sink, "sink");
97   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
98   gst_object_unref (sinkpad);
99
100   srcpad = gst_element_get_static_pad (src, "src");
101   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); /* since we got one */
102   /* get the ghostpad */
103   sinkpad = gst_element_get_static_pad (b2, "sink");
104   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);       /* since we got one */
105
106   GST_DEBUG ("linking srcpad and sinkpad");
107   ret = gst_pad_link (srcpad, sinkpad);
108   GST_DEBUG ("linked srcpad and sinkpad");
109   fail_unless (ret == GST_PAD_LINK_OK);
110   /* Refcount should be unchanged, targets are now decuced using peer pad */
111   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
112   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
113   gst_object_unref (srcpad);
114   gst_object_unref (sinkpad);
115
116   /* now remove the sink from the bin */
117   gst_bin_remove (GST_BIN (b2), sink);
118
119   srcpad = gst_element_get_static_pad (src, "src");
120   /* pad is still linked to ghostpad */
121   fail_if (!gst_pad_is_linked (srcpad));
122   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
123   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
124   gst_object_unref (srcpad);
125   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
126
127   /* cleanup */
128   /* now unlink the pads */
129   gst_pad_unlink (srcpad, sinkpad);
130   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); /* we dropped our ref */
131   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
132
133   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
134   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
135   /* remove b2 from b1 */
136   gst_bin_remove (GST_BIN (b1), b2);
137
138   /* flush the message, dropping the b1 refcount to 1 */
139   gst_element_set_state (b1, GST_STATE_READY);
140   gst_element_set_state (b1, GST_STATE_NULL);
141   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
142   gst_object_unref (b1);
143 }
144
145 GST_END_TEST;
146
147
148
149 /* test if a ghost pad without a target can be linked and
150  * unlinked. An untargeted ghostpad has a default ANY caps unless there 
151  * is a padtemplate that says something else.
152  */
153 GST_START_TEST (test_ghost_pads_notarget)
154 {
155   GstElement *b1, *b2, *sink;
156   GstPad *srcpad, *sinkpad, *peer;
157   GstPadLinkReturn ret;
158   gboolean bret;
159   GstBus *bus;
160   GstCaps *caps;
161
162   b1 = gst_element_factory_make ("pipeline", NULL);
163
164   /* make sure all messages are discarded */
165   bus = gst_pipeline_get_bus (GST_PIPELINE (b1));
166   gst_bus_set_flushing (bus, TRUE);
167   gst_object_unref (bus);
168
169   b2 = gst_element_factory_make ("bin", NULL);
170   sink = gst_element_factory_make ("fakesink", NULL);
171
172   fail_unless (gst_bin_add (GST_BIN (b1), sink));
173   fail_unless (gst_bin_add (GST_BIN (b1), b2));
174
175   srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
176   fail_unless (srcpad != NULL);
177   sinkpad = gst_element_get_static_pad (sink, "sink");
178   fail_unless (sinkpad != NULL);
179
180   ret = gst_pad_link (srcpad, sinkpad);
181   fail_unless (ret == GST_PAD_LINK_OK);
182
183   /* check if the peers are ok */
184   peer = gst_pad_get_peer (srcpad);
185   fail_unless (peer == sinkpad);
186   gst_object_unref (peer);
187
188   peer = gst_pad_get_peer (sinkpad);
189   fail_unless (peer == srcpad);
190   gst_object_unref (peer);
191
192   /* check caps, untargetted pad should return ANY or the padtemplate caps 
193    * when it was created from a template */
194   caps = gst_pad_query_caps (srcpad, NULL);
195   fail_unless (gst_caps_is_any (caps));
196   gst_caps_unref (caps);
197
198   /* unlink */
199   bret = gst_pad_unlink (srcpad, sinkpad);
200   fail_unless (bret == TRUE);
201
202   /* cleanup */
203   gst_object_unref (srcpad);
204   gst_object_unref (sinkpad);
205   gst_object_unref (b1);
206 }
207
208 GST_END_TEST;
209
210 /* Test that removing the target of a ghostpad properly sets the target of the
211  * ghostpad to NULL */
212 GST_START_TEST (test_remove_target)
213 {
214   GstElement *b1, *b2, *src, *sink;
215   GstPad *sinkpad, *ghost, *target;
216
217   b1 = gst_element_factory_make ("pipeline", NULL);
218   b2 = gst_element_factory_make ("bin", NULL);
219   src = gst_element_factory_make ("fakesrc", NULL);
220   sink = gst_element_factory_make ("fakesink", NULL);
221   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
222
223   fail_unless (gst_bin_add (GST_BIN (b2), sink));
224   fail_unless (gst_bin_add (GST_BIN (b1), src));
225   fail_unless (gst_bin_add (GST_BIN (b1), b2));
226   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
227
228   sinkpad = gst_element_get_static_pad (sink, "sink");
229   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
230
231   ghost = gst_element_get_static_pad (b2, "sink");
232
233   target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
234   fail_unless (target == sinkpad);
235   gst_object_unref (target);
236   gst_object_unref (sinkpad);
237
238   gst_bin_remove (GST_BIN (b2), sink);
239
240   target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
241   fail_unless (target == NULL);
242
243   gst_object_unref (b1);
244   gst_object_unref (ghost);
245 }
246
247 GST_END_TEST;
248
249
250 /* test if linking fails over different bins using a pipeline
251  * like this:
252  *
253  * fakesrc num_buffers=10 ! ( fakesink )
254  *
255  */
256 GST_START_TEST (test_link)
257 {
258   GstElement *b1, *b2, *src, *sink;
259   GstPad *srcpad, *sinkpad, *gpad, *ppad, *tmp;
260   GstPadLinkReturn ret;
261
262   b1 = gst_element_factory_make ("pipeline", NULL);
263   b2 = gst_element_factory_make ("bin", NULL);
264   src = gst_element_factory_make ("fakesrc", NULL);
265   sink = gst_element_factory_make ("fakesink", NULL);
266
267   fail_unless (gst_bin_add (GST_BIN (b2), sink));
268   fail_unless (gst_bin_add (GST_BIN (b1), src));
269   fail_unless (gst_bin_add (GST_BIN (b1), b2));
270
271   srcpad = gst_element_get_static_pad (src, "src");
272   fail_unless (srcpad != NULL);
273   sinkpad = gst_element_get_static_pad (sink, "sink");
274   fail_unless (sinkpad != NULL);
275
276   /* linking in different hierarchies should fail */
277   ret = gst_pad_link (srcpad, sinkpad);
278   fail_unless (ret == GST_PAD_LINK_WRONG_HIERARCHY);
279
280   /* now setup a ghostpad */
281   gpad = gst_ghost_pad_new ("sink", sinkpad);
282
283   /* Check if the internal pads are set correctly */
284   ppad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (gpad)));
285   fail_unless (ppad == GST_PAD_PEER (sinkpad));
286   tmp = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ppad)));
287   fail_unless (tmp == gpad);
288   gst_object_unref (tmp);
289   gst_object_unref (ppad);
290   gst_object_unref (sinkpad);
291   /* need to ref as _add_pad takes ownership */
292   gst_object_ref (gpad);
293   gst_element_add_pad (b2, gpad);
294
295   /* our new sinkpad */
296   sinkpad = gpad;
297
298   /* and linking should work now */
299   ret = gst_pad_link (srcpad, sinkpad);
300   fail_unless (ret == GST_PAD_LINK_OK);
301
302   /* flush the message, dropping the b1 refcount to 1 */
303   gst_element_set_state (b1, GST_STATE_READY);
304   gst_element_set_state (b1, GST_STATE_NULL);
305   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
306
307   gst_object_unref (srcpad);
308   gst_object_unref (sinkpad);
309   gst_object_unref (b1);
310 }
311
312 GST_END_TEST;
313
314 /* test if ghostpads are created automagically when using
315  * gst_element_link_pads.
316  *
317  * fakesrc num_buffers=10 ! ( identity ) ! fakesink
318  */
319 GST_START_TEST (test_ghost_pads)
320 {
321   GstElement *b1, *b2, *src, *i1, *sink;
322   GstPad *gsink, *gsrc, *gisrc, *gisink, *isink, *isrc, *fsrc, *fsink;
323   GstStateChangeReturn ret;
324
325   b1 = gst_element_factory_make ("pipeline", NULL);
326   b2 = gst_element_factory_make ("bin", NULL);
327   src = gst_element_factory_make ("fakesrc", NULL);
328   g_object_set (src, "num-buffers", (int) 10, NULL);
329   i1 = gst_element_factory_make ("identity", NULL);
330   sink = gst_element_factory_make ("fakesink", NULL);
331
332   fail_unless (gst_bin_add (GST_BIN (b2), i1));
333   fail_unless (gst_bin_add (GST_BIN (b1), src));
334   fail_unless (gst_bin_add (GST_BIN (b1), b2));
335   fail_unless (gst_bin_add (GST_BIN (b1), sink));
336   fail_unless (gst_element_link_pads (src, NULL, i1, NULL));
337   fail_unless (gst_element_link_pads (i1, NULL, sink, NULL));
338   GST_OBJECT_LOCK (b2);
339   fail_unless (b2->numsinkpads == 1);
340   fail_unless (GST_IS_GHOST_PAD (b2->sinkpads->data));
341   fail_unless (b2->numsrcpads == 1);
342   fail_unless (GST_IS_GHOST_PAD (b2->srcpads->data));
343   GST_OBJECT_UNLOCK (b2);
344
345   fsrc = gst_element_get_static_pad (src, "src");
346   fail_unless (fsrc != NULL);
347   gsink = GST_PAD (gst_object_ref (b2->sinkpads->data));
348   fail_unless (gsink != NULL);
349   gsrc = GST_PAD (gst_object_ref (b2->srcpads->data));
350   fail_unless (gsrc != NULL);
351   fsink = gst_element_get_static_pad (sink, "sink");
352   fail_unless (fsink != NULL);
353
354   isink = gst_element_get_static_pad (i1, "sink");
355   fail_unless (isink != NULL);
356   isrc = gst_element_get_static_pad (i1, "src");
357   fail_unless (isrc != NULL);
358   gisrc = gst_pad_get_peer (isink);
359   fail_unless (gisrc != NULL);
360   gisink = gst_pad_get_peer (isrc);
361   fail_unless (gisink != NULL);
362
363   /* all objects above have one refcount owned by us as well */
364
365   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 2);     /* parent */
366   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 2);   /* parent */
367   ASSERT_OBJECT_REFCOUNT (gsrc, "gsrc", 2);     /* parent */
368   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 2);   /* parent */
369
370   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* parent */
371   ASSERT_OBJECT_REFCOUNT (isink, "isink", 2);   /* parent */
372   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* parent */
373   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 2);     /* parent */
374
375   ret = gst_element_set_state (b1, GST_STATE_PLAYING);
376   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
377   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
378
379   ret = gst_element_set_state (b1, GST_STATE_NULL);
380   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
381   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
382
383   gst_object_unref (b1);
384   /* unreffing the bin will unref all elements, which will unlink and unparent
385    * all pads */
386
387   /* wait for thread to settle down */
388   while (GST_OBJECT_REFCOUNT_VALUE (fsrc) > 1)
389     THREAD_SWITCH ();
390
391   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
392   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 1);
393   ASSERT_OBJECT_REFCOUNT (gsrc, "gsink", 1);
394   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
395
396   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* gsink */
397   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);   /* gsink */
398   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* gsrc */
399   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);     /* gsrc */
400
401   gst_object_unref (gsink);
402   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);
403   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 1);
404   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
405   gst_object_unref (gisrc);
406   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
407
408   gst_object_unref (gsrc);
409   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);
410   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 1);
411   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
412   gst_object_unref (gisink);
413   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
414
415   gst_object_unref (fsrc);
416   gst_object_unref (isrc);
417   gst_object_unref (isink);
418   gst_object_unref (fsink);
419 }
420
421 GST_END_TEST;
422
423 GST_START_TEST (test_ghost_pads_bin)
424 {
425   GstBin *pipeline;
426   GstBin *srcbin;
427   GstBin *sinkbin;
428   GstElement *src;
429   GstElement *sink;
430   GstPad *srcpad, *srcghost, *target;
431   GstPad *sinkpad, *sinkghost;
432
433   pipeline = GST_BIN (gst_pipeline_new ("pipe"));
434   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
435
436   srcbin = GST_BIN (gst_bin_new ("srcbin"));
437   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
438   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
439
440   sinkbin = GST_BIN (gst_bin_new ("sinkbin"));
441   gst_bin_add (pipeline, GST_ELEMENT (sinkbin));
442   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
443
444   src = gst_element_factory_make ("fakesrc", "src");
445   gst_bin_add (srcbin, src);
446   srcpad = gst_element_get_static_pad (src, "src");
447   srcghost = gst_ghost_pad_new ("src", srcpad);
448   gst_object_unref (srcpad);
449   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
450
451   sink = gst_element_factory_make ("fakesink", "sink");
452   gst_bin_add (sinkbin, sink);
453   sinkpad = gst_element_get_static_pad (sink, "sink");
454   sinkghost = gst_ghost_pad_new ("sink", sinkpad);
455   gst_object_unref (sinkpad);
456   gst_element_add_pad (GST_ELEMENT (sinkbin), sinkghost);
457
458   gst_element_link (GST_ELEMENT (srcbin), GST_ELEMENT (sinkbin));
459
460   fail_unless (GST_PAD_PEER (srcghost) != NULL);
461   fail_unless (GST_PAD_PEER (sinkghost) != NULL);
462   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcghost));
463   fail_unless (GST_PAD_PEER (target) != NULL);
464   gst_object_unref (target);
465   target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkghost));
466   fail_unless (GST_PAD_PEER (target) != NULL);
467   gst_object_unref (target);
468
469   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
470
471   gst_object_unref (pipeline);
472 }
473
474 GST_END_TEST;
475
476 typedef struct
477 {
478   GMutex mutex;
479   GCond cond;
480 } BlockData;
481
482 static GstPadProbeReturn
483 block_callback (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
484 {
485   BlockData *block_data = (BlockData *) user_data;
486
487   g_mutex_lock (&block_data->mutex);
488   GST_DEBUG ("blocked\n");
489   g_cond_signal (&block_data->cond);
490   g_mutex_unlock (&block_data->mutex);
491
492   return GST_PAD_PROBE_OK;
493 }
494
495 GST_START_TEST (test_ghost_pads_block)
496 {
497   GstBin *pipeline;
498   GstBin *srcbin;
499   GstElement *src;
500   GstPad *srcpad;
501   GstPad *srcghost;
502   BlockData block_data;
503
504   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
505
506   srcbin = GST_BIN (gst_bin_new ("srcbin"));
507   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
508
509   src = gst_element_factory_make ("fakesrc", "src");
510   gst_bin_add (srcbin, src);
511   srcpad = gst_element_get_static_pad (src, "src");
512   srcghost = gst_ghost_pad_new ("src", srcpad);
513   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
514   gst_object_unref (srcpad);
515
516   g_mutex_init (&block_data.mutex);
517   g_cond_init (&block_data.cond);
518
519   g_mutex_lock (&block_data.mutex);
520   gst_pad_add_probe (srcghost, GST_PAD_PROBE_TYPE_BLOCK, block_callback,
521       &block_data, NULL);
522   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
523   /* and wait now */
524   g_cond_wait (&block_data.cond, &block_data.mutex);
525   g_mutex_unlock (&block_data.mutex);
526   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
527
528   g_mutex_clear (&block_data.mutex);
529   g_cond_clear (&block_data.cond);
530
531   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
532   gst_object_unref (pipeline);
533 }
534
535 GST_END_TEST;
536
537 GST_START_TEST (test_ghost_pads_probes)
538 {
539   GstBin *pipeline;
540   GstBin *srcbin;
541   GstElement *src;
542   GstPad *srcpad;
543   GstPad *srcghost;
544   BlockData block_data;
545
546   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
547
548   srcbin = GST_BIN (gst_bin_new ("srcbin"));
549   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
550
551   src = gst_element_factory_make ("fakesrc", "src");
552   gst_bin_add (srcbin, src);
553   srcpad = gst_element_get_static_pad (src, "src");
554   srcghost = gst_ghost_pad_new ("src", srcpad);
555   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
556   gst_object_unref (srcpad);
557
558   g_mutex_init (&block_data.mutex);
559   g_cond_init (&block_data.cond);
560
561   g_mutex_lock (&block_data.mutex);
562   gst_pad_add_probe (srcghost, GST_PAD_PROBE_TYPE_BLOCK, block_callback,
563       &block_data, NULL);
564   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
565   /* and wait now */
566   g_cond_wait (&block_data.cond, &block_data.mutex);
567   g_mutex_unlock (&block_data.mutex);
568   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
569
570   g_mutex_clear (&block_data.mutex);
571   g_cond_clear (&block_data.cond);
572
573   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
574   gst_object_unref (pipeline);
575 }
576
577 GST_END_TEST;
578
579 GST_START_TEST (test_ghost_pads_new_from_template)
580 {
581   GstPad *sinkpad, *ghostpad;
582   GstPadTemplate *padtempl, *ghosttempl;
583   GstCaps *padcaps, *ghostcaps, *newcaps;
584
585   padcaps = gst_caps_from_string ("some/caps");
586   fail_unless (padcaps != NULL);
587   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
588   fail_unless (ghostcaps != NULL);
589
590   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
591       GST_PAD_ALWAYS, padcaps);
592   fail_unless (padtempl != NULL);
593   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
594       GST_PAD_ALWAYS, ghostcaps);
595
596   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
597   fail_unless (sinkpad != NULL);
598
599   ghostpad = gst_ghost_pad_new_from_template ("ghostpad", sinkpad, ghosttempl);
600   fail_unless (ghostpad != NULL);
601
602   /* check template is properly set */
603   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
604
605   /* check ghostpad caps are from the sinkpad */
606   newcaps = gst_pad_query_caps (ghostpad, NULL);
607   fail_unless (newcaps != NULL);
608   fail_unless (gst_caps_is_equal (newcaps, padcaps));
609   gst_caps_unref (newcaps);
610   gst_caps_unref (padcaps);
611   gst_caps_unref (ghostcaps);
612
613   gst_object_unref (sinkpad);
614   gst_object_unref (ghostpad);
615
616   gst_object_unref (padtempl);
617   gst_object_unref (ghosttempl);
618 }
619
620 GST_END_TEST;
621
622 GST_START_TEST (test_ghost_pads_new_no_target_from_template)
623 {
624   GstPad *sinkpad, *ghostpad;
625   GstPadTemplate *padtempl, *ghosttempl;
626   GstCaps *padcaps, *ghostcaps, *newcaps;
627
628   padcaps = gst_caps_from_string ("some/caps");
629   fail_unless (padcaps != NULL);
630   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
631   fail_unless (ghostcaps != NULL);
632
633   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
634       GST_PAD_ALWAYS, padcaps);
635   fail_unless (padtempl != NULL);
636   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
637       GST_PAD_ALWAYS, ghostcaps);
638
639   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
640   fail_unless (sinkpad != NULL);
641
642   ghostpad = gst_ghost_pad_new_no_target_from_template ("ghostpad", ghosttempl);
643   fail_unless (ghostpad != NULL);
644
645   /* check template is properly set */
646   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
647
648   /* check ghostpad caps are from the ghostpad template */
649   newcaps = gst_pad_query_caps (ghostpad, NULL);
650   fail_unless (newcaps != NULL);
651   fail_unless (gst_caps_is_equal (newcaps, ghostcaps));
652   gst_caps_unref (newcaps);
653
654   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
655
656   /* check ghostpad caps are now from the target pad */
657   newcaps = gst_pad_query_caps (ghostpad, NULL);
658   fail_unless (newcaps != NULL);
659   fail_unless (gst_caps_is_equal (newcaps, padcaps));
660   gst_caps_unref (newcaps);
661
662   gst_object_unref (sinkpad);
663   gst_object_unref (ghostpad);
664
665   gst_object_unref (padtempl);
666   gst_object_unref (ghosttempl);
667
668   gst_caps_unref (padcaps);
669   gst_caps_unref (ghostcaps);
670 }
671
672 GST_END_TEST;
673
674 static void
675 ghost_notify_caps (GObject * object, GParamSpec * pspec, gpointer * user_data)
676 {
677   GST_DEBUG ("caps notify called");
678   (*(gint *) user_data)++;
679 }
680
681 GST_START_TEST (test_ghost_pads_forward_setcaps)
682 {
683   GstCaps *templ_caps, *caps1, *caps2;
684   GstPadTemplate *src_template, *sink_template;
685   GstPad *src, *ghost, *sink;
686   gint notify_counter = 0;
687
688   templ_caps = gst_caps_from_string ("meh; muh");
689   src_template = gst_pad_template_new ("src", GST_PAD_SRC,
690       GST_PAD_ALWAYS, templ_caps);
691   gst_caps_unref (templ_caps);
692
693   templ_caps = gst_caps_from_string ("muh; meh");
694   sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
695       GST_PAD_ALWAYS, templ_caps);
696   gst_caps_unref (templ_caps);
697
698   src = gst_pad_new_from_template (src_template, "src");
699   sink = gst_pad_new_from_template (sink_template, "sink");
700
701   /* ghost source pad, setting caps on the source influences the caps of the
702    * ghostpad. */
703   ghost = gst_ghost_pad_new ("ghostsrc", src);
704   g_signal_connect (ghost, "notify::caps",
705       G_CALLBACK (ghost_notify_caps), &notify_counter);
706   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
707
708   /* Activate pads for caps forwarding/setting to work */
709   gst_pad_set_active (src, TRUE);
710   gst_pad_set_active (ghost, TRUE);
711
712   caps1 = gst_caps_from_string ("meh");
713   fail_unless (gst_pad_set_caps (src, caps1));
714   caps2 = gst_pad_get_current_caps (ghost);
715   fail_unless (gst_caps_is_equal (caps1, caps2));
716   fail_unless_equals_int (notify_counter, 1);
717
718   gst_object_unref (ghost);
719   gst_caps_unref (caps1);
720   gst_caps_unref (caps2);
721
722   /* source 2, setting the caps on the ghostpad does not influence the caps of
723    * the target */
724   notify_counter = 0;
725   ghost = gst_ghost_pad_new ("ghostsrc", src);
726   g_signal_connect (ghost, "notify::caps",
727       G_CALLBACK (ghost_notify_caps), &notify_counter);
728   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
729
730   gst_pad_set_active (ghost, TRUE);
731   gst_pad_set_active (sink, TRUE);
732
733   caps1 = gst_caps_from_string ("meh");
734   fail_unless (gst_pad_set_caps (ghost, caps1));
735 #if 0
736   caps2 = gst_pad_get_current_caps (src);
737   fail_unless (caps2 == NULL);
738 #endif
739   fail_unless_equals_int (notify_counter, 1);
740
741   gst_object_unref (ghost);
742   gst_caps_unref (caps1);
743
744
745   /* ghost sink pad. Setting caps on the ghostpad will also set those caps on
746    * the target pad. */
747   notify_counter = 0;
748   ghost = gst_ghost_pad_new ("ghostsink", sink);
749   g_signal_connect (ghost, "notify::caps",
750       G_CALLBACK (ghost_notify_caps), &notify_counter);
751   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
752
753   gst_pad_set_active (src, TRUE);
754   gst_pad_set_active (ghost, TRUE);
755
756   caps1 = gst_caps_from_string ("muh");
757   fail_unless (gst_pad_set_caps (ghost, caps1));
758   caps2 = gst_pad_get_current_caps (sink);
759   fail_unless (gst_caps_is_equal (caps1, caps2));
760   fail_unless_equals_int (notify_counter, 1);
761
762   gst_object_unref (ghost);
763   gst_caps_unref (caps1);
764   gst_caps_unref (caps2);
765
766   /* clear caps on pads */
767   gst_pad_set_active (src, FALSE);
768   gst_pad_set_active (src, TRUE);
769   gst_pad_set_active (sink, FALSE);
770   gst_pad_set_active (sink, TRUE);
771
772   /* sink pad 2, setting caps just on the target pad should not influence the caps
773    * on the ghostpad. */
774   notify_counter = 0;
775   ghost = gst_ghost_pad_new ("ghostsink", sink);
776   fail_unless (gst_pad_get_current_caps (ghost) == NULL);
777   g_signal_connect (ghost, "notify::caps",
778       G_CALLBACK (ghost_notify_caps), &notify_counter);
779   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
780
781   gst_pad_set_active (ghost, TRUE);
782
783   caps1 = gst_caps_from_string ("muh");
784   fail_unless (gst_pad_set_caps (sink, caps1));
785   caps2 = gst_pad_get_current_caps (ghost);
786   fail_unless (caps2 == NULL);
787   fail_unless_equals_int (notify_counter, 0);
788
789   gst_object_unref (ghost);
790   gst_caps_unref (caps1);
791
792   gst_object_unref (src);
793   gst_object_unref (sink);
794   gst_object_unref (src_template);
795   gst_object_unref (sink_template);
796 }
797
798 GST_END_TEST;
799
800 static gint linked_count1;
801 static gint unlinked_count1;
802 static gint linked_count2;
803 static gint unlinked_count2;
804
805 static GstPadLinkReturn
806 pad_linked1 (GstPad * pad, GstObject * parent, GstPad * peer)
807 {
808   linked_count1++;
809
810   return GST_PAD_LINK_OK;
811 }
812
813 static void
814 pad_unlinked1 (GstPad * pad, GstObject * parent)
815 {
816   unlinked_count1++;
817 }
818
819 static GstPadLinkReturn
820 pad_linked2 (GstPad * pad, GstObject * parent, GstPad * peer)
821 {
822   linked_count2++;
823
824   return GST_PAD_LINK_OK;
825 }
826
827 static void
828 pad_unlinked2 (GstPad * pad, GstObject * parent)
829 {
830   unlinked_count2++;
831 }
832
833 GST_START_TEST (test_ghost_pads_sink_link_unlink)
834 {
835   GstCaps *padcaps;
836   GstPad *srcpad, *sinkpad, *ghostpad;
837   GstPadTemplate *srctempl, *sinktempl;
838   GstPadLinkReturn ret;
839   gboolean res;
840
841   padcaps = gst_caps_from_string ("some/caps");
842   fail_unless (padcaps != NULL);
843   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
844       GST_PAD_ALWAYS, padcaps);
845   gst_caps_unref (padcaps);
846
847   padcaps = gst_caps_from_string ("some/caps");
848   fail_unless (padcaps != NULL);
849   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
850       GST_PAD_ALWAYS, padcaps);
851   gst_caps_unref (padcaps);
852
853   srcpad = gst_pad_new_from_template (srctempl, "src");
854   fail_unless (srcpad != NULL);
855   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
856   fail_unless (sinkpad != NULL);
857
858   /* set up link/unlink functions for the pad */
859   linked_count1 = unlinked_count1 = 0;
860   gst_pad_set_link_function (sinkpad, pad_linked1);
861   gst_pad_set_unlink_function (sinkpad, pad_unlinked1);
862   linked_count2 = unlinked_count2 = 0;
863   gst_pad_set_link_function (srcpad, pad_linked2);
864   gst_pad_set_unlink_function (srcpad, pad_unlinked2);
865
866   /* this should trigger a link from the internal pad to the sinkpad */
867   ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad);
868   fail_unless (ghostpad != NULL);
869   fail_unless (linked_count1 == 1);
870   fail_unless (unlinked_count1 == 0);
871   fail_unless (linked_count2 == 0);
872   fail_unless (unlinked_count2 == 0);
873
874   /* this should not trigger anything because we are not directly
875    * linking/unlinking the sink pad. */
876   ret = gst_pad_link (srcpad, ghostpad);
877   fail_unless (ret == GST_PAD_LINK_OK);
878   fail_unless (linked_count1 == 1);
879   fail_unless (unlinked_count1 == 0);
880   fail_unless (linked_count2 == 1);
881   fail_unless (unlinked_count2 == 0);
882
883   res = gst_pad_unlink (srcpad, ghostpad);
884   fail_unless (res == TRUE);
885   fail_unless (linked_count1 == 1);
886   fail_unless (unlinked_count1 == 0);
887   fail_unless (linked_count2 == 1);
888   fail_unless (unlinked_count2 == 1);
889
890   /* this should trigger the unlink */
891   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
892   fail_unless (res == TRUE);
893   fail_unless (linked_count1 == 1);
894   fail_unless (unlinked_count1 == 1);
895   fail_unless (linked_count2 == 1);
896   fail_unless (unlinked_count2 == 1);
897
898   gst_object_unref (ghostpad);
899   gst_object_unref (sinkpad);
900   gst_object_unref (srcpad);
901   gst_object_unref (srctempl);
902   gst_object_unref (sinktempl);
903 }
904
905 GST_END_TEST;
906
907 GST_START_TEST (test_ghost_pads_src_link_unlink)
908 {
909   GstCaps *padcaps;
910   GstPad *srcpad, *sinkpad, *ghostpad, *dummy;
911   GstPadTemplate *srctempl, *sinktempl;
912   GstPadLinkReturn ret;
913   gboolean res;
914
915   padcaps = gst_caps_from_string ("some/caps");
916   fail_unless (padcaps != NULL);
917   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
918       GST_PAD_ALWAYS, padcaps);
919   gst_caps_unref (padcaps);
920
921   padcaps = gst_caps_from_string ("some/caps");
922   fail_unless (padcaps != NULL);
923   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
924       GST_PAD_ALWAYS, padcaps);
925   gst_caps_unref (padcaps);
926
927   srcpad = gst_pad_new_from_template (srctempl, "src");
928   fail_unless (srcpad != NULL);
929   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
930   fail_unless (sinkpad != NULL);
931
932   /* set up link/unlink functions for the pad */
933   linked_count1 = unlinked_count1 = 0;
934   gst_pad_set_link_function (srcpad, pad_linked1);
935   gst_pad_set_unlink_function (srcpad, pad_unlinked1);
936   linked_count2 = unlinked_count2 = 0;
937   gst_pad_set_link_function (sinkpad, pad_linked2);
938   gst_pad_set_unlink_function (sinkpad, pad_unlinked2);
939
940   /* this should trigger a link from the internal pad to the srcpad */
941   ghostpad = gst_ghost_pad_new ("ghostpad", srcpad);
942   fail_unless (ghostpad != NULL);
943   fail_unless (linked_count1 == 1);
944   fail_unless (unlinked_count1 == 0);
945   fail_unless (linked_count2 == 0);
946   fail_unless (unlinked_count2 == 0);
947
948   /* this should fail with a critial */
949   ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad));
950   fail_unless (dummy == NULL);
951   fail_unless (linked_count1 == 1);
952   fail_unless (unlinked_count1 == 0);
953   fail_unless (linked_count2 == 0);
954   fail_unless (unlinked_count2 == 0);
955
956   /* this should not trigger anything because we are not directly
957    * linking/unlinking the src pad. */
958   ret = gst_pad_link (ghostpad, sinkpad);
959   fail_unless (ret == GST_PAD_LINK_OK);
960   fail_unless (linked_count1 == 1);
961   fail_unless (unlinked_count1 == 0);
962   fail_unless (linked_count2 == 1);
963   fail_unless (unlinked_count2 == 0);
964
965   /* this link should fail because we are already linked. Let's make sure the
966    * link functions are not called */
967   ret = gst_pad_link (ghostpad, sinkpad);
968   fail_unless (ret == GST_PAD_LINK_WAS_LINKED);
969   fail_unless (linked_count1 == 1);
970   fail_unless (unlinked_count1 == 0);
971   fail_unless (linked_count2 == 1);
972   fail_unless (unlinked_count2 == 0);
973
974   res = gst_pad_unlink (ghostpad, sinkpad);
975   fail_unless (res == TRUE);
976   fail_unless (linked_count1 == 1);
977   fail_unless (unlinked_count1 == 0);
978   fail_unless (linked_count2 == 1);
979   fail_unless (unlinked_count2 == 1);
980
981   res = gst_pad_unlink (ghostpad, sinkpad);
982   fail_unless (res == FALSE);
983   fail_unless (linked_count1 == 1);
984   fail_unless (unlinked_count1 == 0);
985   fail_unless (linked_count2 == 1);
986   fail_unless (unlinked_count2 == 1);
987
988   /* this should trigger the unlink function */
989   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
990   fail_unless (res == TRUE);
991   fail_unless (linked_count1 == 1);
992   fail_unless (unlinked_count1 == 1);
993   fail_unless (linked_count2 == 1);
994   fail_unless (unlinked_count2 == 1);
995
996   /* and this the link function again */
997   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad);
998   fail_unless (res == TRUE);
999   fail_unless (linked_count1 == 2);
1000   fail_unless (unlinked_count1 == 1);
1001   fail_unless (linked_count2 == 1);
1002   fail_unless (unlinked_count2 == 1);
1003
1004   gst_object_unref (ghostpad);
1005   gst_object_unref (sinkpad);
1006   gst_object_unref (srcpad);
1007   gst_object_unref (srctempl);
1008   gst_object_unref (sinktempl);
1009 }
1010
1011 GST_END_TEST;
1012
1013 GST_START_TEST (test_ghost_pads_change_when_linked)
1014 {
1015   GstElement *b1, *b2, *src, *fmt, *sink1, *sink2;
1016   GstPad *sinkpad, *ghostpad;
1017   GstCaps *caps;
1018
1019   b1 = gst_element_factory_make ("pipeline", NULL);
1020   b2 = gst_element_factory_make ("bin", NULL);
1021   src = gst_element_factory_make ("fakesrc", NULL);
1022   fmt = gst_element_factory_make ("capsfilter", NULL);
1023   sink1 = gst_element_factory_make ("fakesink", NULL);
1024   sink2 = gst_element_factory_make ("fakesink", NULL);
1025
1026   gst_bin_add (GST_BIN (b2), sink1);
1027   gst_bin_add (GST_BIN (b2), sink2);
1028   gst_bin_add (GST_BIN (b1), src);
1029   gst_bin_add (GST_BIN (b1), fmt);
1030   gst_bin_add (GST_BIN (b1), b2);
1031
1032   caps = gst_caps_from_string ("audio/x-raw, format=S16LE, channels=1");
1033   g_object_set (fmt, "caps", caps, NULL);
1034   gst_caps_unref (caps);
1035
1036   /* create the ghostpad as a sink-pad for bin 2 */
1037   ghostpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1038   gst_element_add_pad (b2, ghostpad);
1039
1040   sinkpad = gst_element_get_static_pad (sink1, "sink");
1041   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1042   gst_object_unref (sinkpad);
1043
1044   fail_unless (gst_element_link_many (src, fmt, b2, NULL));
1045
1046   /* set different target after ghostpad is linked */
1047   sinkpad = gst_element_get_static_pad (sink2, "sink");
1048   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1049   gst_object_unref (sinkpad);
1050
1051   /* clean up */
1052   gst_object_unref (b1);
1053 }
1054
1055 GST_END_TEST;
1056
1057 /* test that setting a ghostpad proxy pad as ghostpad target automatically set
1058  * both ghostpad targets.
1059  *
1060  * fakesrc ! ( ) ! fakesink
1061  */
1062
1063 GST_START_TEST (test_ghost_pads_internal_link)
1064 {
1065   GstElement *pipeline, *src, *bin, *sink;
1066   GstPad *sinkpad, *srcpad, *target;
1067   GstProxyPad *proxypad;
1068
1069   pipeline = gst_element_factory_make ("pipeline", NULL);
1070   bin = gst_element_factory_make ("bin", NULL);
1071   src = gst_element_factory_make ("fakesrc", NULL);
1072   sink = gst_element_factory_make ("fakesink", NULL);
1073
1074   gst_bin_add (GST_BIN (pipeline), src);
1075   gst_bin_add (GST_BIN (pipeline), bin);
1076   gst_bin_add (GST_BIN (pipeline), sink);
1077
1078   /* create the sink ghostpad */
1079   sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1080   proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1081   gst_element_add_pad (bin, sinkpad);
1082
1083   /* create the src ghostpad and link it to sink proxypad */
1084   srcpad = gst_ghost_pad_new ("src", GST_PAD (proxypad));
1085   gst_object_unref (proxypad);
1086   gst_element_add_pad (bin, srcpad);
1087
1088   fail_unless (gst_element_link_many (src, bin, sink, NULL));
1089
1090   /* Check that both targets are set, and point to each other */
1091   target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkpad));
1092   fail_if (target == NULL);
1093   proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (srcpad));
1094   fail_unless (target == GST_PAD (proxypad));
1095   gst_object_unref (target);
1096   gst_object_unref (proxypad);
1097
1098   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcpad));
1099   fail_if (target == NULL);
1100   proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1101   fail_unless (target == GST_PAD (proxypad));
1102   gst_object_unref (target);
1103   gst_object_unref (proxypad);
1104
1105   /* clean up */
1106   gst_object_unref (pipeline);
1107 }
1108
1109 GST_END_TEST;
1110
1111 /* Test that remove a ghostpad that has something flowing through it does not
1112  * crash the program
1113  */
1114
1115 GstElement *bin;
1116 GstPad *ghostsink;
1117 GstPad *ghostsrc;
1118
1119 static GstPadProbeReturn
1120 remove_ghostpad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer data)
1121 {
1122   gst_pad_set_active (ghostsrc, FALSE);
1123   gst_pad_set_active (ghostsink, FALSE);
1124   gst_element_remove_pad (bin, ghostsrc);
1125   gst_element_remove_pad (bin, ghostsink);
1126
1127   return GST_PAD_PROBE_DROP;
1128 }
1129
1130 GST_START_TEST (test_ghost_pads_remove_while_playing)
1131 {
1132   GstPad *sinkpad;
1133   GstPad *srcpad;
1134   GstSegment segment;
1135
1136   bin = gst_bin_new (NULL);
1137   gst_element_set_state (bin, GST_STATE_PLAYING);
1138
1139   ghostsrc = gst_ghost_pad_new_no_target ("ghostsrc", GST_PAD_SRC);
1140   sinkpad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ghostsrc)));
1141   ghostsink = gst_ghost_pad_new ("ghostsink", sinkpad);
1142   gst_object_unref (sinkpad);
1143   gst_pad_set_active (ghostsrc, TRUE);
1144   gst_pad_set_active (ghostsink, TRUE);
1145   gst_element_add_pad (bin, ghostsrc);
1146   gst_element_add_pad (bin, ghostsink);
1147
1148   srcpad = gst_pad_new ("srcpad", GST_PAD_SRC);
1149   gst_pad_set_active (srcpad, TRUE);
1150   gst_pad_link (srcpad, ghostsink);
1151
1152   gst_segment_init (&segment, GST_FORMAT_BYTES);
1153   fail_unless (gst_pad_push_event (srcpad,
1154           gst_event_new_stream_start ("test")) == TRUE);
1155   fail_unless (gst_pad_push_event (srcpad,
1156           gst_event_new_segment (&segment)) == TRUE);
1157
1158   gst_pad_add_probe (ghostsrc, GST_PAD_PROBE_TYPE_BUFFER,
1159       remove_ghostpad_probe_cb, NULL, NULL);
1160
1161   g_assert (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK);
1162
1163   gst_pad_set_active (srcpad, FALSE);
1164   gst_element_set_state (bin, GST_STATE_NULL);
1165   gst_object_unref (bin);
1166   gst_object_unref (srcpad);
1167 }
1168
1169 GST_END_TEST;
1170
1171
1172 GST_START_TEST (test_activate_src)
1173 {
1174   GstHarness *h;
1175   GstElement *b;
1176   GstElement *src;
1177   GstPad *srcpad;
1178
1179   b = gst_bin_new (NULL);
1180   src = gst_element_factory_make ("fakesrc", NULL);
1181   g_object_set (src, "sync", TRUE, NULL);
1182   gst_bin_add (GST_BIN (b), src);
1183
1184   srcpad = gst_element_get_static_pad (src, "src");
1185   gst_element_add_pad (b, gst_ghost_pad_new ("src", srcpad));
1186   gst_object_unref (srcpad);
1187
1188   h = gst_harness_new_with_element (b, NULL, "src");
1189   gst_harness_play (h);
1190
1191   gst_harness_crank_single_clock_wait (h);
1192   gst_buffer_unref (gst_harness_pull (h));
1193
1194   gst_object_unref (b);
1195   gst_harness_teardown (h);
1196 }
1197
1198 GST_END_TEST;
1199
1200 GST_START_TEST (test_activate_sink_and_src)
1201 {
1202   GstHarness *h;
1203   GstElement *b;
1204   GstElement *element;
1205   GstPad *sinkpad;
1206   GstPad *srcpad;
1207
1208   b = gst_bin_new (NULL);
1209   element = gst_element_factory_make ("identity", NULL);
1210   gst_bin_add (GST_BIN (b), element);
1211
1212   sinkpad = gst_element_get_static_pad (element, "sink");
1213   gst_element_add_pad (b, gst_ghost_pad_new ("sink", sinkpad));
1214   gst_object_unref (sinkpad);
1215
1216   srcpad = gst_element_get_static_pad (element, "src");
1217   gst_element_add_pad (b, gst_ghost_pad_new ("src", srcpad));
1218   gst_object_unref (srcpad);
1219
1220   h = gst_harness_new_with_element (b, "sink", "src");
1221   gst_harness_set_src_caps_str (h, "mycaps");
1222
1223   gst_harness_push (h, gst_buffer_new ());
1224   gst_buffer_unref (gst_harness_pull (h));
1225
1226   gst_object_unref (b);
1227   gst_harness_teardown (h);
1228 }
1229
1230 GST_END_TEST;
1231
1232 GST_START_TEST (test_activate_src_pull_mode)
1233 {
1234   GstElement *b;
1235   GstElement *src;
1236   GstPad *srcpad;
1237   GstPad *internalpad;
1238   GstPad *ghost;
1239
1240   b = gst_bin_new (NULL);
1241   src = gst_element_factory_make ("fakesrc", NULL);
1242   gst_bin_add (GST_BIN (b), src);
1243
1244   srcpad = gst_element_get_static_pad (src, "src");
1245   ghost = gst_ghost_pad_new ("src", srcpad);
1246   gst_element_add_pad (b, ghost);
1247
1248   internalpad = (GstPad *) gst_proxy_pad_get_internal ((GstProxyPad *) ghost);
1249
1250   fail_if (GST_PAD_IS_ACTIVE (ghost));
1251   fail_if (GST_PAD_IS_ACTIVE (internalpad));
1252   fail_if (GST_PAD_IS_ACTIVE (srcpad));
1253   fail_unless (gst_pad_activate_mode (ghost, GST_PAD_MODE_PULL, TRUE));
1254   fail_unless (GST_PAD_IS_ACTIVE (ghost));
1255   fail_unless (GST_PAD_IS_ACTIVE (internalpad));
1256   fail_unless (GST_PAD_IS_ACTIVE (srcpad));
1257
1258   gst_object_unref (internalpad);
1259   gst_object_unref (srcpad);
1260   gst_object_unref (b);
1261 }
1262
1263 GST_END_TEST;
1264
1265 GST_START_TEST (test_activate_sink_switch_mode)
1266 {
1267   GstElement *pipeline;
1268   GstElement *b, *src, *identity;
1269   GstPad *srcpad, *sinkpad, *internalpad, *ghost;
1270
1271   pipeline = gst_pipeline_new (NULL);
1272   b = gst_bin_new (NULL);
1273   gst_bin_add (GST_BIN (pipeline), b);
1274   src = gst_element_factory_make ("fakesrc", NULL);
1275   gst_bin_add (GST_BIN (pipeline), src);
1276   identity = gst_element_factory_make ("identity", NULL);
1277   gst_bin_add (GST_BIN (b), identity);
1278
1279   sinkpad = gst_element_get_static_pad (identity, "sink");
1280   ghost = gst_ghost_pad_new ("sink", sinkpad);
1281   gst_element_add_pad (b, ghost);
1282   srcpad = gst_element_get_static_pad (src, "src");
1283   gst_pad_link (srcpad, ghost);
1284
1285   internalpad = (GstPad *) gst_proxy_pad_get_internal ((GstProxyPad *) ghost);
1286
1287   /* We start with no active pads */
1288   fail_if (GST_PAD_IS_ACTIVE (ghost));
1289   fail_if (GST_PAD_IS_ACTIVE (internalpad));
1290   fail_if (GST_PAD_IS_ACTIVE (sinkpad));
1291   fail_if (GST_PAD_IS_ACTIVE (srcpad));
1292
1293   GST_DEBUG ("Activating pads in push mode");
1294   /* Let's first try to activate everything in push-mode, for this we need
1295    * to go on every exposed pad */
1296   fail_unless (gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE));
1297   fail_unless (gst_pad_activate_mode (ghost, GST_PAD_MODE_PUSH, TRUE));
1298   fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE));
1299
1300   GST_DEBUG ("Checking pads are all activated properly");
1301   /* Let's check all pads are now active, including internal ones */
1302   fail_unless (GST_PAD_MODE (ghost) == GST_PAD_MODE_PUSH);
1303   fail_unless (GST_PAD_MODE (internalpad) == GST_PAD_MODE_PUSH);
1304   fail_unless (GST_PAD_MODE (srcpad) == GST_PAD_MODE_PUSH);
1305   fail_unless (GST_PAD_MODE (sinkpad) == GST_PAD_MODE_PUSH);
1306
1307   /* Now simulate a scheduling reconfiguration (PUSH=>PULL) */
1308   fail_unless (gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE));
1309
1310   /* All pads should have switched modes */
1311   fail_unless (GST_PAD_MODE (ghost) == GST_PAD_MODE_PULL);
1312   fail_unless (GST_PAD_MODE (srcpad) == GST_PAD_MODE_PULL);
1313   fail_unless (GST_PAD_MODE (sinkpad) == GST_PAD_MODE_PULL);
1314   fail_unless (GST_PAD_MODE (internalpad) == GST_PAD_MODE_PULL);
1315
1316   gst_object_unref (internalpad);
1317   gst_object_unref (srcpad);
1318   gst_object_unref (sinkpad);
1319   gst_object_unref (pipeline);
1320 }
1321
1322 GST_END_TEST;
1323
1324 static gboolean thread_running;
1325
1326 static gpointer
1327 send_query_to_pad_func (GstPad * pad)
1328 {
1329   GstQuery *query = gst_query_new_latency ();
1330
1331   while (thread_running) {
1332     gst_pad_peer_query (pad, query);
1333     g_thread_yield ();
1334   }
1335
1336   gst_query_unref (query);
1337   return NULL;
1338 }
1339
1340 GST_START_TEST (test_stress_upstream_queries_while_tearing_down)
1341 {
1342   GThread *query_thread;
1343   gint i;
1344   GstPad *pad = gst_pad_new ("sink", GST_PAD_SINK);
1345   gst_pad_set_active (pad, TRUE);
1346
1347   thread_running = TRUE;
1348   query_thread = g_thread_new ("queries",
1349       (GThreadFunc) send_query_to_pad_func, pad);
1350
1351   for (i = 0; i < 1000; i++) {
1352     GstPad *ghostpad = gst_ghost_pad_new ("ghost-sink", pad);
1353     gst_pad_set_active (ghostpad, TRUE);
1354
1355     g_thread_yield ();
1356
1357     gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
1358     gst_pad_set_active (pad, FALSE);
1359     gst_object_unref (ghostpad);
1360   }
1361
1362   thread_running = FALSE;
1363   g_thread_join (query_thread);
1364
1365   gst_object_unref (pad);
1366 }
1367
1368 GST_END_TEST;
1369
1370 GST_START_TEST (test_deactivate_already_deactive_with_no_parent)
1371 {
1372   /* This simulates the behavior where a ghostpad is released while
1373    * deactivating (for instance because of a state change).
1374    * gst_pad_activate_mode() may be be called from
1375    * gst_ghost_pad_internal_activate_push_default() on a pad that is already
1376    * deactivate and unparented. The call chain is really like somethink like
1377    * this:
1378    *   gst_pad_activate_mode(ghostpad)
1379    *    -> ...
1380    *    -> gst_pad_activate_mode(proxypad)
1381    *    -> ...
1382    *    -> gst_pad_activate_mode(ghostpad)
1383    */
1384   GstElement *bin = gst_bin_new ("testbin");
1385   GstPad *pad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
1386   gst_object_ref (pad);
1387
1388   /* We need to add/remove pad because that will update the pad's flags */
1389   fail_unless (gst_element_add_pad (bin, pad));
1390   fail_unless (gst_element_remove_pad (bin, pad));
1391
1392   /* Setting a pad that's already deactive to deactive should not fail. */
1393   fail_if (gst_pad_is_active (pad));
1394   fail_unless (gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, FALSE));
1395
1396   gst_object_unref (bin);
1397   gst_object_unref (pad);
1398 }
1399
1400 GST_END_TEST;
1401
1402 static Suite *
1403 gst_ghost_pad_suite (void)
1404 {
1405   Suite *s = suite_create ("GstGhostPad");
1406
1407   TCase *tc_chain = tcase_create ("ghost pad tests");
1408
1409   suite_add_tcase (s, tc_chain);
1410   tcase_add_test (tc_chain, test_remove1);
1411   tcase_add_test (tc_chain, test_remove2);
1412   tcase_add_test (tc_chain, test_remove_target);
1413   tcase_add_test (tc_chain, test_link);
1414   tcase_add_test (tc_chain, test_ghost_pads);
1415   tcase_add_test (tc_chain, test_ghost_pads_bin);
1416   tcase_add_test (tc_chain, test_ghost_pads_notarget);
1417   tcase_add_test (tc_chain, test_ghost_pads_block);
1418   tcase_add_test (tc_chain, test_ghost_pads_probes);
1419   tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
1420   tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
1421   tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps);
1422   tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink);
1423   tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink);
1424   tcase_add_test (tc_chain, test_ghost_pads_change_when_linked);
1425   tcase_add_test (tc_chain, test_ghost_pads_internal_link);
1426   tcase_add_test (tc_chain, test_ghost_pads_remove_while_playing);
1427
1428   tcase_add_test (tc_chain, test_activate_src);
1429   tcase_add_test (tc_chain, test_activate_sink_and_src);
1430   tcase_add_test (tc_chain, test_activate_src_pull_mode);
1431   tcase_add_test (tc_chain, test_activate_sink_switch_mode);
1432   tcase_add_test (tc_chain, test_deactivate_already_deactive_with_no_parent);
1433   tcase_add_test (tc_chain, test_stress_upstream_queries_while_tearing_down);
1434
1435   return s;
1436 }
1437
1438 GST_CHECK_MAIN (gst_ghost_pad);