• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_stop (GstAudioRingBuffer * buf);
121 static guint gst_audio_sink_ring_buffer_delay (GstAudioRingBuffer * buf);
122 static gboolean gst_audio_sink_ring_buffer_activate (GstAudioRingBuffer * buf,
123     gboolean active);
124 
125 /* ringbuffer abstract base class */
126 static GType
gst_audio_sink_ring_buffer_get_type(void)127 gst_audio_sink_ring_buffer_get_type (void)
128 {
129   static GType ringbuffer_type = 0;
130 
131   if (!ringbuffer_type) {
132     static const GTypeInfo ringbuffer_info = {
133       sizeof (GstAudioSinkRingBufferClass),
134       NULL,
135       NULL,
136       (GClassInitFunc) gst_audio_sink_ring_buffer_class_init,
137       NULL,
138       NULL,
139       sizeof (GstAudioSinkRingBuffer),
140       0,
141       (GInstanceInitFunc) gst_audio_sink_ring_buffer_init,
142       NULL
143     };
144 
145     ringbuffer_type =
146         g_type_register_static (GST_TYPE_AUDIO_RING_BUFFER,
147         "GstAudioSinkRingBuffer", &ringbuffer_info, 0);
148   }
149   return ringbuffer_type;
150 }
151 
152 static void
gst_audio_sink_ring_buffer_class_init(GstAudioSinkRingBufferClass * klass)153 gst_audio_sink_ring_buffer_class_init (GstAudioSinkRingBufferClass * klass)
154 {
155   GObjectClass *gobject_class;
156   GstAudioRingBufferClass *gstringbuffer_class;
157 
158   gobject_class = (GObjectClass *) klass;
159   gstringbuffer_class = (GstAudioRingBufferClass *) klass;
160 
161   ring_parent_class = g_type_class_peek_parent (klass);
162 
163   gobject_class->dispose = gst_audio_sink_ring_buffer_dispose;
164   gobject_class->finalize = gst_audio_sink_ring_buffer_finalize;
165 
166   gstringbuffer_class->open_device =
167       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_open_device);
168   gstringbuffer_class->close_device =
169       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_close_device);
170   gstringbuffer_class->acquire =
171       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_acquire);
172   gstringbuffer_class->release =
173       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_release);
174   gstringbuffer_class->start =
175       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_start);
176   gstringbuffer_class->pause =
177       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_pause);
178   gstringbuffer_class->resume =
179       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_start);
180   gstringbuffer_class->stop =
181       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_stop);
182 
183   gstringbuffer_class->delay =
184       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_delay);
185   gstringbuffer_class->activate =
186       GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_activate);
187 }
188 
189 typedef gint (*WriteFunc) (GstAudioSink * sink, gpointer data, guint length);
190 
191 /* this internal thread does nothing else but write samples to the audio device.
192  * It will write each segment in the ringbuffer and will update the play
193  * pointer.
194  * The start/stop methods control the thread.
195  */
196 static void
audioringbuffer_thread_func(GstAudioRingBuffer * buf)197 audioringbuffer_thread_func (GstAudioRingBuffer * buf)
198 {
199   GstAudioSink *sink;
200   GstAudioSinkClass *csink;
201   GstAudioSinkRingBuffer *abuf = GST_AUDIO_SINK_RING_BUFFER_CAST (buf);
202   WriteFunc writefunc;
203   GstMessage *message;
204   GValue val = { 0 };
205 
206   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
207   csink = GST_AUDIO_SINK_GET_CLASS (sink);
208 
209   GST_DEBUG_OBJECT (sink, "enter thread");
210 
211   GST_OBJECT_LOCK (abuf);
212   GST_DEBUG_OBJECT (sink, "signal wait");
213   GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
214   GST_OBJECT_UNLOCK (abuf);
215 
216   writefunc = csink->write;
217   if (writefunc == NULL)
218     goto no_function;
219 
220   if (G_UNLIKELY (!__gst_audio_set_thread_priority ()))
221     GST_WARNING_OBJECT (sink, "failed to set thread priority");
222 
223   message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
224       GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
225   g_value_init (&val, GST_TYPE_G_THREAD);
226   g_value_set_boxed (&val, g_thread_self ());
227   gst_message_set_stream_status_object (message, &val);
228   g_value_unset (&val);
229   GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
230   gst_element_post_message (GST_ELEMENT_CAST (sink), message);
231 
232   while (TRUE) {
233     gint left, len;
234     guint8 *readptr;
235     gint readseg;
236 
237     /* buffer must be started */
238     if (gst_audio_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
239       gint written;
240 
241       left = len;
242       do {
243         written = writefunc (sink, readptr, left);
244         GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d",
245             written, left, readseg);
246         if (written < 0 || written > left) {
247           /* might not be critical, it e.g. happens when aborting playback */
248           GST_WARNING_OBJECT (sink,
249               "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
250               GST_DEBUG_FUNCPTR_NAME (writefunc),
251               (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
252           break;
253         }
254         left -= written;
255         readptr += written;
256       } while (left > 0);
257 
258       /* clear written samples */
259       gst_audio_ring_buffer_clear (buf, readseg);
260 
261       /* we wrote one segment */
262       gst_audio_ring_buffer_advance (buf, 1);
263     } else {
264       GST_OBJECT_LOCK (abuf);
265       if (!abuf->running)
266         goto stop_running;
267       if (G_UNLIKELY (g_atomic_int_get (&buf->state) ==
268               GST_AUDIO_RING_BUFFER_STATE_STARTED)) {
269         GST_OBJECT_UNLOCK (abuf);
270         continue;
271       }
272       GST_DEBUG_OBJECT (sink, "signal wait");
273       GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
274       GST_DEBUG_OBJECT (sink, "wait for action");
275       GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
276       GST_DEBUG_OBJECT (sink, "got signal");
277       if (!abuf->running)
278         goto stop_running;
279       GST_DEBUG_OBJECT (sink, "continue running");
280       GST_OBJECT_UNLOCK (abuf);
281     }
282   }
283 
284   /* Will never be reached */
285   g_assert_not_reached ();
286   return;
287 
288   /* ERROR */
289 no_function:
290   {
291     GST_DEBUG_OBJECT (sink, "no write function, exit thread");
292     return;
293   }
294 stop_running:
295   {
296     GST_OBJECT_UNLOCK (abuf);
297     GST_DEBUG_OBJECT (sink, "stop running, exit thread");
298     message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
299         GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
300     g_value_init (&val, GST_TYPE_G_THREAD);
301     g_value_set_boxed (&val, g_thread_self ());
302     gst_message_set_stream_status_object (message, &val);
303     g_value_unset (&val);
304     GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
305     gst_element_post_message (GST_ELEMENT_CAST (sink), message);
306     return;
307   }
308 }
309 
310 static void
gst_audio_sink_ring_buffer_init(GstAudioSinkRingBuffer * ringbuffer,GstAudioSinkRingBufferClass * g_class)311 gst_audio_sink_ring_buffer_init (GstAudioSinkRingBuffer * ringbuffer,
312     GstAudioSinkRingBufferClass * g_class)
313 {
314   ringbuffer->running = FALSE;
315   ringbuffer->queuedseg = 0;
316 
317   g_cond_init (&ringbuffer->cond);
318 }
319 
320 static void
gst_audio_sink_ring_buffer_dispose(GObject * object)321 gst_audio_sink_ring_buffer_dispose (GObject * object)
322 {
323   G_OBJECT_CLASS (ring_parent_class)->dispose (object);
324 }
325 
326 static void
gst_audio_sink_ring_buffer_finalize(GObject * object)327 gst_audio_sink_ring_buffer_finalize (GObject * object)
328 {
329   GstAudioSinkRingBuffer *ringbuffer = GST_AUDIO_SINK_RING_BUFFER_CAST (object);
330 
331   g_cond_clear (&ringbuffer->cond);
332 
333   G_OBJECT_CLASS (ring_parent_class)->finalize (object);
334 }
335 
336 static gboolean
gst_audio_sink_ring_buffer_open_device(GstAudioRingBuffer * buf)337 gst_audio_sink_ring_buffer_open_device (GstAudioRingBuffer * buf)
338 {
339   GstAudioSink *sink;
340   GstAudioSinkClass *csink;
341   gboolean result = TRUE;
342 
343   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
344   csink = GST_AUDIO_SINK_GET_CLASS (sink);
345 
346   if (csink->open)
347     result = csink->open (sink);
348 
349   if (!result)
350     goto could_not_open;
351 
352   return result;
353 
354 could_not_open:
355   {
356     GST_DEBUG_OBJECT (sink, "could not open device");
357     return FALSE;
358   }
359 }
360 
361 static gboolean
gst_audio_sink_ring_buffer_close_device(GstAudioRingBuffer * buf)362 gst_audio_sink_ring_buffer_close_device (GstAudioRingBuffer * buf)
363 {
364   GstAudioSink *sink;
365   GstAudioSinkClass *csink;
366   gboolean result = TRUE;
367 
368   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
369   csink = GST_AUDIO_SINK_GET_CLASS (sink);
370 
371   if (csink->close)
372     result = csink->close (sink);
373 
374   if (!result)
375     goto could_not_close;
376 
377   return result;
378 
379 could_not_close:
380   {
381     GST_DEBUG_OBJECT (sink, "could not close device");
382     return FALSE;
383   }
384 }
385 
386 static gboolean
gst_audio_sink_ring_buffer_acquire(GstAudioRingBuffer * buf,GstAudioRingBufferSpec * spec)387 gst_audio_sink_ring_buffer_acquire (GstAudioRingBuffer * buf,
388     GstAudioRingBufferSpec * spec)
389 {
390   GstAudioSink *sink;
391   GstAudioSinkClass *csink;
392   gboolean result = FALSE;
393 
394   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
395   csink = GST_AUDIO_SINK_GET_CLASS (sink);
396 
397   if (csink->prepare)
398     result = csink->prepare (sink, spec);
399   if (!result)
400     goto could_not_prepare;
401 
402   /* set latency to one more segment as we need some headroom */
403   spec->seglatency = spec->segtotal + 1;
404 
405   buf->size = spec->segtotal * spec->segsize;
406 
407   buf->memory = g_malloc (buf->size);
408 
409   if (buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
410     gst_audio_format_fill_silence (buf->spec.info.finfo, buf->memory,
411         buf->size);
412   } else {
413     /* FIXME, non-raw formats get 0 as the empty sample */
414     memset (buf->memory, 0, buf->size);
415   }
416 
417 
418   return TRUE;
419 
420   /* ERRORS */
421 could_not_prepare:
422   {
423     GST_DEBUG_OBJECT (sink, "could not prepare device");
424     return FALSE;
425   }
426 }
427 
428 static gboolean
gst_audio_sink_ring_buffer_activate(GstAudioRingBuffer * buf,gboolean active)429 gst_audio_sink_ring_buffer_activate (GstAudioRingBuffer * buf, gboolean active)
430 {
431   GstAudioSink *sink;
432   GstAudioSinkRingBuffer *abuf;
433   GError *error = NULL;
434 
435   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
436   abuf = GST_AUDIO_SINK_RING_BUFFER_CAST (buf);
437 
438   if (active) {
439     abuf->running = TRUE;
440 
441     GST_DEBUG_OBJECT (sink, "starting thread");
442 
443     sink->thread = g_thread_try_new ("audiosink-ringbuffer",
444         (GThreadFunc) audioringbuffer_thread_func, buf, &error);
445 
446     if (!sink->thread || error != NULL)
447       goto thread_failed;
448 
449     GST_DEBUG_OBJECT (sink, "waiting for thread");
450     /* the object lock is taken */
451     GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
452     GST_DEBUG_OBJECT (sink, "thread is started");
453   } else {
454     abuf->running = FALSE;
455     GST_DEBUG_OBJECT (sink, "signal wait");
456     GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
457 
458     GST_OBJECT_UNLOCK (buf);
459 
460     /* join the thread */
461     g_thread_join (sink->thread);
462 
463     GST_OBJECT_LOCK (buf);
464   }
465   return TRUE;
466 
467   /* ERRORS */
468 thread_failed:
469   {
470     if (error)
471       GST_ERROR_OBJECT (sink, "could not create thread %s", error->message);
472     else
473       GST_ERROR_OBJECT (sink, "could not create thread for unknown reason");
474     g_clear_error (&error);
475     return FALSE;
476   }
477 }
478 
479 /* function is called with LOCK */
480 static gboolean
gst_audio_sink_ring_buffer_release(GstAudioRingBuffer * buf)481 gst_audio_sink_ring_buffer_release (GstAudioRingBuffer * buf)
482 {
483   GstAudioSink *sink;
484   GstAudioSinkClass *csink;
485   gboolean result = FALSE;
486 
487   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
488   csink = GST_AUDIO_SINK_GET_CLASS (sink);
489 
490   /* free the buffer */
491   g_free (buf->memory);
492   buf->memory = NULL;
493 
494   if (csink->unprepare)
495     result = csink->unprepare (sink);
496 
497   if (!result)
498     goto could_not_unprepare;
499 
500   GST_DEBUG_OBJECT (sink, "unprepared");
501 
502   return result;
503 
504 could_not_unprepare:
505   {
506     GST_DEBUG_OBJECT (sink, "could not unprepare device");
507     return FALSE;
508   }
509 }
510 
511 static gboolean
gst_audio_sink_ring_buffer_start(GstAudioRingBuffer * buf)512 gst_audio_sink_ring_buffer_start (GstAudioRingBuffer * buf)
513 {
514   GstAudioSink *sink;
515 
516   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
517 
518   GST_DEBUG_OBJECT (sink, "start, sending signal");
519   GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
520 
521   return TRUE;
522 }
523 
524 static gboolean
gst_audio_sink_ring_buffer_pause(GstAudioRingBuffer * buf)525 gst_audio_sink_ring_buffer_pause (GstAudioRingBuffer * buf)
526 {
527   GstAudioSink *sink;
528   GstAudioSinkClass *csink;
529 
530   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
531   csink = GST_AUDIO_SINK_GET_CLASS (sink);
532 
533   /* unblock any pending writes to the audio device */
534   if (csink->reset) {
535     GST_DEBUG_OBJECT (sink, "reset...");
536     csink->reset (sink);
537     GST_DEBUG_OBJECT (sink, "reset done");
538   }
539 
540   return TRUE;
541 }
542 
543 static gboolean
gst_audio_sink_ring_buffer_stop(GstAudioRingBuffer * buf)544 gst_audio_sink_ring_buffer_stop (GstAudioRingBuffer * buf)
545 {
546   GstAudioSink *sink;
547   GstAudioSinkClass *csink;
548 
549   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
550   csink = GST_AUDIO_SINK_GET_CLASS (sink);
551 
552   /* unblock any pending writes to the audio device */
553   if (csink->reset) {
554     GST_DEBUG_OBJECT (sink, "reset...");
555     csink->reset (sink);
556     GST_DEBUG_OBJECT (sink, "reset done");
557   }
558 #if 0
559   if (abuf->running) {
560     GST_DEBUG_OBJECT (sink, "stop, waiting...");
561     GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
562     GST_DEBUG_OBJECT (sink, "stopped");
563   }
564 #endif
565 
566   return TRUE;
567 }
568 
569 static guint
gst_audio_sink_ring_buffer_delay(GstAudioRingBuffer * buf)570 gst_audio_sink_ring_buffer_delay (GstAudioRingBuffer * buf)
571 {
572   GstAudioSink *sink;
573   GstAudioSinkClass *csink;
574   guint res = 0;
575 
576   sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
577   csink = GST_AUDIO_SINK_GET_CLASS (sink);
578 
579   if (csink->delay)
580     res = csink->delay (sink);
581 
582   return res;
583 }
584 
585 /* AudioSink signals and args */
586 enum
587 {
588   /* FILL ME */
589   LAST_SIGNAL
590 };
591 
592 enum
593 {
594   ARG_0,
595 };
596 
597 #define _do_init \
598     GST_DEBUG_CATEGORY_INIT (gst_audio_sink_debug, "audiosink", 0, "audiosink element");
599 #define gst_audio_sink_parent_class parent_class
600 G_DEFINE_TYPE_WITH_CODE (GstAudioSink, gst_audio_sink,
601     GST_TYPE_AUDIO_BASE_SINK, _do_init);
602 
603 static GstAudioRingBuffer *gst_audio_sink_create_ringbuffer (GstAudioBaseSink *
604     sink);
605 
606 static void
gst_audio_sink_class_init(GstAudioSinkClass * klass)607 gst_audio_sink_class_init (GstAudioSinkClass * klass)
608 {
609   GstAudioBaseSinkClass *gstaudiobasesink_class;
610 
611   gstaudiobasesink_class = (GstAudioBaseSinkClass *) klass;
612 
613   gstaudiobasesink_class->create_ringbuffer =
614       GST_DEBUG_FUNCPTR (gst_audio_sink_create_ringbuffer);
615 
616   g_type_class_ref (GST_TYPE_AUDIO_SINK_RING_BUFFER);
617 }
618 
619 static void
gst_audio_sink_init(GstAudioSink * audiosink)620 gst_audio_sink_init (GstAudioSink * audiosink)
621 {
622 }
623 
624 static GstAudioRingBuffer *
gst_audio_sink_create_ringbuffer(GstAudioBaseSink * sink)625 gst_audio_sink_create_ringbuffer (GstAudioBaseSink * sink)
626 {
627   GstAudioRingBuffer *buffer;
628 
629   GST_DEBUG_OBJECT (sink, "creating ringbuffer");
630   buffer = g_object_new (GST_TYPE_AUDIO_SINK_RING_BUFFER, NULL);
631   GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer);
632 
633   return buffer;
634 }
635