s/gst_element_install_std_props/gst_element_class_install_std_props/ -- it just makes...
[platform/upstream/gstreamer.git] / gst / autoplug / gstspider.c
1 /* GStreamer
2  * Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
3  *               2002 Wim Taymans <wtay@chello.be>
4  *
5  * gstspider.c: element to automatically connect sinks and sources
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22  
23 /**
24  * TODO:
25  * - handle automatic removal of unneeded elements
26  * - make the spider handle and send events (esp. new media)
27  * - decide if we plug pads or elements, currently it's a mess
28  * - allow disconnecting
29  * - implement proper saving/loading from xml
30  * - implement a way to allow merging/splitting (aka tee)
31  * - find ways to define which elements to use when plugging
32  * - remove pads
33  * - improve typefinding
34  * - react to errors inside the pipeline
35  * - implement more properties, change the current
36  * - emit signals (most important: "NOT PLUGGABLE")
37  * - implement something for reporting the state of the spider
38  *   to allow easier debugging.
39  *   (could be useful for bins in general)
40  * - fix bugs
41  * ...
42  */
43  
44 #include "gstspider.h"
45 #include "gstspideridentity.h"
46 #include "gstsearchfuncs.h"
47  
48 /* signals and args */
49 enum {
50   /* FILL ME */
51   LAST_SIGNAL
52 };
53
54 enum {
55   ARG_0,
56   ARG_FACTORIES,
57   /* FILL ME TOO */
58 };
59
60 /* generic templates */
61 GST_PADTEMPLATE_FACTORY (spider_src_factory,
62   "src_%d",
63   GST_PAD_SRC,
64   GST_PAD_REQUEST,
65   NULL      /* no caps */
66 );
67
68 GST_PADTEMPLATE_FACTORY (spider_sink_factory,
69   "sink_%d",
70   GST_PAD_SINK,
71   GST_PAD_REQUEST,
72   NULL      /* no caps */
73 );
74
75
76
77 /* standard GObject stuff */
78 static void                     gst_spider_class_init                   (GstSpiderClass *klass);
79 static void                     gst_spider_init                         (GstSpider *spider);
80 static void                     gst_spider_dispose                      (GObject *object);
81
82 /* element class functions */
83 static GstPad*                  gst_spider_request_new_pad              (GstElement *element, GstPadTemplate *templ, const gchar *name);
84 static void                     gst_spider_set_property                 (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
85 static void                     gst_spider_get_property                 (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
86
87 /* connection functions */
88 static GstSpiderConnection *    gst_spider_connection_new               (GstSpiderIdentity *sink, GstSpiderIdentity *src);
89 static void                     gst_spider_connection_destroy           (GstSpiderConnection *conn);
90 static void                     gst_spider_connection_reset             (GstSpiderConnection *conn, GstElement *to);
91 static void                     gst_spider_connection_add               (GstSpiderConnection *conn, GstElement *element);
92 static GstSpiderConnection *    gst_spider_connection_find              (GstSpiderIdentity *sink, GstSpiderIdentity *src);
93 static GstSpiderConnection *    gst_spider_connection_get               (GstSpiderIdentity *sink, GstSpiderIdentity *src);
94
95 /* autoplugging functions */
96 static GstElement *             gst_spider_find_element_to_plug         (GstElement *src, GstElementFactory *fac, GstPadDirection dir);
97 static GstPadConnectReturn      gst_spider_plug                         (GstSpiderConnection *conn);
98 static GstPadConnectReturn      gst_spider_plug_from_srcpad             (GstSpiderConnection *conn, GstPad *srcpad);
99 //static GstPadConnectReturn      gst_spider_plug_peers                 (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad);
100 static GstPadConnectReturn      gst_spider_create_and_plug              (GstSpiderConnection *conn, GList *plugpath);
101
102 /* random functions */
103 static gchar *                  gst_spider_unused_elementname           (GstBin *bin, const gchar *startwith);
104
105 /* debugging stuff
106 static void                     print_spider_contents                   (GstSpider *spider);
107 static void                     print_spider_connection                 (GstSpiderConnection *conn); */
108
109 /* === variables === */
110 static                          GstElementClass *                       parent_class = NULL;
111
112 /* no signals yet
113 static guint gst_spider_signals[LAST_SIGNAL] = { 0 };*/
114
115 /* let gstreamer know that we have some request pads available */
116 GST_PADTEMPLATE_FACTORY (gst_spider_sink_template_factory,
117   "sink%d",
118   GST_PAD_SINK,
119   GST_PAD_REQUEST,
120   NULL
121 );  
122 GST_PADTEMPLATE_FACTORY (gst_spider_src_template_factory,
123   "src%d",
124   GST_PAD_SRC,
125   GST_PAD_REQUEST,
126   NULL
127 );  
128
129 /* GObject and GStreamer init functions */
130 GType
131 gst_spider_get_type(void)
132 {
133   static GType spider_type = 0;
134
135   if (!spider_type) {
136     static const GTypeInfo spider_info = {
137       sizeof(GstSpiderClass),
138       NULL,
139       NULL,
140       (GClassInitFunc) gst_spider_class_init,
141       NULL,
142       NULL,
143       sizeof(GstSpider),
144       0,
145       (GInstanceInitFunc)gst_spider_init,
146     };
147     spider_type = g_type_register_static (GST_TYPE_BIN, "GstSpider", &spider_info, 0);
148   }
149   return spider_type;
150 }
151
152 static void
153 gst_spider_class_init (GstSpiderClass *klass)
154 {
155   GObjectClass     *gobject_class;
156   GstElementClass  *gstelement_class;
157
158   gobject_class = (GObjectClass*) klass;
159   gstelement_class = (GstElementClass*) klass;
160
161   parent_class = g_type_class_ref(GST_TYPE_BIN);
162
163   /* properties */
164   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FACTORIES,
165   g_param_spec_pointer ("factories", "allowed factories", "allowed factories for autoplugging", G_PARAM_READWRITE));
166
167   gobject_class->set_property = gst_spider_set_property;
168   gobject_class->get_property = gst_spider_get_property;
169   gobject_class->dispose = gst_spider_dispose;
170
171   gst_element_class_add_padtemplate (gstelement_class, gst_spider_src_template_factory());
172   gst_element_class_add_padtemplate (gstelement_class, gst_spider_sink_template_factory());
173   
174   gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_spider_request_new_pad);
175 }
176 static void 
177 gst_spider_init (GstSpider *spider) 
178 {
179   /* use only elements which have sources and sinks and where the sinks have caps */
180   /* FIXME: How do we handle factories that are added after the spider was constructed? */
181   spider->factories = gst_autoplug_factories_filters_with_sink_caps ((GList *) gst_elementfactory_get_list ());
182
183   spider->connections = NULL;
184 }
185
186 static void
187 gst_spider_dispose (GObject *object)
188 {
189   GstSpider *spider;
190   
191   spider = GST_SPIDER (object);
192   g_list_free (spider->factories);
193   
194   ((GObjectClass *) parent_class)->dispose (object);
195 }
196 static GstPad *
197 gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name)
198 {
199   GstPad *returnpad;
200   gchar *padname;
201   GstSpiderIdentity *identity;
202   GstSpider *spider;
203   
204   g_return_val_if_fail (templ != NULL, NULL);
205   g_return_val_if_fail (GST_IS_PADTEMPLATE (templ), NULL);
206   
207   spider = GST_SPIDER (element);
208   
209   /* create an identity object, so we have a pad */
210   switch ( GST_PADTEMPLATE_DIRECTION (templ))
211   {
212     case GST_PAD_SRC:
213       padname = gst_spider_unused_elementname ((GstBin *)spider, "src_");
214       identity = gst_spider_identity_new_src (padname);
215       returnpad = identity->src;
216       break;
217     case GST_PAD_SINK:
218       padname = gst_spider_unused_elementname ((GstBin *)spider, "sink_");
219       identity = gst_spider_identity_new_sink (padname);
220       returnpad = identity->sink;
221       break;
222     case GST_PAD_UNKNOWN:
223     default:
224       g_warning("Spider: you must request a source or sink pad.");
225       return NULL;
226   }
227   
228   /* FIXME: use the requested name for the pad */
229
230   gst_object_ref (GST_OBJECT (templ));
231   GST_PAD_PADTEMPLATE (returnpad) = templ;
232   
233   gst_bin_add (GST_BIN (element), GST_ELEMENT (identity));
234   
235   returnpad = gst_element_add_ghost_pad (element, returnpad, padname);
236   GST_DEBUG (GST_CAT_ELEMENT_PADS, "successuflly created requested pad %s:%s\n", GST_DEBUG_PAD_NAME (returnpad));
237   
238   return returnpad;
239 }
240
241 static void
242 gst_spider_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
243 {
244   GstSpider *spider;
245   GList *list;
246   
247   /* it's not null if we got it, but it might not be ours */
248   g_return_if_fail (GST_IS_SPIDER (object));
249
250   spider = GST_SPIDER (object);
251
252   switch (prop_id) {
253     case ARG_FACTORIES:
254       list = (GList *) g_value_get_pointer (value);
255       while (list)
256       {
257         g_return_if_fail (list->data != NULL);
258         g_return_if_fail (GST_IS_ELEMENTFACTORY (list->data));
259         list = g_list_next (list);
260       }
261       g_list_free (spider->factories);
262       spider->factories = (GList *) g_value_get_pointer (value);
263       break;
264     default:
265       break;
266   }
267 }
268 static void
269 gst_spider_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
270 {
271   GstSpider *spider;
272
273   /* it's not null if we got it, but it might not be ours */
274   spider = GST_SPIDER(object);
275
276   switch (prop_id) {
277     case ARG_FACTORIES:
278       g_value_set_pointer (value, spider->factories);
279       break;
280     default:
281       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
282       break;
283   }
284 }
285 /* get a name for an element that isn't used yet */
286 static gchar *
287 gst_spider_unused_elementname (GstBin *bin, const gchar *startwith)
288 {
289   gchar * name = g_strdup_printf ("%s%d", startwith, 0);
290   guint i;
291   
292   for (i = 0; gst_bin_get_by_name (bin, name) != NULL; )
293   {
294     g_free (name);
295     name = g_strdup_printf ("%s%d", startwith, ++i);
296   }
297   
298   return name;
299 }
300 static void
301 gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnection *conn)
302 {
303   gboolean restart = FALSE;
304   gulong signal_id = conn->signal_id;
305   GstPad *sinkpad = conn->src->sink;
306   GstSpider *spider = GST_SPIDER (GST_OBJECT_PARENT (conn->sink));
307   
308   /* check if restarting is necessary */
309   if (gst_element_get_state ((GstElement *) spider) == GST_STATE_PLAYING)
310   {
311     restart = TRUE;
312     gst_element_set_state ((GstElement *) spider, GST_STATE_PAUSED);
313   }
314   
315   /* try to autoplug the elements */
316   if (gst_spider_plug_from_srcpad (conn, pad) != GST_PAD_CONNECT_REFUSED) {
317     GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%s:%s was autoplugged to %s:%s, removing callback\n", GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (sinkpad));
318     g_signal_handler_disconnect (src, signal_id);
319     signal_id = 0;
320   }
321   
322   /* restart if needed */
323   if (restart)
324   {
325     gst_element_set_state ((GstElement *) spider, GST_STATE_PLAYING);
326   }
327 }
328 /* create a new connection from those two elements */
329 static GstSpiderConnection *
330 gst_spider_connection_new (GstSpiderIdentity *sink, GstSpiderIdentity *src)
331 {
332   GstSpider *spider;
333   
334   GstSpiderConnection *conn = g_new0 (GstSpiderConnection, 1);
335   conn->src = src;
336   conn->sink = sink;
337   conn->current = (GstElement *) sink;
338   conn->path = NULL;
339   spider = GST_SPIDER (GST_OBJECT_PARENT (src));
340   spider->connections = g_list_prepend (spider->connections, conn);
341   
342   return conn;
343 }
344 static void
345 gst_spider_connection_destroy (GstSpiderConnection *conn)
346 {
347   /* reset connection to unplugged */
348   gst_spider_connection_reset (conn, (GstElement *) conn->sink);
349   g_free (conn);
350 }
351 static void
352 gst_spider_connection_reset (GstSpiderConnection *conn, GstElement *to)
353 {
354   GST_DEBUG (GST_CAT_AUTOPLUG, "resetting connection from %s to %s, currently at %s to %s\n", GST_ELEMENT_NAME (conn->sink), 
355              GST_ELEMENT_NAME (conn->src), GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (to));
356   while ((conn->path != NULL) && ((GstElement *) conn->path->data != to))
357   {
358     gst_object_unref ((GstObject *) conn->path->data);
359     conn->path = g_list_delete_link (conn->path, conn->path);
360   }
361   if (conn->path == NULL)
362   {
363     conn->current = (GstElement *) conn->sink;
364   } else {
365     conn->current = to;
366   }
367 }
368 /* add an element to the connection */
369 static void
370 gst_spider_connection_add (GstSpiderConnection *conn, GstElement *element)
371 {
372   gst_object_ref ((GstObject *) element);
373   gst_object_sink ((GstObject *) element);
374   conn->path = g_list_prepend (conn->path, element);
375   conn->current = element;
376 }
377 /* find the connection from those two elements */
378 static GstSpiderConnection *
379 gst_spider_connection_find (GstSpiderIdentity *sink, GstSpiderIdentity *src)
380 {
381   GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (src);
382   GList *list = spider->connections;
383   
384   g_assert (spider == (GstSpider *) GST_OBJECT_PARENT (sink));
385   
386   while (list)
387   {
388     GstSpiderConnection *conn = (GstSpiderConnection *) list->data;
389     if (conn->src == src && conn->sink == sink)
390       return conn;
391     list = g_list_next(list);
392   }
393   return NULL;
394 }
395 /* get a new connection from those two elements
396  * search first; if none is found, create a new one */
397 static GstSpiderConnection *
398 gst_spider_connection_get (GstSpiderIdentity *sink, GstSpiderIdentity *src)
399 {
400   GstSpiderConnection *ret;
401   
402   if ((ret = gst_spider_connection_find (sink, src)) != NULL)
403   {
404     return ret;
405   }
406   return gst_spider_connection_new (sink, src);
407 }  
408 void                    
409 gst_spider_identity_plug (GstSpiderIdentity *ident)
410 {
411   GstSpider *spider;
412   GList *padlist;
413   GstPadDirection dir;
414   GstSpiderConnection *conn;
415   
416   /* checks */
417   g_return_if_fail (ident != NULL);
418   g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
419   spider = GST_SPIDER (GST_ELEMENT_PARENT (ident));
420   g_assert (spider != NULL);
421   g_assert (GST_IS_SPIDER (spider));
422   
423   /* return if we're already plugged */
424   if (ident->plugged) return;
425
426   /* get the direction of our ident */
427   if (GST_PAD_PEER (ident->sink))
428   {
429     if (GST_PAD_PEER (ident->src))
430     {
431       /* Hey, the ident is connected on both sides */
432       g_warning ("Trying to autoplug a connected element. Aborting...");
433       return;
434     } else {
435       dir = GST_PAD_SINK;
436     }
437   } else {
438     if (GST_PAD_PEER (ident->src))
439     {
440       dir = GST_PAD_SRC;
441     } else {
442       /* the ident isn't connected on either side */
443       g_warning ("Trying to autoplug an unconnected element. Aborting...");
444       return;
445     }
446   }
447
448   /* now iterate all possible pads and connect when needed */
449   padlist = gst_element_get_pad_list (GST_ELEMENT (spider));
450   while (padlist)
451   {
452     GstPad *otherpad = (GstPad *) GST_GPAD_REALPAD (padlist->data);
453     GstSpiderIdentity *peer = (GstSpiderIdentity *) GST_PAD_PARENT (otherpad);
454     /* we only want to connect to the other side */
455     if (dir != GST_PAD_DIRECTION (otherpad))
456     {
457       /* we only connect to plugged in elements */
458       if (peer->plugged == TRUE) 
459       {
460         /* plug in the right direction */
461         if (dir == GST_PAD_SINK)
462         {
463           conn = gst_spider_connection_get (ident, peer);
464         } else {
465           conn = gst_spider_connection_get (peer, ident);
466         }
467         if ((GstElement *) conn->sink == conn->current)
468         {
469           gst_spider_plug (conn);
470         }
471       }
472     }
473     padlist = g_list_next (padlist);
474   }
475   
476   ident->plugged = TRUE; 
477 }
478 void
479 gst_spider_identity_unplug (GstSpiderIdentity *ident)
480 {
481   GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (ident);
482   GList *list = spider->connections;
483   
484   while (list)
485   {
486     GstSpiderConnection *conn = list->data;
487     GList *cur = list;
488     list = g_list_next (list);
489     if ((conn->src == ident) || (conn->sink == ident))
490     {
491       g_list_delete_link (spider->connections, cur);
492       gst_spider_connection_destroy (conn);
493     }
494   }
495   ident->plugged = FALSE;
496 }
497 /* connects src to sink using the elementfactories in plugpath
498  * plugpath will be removed afterwards */
499 static GstPadConnectReturn
500 gst_spider_create_and_plug (GstSpiderConnection *conn, GList *plugpath)
501 {
502   GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->sink);
503   GList *endelements = NULL, *templist = NULL;
504   GstElement *element;
505   
506   /* exit if plugging is already done */
507   if ((GstElement *) conn->src == conn->current)
508     return GST_PAD_CONNECT_DONE;
509   
510   /* try to shorten the list at the end and not duplicate connection code */
511   if (plugpath != NULL)
512   {
513     templist = g_list_last (plugpath);
514     element = (GstElement *) conn->src;
515     while ((plugpath != NULL) && (element = gst_spider_find_element_to_plug (element, (GstElementFactory *) plugpath->data, GST_PAD_SINK)))
516     {
517       GList *cur = templist;
518       endelements = g_list_prepend (endelements, element);
519       templist = g_list_previous (templist);
520       g_list_delete_link (cur, cur);    
521     }
522   }
523   
524   /* do the connecting */
525   while (conn->current != (GstElement *) (endelements == NULL ? conn->src : endelements->data))
526   {
527     /* get sink element to plug, src is conn->current */
528     if (plugpath == NULL)
529     {
530       element = (GstElement *) (endelements == NULL ? conn->src : endelements->data);
531     } else {
532       element = gst_elementfactory_create ((GstElementFactory *) plugpath->data, NULL);
533       gst_bin_add (GST_BIN (spider), element);
534     }
535     /* insert and connect new element */
536     if (!gst_element_connect_elements (conn->current, element))
537     {
538       /* check if the src has SOMETIMES templates. If so, connect a callback */
539       GList *templs = gst_element_get_padtemplate_list (conn->current);
540          
541       /* remove element that couldn't be connected, if it wasn't the endpoint */
542       if (element != (GstElement *) conn->src)
543         gst_bin_remove (GST_BIN (spider), element);
544     
545       while (templs) {
546         GstPadTemplate *templ = (GstPadTemplate *) templs->data;
547         if ((GST_PADTEMPLATE_DIRECTION (templ) == GST_PAD_SRC) && (GST_PADTEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES))
548         {
549           GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "adding callback to connect element %s to %s\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
550           conn->signal_id = g_signal_connect (G_OBJECT (conn->current), "new_pad", 
551                                               G_CALLBACK (gst_spider_connect_sometimes), conn);
552           g_list_free (plugpath);
553           return GST_PAD_CONNECT_DELAYED;
554         }
555         templs = g_list_next (templs);
556       }
557       GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to connect element %s to %s\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
558       g_list_free (plugpath);
559       return GST_PAD_CONNECT_REFUSED;
560     }
561     GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "added element %s and attached it to element %s\n", GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (conn->current));
562     gst_spider_connection_add (conn, element);
563     if (plugpath != NULL)
564       plugpath = g_list_delete_link (plugpath, plugpath);
565   }
566   
567   /* ref all elements at the end */
568   while (endelements)
569   {
570     gst_spider_connection_add (conn, endelements->data);
571     endelements = g_list_delete_link (endelements, endelements);
572   }
573   
574   return GST_PAD_CONNECT_DONE;
575 }
576 /* checks, if src is already connected to an element from factory fac on direction dir */
577 static GstElement *
578 gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir)
579 {
580   GList *padlist = GST_ELEMENT_PADS (src);
581   
582   while (padlist)
583   {
584     GstPad *pad = (GstPad *) GST_PAD_REALIZE (padlist->data);
585     /* is the pad on the right side and is it connected? */
586     if ((GST_PAD_DIRECTION (pad) == dir) && (pad = GST_PAD (GST_RPAD_PEER (pad))))
587     {
588       /* is the element the pad is connected to of the right type? */
589       GstElement *element = GST_PAD_PARENT (pad);
590       if (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))->elementfactory == fac) {
591         return element;
592       }
593     }
594     padlist = g_list_next (padlist);
595   }
596   
597   return NULL;
598 }
599 /* try to establish the connection */
600 static GstPadConnectReturn
601 gst_spider_plug (GstSpiderConnection *conn)
602 {
603   if ((GstElement *) conn->src == conn->current)
604     return GST_PAD_CONNECT_DONE;
605   if ((GstElement *) conn->sink == conn->current)
606     return gst_spider_plug_from_srcpad (conn, conn->sink->src);
607   g_warning ("FIXME: autoplugging only possible from GstSpiderIdentity conn->sink yet (yep, that's technical)\n");
608   return GST_PAD_CONNECT_REFUSED;
609 }
610 /* try to establish the connection using this pad */
611 static GstPadConnectReturn
612 gst_spider_plug_from_srcpad (GstSpiderConnection *conn, GstPad *srcpad)
613 {
614   GstElement *element;
615   GList *plugpath;
616   gboolean result = TRUE;
617   GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->src);
618   GstElement *startelement = conn->current;
619
620   g_assert ((GstElement *) GST_OBJECT_PARENT (srcpad) == conn->current);
621   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug from %s:%s to %s\n", GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (conn->src));
622   
623   /* find a path from src to sink */
624   /* FIXME: make that if go away and work anyway */
625   if (srcpad == conn->sink->src)
626   {
627     plugpath = gst_autoplug_sp (gst_pad_get_caps ((GstPad *) GST_RPAD_PEER (conn->sink->sink)), gst_pad_get_caps (conn->src->sink), spider->factories);
628   } else {
629     plugpath = gst_autoplug_sp (gst_pad_get_caps (srcpad), gst_pad_get_caps (conn->src->sink), spider->factories);
630   }
631   
632   /* prints out the path that was found for plugging */
633   /* g_print ("found path from %s to %s:\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
634   templist = plugpath;
635   while (templist)
636   {
637     g_print("%s\n", GST_OBJECT_NAME (templist->data));
638     templist = g_list_next (templist);
639   }*/
640     
641   /* if there is no way to plug: return */
642   if (plugpath == NULL) {
643     GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to plug from %s to %s\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
644     return GST_PAD_CONNECT_REFUSED;
645   }
646   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a connection that needs %d elements\n", g_list_length (plugpath));
647
648   /* now remove non-needed elements from the beginning of the path 
649    * alter src to point to the new element where we need to start 
650    * plugging and alter the plugpath to represent the elements, that must be plugged
651    */
652   element = conn->current;
653   while ((plugpath != NULL) && (element = gst_spider_find_element_to_plug (element, (GstElementFactory *) plugpath->data, GST_PAD_SRC)))
654   {
655     gst_spider_connection_add (conn, element);
656     plugpath = g_list_delete_link (plugpath, plugpath);
657   }
658   
659   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%d elements must be inserted to establish the connection\n", g_list_length (plugpath));
660   /* create the elements and plug them */
661   result = gst_spider_create_and_plug (conn, plugpath);
662   
663   /* reset the "current" element */
664   if (result == GST_PAD_CONNECT_REFUSED)
665   {
666      gst_spider_connection_reset (conn, startelement);
667   }
668   
669   return result;  
670 }
671
672 GstElementDetails gst_spider_details = {
673   "Spider",
674   "Filter/Autplug",
675   "Automatically connect sinks and sources",
676   VERSION,
677   "Benjamin Otte <in7y118@public.uni-hamburg.de>",
678   "(C) 2002",
679 };
680
681 static gboolean
682 plugin_init (GModule *module, GstPlugin *plugin)
683 {
684   GstElementFactory *factory;
685
686   factory = gst_elementfactory_new("spider", GST_TYPE_SPIDER,
687                                    &gst_spider_details);
688   g_return_val_if_fail(factory != NULL, FALSE);
689
690   gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (spider_src_factory));
691   gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (spider_sink_factory));
692
693   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
694
695   return TRUE;
696 }
697
698 GstPluginDesc plugin_desc = {
699   GST_VERSION_MAJOR,
700   GST_VERSION_MINOR,
701   "gstspider",
702   plugin_init
703 };
704
705   
706