- The clock_wait now returns the difference between requested time and unlock time.
[platform/upstream/gstreamer.git] / plugins / elements / gstqueue.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstqueue.c:
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 /* #define DEBUG_ENABLED */
24 /* #define STATUS_ENABLED */
25 #ifdef STATUS_ENABLED
26 #define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue))
27 #else
28 #define STATUS(A)
29 #endif
30
31 #include <pthread.h>
32
33 #include "config.h"
34 #include "gst_private.h"
35
36 #include "gstqueue.h"
37 #include "gstscheduler.h"
38 #include "gstevent.h"
39
40 GstElementDetails gst_queue_details = {
41   "Queue",
42   "Generic",
43   "Simple data queue",
44   VERSION,
45   "Erik Walthinsen <omega@cse.ogi.edu>",
46   "(C) 1999",
47 };
48
49
50 /* Queue signals and args */
51 enum {
52   LOW_WATERMARK,
53   HIGH_WATERMARK,
54   LAST_SIGNAL
55 };
56
57 enum {
58   ARG_0,
59   ARG_LEVEL_BUFFERS,
60   ARG_LEVEL_BYTES,
61   ARG_LEVEL_TIME,
62   ARG_SIZE_BUFFERS,
63   ARG_SIZE_BYTES,
64   ARG_SIZE_TIME,
65   ARG_LEAKY,
66   ARG_LEVEL,
67   ARG_MAX_LEVEL,
68   ARG_MAY_DEADLOCK,
69 };
70
71
72 static void                     gst_queue_class_init            (GstQueueClass *klass);
73 static void                     gst_queue_init                  (GstQueue *queue);
74 static void                     gst_queue_dispose               (GObject *object);
75
76 static void                     gst_queue_set_property          (GObject *object, guint prop_id, 
77                                                                  const GValue *value, GParamSpec *pspec);
78 static void                     gst_queue_get_property          (GObject *object, guint prop_id, 
79                                                                  GValue *value, GParamSpec *pspec);
80
81 static void                     gst_queue_chain                 (GstPad *pad, GstBuffer *buf);
82 static GstBuffer *              gst_queue_get                   (GstPad *pad);
83 static GstBufferPool*           gst_queue_get_bufferpool        (GstPad *pad);
84         
85 static gboolean                 gst_queue_handle_src_event      (GstPad *pad, GstEvent *event);
86
87
88 static void                     gst_queue_locked_flush          (GstQueue *queue);
89
90 static GstElementStateReturn    gst_queue_change_state          (GstElement *element);
91 static gboolean                 gst_queue_release_locks         (GstElement *element);
92
93   
94 #define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type())
95 static GType
96 queue_leaky_get_type(void) {
97   static GType queue_leaky_type = 0;
98   static GEnumValue queue_leaky[] = {
99     { GST_QUEUE_NO_LEAK,                "0", "Not Leaky" },
100     { GST_QUEUE_LEAK_UPSTREAM,          "1", "Leaky on Upstream" },
101     { GST_QUEUE_LEAK_DOWNSTREAM,        "2", "Leaky on Downstream" },
102     { 0, NULL, NULL },
103   };
104   if (!queue_leaky_type) {
105     queue_leaky_type = g_enum_register_static("GstQueueLeaky", queue_leaky);
106   }
107   return queue_leaky_type;
108 }
109
110 static GstElementClass *parent_class = NULL;
111 /* static guint gst_queue_signals[LAST_SIGNAL] = { 0 }; */
112
113 GType
114 gst_queue_get_type(void) 
115 {
116   static GType queue_type = 0;
117
118   if (!queue_type) {
119     static const GTypeInfo queue_info = {
120       sizeof(GstQueueClass),
121       NULL,
122       NULL,
123       (GClassInitFunc)gst_queue_class_init,
124       NULL,
125       NULL,
126       sizeof(GstQueue),
127       4,
128       (GInstanceInitFunc)gst_queue_init,
129       NULL
130     };
131     queue_type = g_type_register_static (GST_TYPE_ELEMENT, "GstQueue", &queue_info, 0);
132   }
133   return queue_type;
134 }
135
136 static void
137 gst_queue_class_init (GstQueueClass *klass)
138 {
139   GObjectClass *gobject_class;
140   GstElementClass *gstelement_class;
141
142   gobject_class = (GObjectClass*)klass;
143   gstelement_class = (GstElementClass*)klass;
144
145   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
146
147   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LEAKY,
148     g_param_spec_enum ("leaky", "Leaky", "Where the queue leaks, if at all.",
149                        GST_TYPE_QUEUE_LEAKY, GST_QUEUE_NO_LEAK, G_PARAM_READWRITE));
150   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LEVEL,
151     g_param_spec_int ("level", "Level", "How many buffers are in the queue.",
152                       0, G_MAXINT, 0, G_PARAM_READABLE));
153   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_LEVEL,
154     g_param_spec_int ("max_level", "Maximum Level", "How many buffers the queue holds.",
155                       0, G_MAXINT, 100, G_PARAM_READWRITE));
156   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAY_DEADLOCK,
157     g_param_spec_boolean ("may_deadlock", "May Deadlock", "The queue may deadlock if it's full and not PLAYING",
158                       TRUE, G_PARAM_READWRITE));
159
160   gobject_class->dispose                = GST_DEBUG_FUNCPTR (gst_queue_dispose);
161   gobject_class->set_property           = GST_DEBUG_FUNCPTR (gst_queue_set_property);
162   gobject_class->get_property           = GST_DEBUG_FUNCPTR (gst_queue_get_property);
163
164   gstelement_class->change_state  = GST_DEBUG_FUNCPTR(gst_queue_change_state);
165   gstelement_class->release_locks = GST_DEBUG_FUNCPTR(gst_queue_release_locks);
166 }
167
168 static GstPadConnectReturn
169 gst_queue_connect (GstPad *pad, GstCaps *caps)
170 {
171   GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
172   GstPad *otherpad;
173
174   if (pad == queue->srcpad) 
175     otherpad = queue->sinkpad;
176   else
177     otherpad = queue->srcpad;
178
179   return gst_pad_proxy_connect (otherpad, caps);
180 }
181
182 static GstCaps*
183 gst_queue_getcaps (GstPad *pad, GstCaps *caps)
184 {
185   GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
186   GstPad *otherpad;
187
188   if (pad == queue->srcpad) 
189     otherpad = queue->sinkpad;
190   else
191     otherpad = queue->srcpad;
192
193   return gst_pad_get_allowed_caps (otherpad);
194 }
195
196 static void
197 gst_queue_init (GstQueue *queue)
198 {
199   /* scheduling on this kind of element is, well, interesting */
200   GST_FLAG_SET (queue, GST_ELEMENT_DECOUPLED);
201   GST_FLAG_SET (queue, GST_ELEMENT_EVENT_AWARE);
202
203   queue->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
204   gst_pad_set_chain_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_chain));
205   gst_element_add_pad (GST_ELEMENT (queue), queue->sinkpad);
206   gst_pad_set_bufferpool_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_get_bufferpool));
207   gst_pad_set_connect_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_connect));
208   gst_pad_set_getcaps_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps));
209
210   queue->srcpad = gst_pad_new ("src", GST_PAD_SRC);
211   gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_get));
212   gst_element_add_pad (GST_ELEMENT (queue), queue->srcpad);
213   gst_pad_set_connect_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_connect));
214   gst_pad_set_getcaps_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps));
215   gst_pad_set_event_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_handle_src_event));
216
217   queue->leaky = GST_QUEUE_NO_LEAK;
218   queue->queue = NULL;
219   queue->level_buffers = 0;
220   queue->level_bytes = 0;
221   queue->level_time = 0LL;
222   queue->size_buffers = 100;            /* 100 buffers */
223   queue->size_bytes = 100 * 1024;       /* 100KB */
224   queue->size_time = 1000000000LL;      /* 1sec */
225   queue->may_deadlock = TRUE;
226
227   queue->qlock = g_mutex_new ();
228   queue->reader = FALSE;
229   queue->writer = FALSE;
230   queue->not_empty = g_cond_new ();
231   queue->not_full = g_cond_new ();
232   GST_DEBUG_ELEMENT (GST_CAT_THREAD, queue, "initialized queue's not_empty & not_full conditions");
233 }
234
235 static void
236 gst_queue_dispose (GObject *object)
237 {
238   GstQueue *queue = GST_QUEUE (object);
239
240   g_mutex_free (queue->qlock);
241   g_cond_free (queue->not_empty);
242   g_cond_free (queue->not_full);
243
244   G_OBJECT_CLASS (parent_class)->dispose (object);
245 }
246
247 static GstBufferPool*
248 gst_queue_get_bufferpool (GstPad *pad)
249 {
250   GstQueue *queue;
251
252   queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
253
254   return gst_pad_get_bufferpool (queue->srcpad);
255 }
256
257 static void
258 gst_queue_cleanup_buffers (gpointer data, const gpointer user_data)
259 {
260   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, user_data, "cleaning buffer %p", data);
261
262   if (GST_IS_BUFFER (data)) {
263     gst_buffer_unref (GST_BUFFER (data));
264   }
265   else {
266     gst_event_free (GST_EVENT (data));
267   }
268 }
269
270 static void
271 gst_queue_locked_flush (GstQueue *queue)
272 {
273   g_list_foreach (queue->queue, gst_queue_cleanup_buffers,
274                   (gpointer) queue);
275   g_list_free (queue->queue);
276
277   queue->queue = NULL;
278   queue->level_buffers = 0;
279   queue->timeval = NULL;
280 }
281
282 static void
283 gst_queue_chain (GstPad *pad, GstBuffer *buf)
284 {
285   GstQueue *queue;
286   gboolean reader;
287
288   g_return_if_fail (pad != NULL);
289   g_return_if_fail (GST_IS_PAD (pad));
290   g_return_if_fail (buf != NULL);
291
292   queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
293
294 restart:
295   /* we have to lock the queue since we span threads */
296   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld", pthread_self ());
297   g_mutex_lock (queue->qlock);
298   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locked t:%ld", pthread_self ());
299
300   if (GST_IS_EVENT (buf)) {
301     switch (GST_EVENT_TYPE (buf)) {
302       case GST_EVENT_FLUSH:
303         GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "FLUSH event, flushing queue\n");
304         gst_queue_locked_flush (queue);
305         break;
306       case GST_EVENT_EOS:
307         GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "eos in on %s %d\n", 
308                            GST_ELEMENT_NAME (queue), queue->level_buffers);
309         break;
310       case GST_EVENT_DISCONTINUOUS:
311         //gst_queue_locked_flush (queue);
312         break;
313       default:
314         /*gst_pad_event_default (pad, GST_EVENT (buf)); */
315         break;
316     }
317   }
318
319   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "adding buffer %p of size %d",buf,GST_BUFFER_SIZE(buf));
320
321   if (queue->level_buffers == queue->size_buffers) {
322     /* if this is a leaky queue... */
323     if (queue->leaky) {
324       /* FIXME don't want to leak events! */
325       /* if we leak on the upstream side, drop the current buffer */
326       if (queue->leaky == GST_QUEUE_LEAK_UPSTREAM) {
327         GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end");
328         if (GST_IS_EVENT (buf))
329           fprintf(stderr, "Error: queue [%s] leaked an event, type:%d\n",
330               GST_ELEMENT_NAME(GST_ELEMENT(queue)),
331               GST_EVENT_TYPE(GST_EVENT(buf)));
332           GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end");
333         gst_buffer_unref(buf);
334         /* now we have to clean up and exit right away */
335         g_mutex_unlock (queue->qlock);
336         return;
337       }
338       /* otherwise we have to push a buffer off the other end */
339       else {
340         GList *front;
341         GstBuffer *leakbuf;
342         GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end");
343         front = queue->queue;
344         leakbuf = (GstBuffer *)(front->data);
345         if (GST_IS_EVENT (leakbuf))
346           fprintf(stderr, "Error: queue [%s] leaked an event, type:%d\n",
347               GST_ELEMENT_NAME(GST_ELEMENT(queue)),
348               GST_EVENT_TYPE(GST_EVENT(leakbuf)));
349         queue->level_buffers--;
350         queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
351         gst_buffer_unref(leakbuf);
352         queue->queue = g_list_remove_link (queue->queue, front);
353         g_list_free (front);
354       }
355     }
356
357     GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "pre full wait, level:%d/%d",
358         queue->level_buffers, queue->size_buffers);
359     while (queue->level_buffers == queue->size_buffers) {
360       /* if there's a pending state change for this queue or its manager, switch */
361       /* back to iterator so bottom half of state change executes */
362       //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
363       if (queue->interrupt) {
364         GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!");
365         g_mutex_unlock (queue->qlock);
366         if (gst_element_interrupt (GST_ELEMENT (queue)))
367           return;
368         goto restart;
369       }
370       if (GST_STATE (queue) != GST_STATE_PLAYING) {
371         /* this means the other end is shut down */
372         /* try to signal to resolve the error */
373         if (!queue->may_deadlock) {
374           if (GST_IS_BUFFER (buf)) gst_buffer_unref (buf);
375           else gst_event_free (GST_EVENT (buf));
376           g_mutex_unlock (queue->qlock);
377           gst_element_error (GST_ELEMENT (queue), "deadlock found, source pad elements are shut down");
378           return;
379         }
380         else {
381           g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue));
382         }
383       }
384
385       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for not_full, level:%d/%d", 
386                       queue->level_buffers, queue->size_buffers);
387       if (queue->writer)
388         GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "WARNING: multiple writers on queue!");
389       queue->writer = TRUE;
390       g_cond_wait (queue->not_full, queue->qlock);
391       queue->writer = FALSE;
392       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "got not_full signal");
393     }
394     GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "post full wait, level:%d/%d",
395         queue->level_buffers, queue->size_buffers);
396   }
397
398   /* put the buffer on the tail of the list */
399   queue->queue = g_list_append (queue->queue, buf);
400   queue->level_buffers++;
401   queue->level_bytes += GST_BUFFER_SIZE(buf);
402
403   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "(%s:%s)+ level:%d/%d",
404       GST_DEBUG_PAD_NAME(pad),
405       queue->level_buffers, queue->size_buffers);
406
407   /* this assertion _has_ to hold */
408   /* g_assert (g_list_length (queue->queue) == queue->level_buffers); */
409
410   /* reader waiting on an empty queue */
411   reader = queue->reader;
412
413   g_mutex_unlock (queue->qlock);
414
415   if (reader)
416   {
417     GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "signalling not_empty");
418     g_cond_signal (queue->not_empty);
419   }
420 }
421
422 static GstBuffer *
423 gst_queue_get (GstPad *pad)
424 {
425   GstQueue *queue;
426   GstBuffer *buf = NULL;
427   GList *front;
428   gboolean writer;
429
430   g_assert(pad != NULL);
431   g_assert(GST_IS_PAD(pad));
432   g_return_val_if_fail (pad != NULL, NULL);
433   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
434
435   queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
436
437 restart:
438   /* have to lock for thread-safety */
439   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld", pthread_self ());
440   g_mutex_lock (queue->qlock);
441   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locked t:%ld %p", pthread_self (), queue->not_empty);
442
443   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "pre empty wait, level:%d/%d", queue->level_buffers, queue->size_buffers);
444   while (queue->level_buffers == 0) {
445     /* if there's a pending state change for this queue or its manager, switch
446      * back to iterator so bottom half of state change executes
447      */ 
448     //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
449     if (queue->interrupt) {
450       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!");
451       g_mutex_unlock (queue->qlock);
452       if (gst_element_interrupt (GST_ELEMENT (queue)))
453         return NULL;
454       goto restart;
455     }
456     if (GST_STATE (queue) != GST_STATE_PLAYING) {
457       /* this means the other end is shut down */
458       if (!queue->may_deadlock) {
459         g_mutex_unlock (queue->qlock);
460         gst_element_error (GST_ELEMENT (queue), "deadlock found, sink pad elements are shut down");
461         goto restart;
462       }
463       else {
464         g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue));
465       }
466     }
467
468     GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for not_empty, level:%d/%d", queue->level_buffers, queue->size_buffers);
469     if (queue->reader)
470       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "WARNING: multiple readers on queue!");
471     queue->reader = TRUE;
472     g_cond_wait (queue->not_empty, queue->qlock);
473     queue->reader = FALSE;
474     GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "got not_empty signal");
475   }
476   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "post empty wait, level:%d/%d", queue->level_buffers, queue->size_buffers);
477
478   front = queue->queue;
479   buf = (GstBuffer *)(front->data);
480   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "retrieved buffer %p from queue", buf);
481   queue->queue = g_list_remove_link (queue->queue, front);
482   g_list_free (front);
483
484   queue->level_buffers--;
485   queue->level_bytes -= GST_BUFFER_SIZE(buf);
486
487   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "(%s:%s)- level:%d/%d",
488       GST_DEBUG_PAD_NAME(pad),
489       queue->level_buffers, queue->size_buffers);
490
491   /* this assertion _has_ to hold */
492   /* g_assert (g_list_length (queue->queue) == queue->level_buffers); */
493
494   /* writer waiting on a full queue */
495   writer = queue->writer;
496
497   g_mutex_unlock (queue->qlock);
498
499   if (writer)
500   {
501     GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "signalling not_full");
502     g_cond_signal (queue->not_full);
503   }
504
505   /* FIXME where should this be? locked? */
506   if (GST_IS_EVENT(buf)) {
507     GstEvent *event = GST_EVENT(buf);
508     switch (GST_EVENT_TYPE(event)) {
509       case GST_EVENT_EOS:
510         GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue \"%s\" eos", GST_ELEMENT_NAME (queue));
511         gst_element_set_eos (GST_ELEMENT (queue));
512         break;
513       default:
514         break;
515     }
516   }
517
518   return buf;
519 }
520
521
522 static gboolean
523 gst_queue_handle_src_event (GstPad *pad, GstEvent *event)
524 {
525   GstQueue *queue;
526
527   queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
528
529   g_mutex_lock (queue->qlock);
530
531   if (gst_element_get_state (GST_ELEMENT (queue)) == GST_STATE_PLAYING) {
532     g_warning ("queue event in playing state");
533   }
534
535   switch (GST_EVENT_TYPE (event)) {
536     case GST_EVENT_FLUSH:
537       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "FLUSH event, flushing queue\n");
538       gst_queue_locked_flush (queue);
539       break;
540     case GST_EVENT_SEEK:
541       gst_queue_locked_flush (queue);
542     default:
543       gst_pad_event_default (pad, event); 
544       break;
545   }
546   g_mutex_unlock (queue->qlock);
547   return TRUE;
548 }
549
550 static gboolean
551 gst_queue_release_locks (GstElement *element)
552 {
553   GstQueue *queue;
554
555   queue = GST_QUEUE (element);
556
557   g_mutex_lock (queue->qlock);
558   queue->interrupt = TRUE;
559   g_cond_signal (queue->not_full);
560   g_cond_signal (queue->not_empty); 
561   g_mutex_unlock (queue->qlock);
562
563   return TRUE;
564 }
565
566 static GstElementStateReturn
567 gst_queue_change_state (GstElement *element)
568 {
569   GstQueue *queue;
570   GstElementStateReturn ret;
571   GstElementState new_state;
572   g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE);
573
574   queue = GST_QUEUE (element);
575
576   GST_DEBUG_ENTER("('%s')", GST_ELEMENT_NAME (element));
577
578   /* lock the queue so another thread (not in sync with this thread's state)
579    * can't call this queue's _get (or whatever)
580    */
581   g_mutex_lock (queue->qlock);
582
583   new_state = GST_STATE_PENDING (element);
584
585   if (new_state == GST_STATE_PAUSED) {
586     /*g_cond_signal (queue->not_full); */
587     /*g_cond_signal (queue->not_empty); */
588   }
589   else if (new_state == GST_STATE_READY) {
590     gst_queue_locked_flush (queue);
591   }
592   else if (new_state == GST_STATE_PLAYING) {
593     if (!GST_PAD_IS_CONNECTED (queue->sinkpad)) {
594       GST_DEBUG_ELEMENT (GST_CAT_STATES, queue, "queue %s is not connected", GST_ELEMENT_NAME (queue));
595       /* FIXME can this be? */
596       if (queue->reader)
597         g_cond_signal (queue->not_empty);
598       g_mutex_unlock (queue->qlock);
599
600       return GST_STATE_FAILURE;
601     }
602     queue->interrupt = FALSE;
603   }
604
605   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
606   g_mutex_unlock (queue->qlock);
607
608   GST_DEBUG_LEAVE("('%s')", GST_ELEMENT_NAME (element));
609   return ret;
610 }
611
612
613 static void
614 gst_queue_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
615 {
616   GstQueue *queue;
617
618   /* it's not null if we got it, but it might not be ours */
619   g_return_if_fail (GST_IS_QUEUE (object));
620
621   queue = GST_QUEUE (object);
622
623   switch (prop_id) {
624     case ARG_LEAKY:
625       queue->leaky = g_value_get_enum (value);
626       break;
627     case ARG_MAX_LEVEL:
628       queue->size_buffers = g_value_get_int (value);
629       break;
630     case ARG_MAY_DEADLOCK:
631       queue->may_deadlock = g_value_get_boolean (value);
632       break;
633     default:
634       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
635       break;
636   }
637 }
638
639 static void
640 gst_queue_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
641 {
642   GstQueue *queue;
643
644   /* it's not null if we got it, but it might not be ours */
645   g_return_if_fail (GST_IS_QUEUE (object));
646
647   queue = GST_QUEUE (object);
648
649   switch (prop_id) {
650     case ARG_LEAKY:
651       g_value_set_enum (value, queue->leaky);
652       break;
653     case ARG_LEVEL:
654       g_value_set_int (value, queue->level_buffers);
655       break;
656     case ARG_MAX_LEVEL:
657       g_value_set_int (value, queue->size_buffers);
658       break;
659     case ARG_MAY_DEADLOCK:
660       g_value_set_boolean (value, queue->may_deadlock);
661       break;
662     default:
663       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
664       break;
665   }
666 }