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