First THREADED backport attempt, focusing on adding locks and making sure the API...
[platform/upstream/gstreamer.git] / gst / gstscheduler.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wim.taymans@chello.be>
4  *
5  * gstscheduler.c: Default scheduling code for most cases
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 #include "gst_private.h"
24
25 #include "gstsystemclock.h"
26 #include "gstscheduler.h"
27 #include "gstinfo.h"
28 #include "gstregistrypool.h"
29
30 static void gst_scheduler_class_init (GstSchedulerClass * klass);
31 static void gst_scheduler_init (GstScheduler * sched);
32 static void gst_scheduler_dispose (GObject * object);
33
34 static GstObjectClass *parent_class = NULL;
35
36 static gchar *_default_name = NULL;
37
38 GType
39 gst_scheduler_get_type (void)
40 {
41   static GType _gst_scheduler_type = 0;
42
43   if (!_gst_scheduler_type) {
44     static const GTypeInfo scheduler_info = {
45       sizeof (GstSchedulerClass),
46       NULL,
47       NULL,
48       (GClassInitFunc) gst_scheduler_class_init,
49       NULL,
50       NULL,
51       sizeof (GstScheduler),
52       0,
53       (GInstanceInitFunc) gst_scheduler_init,
54       NULL
55     };
56
57     _gst_scheduler_type =
58         g_type_register_static (GST_TYPE_OBJECT, "GstScheduler",
59         &scheduler_info, G_TYPE_FLAG_ABSTRACT);
60   }
61   return _gst_scheduler_type;
62 }
63
64 static void
65 gst_scheduler_class_init (GstSchedulerClass * klass)
66 {
67   GObjectClass *gobject_class;
68
69   gobject_class = (GObjectClass *) klass;
70
71   parent_class = g_type_class_ref (GST_TYPE_OBJECT);
72
73   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_scheduler_dispose);
74 }
75
76 static void
77 gst_scheduler_init (GstScheduler * sched)
78 {
79   sched->clock_providers = NULL;
80   sched->clock_receivers = NULL;
81   sched->schedulers = NULL;
82   sched->state = GST_SCHEDULER_STATE_NONE;
83   sched->parent = NULL;
84   sched->parent_sched = NULL;
85   sched->clock = NULL;
86 }
87
88 static void
89 gst_scheduler_dispose (GObject * object)
90 {
91   GstScheduler *sched = GST_SCHEDULER (object);
92
93   /* thse lists should all be NULL */
94   GST_DEBUG ("scheduler %p dispose %p %p %p",
95       object,
96       sched->clock_providers, sched->clock_receivers, sched->schedulers);
97
98   gst_object_replace ((GstObject **) & sched->current_clock, NULL);
99   gst_object_replace ((GstObject **) & sched->clock, NULL);
100
101   /* kids are held reference to, so dereference here. */
102   while (sched->schedulers != NULL) {
103     gst_scheduler_remove_scheduler (sched,
104         GST_SCHEDULER (sched->schedulers->data));
105   }
106
107   G_OBJECT_CLASS (parent_class)->dispose (object);
108 }
109
110 /**
111  * gst_scheduler_setup:
112  * @sched: the scheduler
113  *
114  * Prepare the scheduler.
115  */
116 void
117 gst_scheduler_setup (GstScheduler * sched)
118 {
119   GstSchedulerClass *sclass;
120
121   g_return_if_fail (GST_IS_SCHEDULER (sched));
122
123   sclass = GST_SCHEDULER_GET_CLASS (sched);
124
125   if (sclass->setup)
126     sclass->setup (sched);
127 }
128
129 /**
130  * gst_scheduler_reset:
131  * @sched: a #GstScheduler to reset.
132  *
133  * Reset the schedulers.
134  */
135 void
136 gst_scheduler_reset (GstScheduler * sched)
137 {
138   GstSchedulerClass *sclass;
139
140   g_return_if_fail (GST_IS_SCHEDULER (sched));
141
142   sclass = GST_SCHEDULER_GET_CLASS (sched);
143
144   if (sclass->reset)
145     sclass->reset (sched);
146 }
147
148 /**
149  * gst_scheduler_pad_link:
150  * @sched: the scheduler
151  * @srcpad: the srcpad to link
152  * @sinkpad: the sinkpad to link to
153  *
154  * Links the srcpad to the given sinkpad.
155  */
156 void
157 gst_scheduler_pad_link (GstScheduler * sched, GstPad * srcpad, GstPad * sinkpad)
158 {
159   GstSchedulerClass *sclass;
160
161   g_return_if_fail (GST_IS_SCHEDULER (sched));
162   g_return_if_fail (GST_IS_PAD (srcpad));
163   g_return_if_fail (GST_IS_PAD (sinkpad));
164
165   sclass = GST_SCHEDULER_GET_CLASS (sched);
166
167   if (sclass->pad_link)
168     sclass->pad_link (sched, srcpad, sinkpad);
169 }
170
171 /**
172  * gst_scheduler_pad_unlink:
173  * @sched: the scheduler
174  * @srcpad: the srcpad to unlink
175  * @sinkpad: the sinkpad to unlink from
176  *
177  * Unlinks the srcpad from the given sinkpad.
178  */
179 void
180 gst_scheduler_pad_unlink (GstScheduler * sched, GstPad * srcpad,
181     GstPad * sinkpad)
182 {
183   GstSchedulerClass *sclass;
184
185   g_return_if_fail (GST_IS_SCHEDULER (sched));
186   g_return_if_fail (GST_IS_PAD (srcpad));
187   g_return_if_fail (GST_IS_PAD (sinkpad));
188
189   sclass = GST_SCHEDULER_GET_CLASS (sched);
190
191   if (sclass->pad_unlink)
192     sclass->pad_unlink (sched, srcpad, sinkpad);
193 }
194
195 /**
196  * gst_scheduler_pad_select:
197  * @sched: the scheduler
198  * @padlist: the padlist to select on
199  *
200  * register the given padlist for a select operation. 
201  *
202  * Returns: the pad which received a buffer.
203  */
204 GstPad *
205 gst_scheduler_pad_select (GstScheduler * sched, GList * padlist)
206 {
207   g_return_val_if_fail (GST_IS_SCHEDULER (sched), NULL);
208   g_return_val_if_fail (padlist != NULL, NULL);
209
210   return NULL;
211 }
212
213 /**
214  * gst_scheduler_add_element:
215  * @sched: the scheduler
216  * @element: the element to add to the scheduler
217  *
218  * Add an element to the scheduler.
219  */
220 void
221 gst_scheduler_add_element (GstScheduler * sched, GstElement * element)
222 {
223   GstSchedulerClass *sclass;
224   gboolean redistribute_clock = FALSE;
225
226   g_return_if_fail (GST_IS_SCHEDULER (sched));
227   g_return_if_fail (GST_IS_ELEMENT (element));
228
229   /* if it's already in this scheduler, don't bother doing anything */
230   if (GST_ELEMENT_SCHEDULER (element) == sched) {
231     GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element %s already in scheduler %p",
232         GST_ELEMENT_NAME (element), sched);
233     return;
234   }
235
236   /* if it's not inside this scheduler, it has to be NULL */
237   g_assert (GST_ELEMENT_SCHEDULER (element) == NULL);
238
239   if (gst_element_provides_clock (element)) {
240     sched->clock_providers = g_list_prepend (sched->clock_providers, element);
241     GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock provider %s",
242         GST_ELEMENT_NAME (element));
243     redistribute_clock = TRUE;
244   }
245   if (gst_element_requires_clock (element)) {
246     sched->clock_receivers = g_list_prepend (sched->clock_receivers, element);
247     GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock receiver %s",
248         GST_ELEMENT_NAME (element));
249     redistribute_clock = TRUE;
250   }
251
252   gst_element_set_scheduler (element, sched);
253
254   if (redistribute_clock) {
255     GstClock *clock;
256
257     clock = gst_scheduler_get_clock (sched);
258     gst_scheduler_set_clock (sched, clock);
259   }
260
261   sclass = GST_SCHEDULER_GET_CLASS (sched);
262
263   if (sclass->add_element)
264     sclass->add_element (sched, element);
265 }
266
267 /**
268  * gst_scheduler_remove_element:
269  * @sched: the scheduler
270  * @element: the element to remove
271  *
272  * Remove an element from the scheduler.
273  */
274 void
275 gst_scheduler_remove_element (GstScheduler * sched, GstElement * element)
276 {
277   GstSchedulerClass *sclass;
278   GList *link;
279   gboolean redistribute_clock = FALSE;
280
281   g_return_if_fail (GST_IS_SCHEDULER (sched));
282   g_return_if_fail (GST_IS_ELEMENT (element));
283
284   link = g_list_find (sched->clock_providers, element);
285   if (link) {
286     sched->clock_providers = g_list_delete_link (sched->clock_providers, link);
287     GST_CAT_DEBUG (GST_CAT_CLOCK, "removed clock provider %s",
288         GST_ELEMENT_NAME (element));
289     redistribute_clock = TRUE;
290   }
291   link = g_list_find (sched->clock_receivers, element);
292   if (link) {
293     sched->clock_receivers = g_list_delete_link (sched->clock_receivers, link);
294     GST_CAT_DEBUG (GST_CAT_CLOCK, "removed clock receiver %s",
295         GST_ELEMENT_NAME (element));
296     redistribute_clock = TRUE;
297   }
298
299   if (redistribute_clock) {
300     GstClock *clock;
301
302     clock = gst_scheduler_get_clock (sched);
303     gst_scheduler_set_clock (sched, clock);
304   }
305
306   sclass = GST_SCHEDULER_GET_CLASS (sched);
307
308   if (sclass->remove_element)
309     sclass->remove_element (sched, element);
310
311   gst_element_set_scheduler (element, NULL);
312 }
313
314 /**
315  * gst_scheduler_state_transition:
316  * @sched: the scheduler
317  * @element: the element with the state transition
318  * @transition: the state transition
319  *
320  * Tell the scheduler that an element changed its state.
321  *
322  * Returns: a GstElementStateReturn indicating success or failure
323  * of the state transition.
324  */
325 GstElementStateReturn
326 gst_scheduler_state_transition (GstScheduler * sched, GstElement * element,
327     gint transition)
328 {
329   GstSchedulerClass *sclass;
330
331   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE);
332   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
333
334   if (element == sched->parent && sched->parent_sched == NULL) {
335     /* FIXME is distributing the clock in the state change still needed
336      * when we distribute as soon as we add/remove elements? I think not.*/
337     switch (transition) {
338       case GST_STATE_READY_TO_PAUSED:
339       {
340         GstClock *clock = gst_scheduler_get_clock (sched);
341
342         GST_CAT_DEBUG (GST_CAT_CLOCK,
343             "scheduler READY to PAUSED clock is %p (%s)", clock,
344             (clock ? GST_OBJECT_NAME (clock) : "nil"));
345
346         gst_scheduler_set_clock (sched, clock);
347         break;
348       }
349     }
350   }
351
352   sclass = GST_SCHEDULER_GET_CLASS (sched);
353
354   if (sclass->state_transition)
355     return sclass->state_transition (sched, element, transition);
356
357   return GST_STATE_SUCCESS;
358 }
359
360 /**
361  * gst_scheduler_scheduling_change:
362  * @sched: the scheduler
363  * @element: the element that changed its scheduling strategy
364  *
365  * Tell the scheduler that an element changed its scheduling strategy.
366  * An element could, for example, change its loop function or changes
367  * from a loop based element to a chain based element.
368  */
369 void
370 gst_scheduler_scheduling_change (GstScheduler * sched, GstElement * element)
371 {
372   GstSchedulerClass *sclass;
373
374   g_return_if_fail (GST_IS_SCHEDULER (sched));
375   g_return_if_fail (GST_IS_ELEMENT (element));
376
377   sclass = GST_SCHEDULER_GET_CLASS (sched);
378
379   if (sclass->scheduling_change)
380     sclass->scheduling_change (sched, element);
381 }
382
383 /**
384  * gst_scheduler_add_scheduler:
385  * @sched: a  #GstScheduler to add to
386  * @sched2: the #GstScheduler to add
387  *
388  * Notifies the scheduler that it has to monitor this scheduler.
389  */
390 void
391 gst_scheduler_add_scheduler (GstScheduler * sched, GstScheduler * sched2)
392 {
393   GstSchedulerClass *sclass;
394
395   g_return_if_fail (GST_IS_SCHEDULER (sched));
396   g_return_if_fail (GST_IS_SCHEDULER (sched2));
397   g_return_if_fail (sched2->parent_sched == NULL);
398
399   GST_DEBUG ("gstscheduler: %p add scheduler %p", sched, sched2);
400
401   gst_object_ref (GST_OBJECT (sched2));
402   gst_object_ref (GST_OBJECT (sched));
403
404   sched->schedulers = g_list_prepend (sched->schedulers, sched2);
405   sched2->parent_sched = sched;
406
407   sclass = GST_SCHEDULER_GET_CLASS (sched);
408
409   if (sclass->add_scheduler)
410     sclass->add_scheduler (sched, sched2);
411 }
412
413 /**
414  * gst_scheduler_remove_scheduler:
415  * @sched: the scheduler
416  * @sched2: the scheduler to remove
417  *
418  a Notifies the scheduler that it can stop monitoring this scheduler.
419  */
420 void
421 gst_scheduler_remove_scheduler (GstScheduler * sched, GstScheduler * sched2)
422 {
423   GstSchedulerClass *sclass;
424
425   g_return_if_fail (GST_IS_SCHEDULER (sched));
426   g_return_if_fail (GST_IS_SCHEDULER (sched2));
427   g_return_if_fail (sched2->parent_sched == sched);
428
429   GST_DEBUG ("gstscheduler: %p remove scheduler %p", sched, sched2);
430
431   sclass = GST_SCHEDULER_GET_CLASS (sched);
432
433   if (sclass->remove_scheduler)
434     sclass->remove_scheduler (sched, sched2);
435
436   sched->schedulers = g_list_remove (sched->schedulers, sched2);
437   sched2->parent_sched = NULL;
438
439   gst_object_unref (GST_OBJECT (sched2));
440   gst_object_unref (GST_OBJECT (sched));
441 }
442
443 /**
444  * gst_scheduler_lock_element:
445  * @sched: the scheduler
446  * @element: the element to lock
447  *
448  * Acquire a lock on the given element in the given scheduler.
449  */
450 void
451 gst_scheduler_lock_element (GstScheduler * sched, GstElement * element)
452 {
453   g_return_if_fail (GST_IS_SCHEDULER (sched));
454   g_return_if_fail (GST_IS_ELEMENT (element));
455 }
456
457 /**
458  * gst_scheduler_unlock_element:
459  * @sched: the scheduler
460  * @element: the element to unlock
461  *
462  * Release the lock on the given element in the given scheduler.
463  */
464 void
465 gst_scheduler_unlock_element (GstScheduler * sched, GstElement * element)
466 {
467   GstSchedulerClass *sclass;
468
469   g_return_if_fail (GST_IS_SCHEDULER (sched));
470   g_return_if_fail (GST_IS_ELEMENT (element));
471
472   sclass = GST_SCHEDULER_GET_CLASS (sched);
473 }
474
475 /**
476  * gst_scheduler_error:
477  * @sched: the scheduler
478  * @element: the element with the error
479  *
480  * Tell the scheduler an element was in error
481  */
482 void
483 gst_scheduler_error (GstScheduler * sched, GstElement * element)
484 {
485   GstSchedulerClass *sclass;
486
487   g_return_if_fail (GST_IS_SCHEDULER (sched));
488   g_return_if_fail (GST_IS_ELEMENT (element));
489
490   sclass = GST_SCHEDULER_GET_CLASS (sched);
491
492   if (sclass->error)
493     sclass->error (sched, element);
494 }
495
496 /**
497  * gst_scheduler_yield:
498  * @sched: the scheduler
499  * @element: the element requesting a yield
500  *
501  * Tell the scheduler to schedule another element.
502  *
503  * Returns: TRUE if the element should save its state, FALSE
504  * if the scheduler can perform this action itself.
505  */
506 gboolean
507 gst_scheduler_yield (GstScheduler * sched, GstElement * element)
508 {
509   GstSchedulerClass *sclass;
510
511   g_return_val_if_fail (GST_IS_SCHEDULER (sched), TRUE);
512   g_return_val_if_fail (GST_IS_ELEMENT (element), TRUE);
513
514   sclass = GST_SCHEDULER_GET_CLASS (sched);
515
516   if (sclass->yield)
517     return sclass->yield (sched, element);
518
519   return TRUE;
520 }
521
522 /**
523  * gst_scheduler_interrupt:
524  * @sched: the scheduler
525  * @element: the element requesting an interrupt
526  *
527  * Tell the scheduler to interrupt execution of this element.
528  *
529  * Returns: TRUE if the element should return NULL from the chain/get
530  * function.
531  */
532 gboolean
533 gst_scheduler_interrupt (GstScheduler * sched, GstElement * element)
534 {
535   GstSchedulerClass *sclass;
536
537   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
538   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
539
540   sclass = GST_SCHEDULER_GET_CLASS (sched);
541
542   if (sclass->interrupt)
543     return sclass->interrupt (sched, element);
544
545   return FALSE;
546 }
547
548 /**
549  * gst_scheduler_get_clock:
550  * @sched: the scheduler
551  *
552  * Gets the current clock used by the scheduler.
553  *
554  * Returns: a GstClock
555  */
556 GstClock *
557 gst_scheduler_get_clock (GstScheduler * sched)
558 {
559   GstClock *clock = NULL;
560
561   /* if we have a fixed clock, use that one */
562   if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) {
563     clock = sched->clock;
564
565     GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)",
566         clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
567   } else {
568     GList *schedulers = sched->schedulers;
569     GList *providers = sched->clock_providers;
570
571     /* try to get a clock from one of the schedulers we manage first */
572     while (schedulers) {
573       GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
574
575       clock = gst_scheduler_get_clock (scheduler);
576       if (clock) {
577         GST_CAT_DEBUG (GST_CAT_CLOCK,
578             "scheduler found managed sched clock %p (%s)",
579             clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
580         break;
581       }
582
583       schedulers = g_list_next (schedulers);
584     }
585     /* still no clock, try to find one in the providers */
586     while (!clock && providers) {
587       clock = gst_element_get_clock (GST_ELEMENT (providers->data));
588       if (clock)
589         GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler found provider clock: %p (%s)",
590             clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
591       providers = g_list_next (providers);
592     }
593     /* still no clock, use a system clock */
594     if (!clock && sched->parent_sched == NULL) {
595       clock = gst_system_clock_obtain ();
596       /* we unref since this function is not supposed to increase refcount
597        * of clock object returned; this is ok since the systemclock always
598        * has a refcount of at least one in the current code. */
599       gst_object_unref (GST_OBJECT (clock));
600       GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler obtained system clock: %p (%s)",
601           clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
602     }
603   }
604
605   return clock;
606 }
607
608 /**
609  * gst_scheduler_use_clock:
610  * @sched: the scheduler
611  * @clock: the clock to use
612  *
613  * Force the scheduler to use the given clock. The scheduler will
614  * always use the given clock even if new clock providers are added
615  * to this scheduler.
616  */
617 void
618 gst_scheduler_use_clock (GstScheduler * sched, GstClock * clock)
619 {
620   g_return_if_fail (sched != NULL);
621   g_return_if_fail (GST_IS_SCHEDULER (sched));
622
623   GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
624
625   gst_object_replace ((GstObject **) & sched->clock, (GstObject *) clock);
626
627   GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock,
628       (clock ? GST_OBJECT_NAME (clock) : "nil"));
629 }
630
631 /**
632  * gst_scheduler_set_clock:
633  * @sched: the scheduler
634  * @clock: the clock to set
635  *
636  * Set the clock for the scheduler. The clock will be distributed
637  * to all the elements managed by the scheduler.
638  */
639 void
640 gst_scheduler_set_clock (GstScheduler * sched, GstClock * clock)
641 {
642   GList *receivers;
643   GList *schedulers;
644
645   g_return_if_fail (sched != NULL);
646   g_return_if_fail (GST_IS_SCHEDULER (sched));
647
648   receivers = sched->clock_receivers;
649   schedulers = sched->schedulers;
650
651   gst_object_replace ((GstObject **) & sched->current_clock,
652       (GstObject *) clock);
653
654   while (receivers) {
655     GstElement *element = GST_ELEMENT (receivers->data);
656
657     GST_CAT_DEBUG (GST_CAT_CLOCK,
658         "scheduler setting clock %p (%s) on element %s", clock,
659         (clock ? GST_OBJECT_NAME (clock) : "nil"), GST_ELEMENT_NAME (element));
660
661     gst_element_set_clock (element, clock);
662     receivers = g_list_next (receivers);
663   }
664   while (schedulers) {
665     GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
666
667     GST_CAT_DEBUG (GST_CAT_CLOCK,
668         "scheduler setting clock %p (%s) on scheduler %p", clock,
669         (clock ? GST_OBJECT_NAME (clock) : "nil"), scheduler);
670     gst_scheduler_set_clock (scheduler, clock);
671     schedulers = g_list_next (schedulers);
672   }
673 }
674
675 /**
676  * gst_scheduler_auto_clock:
677  * @sched: the scheduler
678  *
679  * Let the scheduler select a clock automatically.
680  */
681 void
682 gst_scheduler_auto_clock (GstScheduler * sched)
683 {
684   g_return_if_fail (sched != NULL);
685   g_return_if_fail (GST_IS_SCHEDULER (sched));
686
687   GST_FLAG_UNSET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
688
689   gst_object_replace ((GstObject **) & sched->clock, NULL);
690
691   GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using automatic clock");
692 }
693
694 GstClockReturn gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter);
695
696 /**
697  * gst_scheduler_clock_wait:
698  * @sched: the scheduler
699  * @element: the element that wants to wait
700  * @id: the clockid to use
701  * @jitter: the time difference between requested time and actual time
702  *
703  * Wait till the clock reaches a specific time. The ClockID can
704  * be obtained from #gst_clock_new_single_shot_id. 
705  *
706  * Returns: the status of the operation
707  */
708 GstClockReturn
709 gst_scheduler_clock_wait (GstScheduler * sched, GstElement * element,
710     GstClockID id, GstClockTimeDiff * jitter)
711 {
712   GstSchedulerClass *sclass;
713
714   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_CLOCK_ERROR);
715   g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
716
717   sclass = GST_SCHEDULER_GET_CLASS (sched);
718
719   if (sclass->clock_wait)
720     return sclass->clock_wait (sched, element, id, jitter);
721   else
722     return gst_clock_id_wait (id, jitter);
723 }
724
725 /**
726  * gst_scheduler_iterate:
727  * @sched: the scheduler
728  *
729  * Perform one iteration on the scheduler.
730  *
731  * Returns: a boolean indicating something usefull has happened.
732  */
733 gboolean
734 gst_scheduler_iterate (GstScheduler * sched)
735 {
736   GstSchedulerClass *sclass;
737   gboolean res = FALSE;
738
739   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
740
741   sclass = GST_SCHEDULER_GET_CLASS (sched);
742
743   if (sclass->iterate) {
744     res = sclass->iterate (sched);
745   }
746
747   return res;
748 }
749
750
751 /**
752  * gst_scheduler_show:
753  * @sched: the scheduler
754  *
755  * Dump the state of the scheduler
756  */
757 void
758 gst_scheduler_show (GstScheduler * sched)
759 {
760   GstSchedulerClass *sclass;
761
762   g_return_if_fail (GST_IS_SCHEDULER (sched));
763
764   sclass = GST_SCHEDULER_GET_CLASS (sched);
765
766   if (sclass->show)
767     sclass->show (sched);
768 }
769
770 /*
771  * Factory stuff starts here
772  *
773  */
774 static void gst_scheduler_factory_class_init (GstSchedulerFactoryClass * klass);
775 static void gst_scheduler_factory_init (GstSchedulerFactory * factory);
776
777 static GstPluginFeatureClass *factory_parent_class = NULL;
778
779 /* static guint gst_scheduler_factory_signals[LAST_SIGNAL] = { 0 }; */
780
781 GType
782 gst_scheduler_factory_get_type (void)
783 {
784   static GType schedulerfactory_type = 0;
785
786   if (!schedulerfactory_type) {
787     static const GTypeInfo schedulerfactory_info = {
788       sizeof (GstSchedulerFactoryClass),
789       NULL,
790       NULL,
791       (GClassInitFunc) gst_scheduler_factory_class_init,
792       NULL,
793       NULL,
794       sizeof (GstSchedulerFactory),
795       0,
796       (GInstanceInitFunc) gst_scheduler_factory_init,
797       NULL
798     };
799
800     schedulerfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE,
801         "GstSchedulerFactory", &schedulerfactory_info, 0);
802   }
803   return schedulerfactory_type;
804 }
805
806 static void
807 gst_scheduler_factory_class_init (GstSchedulerFactoryClass * klass)
808 {
809   GObjectClass *gobject_class;
810   GstObjectClass *gstobject_class;
811   GstPluginFeatureClass *gstpluginfeature_class;
812
813   gobject_class = (GObjectClass *) klass;
814   gstobject_class = (GstObjectClass *) klass;
815   gstpluginfeature_class = (GstPluginFeatureClass *) klass;
816
817   factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
818
819   if (!_default_name) {
820     if (g_getenv ("GST_SCHEDULER")) {
821       _default_name = g_strdup (g_getenv ("GST_SCHEDULER"));
822     } else {
823       _default_name = g_strdup (GST_SCHEDULER_DEFAULT_NAME);
824     }
825   }
826   g_assert (_default_name);
827 }
828
829 static void
830 gst_scheduler_factory_init (GstSchedulerFactory * factory)
831 {
832 }
833
834
835 /**
836  * gst_scheduler_register:
837  * @plugin: a #GstPlugin
838  * @name: name of the scheduler to register
839  * @longdesc: description of the scheduler
840  * @type: #GType of the scheduler to register
841  *
842  * Registers a scheduler with GStreamer.
843  *
844  * Returns: TRUE, if the registering succeeded, FALSE on error.
845  *
846  * Since: 0.8.5
847  **/
848 gboolean
849 gst_scheduler_register (GstPlugin * plugin, const gchar * name,
850     const gchar * longdesc, GType type)
851 {
852   GstSchedulerFactory *factory;
853
854   g_return_val_if_fail (plugin != NULL, FALSE);
855   g_return_val_if_fail (name != NULL, FALSE);
856   g_return_val_if_fail (longdesc != NULL, FALSE);
857   g_return_val_if_fail (g_type_is_a (type, GST_TYPE_SCHEDULER), FALSE);
858
859   factory = gst_scheduler_factory_find (name);
860   if (factory) {
861     g_return_val_if_fail (factory->type == 0, FALSE);
862     g_free (factory->longdesc);
863     factory->longdesc = g_strdup (longdesc);
864     factory->type = type;
865   } else {
866     factory = gst_scheduler_factory_new (name, longdesc, type);
867     g_return_val_if_fail (factory, FALSE);
868     gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
869   }
870
871   return TRUE;
872 }
873
874 /**
875  * gst_scheduler_factory_new:
876  * @name: name of schedulerfactory to create
877  * @longdesc: long description of schedulerfactory to create
878  * @type: the gtk type of the GstScheduler element of this factory
879  *
880  * Create a new schedulerfactory with the given parameters
881  *
882  * Returns: a new #GstSchedulerFactory.
883  */
884 GstSchedulerFactory *
885 gst_scheduler_factory_new (const gchar * name, const gchar * longdesc,
886     GType type)
887 {
888   GstSchedulerFactory *factory;
889
890   g_return_val_if_fail (name != NULL, NULL);
891
892   factory = gst_scheduler_factory_find (name);
893
894   if (!factory) {
895     factory =
896         GST_SCHEDULER_FACTORY (g_object_new (GST_TYPE_SCHEDULER_FACTORY, NULL));
897     GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
898   } else {
899     g_free (factory->longdesc);
900   }
901
902   factory->longdesc = g_strdup (longdesc);
903   factory->type = type;
904
905   return factory;
906 }
907
908 /**
909  * gst_scheduler_factory_destroy:
910  * @factory: factory to destroy
911  *
912  * Removes the scheduler from the global list.
913  */
914 void
915 gst_scheduler_factory_destroy (GstSchedulerFactory * factory)
916 {
917   g_return_if_fail (factory != NULL);
918
919   /* we don't free the struct bacause someone might  have a handle to it.. */
920 }
921
922 /**
923  * gst_scheduler_factory_find:
924  * @name: name of schedulerfactory to find
925  *
926  * Search for an schedulerfactory of the given name.
927  *
928  * Returns: #GstSchedulerFactory if found, NULL otherwise
929  */
930 GstSchedulerFactory *
931 gst_scheduler_factory_find (const gchar * name)
932 {
933   GstPluginFeature *feature;
934
935   g_return_val_if_fail (name != NULL, NULL);
936
937   GST_DEBUG ("gstscheduler: find \"%s\"", name);
938
939   feature = gst_registry_pool_find_feature (name, GST_TYPE_SCHEDULER_FACTORY);
940
941   if (feature)
942     return GST_SCHEDULER_FACTORY (feature);
943
944   return NULL;
945 }
946
947 /**
948  * gst_scheduler_factory_create:
949  * @factory: the factory used to create the instance
950  * @parent: the parent element of this scheduler
951  *
952  * Create a new #GstScheduler instance from the 
953  * given schedulerfactory with the given parent. @parent will
954  * have its scheduler set to the returned #GstScheduler instance.
955  *
956  * Returns: A new #GstScheduler instance with a reference count of %1.
957  */
958 GstScheduler *
959 gst_scheduler_factory_create (GstSchedulerFactory * factory,
960     GstElement * parent)
961 {
962   GstScheduler *sched = NULL;
963
964   g_return_val_if_fail (factory != NULL, NULL);
965   g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
966
967   if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
968     g_return_val_if_fail (factory->type != 0, NULL);
969
970     sched = GST_SCHEDULER (g_object_new (factory->type, NULL));
971     sched->parent = parent;
972
973     GST_ELEMENT_SCHEDULER (parent) = sched;
974
975     /* let's refcount the scheduler */
976     gst_object_ref (GST_OBJECT (sched));
977     gst_object_sink (GST_OBJECT (sched));
978   }
979
980   return sched;
981 }
982
983 /**
984  * gst_scheduler_factory_make:
985  * @name: the name of the factory used to create the instance
986  * @parent: the parent element of this scheduler
987  *
988  * Create a new #GstScheduler instance from the 
989  * schedulerfactory with the given name and parent. @parent will
990  * have its scheduler set to the returned #GstScheduler instance.
991  * If %NULL is passed as @name, the default scheduler name will
992  * be used.
993  *
994  * Returns: A new #GstScheduler instance with a reference count of %1.
995  */
996 GstScheduler *
997 gst_scheduler_factory_make (const gchar * name, GstElement * parent)
998 {
999   GstSchedulerFactory *factory;
1000   const gchar *default_name = gst_scheduler_factory_get_default_name ();
1001
1002   if (name)
1003     factory = gst_scheduler_factory_find (name);
1004   else {
1005     /* FIXME: do better error handling */
1006     if (default_name == NULL)
1007       g_error ("No default scheduler name - do you have a registry ?");
1008     factory = gst_scheduler_factory_find (default_name);
1009   }
1010
1011   if (factory == NULL)
1012     return NULL;
1013
1014   return gst_scheduler_factory_create (factory, parent);
1015 }
1016
1017 /**
1018  * gst_scheduler_factory_set_default_name:
1019  * @name: the name of the factory used as a default
1020  *
1021  * Set the default schedulerfactory name.
1022  */
1023 void
1024 gst_scheduler_factory_set_default_name (const gchar * name)
1025 {
1026   g_free (_default_name);
1027
1028   _default_name = g_strdup (name);
1029 }
1030
1031 /**
1032  * gst_scheduler_factory_get_default_name:
1033  *
1034  * Get the default schedulerfactory name.
1035  *
1036  * Returns: the name of the default scheduler.
1037  */
1038 const gchar *
1039 gst_scheduler_factory_get_default_name (void)
1040 {
1041   return _default_name;
1042 }