0aa44332eb3a6dcfae064ad22da771b953f39026
[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
209   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
210   csink = GST_AUDIO_SINK_GET_CLASS (sink);
211
212   GST_DEBUG_OBJECT (sink, "enter thread");
213
214   GST_OBJECT_LOCK (abuf);
215   GST_DEBUG_OBJECT (sink, "signal wait");
216   GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
217   GST_OBJECT_UNLOCK (abuf);
218
219   writefunc = csink->write;
220   if (writefunc == NULL)
221     goto no_function;
222
223   if (G_UNLIKELY (!__gst_audio_set_thread_priority ()))
224     GST_WARNING_OBJECT (sink, "failed to set thread priority");
225
226   message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
227       GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
228   g_value_init (&val, GST_TYPE_G_THREAD);
229   g_value_set_boxed (&val, g_thread_self ());
230   gst_message_set_stream_status_object (message, &val);
231   g_value_unset (&val);
232   GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
233   gst_element_post_message (GST_ELEMENT_CAST (sink), message);
234
235   while (TRUE) {
236     gint left, len;
237     guint8 *readptr;
238     gint readseg;
239
240     /* buffer must be started */
241     if (gst_audio_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
242       gint written;
243
244       left = len;
245       do {
246         written = writefunc (sink, readptr, left);
247         GST_LOG_OBJECT (sink, "transferred %d bytes of %d from segment %d",
248             written, left, readseg);
249         if (written < 0 || written > left) {
250           /* might not be critical, it e.g. happens when aborting playback */
251           GST_WARNING_OBJECT (sink,
252               "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
253               GST_DEBUG_FUNCPTR_NAME (writefunc),
254               (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
255           break;
256         }
257         left -= written;
258         readptr += written;
259       } while (left > 0);
260
261       /* clear written samples */
262       gst_audio_ring_buffer_clear (buf, readseg);
263
264       /* we wrote one segment */
265       gst_audio_ring_buffer_advance (buf, 1);
266     } else {
267       GST_OBJECT_LOCK (abuf);
268       if (!abuf->running)
269         goto stop_running;
270       if (G_UNLIKELY (g_atomic_int_get (&buf->state) ==
271               GST_AUDIO_RING_BUFFER_STATE_STARTED)) {
272         GST_OBJECT_UNLOCK (abuf);
273         continue;
274       }
275       GST_DEBUG_OBJECT (sink, "signal wait");
276       GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
277       GST_DEBUG_OBJECT (sink, "wait for action");
278       GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
279       GST_DEBUG_OBJECT (sink, "got signal");
280       if (!abuf->running)
281         goto stop_running;
282       GST_DEBUG_OBJECT (sink, "continue running");
283       GST_OBJECT_UNLOCK (abuf);
284     }
285   }
286
287   /* Will never be reached */
288   g_assert_not_reached ();
289   return;
290
291   /* ERROR */
292 no_function:
293   {
294     GST_DEBUG_OBJECT (sink, "no write function, exit thread");
295     return;
296   }
297 stop_running:
298   {
299     GST_OBJECT_UNLOCK (abuf);
300     GST_DEBUG_OBJECT (sink, "stop running, exit thread");
301     message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
302         GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
303     g_value_init (&val, GST_TYPE_G_THREAD);
304     g_value_set_boxed (&val, g_thread_self ());
305     gst_message_set_stream_status_object (message, &val);
306     g_value_unset (&val);
307     GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
308     gst_element_post_message (GST_ELEMENT_CAST (sink), message);
309     return;
310   }
311 }
312
313 static void
314 gst_audio_sink_ring_buffer_init (GstAudioSinkRingBuffer * ringbuffer,
315     GstAudioSinkRingBufferClass * g_class)
316 {
317   ringbuffer->running = FALSE;
318   ringbuffer->queuedseg = 0;
319
320   g_cond_init (&ringbuffer->cond);
321 }
322
323 static void
324 gst_audio_sink_ring_buffer_dispose (GObject * object)
325 {
326   G_OBJECT_CLASS (ring_parent_class)->dispose (object);
327 }
328
329 static void
330 gst_audio_sink_ring_buffer_finalize (GObject * object)
331 {
332   GstAudioSinkRingBuffer *ringbuffer = GST_AUDIO_SINK_RING_BUFFER_CAST (object);
333
334   g_cond_clear (&ringbuffer->cond);
335
336   G_OBJECT_CLASS (ring_parent_class)->finalize (object);
337 }
338
339 static gboolean
340 gst_audio_sink_ring_buffer_open_device (GstAudioRingBuffer * buf)
341 {
342   GstAudioSink *sink;
343   GstAudioSinkClass *csink;
344   gboolean result = TRUE;
345
346   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
347   csink = GST_AUDIO_SINK_GET_CLASS (sink);
348
349   if (csink->open)
350     result = csink->open (sink);
351
352   if (!result)
353     goto could_not_open;
354
355   return result;
356
357 could_not_open:
358   {
359     GST_DEBUG_OBJECT (sink, "could not open device");
360     return FALSE;
361   }
362 }
363
364 static gboolean
365 gst_audio_sink_ring_buffer_close_device (GstAudioRingBuffer * buf)
366 {
367   GstAudioSink *sink;
368   GstAudioSinkClass *csink;
369   gboolean result = TRUE;
370
371   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
372   csink = GST_AUDIO_SINK_GET_CLASS (sink);
373
374   if (csink->close)
375     result = csink->close (sink);
376
377   if (!result)
378     goto could_not_close;
379
380   return result;
381
382 could_not_close:
383   {
384     GST_DEBUG_OBJECT (sink, "could not close device");
385     return FALSE;
386   }
387 }
388
389 static gboolean
390 gst_audio_sink_ring_buffer_acquire (GstAudioRingBuffer * buf,
391     GstAudioRingBufferSpec * spec)
392 {
393   GstAudioSink *sink;
394   GstAudioSinkClass *csink;
395   gboolean result = FALSE;
396
397   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
398   csink = GST_AUDIO_SINK_GET_CLASS (sink);
399
400   if (csink->prepare)
401     result = csink->prepare (sink, spec);
402   if (!result)
403     goto could_not_prepare;
404
405   /* set latency to one more segment as we need some headroom */
406   spec->seglatency = spec->segtotal + 1;
407
408   buf->size = spec->segtotal * spec->segsize;
409
410   buf->memory = g_malloc (buf->size);
411
412   if (buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
413     gst_audio_format_fill_silence (buf->spec.info.finfo, buf->memory,
414         buf->size);
415   } else {
416     /* FIXME, non-raw formats get 0 as the empty sample */
417     memset (buf->memory, 0, buf->size);
418   }
419
420
421   return TRUE;
422
423   /* ERRORS */
424 could_not_prepare:
425   {
426     GST_DEBUG_OBJECT (sink, "could not prepare device");
427     return FALSE;
428   }
429 }
430
431 static gboolean
432 gst_audio_sink_ring_buffer_activate (GstAudioRingBuffer * buf, gboolean active)
433 {
434   GstAudioSink *sink;
435   GstAudioSinkRingBuffer *abuf;
436   GError *error = NULL;
437
438   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
439   abuf = GST_AUDIO_SINK_RING_BUFFER_CAST (buf);
440
441   if (active) {
442     abuf->running = TRUE;
443
444     GST_DEBUG_OBJECT (sink, "starting thread");
445
446     sink->thread = g_thread_try_new ("audiosink-ringbuffer",
447         (GThreadFunc) audioringbuffer_thread_func, buf, &error);
448
449     if (!sink->thread || error != NULL)
450       goto thread_failed;
451
452     GST_DEBUG_OBJECT (sink, "waiting for thread");
453     /* the object lock is taken */
454     GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
455     GST_DEBUG_OBJECT (sink, "thread is started");
456   } else {
457     abuf->running = FALSE;
458     GST_DEBUG_OBJECT (sink, "signal wait");
459     GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
460
461     GST_OBJECT_UNLOCK (buf);
462
463     /* join the thread */
464     g_thread_join (sink->thread);
465
466     GST_OBJECT_LOCK (buf);
467   }
468   return TRUE;
469
470   /* ERRORS */
471 thread_failed:
472   {
473     if (error)
474       GST_ERROR_OBJECT (sink, "could not create thread %s", error->message);
475     else
476       GST_ERROR_OBJECT (sink, "could not create thread for unknown reason");
477     g_clear_error (&error);
478     return FALSE;
479   }
480 }
481
482 /* function is called with LOCK */
483 static gboolean
484 gst_audio_sink_ring_buffer_release (GstAudioRingBuffer * buf)
485 {
486   GstAudioSink *sink;
487   GstAudioSinkClass *csink;
488   gboolean result = FALSE;
489
490   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
491   csink = GST_AUDIO_SINK_GET_CLASS (sink);
492
493   /* free the buffer */
494   g_free (buf->memory);
495   buf->memory = NULL;
496
497   if (csink->unprepare)
498     result = csink->unprepare (sink);
499
500   if (!result)
501     goto could_not_unprepare;
502
503   GST_DEBUG_OBJECT (sink, "unprepared");
504
505   return result;
506
507 could_not_unprepare:
508   {
509     GST_DEBUG_OBJECT (sink, "could not unprepare device");
510     return FALSE;
511   }
512 }
513
514 static gboolean
515 gst_audio_sink_ring_buffer_start (GstAudioRingBuffer * buf)
516 {
517   GstAudioSink *sink;
518
519   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
520
521   GST_DEBUG_OBJECT (sink, "start, sending signal");
522   GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
523
524   return TRUE;
525 }
526
527 static gboolean
528 gst_audio_sink_ring_buffer_pause (GstAudioRingBuffer * buf)
529 {
530   GstAudioSink *sink;
531   GstAudioSinkClass *csink;
532
533   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
534   csink = GST_AUDIO_SINK_GET_CLASS (sink);
535
536   /* unblock any pending writes to the audio device */
537   if (csink->pause) {
538     GST_DEBUG_OBJECT (sink, "pause...");
539     csink->pause (sink);
540     GST_DEBUG_OBJECT (sink, "pause done");
541   } else if (csink->reset) {
542     /* fallback to reset for audio sinks that don't provide pause */
543     GST_DEBUG_OBJECT (sink, "reset...");
544     csink->reset (sink);
545     GST_DEBUG_OBJECT (sink, "reset done");
546   }
547   return TRUE;
548 }
549
550 static gboolean
551 gst_audio_sink_ring_buffer_resume (GstAudioRingBuffer * buf)
552 {
553   GstAudioSink *sink;
554   GstAudioSinkClass *csink;
555
556   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
557   csink = GST_AUDIO_SINK_GET_CLASS (sink);
558
559   if (csink->resume) {
560     GST_DEBUG_OBJECT (sink, "resume...");
561     csink->resume (sink);
562     GST_DEBUG_OBJECT (sink, "resume done");
563   }
564
565   gst_audio_sink_ring_buffer_start (buf);
566
567   return TRUE;
568 }
569
570 static gboolean
571 gst_audio_sink_ring_buffer_stop (GstAudioRingBuffer * buf)
572 {
573   GstAudioSink *sink;
574   GstAudioSinkClass *csink;
575
576   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
577   csink = GST_AUDIO_SINK_GET_CLASS (sink);
578
579   /* unblock any pending writes to the audio device */
580   if (csink->stop) {
581     GST_DEBUG_OBJECT (sink, "stop...");
582     csink->stop (sink);
583     GST_DEBUG_OBJECT (sink, "stop done");
584   } else if (csink->reset) {
585     /* fallback to reset for audio sinks that don't provide stop */
586     GST_DEBUG_OBJECT (sink, "reset...");
587     csink->reset (sink);
588     GST_DEBUG_OBJECT (sink, "reset done");
589   }
590 #if 0
591   if (abuf->running) {
592     GST_DEBUG_OBJECT (sink, "stop, waiting...");
593     GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
594     GST_DEBUG_OBJECT (sink, "stopped");
595   }
596 #endif
597
598   return TRUE;
599 }
600
601 static guint
602 gst_audio_sink_ring_buffer_delay (GstAudioRingBuffer * buf)
603 {
604   GstAudioSink *sink;
605   GstAudioSinkClass *csink;
606   guint res = 0;
607
608   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
609   csink = GST_AUDIO_SINK_GET_CLASS (sink);
610
611   if (csink->delay)
612     res = csink->delay (sink);
613
614   return res;
615 }
616
617 static void
618 gst_audio_sink_ring_buffer_clear_all (GstAudioRingBuffer * buf)
619 {
620   GstAudioSink *sink;
621   GstAudioSinkClass *csink;
622
623   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
624   csink = GST_AUDIO_SINK_GET_CLASS (sink);
625
626   if (csink->extension->clear_all) {
627     GST_DEBUG_OBJECT (sink, "clear all");
628     csink->extension->clear_all (sink);
629   }
630
631   /* chain up to the parent implementation */
632   ring_parent_class->clear_all (buf);
633 }
634
635 /* AudioSink signals and args */
636 enum
637 {
638   /* FILL ME */
639   LAST_SIGNAL
640 };
641
642 enum
643 {
644   ARG_0,
645 };
646
647 #define _do_init \
648     GST_DEBUG_CATEGORY_INIT (gst_audio_sink_debug, "audiosink", 0, "audiosink element"); \
649     g_type_add_class_private (g_define_type_id, \
650         sizeof (GstAudioSinkClassExtension));
651 #define gst_audio_sink_parent_class parent_class
652 G_DEFINE_TYPE_WITH_CODE (GstAudioSink, gst_audio_sink,
653     GST_TYPE_AUDIO_BASE_SINK, _do_init);
654
655 static GstAudioRingBuffer *gst_audio_sink_create_ringbuffer (GstAudioBaseSink *
656     sink);
657
658 static void
659 gst_audio_sink_class_init (GstAudioSinkClass * klass)
660 {
661   GstAudioBaseSinkClass *gstaudiobasesink_class;
662
663   gstaudiobasesink_class = (GstAudioBaseSinkClass *) klass;
664
665   gstaudiobasesink_class->create_ringbuffer =
666       GST_DEBUG_FUNCPTR (gst_audio_sink_create_ringbuffer);
667
668   g_type_class_ref (GST_TYPE_AUDIO_SINK_RING_BUFFER);
669
670   klass->extension = G_TYPE_CLASS_GET_PRIVATE (klass,
671       GST_TYPE_AUDIO_SINK, GstAudioSinkClassExtension);
672 }
673
674 static void
675 gst_audio_sink_init (GstAudioSink * audiosink)
676 {
677 }
678
679 static GstAudioRingBuffer *
680 gst_audio_sink_create_ringbuffer (GstAudioBaseSink * sink)
681 {
682   GstAudioRingBuffer *buffer;
683
684   GST_DEBUG_OBJECT (sink, "creating ringbuffer");
685   buffer = g_object_new (GST_TYPE_AUDIO_SINK_RING_BUFFER, NULL);
686   GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer);
687
688   return buffer;
689 }