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