audioutilsprivate: restore thread priority before ending
[platform/upstream/gstreamer.git] / gst-libs / gst / audio / gstaudiosink.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2005 Wim Taymans <wim@fluendo.com>
4  *
5  * gstaudiosink.c: simple audio sink base class
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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:gstaudiosink
25  * @title: GstAudioSink
26  * @short_description: Simple base class for audio sinks
27  * @see_also: #GstAudioBaseSink, #GstAudioRingBuffer, #GstAudioSink.
28  *
29  * This is the most simple base class for audio sinks that only requires
30  * subclasses to implement a set of simple functions:
31  *
32  * * `open()` :Open the device.
33  *
34  * * `prepare()` :Configure the device with the specified format.
35  *
36  * * `write()` :Write samples to the device.
37  *
38  * * `reset()` :Unblock writes and flush the device.
39  *
40  * * `delay()` :Get the number of samples written but not yet played
41  * by the device.
42  *
43  * * `unprepare()` :Undo operations done by prepare.
44  *
45  * * `close()` :Close the device.
46  *
47  * All scheduling of samples and timestamps is done in this base class
48  * together with #GstAudioBaseSink using a default implementation of a
49  * #GstAudioRingBuffer that uses threads.
50  */
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
54
55 #include <string.h>
56
57 #include <gst/audio/audio.h>
58 #include "gstaudiosink.h"
59 #include "gstaudioutilsprivate.h"
60
61 GST_DEBUG_CATEGORY_STATIC (gst_audio_sink_debug);
62 #define GST_CAT_DEFAULT gst_audio_sink_debug
63
64 #define GST_TYPE_AUDIO_SINK_RING_BUFFER        \
65         (gst_audio_sink_ring_buffer_get_type())
66 #define GST_AUDIO_SINK_RING_BUFFER(obj)        \
67         (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_SINK_RING_BUFFER,GstAudioSinkRingBuffer))
68 #define GST_AUDIO_SINK_RING_BUFFER_CLASS(klass) \
69         (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_SINK_RING_BUFFER,GstAudioSinkRingBufferClass))
70 #define GST_AUDIO_SINK_RING_BUFFER_GET_CLASS(obj) \
71         (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_AUDIO_SINK_RING_BUFFER, GstAudioSinkRingBufferClass))
72 #define GST_AUDIO_SINK_RING_BUFFER_CAST(obj)        \
73         ((GstAudioSinkRingBuffer *)obj)
74 #define GST_IS_AUDIO_SINK_RING_BUFFER(obj)     \
75         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_SINK_RING_BUFFER))
76 #define GST_IS_AUDIO_SINK_RING_BUFFER_CLASS(klass)\
77         (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_SINK_RING_BUFFER))
78
79 typedef struct _GstAudioSinkRingBuffer GstAudioSinkRingBuffer;
80 typedef struct _GstAudioSinkRingBufferClass GstAudioSinkRingBufferClass;
81
82 #define GST_AUDIO_SINK_RING_BUFFER_GET_COND(buf) (&(((GstAudioSinkRingBuffer *)buf)->cond))
83 #define GST_AUDIO_SINK_RING_BUFFER_WAIT(buf)     (g_cond_wait (GST_AUDIO_SINK_RING_BUFFER_GET_COND (buf), GST_OBJECT_GET_LOCK (buf)))
84 #define GST_AUDIO_SINK_RING_BUFFER_SIGNAL(buf)   (g_cond_signal (GST_AUDIO_SINK_RING_BUFFER_GET_COND (buf)))
85 #define GST_AUDIO_SINK_RING_BUFFER_BROADCAST(buf)(g_cond_broadcast (GST_AUDIO_SINK_RING_BUFFER_GET_COND (buf)))
86
87 struct _GstAudioSinkRingBuffer
88 {
89   GstAudioRingBuffer object;
90
91   gboolean running;
92   gint queuedseg;
93
94   GCond cond;
95 };
96
97 struct _GstAudioSinkRingBufferClass
98 {
99   GstAudioRingBufferClass parent_class;
100 };
101
102 static void gst_audio_sink_ring_buffer_class_init (GstAudioSinkRingBufferClass *
103     klass);
104 static void gst_audio_sink_ring_buffer_init (GstAudioSinkRingBuffer *
105     ringbuffer, GstAudioSinkRingBufferClass * klass);
106 static void gst_audio_sink_ring_buffer_dispose (GObject * object);
107 static void gst_audio_sink_ring_buffer_finalize (GObject * object);
108
109 static GstAudioRingBufferClass *ring_parent_class = NULL;
110
111 static gboolean gst_audio_sink_ring_buffer_open_device (GstAudioRingBuffer *
112     buf);
113 static gboolean gst_audio_sink_ring_buffer_close_device (GstAudioRingBuffer *
114     buf);
115 static gboolean gst_audio_sink_ring_buffer_acquire (GstAudioRingBuffer * buf,
116     GstAudioRingBufferSpec * spec);
117 static gboolean gst_audio_sink_ring_buffer_release (GstAudioRingBuffer * buf);
118 static gboolean gst_audio_sink_ring_buffer_start (GstAudioRingBuffer * buf);
119 static gboolean gst_audio_sink_ring_buffer_pause (GstAudioRingBuffer * buf);
120 static gboolean gst_audio_sink_ring_buffer_resume (GstAudioRingBuffer * buf);
121 static gboolean gst_audio_sink_ring_buffer_stop (GstAudioRingBuffer * buf);
122 static guint gst_audio_sink_ring_buffer_delay (GstAudioRingBuffer * buf);
123 static gboolean gst_audio_sink_ring_buffer_activate (GstAudioRingBuffer * buf,
124     gboolean active);
125 static void gst_audio_sink_ring_buffer_clear_all (GstAudioRingBuffer * buf);
126
127 /* ringbuffer abstract base class */
128 static GType
129 gst_audio_sink_ring_buffer_get_type (void)
130 {
131   static GType ringbuffer_type = 0;
132
133   if (!ringbuffer_type) {
134     static const GTypeInfo ringbuffer_info = {
135       sizeof (GstAudioSinkRingBufferClass),
136       NULL,
137       NULL,
138       (GClassInitFunc) gst_audio_sink_ring_buffer_class_init,
139       NULL,
140       NULL,
141       sizeof (GstAudioSinkRingBuffer),
142       0,
143       (GInstanceInitFunc) gst_audio_sink_ring_buffer_init,
144       NULL
145     };
146
147     ringbuffer_type =
148         g_type_register_static (GST_TYPE_AUDIO_RING_BUFFER,
149         "GstAudioSinkRingBuffer", &ringbuffer_info, 0);
150   }
151   return ringbuffer_type;
152 }
153
154 static void
155 gst_audio_sink_ring_buffer_class_init (GstAudioSinkRingBufferClass * klass)
156 {
157   GObjectClass *gobject_class;
158   GstAudioRingBufferClass *gstringbuffer_class;
159
160   gobject_class = (GObjectClass *) klass;
161   gstringbuffer_class = (GstAudioRingBufferClass *) klass;
162
163   ring_parent_class = g_type_class_peek_parent (klass);
164
165   gobject_class->dispose = gst_audio_sink_ring_buffer_dispose;
166   gobject_class->finalize = gst_audio_sink_ring_buffer_finalize;
167
168   gstringbuffer_class->open_device =
169       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_open_device);
170   gstringbuffer_class->close_device =
171       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_close_device);
172   gstringbuffer_class->acquire =
173       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_acquire);
174   gstringbuffer_class->release =
175       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_release);
176   gstringbuffer_class->start =
177       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_start);
178   gstringbuffer_class->pause =
179       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_pause);
180   gstringbuffer_class->resume =
181       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_resume);
182   gstringbuffer_class->stop =
183       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_stop);
184   gstringbuffer_class->delay =
185       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_delay);
186   gstringbuffer_class->activate =
187       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_activate);
188   gstringbuffer_class->clear_all =
189       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_clear_all);
190 }
191
192 typedef gint (*WriteFunc) (GstAudioSink * sink, gpointer data, guint length);
193
194 /* this internal thread does nothing else but write samples to the audio device.
195  * It will write each segment in the ringbuffer and will update the play
196  * pointer.
197  * The start/stop methods control the thread.
198  */
199 static void
200 audioringbuffer_thread_func (GstAudioRingBuffer * buf)
201 {
202   GstAudioSink *sink;
203   GstAudioSinkClass *csink;
204   GstAudioSinkRingBuffer *abuf = GST_AUDIO_SINK_RING_BUFFER_CAST (buf);
205   WriteFunc writefunc;
206   GstMessage *message;
207   GValue val = { 0 };
208   gpointer handle;
209
210   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
211   csink = GST_AUDIO_SINK_GET_CLASS (sink);
212
213   GST_DEBUG_OBJECT (sink, "enter thread");
214
215   GST_OBJECT_LOCK (abuf);
216   GST_DEBUG_OBJECT (sink, "signal wait");
217   GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
218   GST_OBJECT_UNLOCK (abuf);
219
220   writefunc = csink->write;
221   if (writefunc == NULL)
222     goto no_function;
223
224   if (G_UNLIKELY (!__gst_audio_set_thread_priority (&handle)))
225     GST_WARNING_OBJECT (sink, "failed to set thread priority");
226
227   message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
228       GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
229   g_value_init (&val, GST_TYPE_G_THREAD);
230   g_value_set_boxed (&val, g_thread_self ());
231   gst_message_set_stream_status_object (message, &val);
232   g_value_unset (&val);
233   GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
234   gst_element_post_message (GST_ELEMENT_CAST (sink), message);
235
236   while (TRUE) {
237     gint left, len;
238     guint8 *readptr;
239     gint readseg;
240
241     /* buffer must be started */
242     if (gst_audio_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
243       gint written;
244
245       left = len;
246       do {
247         written = writefunc (sink, readptr, left);
248         GST_LOG_OBJECT (sink, "transferred %d bytes of %d from segment %d",
249             written, left, readseg);
250         if (written < 0 || written > left) {
251           /* might not be critical, it e.g. happens when aborting playback */
252           GST_WARNING_OBJECT (sink,
253               "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
254               GST_DEBUG_FUNCPTR_NAME (writefunc),
255               (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
256           break;
257         }
258         left -= written;
259         readptr += written;
260       } while (left > 0);
261
262       /* clear written samples */
263       gst_audio_ring_buffer_clear (buf, readseg);
264
265       /* we wrote one segment */
266       gst_audio_ring_buffer_advance (buf, 1);
267     } else {
268       GST_OBJECT_LOCK (abuf);
269       if (!abuf->running)
270         goto stop_running;
271       if (G_UNLIKELY (g_atomic_int_get (&buf->state) ==
272               GST_AUDIO_RING_BUFFER_STATE_STARTED)) {
273         GST_OBJECT_UNLOCK (abuf);
274         continue;
275       }
276       GST_DEBUG_OBJECT (sink, "signal wait");
277       GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
278       GST_DEBUG_OBJECT (sink, "wait for action");
279       GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
280       GST_DEBUG_OBJECT (sink, "got signal");
281       if (!abuf->running)
282         goto stop_running;
283       GST_DEBUG_OBJECT (sink, "continue running");
284       GST_OBJECT_UNLOCK (abuf);
285     }
286   }
287
288   /* Will never be reached */
289   g_assert_not_reached ();
290   return;
291
292   /* ERROR */
293 no_function:
294   {
295     GST_DEBUG_OBJECT (sink, "no write function, exit thread");
296     return;
297   }
298 stop_running:
299   {
300     GST_OBJECT_UNLOCK (abuf);
301     GST_DEBUG_OBJECT (sink, "stop running, exit thread");
302     message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
303         GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
304     g_value_init (&val, GST_TYPE_G_THREAD);
305     g_value_set_boxed (&val, g_thread_self ());
306     gst_message_set_stream_status_object (message, &val);
307     g_value_unset (&val);
308     GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
309     gst_element_post_message (GST_ELEMENT_CAST (sink), message);
310
311     if (G_UNLIKELY (!__gst_audio_restore_thread_priority (handle)))
312       GST_WARNING_OBJECT (sink, "failed to restore thread priority");
313     return;
314   }
315 }
316
317 static void
318 gst_audio_sink_ring_buffer_init (GstAudioSinkRingBuffer * ringbuffer,
319     GstAudioSinkRingBufferClass * g_class)
320 {
321   ringbuffer->running = FALSE;
322   ringbuffer->queuedseg = 0;
323
324   g_cond_init (&ringbuffer->cond);
325 }
326
327 static void
328 gst_audio_sink_ring_buffer_dispose (GObject * object)
329 {
330   G_OBJECT_CLASS (ring_parent_class)->dispose (object);
331 }
332
333 static void
334 gst_audio_sink_ring_buffer_finalize (GObject * object)
335 {
336   GstAudioSinkRingBuffer *ringbuffer = GST_AUDIO_SINK_RING_BUFFER_CAST (object);
337
338   g_cond_clear (&ringbuffer->cond);
339
340   G_OBJECT_CLASS (ring_parent_class)->finalize (object);
341 }
342
343 static gboolean
344 gst_audio_sink_ring_buffer_open_device (GstAudioRingBuffer * buf)
345 {
346   GstAudioSink *sink;
347   GstAudioSinkClass *csink;
348   gboolean result = TRUE;
349
350   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
351   csink = GST_AUDIO_SINK_GET_CLASS (sink);
352
353   if (csink->open)
354     result = csink->open (sink);
355
356   if (!result)
357     goto could_not_open;
358
359   return result;
360
361 could_not_open:
362   {
363     GST_DEBUG_OBJECT (sink, "could not open device");
364     return FALSE;
365   }
366 }
367
368 static gboolean
369 gst_audio_sink_ring_buffer_close_device (GstAudioRingBuffer * buf)
370 {
371   GstAudioSink *sink;
372   GstAudioSinkClass *csink;
373   gboolean result = TRUE;
374
375   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
376   csink = GST_AUDIO_SINK_GET_CLASS (sink);
377
378   if (csink->close)
379     result = csink->close (sink);
380
381   if (!result)
382     goto could_not_close;
383
384   return result;
385
386 could_not_close:
387   {
388     GST_DEBUG_OBJECT (sink, "could not close device");
389     return FALSE;
390   }
391 }
392
393 static gboolean
394 gst_audio_sink_ring_buffer_acquire (GstAudioRingBuffer * buf,
395     GstAudioRingBufferSpec * spec)
396 {
397   GstAudioSink *sink;
398   GstAudioSinkClass *csink;
399   gboolean result = FALSE;
400
401   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
402   csink = GST_AUDIO_SINK_GET_CLASS (sink);
403
404   if (csink->prepare)
405     result = csink->prepare (sink, spec);
406   if (!result)
407     goto could_not_prepare;
408
409   /* set latency to one more segment as we need some headroom */
410   spec->seglatency = spec->segtotal + 1;
411
412   buf->size = spec->segtotal * spec->segsize;
413
414   buf->memory = g_malloc (buf->size);
415
416   if (buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
417     gst_audio_format_fill_silence (buf->spec.info.finfo, buf->memory,
418         buf->size);
419   } else {
420     /* FIXME, non-raw formats get 0 as the empty sample */
421     memset (buf->memory, 0, buf->size);
422   }
423
424
425   return TRUE;
426
427   /* ERRORS */
428 could_not_prepare:
429   {
430     GST_DEBUG_OBJECT (sink, "could not prepare device");
431     return FALSE;
432   }
433 }
434
435 static gboolean
436 gst_audio_sink_ring_buffer_activate (GstAudioRingBuffer * buf, gboolean active)
437 {
438   GstAudioSink *sink;
439   GstAudioSinkRingBuffer *abuf;
440   GError *error = NULL;
441
442   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
443   abuf = GST_AUDIO_SINK_RING_BUFFER_CAST (buf);
444
445   if (active) {
446     abuf->running = TRUE;
447
448     GST_DEBUG_OBJECT (sink, "starting thread");
449
450     sink->thread = g_thread_try_new ("audiosink-ringbuffer",
451         (GThreadFunc) audioringbuffer_thread_func, buf, &error);
452
453     if (!sink->thread || error != NULL)
454       goto thread_failed;
455
456     GST_DEBUG_OBJECT (sink, "waiting for thread");
457     /* the object lock is taken */
458     GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
459     GST_DEBUG_OBJECT (sink, "thread is started");
460   } else {
461     abuf->running = FALSE;
462     GST_DEBUG_OBJECT (sink, "signal wait");
463     GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
464
465     GST_OBJECT_UNLOCK (buf);
466
467     /* join the thread */
468     g_thread_join (sink->thread);
469
470     GST_OBJECT_LOCK (buf);
471   }
472   return TRUE;
473
474   /* ERRORS */
475 thread_failed:
476   {
477     if (error)
478       GST_ERROR_OBJECT (sink, "could not create thread %s", error->message);
479     else
480       GST_ERROR_OBJECT (sink, "could not create thread for unknown reason");
481     g_clear_error (&error);
482     return FALSE;
483   }
484 }
485
486 /* function is called with LOCK */
487 static gboolean
488 gst_audio_sink_ring_buffer_release (GstAudioRingBuffer * buf)
489 {
490   GstAudioSink *sink;
491   GstAudioSinkClass *csink;
492   gboolean result = FALSE;
493
494   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
495   csink = GST_AUDIO_SINK_GET_CLASS (sink);
496
497   /* free the buffer */
498   g_free (buf->memory);
499   buf->memory = NULL;
500
501   if (csink->unprepare)
502     result = csink->unprepare (sink);
503
504   if (!result)
505     goto could_not_unprepare;
506
507   GST_DEBUG_OBJECT (sink, "unprepared");
508
509   return result;
510
511 could_not_unprepare:
512   {
513     GST_DEBUG_OBJECT (sink, "could not unprepare device");
514     return FALSE;
515   }
516 }
517
518 static gboolean
519 gst_audio_sink_ring_buffer_start (GstAudioRingBuffer * buf)
520 {
521   GstAudioSink *sink;
522
523   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
524
525   GST_DEBUG_OBJECT (sink, "start, sending signal");
526   GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
527
528   return TRUE;
529 }
530
531 static gboolean
532 gst_audio_sink_ring_buffer_pause (GstAudioRingBuffer * buf)
533 {
534   GstAudioSink *sink;
535   GstAudioSinkClass *csink;
536
537   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
538   csink = GST_AUDIO_SINK_GET_CLASS (sink);
539
540   /* unblock any pending writes to the audio device */
541   if (csink->pause) {
542     GST_DEBUG_OBJECT (sink, "pause...");
543     csink->pause (sink);
544     GST_DEBUG_OBJECT (sink, "pause done");
545   } else if (csink->reset) {
546     /* fallback to reset for audio sinks that don't provide pause */
547     GST_DEBUG_OBJECT (sink, "reset...");
548     csink->reset (sink);
549     GST_DEBUG_OBJECT (sink, "reset done");
550   }
551   return TRUE;
552 }
553
554 static gboolean
555 gst_audio_sink_ring_buffer_resume (GstAudioRingBuffer * buf)
556 {
557   GstAudioSink *sink;
558   GstAudioSinkClass *csink;
559
560   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
561   csink = GST_AUDIO_SINK_GET_CLASS (sink);
562
563   if (csink->resume) {
564     GST_DEBUG_OBJECT (sink, "resume...");
565     csink->resume (sink);
566     GST_DEBUG_OBJECT (sink, "resume done");
567   }
568
569   gst_audio_sink_ring_buffer_start (buf);
570
571   return TRUE;
572 }
573
574 static gboolean
575 gst_audio_sink_ring_buffer_stop (GstAudioRingBuffer * buf)
576 {
577   GstAudioSink *sink;
578   GstAudioSinkClass *csink;
579
580   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
581   csink = GST_AUDIO_SINK_GET_CLASS (sink);
582
583   /* unblock any pending writes to the audio device */
584   if (csink->stop) {
585     GST_DEBUG_OBJECT (sink, "stop...");
586     csink->stop (sink);
587     GST_DEBUG_OBJECT (sink, "stop done");
588   } else if (csink->reset) {
589     /* fallback to reset for audio sinks that don't provide stop */
590     GST_DEBUG_OBJECT (sink, "reset...");
591     csink->reset (sink);
592     GST_DEBUG_OBJECT (sink, "reset done");
593   }
594 #if 0
595   if (abuf->running) {
596     GST_DEBUG_OBJECT (sink, "stop, waiting...");
597     GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
598     GST_DEBUG_OBJECT (sink, "stopped");
599   }
600 #endif
601
602   return TRUE;
603 }
604
605 static guint
606 gst_audio_sink_ring_buffer_delay (GstAudioRingBuffer * buf)
607 {
608   GstAudioSink *sink;
609   GstAudioSinkClass *csink;
610   guint res = 0;
611
612   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
613   csink = GST_AUDIO_SINK_GET_CLASS (sink);
614
615   if (csink->delay)
616     res = csink->delay (sink);
617
618   return res;
619 }
620
621 static void
622 gst_audio_sink_ring_buffer_clear_all (GstAudioRingBuffer * buf)
623 {
624   GstAudioSink *sink;
625   GstAudioSinkClass *csink;
626
627   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
628   csink = GST_AUDIO_SINK_GET_CLASS (sink);
629
630   if (csink->extension->clear_all) {
631     GST_DEBUG_OBJECT (sink, "clear all");
632     csink->extension->clear_all (sink);
633   }
634
635   /* chain up to the parent implementation */
636   ring_parent_class->clear_all (buf);
637 }
638
639 /* AudioSink signals and args */
640 enum
641 {
642   /* FILL ME */
643   LAST_SIGNAL
644 };
645
646 enum
647 {
648   ARG_0,
649 };
650
651 #define _do_init \
652     GST_DEBUG_CATEGORY_INIT (gst_audio_sink_debug, "audiosink", 0, "audiosink element"); \
653     g_type_add_class_private (g_define_type_id, \
654         sizeof (GstAudioSinkClassExtension));
655 #define gst_audio_sink_parent_class parent_class
656 G_DEFINE_TYPE_WITH_CODE (GstAudioSink, gst_audio_sink,
657     GST_TYPE_AUDIO_BASE_SINK, _do_init);
658
659 static GstAudioRingBuffer *gst_audio_sink_create_ringbuffer (GstAudioBaseSink *
660     sink);
661
662 static void
663 gst_audio_sink_class_init (GstAudioSinkClass * klass)
664 {
665   GstAudioBaseSinkClass *gstaudiobasesink_class;
666
667   gstaudiobasesink_class = (GstAudioBaseSinkClass *) klass;
668
669   gstaudiobasesink_class->create_ringbuffer =
670       GST_DEBUG_FUNCPTR (gst_audio_sink_create_ringbuffer);
671
672   g_type_class_ref (GST_TYPE_AUDIO_SINK_RING_BUFFER);
673
674   klass->extension = G_TYPE_CLASS_GET_PRIVATE (klass,
675       GST_TYPE_AUDIO_SINK, GstAudioSinkClassExtension);
676 }
677
678 static void
679 gst_audio_sink_init (GstAudioSink * audiosink)
680 {
681 }
682
683 static GstAudioRingBuffer *
684 gst_audio_sink_create_ringbuffer (GstAudioBaseSink * sink)
685 {
686   GstAudioRingBuffer *buffer;
687
688   GST_DEBUG_OBJECT (sink, "creating ringbuffer");
689   buffer = g_object_new (GST_TYPE_AUDIO_SINK_RING_BUFFER, NULL);
690   GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer);
691
692   return buffer;
693 }