1 /*
2  * GStreamer
3  *
4  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
5  * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
6  * Copyright (C) 2009-2010 Chris Robinson <chris.kcat@gmail.com>
7  * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 /**
26  * SECTION:element-openalsink
27  * @title: openalsink
28  * @see_also: openalsrc
29  * @short_description: capture raw audio samples through OpenAL
30  *
31  * This element plays raw audio samples through OpenAL.
32  *
33  * Unfortunately the capture API doesn't have a format enumeration/check. all you can do is try opening it and see if it works.
34  *
35  * ## Example pipelines
36  * |[
37  * gst-launch-1.0 audiotestsrc ! audioconvert ! volume volume=0.5 ! openalsink
38  * ]| will play a sine wave (continuous beep sound) through OpenAL.
39  * |[
40  * gst-launch-1.0 filesrc location=stream.wav ! decodebin ! audioconvert ! openalsink
41  * ]| will play a wav audio file through OpenAL.
42  * |[
43  * gst-launch-1.0 openalsrc ! "audio/x-raw,format=S16LE,rate=44100" ! audioconvert ! volume volume=0.25 ! openalsink
44  * ]| will capture and play audio through OpenAL.
45  *
46  */
47 
48 /*
49  * DEV:
50  * To get better timing/delay information you may also be interested in this:
51  *  http://kcat.strangesoft.net/openal-extensions/SOFT_source_latency.txt
52  */
53 
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
57 
58 #include <gst/gst.h>
59 #include <gst/gsterror.h>
60 
61 GST_DEBUG_CATEGORY_EXTERN (openal_debug);
62 #define GST_CAT_DEFAULT openal_debug
63 
64 #include "gstopenalsink.h"
65 
66 static void gst_openal_sink_dispose (GObject * object);
67 static void gst_openal_sink_finalize (GObject * object);
68 
69 static void gst_openal_sink_get_property (GObject * object, guint prop_id,
70     GValue * value, GParamSpec * pspec);
71 static void gst_openal_sink_set_property (GObject * object, guint prop_id,
72     const GValue * value, GParamSpec * pspec);
73 static GstCaps *gst_openal_sink_getcaps (GstBaseSink * basesink,
74     GstCaps * filter);
75 static gboolean gst_openal_sink_open (GstAudioSink * audiosink);
76 static gboolean gst_openal_sink_close (GstAudioSink * audiosink);
77 static gboolean gst_openal_sink_prepare (GstAudioSink * audiosink,
78     GstAudioRingBufferSpec * spec);
79 static gboolean gst_openal_sink_unprepare (GstAudioSink * audiosink);
80 static gint gst_openal_sink_write (GstAudioSink * audiosink, gpointer data,
81     guint length);
82 static guint gst_openal_sink_delay (GstAudioSink * audiosink);
83 static void gst_openal_sink_reset (GstAudioSink * audiosink);
84 
85 #define OPENAL_DEFAULT_DEVICE NULL
86 
87 #define OPENAL_MIN_RATE 8000
88 #define OPENAL_MAX_RATE 192000
89 
90 enum
91 {
92   PROP_0,
93 
94   PROP_DEVICE,
95   PROP_DEVICE_NAME,
96 
97   PROP_USER_DEVICE,
98   PROP_USER_CONTEXT,
99   PROP_USER_SOURCE
100 };
101 
102 static GstStaticPadTemplate openalsink_factory =
103     GST_STATIC_PAD_TEMPLATE ("sink",
104     GST_PAD_SINK,
105     GST_PAD_ALWAYS,
106     GST_STATIC_CAPS ("audio/x-raw, " "format = (string) " GST_AUDIO_NE (F64)
107         ", " "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
108         "audio/x-raw, " "format = (string) " GST_AUDIO_NE (F32) ", "
109         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
110         "audio/x-raw, " "format = (string) " GST_AUDIO_NE (S16) ", "
111         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
112         "audio/x-raw, " "format = (string) " G_STRINGIFY (U8) ", "
113         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
114         /* These caps do not work on my card */
115         // "audio/x-adpcm, " "layout = (string) ima, "
116         // "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
117         // "audio/x-alaw, " "rate = (int) [ 1, MAX ], "
118         // "channels = (int) [ 1, 2 ]; "
119         // "audio/x-mulaw, " "rate = (int) [ 1, MAX ], "
120         // "channels = (int) [ 1, MAX ]"
121     )
122     );
123 
124 static PFNALCSETTHREADCONTEXTPROC palcSetThreadContext;
125 static PFNALCGETTHREADCONTEXTPROC palcGetThreadContext;
126 
127 static inline ALCcontext *
pushContext(ALCcontext * context)128 pushContext (ALCcontext * context)
129 {
130   ALCcontext *old;
131   if (!palcGetThreadContext || !palcSetThreadContext)
132     return NULL;
133 
134   old = palcGetThreadContext ();
135   if (old != context)
136     palcSetThreadContext (context);
137   return old;
138 }
139 
140 static inline void
popContext(ALCcontext * old,ALCcontext * context)141 popContext (ALCcontext * old, ALCcontext * context)
142 {
143   if (!palcGetThreadContext || !palcSetThreadContext)
144     return;
145 
146   if (old != context)
147     palcSetThreadContext (old);
148 }
149 
150 static inline ALenum
checkALError(const char * fname,unsigned int fline)151 checkALError (const char *fname, unsigned int fline)
152 {
153   ALenum err = alGetError ();
154   if (err != AL_NO_ERROR)
155     g_warning ("%s:%u: context error: %s", fname, fline, alGetString (err));
156   return err;
157 }
158 
159 #define checkALError() checkALError(__FILE__, __LINE__)
160 
161 G_DEFINE_TYPE (GstOpenALSink, gst_openal_sink, GST_TYPE_AUDIO_SINK);
162 
163 static void
gst_openal_sink_dispose(GObject * object)164 gst_openal_sink_dispose (GObject * object)
165 {
166   GstOpenALSink *sink = GST_OPENAL_SINK (object);
167 
168   if (sink->probed_caps)
169     gst_caps_unref (sink->probed_caps);
170   sink->probed_caps = NULL;
171 
172   G_OBJECT_CLASS (gst_openal_sink_parent_class)->dispose (object);
173 }
174 
175 static void
gst_openal_sink_class_init(GstOpenALSinkClass * klass)176 gst_openal_sink_class_init (GstOpenALSinkClass * klass)
177 {
178   GObjectClass *gobject_class = (GObjectClass *) klass;
179   GstElementClass *gstelement_class = (GstElementClass *) klass;
180   GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
181   GstAudioSinkClass *gstaudiosink_class = (GstAudioSinkClass *) klass;
182 
183   if (alcIsExtensionPresent (NULL, "ALC_EXT_thread_local_context")) {
184     palcSetThreadContext = alcGetProcAddress (NULL, "alcSetThreadContext");
185     palcGetThreadContext = alcGetProcAddress (NULL, "alcGetThreadContext");
186   }
187 
188   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_openal_sink_dispose);
189   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_openal_sink_finalize);
190   gobject_class->set_property =
191       GST_DEBUG_FUNCPTR (gst_openal_sink_set_property);
192   gobject_class->get_property =
193       GST_DEBUG_FUNCPTR (gst_openal_sink_get_property);
194 
195   gst_openal_sink_parent_class = g_type_class_peek_parent (klass);
196 
197   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_openal_sink_getcaps);
198 
199   gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_openal_sink_open);
200   gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_openal_sink_close);
201   gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_openal_sink_prepare);
202   gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_openal_sink_unprepare);
203   gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_openal_sink_write);
204   gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_openal_sink_delay);
205   gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_openal_sink_reset);
206 
207   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
208       g_param_spec_string ("device-name", "Device name",
209           "Human-readable name of the opened device", "", G_PARAM_READABLE));
210 
211   g_object_class_install_property (gobject_class, PROP_DEVICE,
212       g_param_spec_string ("device", "Device",
213           "Human-readable name of the device", OPENAL_DEFAULT_DEVICE,
214           G_PARAM_READWRITE));
215 
216   g_object_class_install_property (gobject_class, PROP_USER_DEVICE,
217       g_param_spec_pointer ("user-device", "ALCdevice", "User device",
218           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
219 
220   g_object_class_install_property (gobject_class, PROP_USER_CONTEXT,
221       g_param_spec_pointer ("user-context", "ALCcontext", "User context",
222           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
223 
224   g_object_class_install_property (gobject_class, PROP_USER_SOURCE,
225       g_param_spec_uint ("user-source", "ALsource", "User source", 0, UINT_MAX,
226           0, G_PARAM_READWRITE));
227 
228   gst_element_class_set_static_metadata (gstelement_class, "OpenAL Audio Sink",
229       "Sink/Audio", "Output audio through OpenAL",
230       "Juan Manuel Borges Caño <juanmabcmail@gmail.com>");
231 
232   gst_element_class_add_static_pad_template (gstelement_class,
233       &openalsink_factory);
234 
235 }
236 
237 static void
gst_openal_sink_init(GstOpenALSink * sink)238 gst_openal_sink_init (GstOpenALSink * sink)
239 {
240   GST_DEBUG_OBJECT (sink, "initializing");
241 
242   sink->device_name = g_strdup (OPENAL_DEFAULT_DEVICE);
243 
244   sink->user_device = NULL;
245   sink->user_context = NULL;
246   sink->user_source = 0;
247 
248   sink->default_device = NULL;
249   sink->default_context = NULL;
250   sink->default_source = 0;
251 
252   sink->buffer_idx = 0;
253   sink->buffer_count = 0;
254   sink->buffers = NULL;
255   sink->buffer_length = 0;
256 
257   sink->write_reset = AL_FALSE;
258   sink->probed_caps = NULL;
259 
260   g_mutex_init (&sink->openal_lock);
261 }
262 
263 static void
gst_openal_sink_finalize(GObject * object)264 gst_openal_sink_finalize (GObject * object)
265 {
266   GstOpenALSink *sink = GST_OPENAL_SINK (object);
267 
268   g_free (sink->device_name);
269   sink->device_name = NULL;
270   g_mutex_clear (&sink->openal_lock);
271 
272   G_OBJECT_CLASS (gst_openal_sink_parent_class)->finalize (object);
273 }
274 
275 static void
gst_openal_sink_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)276 gst_openal_sink_set_property (GObject * object, guint prop_id,
277     const GValue * value, GParamSpec * pspec)
278 {
279   GstOpenALSink *sink = GST_OPENAL_SINK (object);
280 
281   switch (prop_id) {
282     case PROP_DEVICE:
283       g_free (sink->device_name);
284       sink->device_name = g_value_dup_string (value);
285       if (sink->probed_caps)
286         gst_caps_unref (sink->probed_caps);
287       sink->probed_caps = NULL;
288       break;
289     case PROP_USER_DEVICE:
290       if (!sink->default_device)
291         sink->user_device = g_value_get_pointer (value);
292       break;
293     case PROP_USER_CONTEXT:
294       if (!sink->default_device)
295         sink->user_context = g_value_get_pointer (value);
296       break;
297     case PROP_USER_SOURCE:
298       if (!sink->default_device)
299         sink->user_source = g_value_get_uint (value);
300       break;
301 
302     default:
303       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
304       break;
305   }
306 }
307 
308 static void
gst_openal_sink_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)309 gst_openal_sink_get_property (GObject * object, guint prop_id, GValue * value,
310     GParamSpec * pspec)
311 {
312   GstOpenALSink *sink = GST_OPENAL_SINK (object);
313   const ALCchar *device_name = sink->device_name;
314   ALCdevice *device = sink->default_device;
315   ALCcontext *context = sink->default_context;
316   ALuint source = sink->default_source;
317 
318   switch (prop_id) {
319     case PROP_DEVICE_NAME:
320       device_name = "";
321       if (device)
322         device_name = alcGetString (device, ALC_DEVICE_SPECIFIER);
323       /* fall-through */
324     case PROP_DEVICE:
325       g_value_set_string (value, device_name);
326       break;
327     case PROP_USER_DEVICE:
328       if (!device)
329         device = sink->user_device;
330       g_value_set_pointer (value, device);
331       break;
332     case PROP_USER_CONTEXT:
333       if (!context)
334         context = sink->user_context;
335       g_value_set_pointer (value, context);
336       break;
337     case PROP_USER_SOURCE:
338       if (!source)
339         source = sink->user_source;
340       g_value_set_uint (value, source);
341       break;
342 
343     default:
344       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
345       break;
346   }
347 }
348 
349 static GstCaps *
gst_openal_helper_probe_caps(ALCcontext * context)350 gst_openal_helper_probe_caps (ALCcontext * context)
351 {
352   static const struct
353   {
354     gint count;
355     GstAudioChannelPosition positions[8];
356   } chans[] = {
357     {
358       1, {
359       GST_AUDIO_CHANNEL_POSITION_MONO}
360     }, {
361       2, {
362       GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
363             GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}
364     }, {
365       4, {
366       GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
367             GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
368             GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
369             GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}
370     }, {
371       6, {
372       GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
373             GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
374             GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
375             GST_AUDIO_CHANNEL_POSITION_LFE1,
376             GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
377             GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}
378     }, {
379       7, {
380       GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
381             GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
382             GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
383             GST_AUDIO_CHANNEL_POSITION_LFE1,
384             GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
385             GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
386             GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
387     }, {
388       8, {
389       GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
390             GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
391             GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
392             GST_AUDIO_CHANNEL_POSITION_LFE1,
393             GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
394             GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
395             GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
396             GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
397   },};
398   GstStructure *structure;
399   guint64 channel_mask;
400   GstCaps *caps;
401   ALCcontext *old;
402 
403   old = pushContext (context);
404 
405   caps = gst_caps_new_empty ();
406 
407   if (alIsExtensionPresent ("AL_EXT_MCFORMATS")) {
408     const char *fmt32[] = {
409       "AL_FORMAT_MONO_FLOAT32",
410       "AL_FORMAT_STEREO_FLOAT32",
411       "AL_FORMAT_QUAD32",
412       "AL_FORMAT_51CHN32",
413       "AL_FORMAT_61CHN32",
414       "AL_FORMAT_71CHN32",
415       NULL
416     }, *fmt16[] = {
417     "AL_FORMAT_MONO16",
418           "AL_FORMAT_STEREO16",
419           "AL_FORMAT_QUAD16",
420           "AL_FORMAT_51CHN16",
421           "AL_FORMAT_61CHN16", "AL_FORMAT_71CHN16", NULL}, *fmt8[] = {
422     "AL_FORMAT_MONO8",
423           "AL_FORMAT_STEREO8",
424           "AL_FORMAT_QUAD8",
425           "AL_FORMAT_51CHN8", "AL_FORMAT_61CHN8", "AL_FORMAT_71CHN8", NULL};
426     int i;
427 
428     if (alIsExtensionPresent ("AL_EXT_FLOAT32")) {
429       for (i = 0; fmt32[i]; i++) {
430         ALenum value = alGetEnumValue (fmt32[i]);
431         if (checkALError () != AL_NO_ERROR || value == 0 || value == -1)
432           continue;
433 
434         structure =
435             gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING,
436             GST_AUDIO_NE (F32), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE,
437             OPENAL_MAX_RATE, "channels", G_TYPE_INT, chans[i].count, NULL);
438         if (chans[i].count > 2) {
439           gst_audio_channel_positions_to_mask (chans[i].positions,
440               chans[i].count, FALSE, &channel_mask);
441           gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK,
442               channel_mask, NULL);
443         }
444         gst_caps_append_structure (caps, structure);
445       }
446     }
447 
448     for (i = 0; fmt16[i]; i++) {
449       ALenum value = alGetEnumValue (fmt16[i]);
450       if (checkALError () != AL_NO_ERROR || value == 0 || value == -1)
451         continue;
452 
453       structure =
454           gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING,
455           GST_AUDIO_NE (S16), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE,
456           OPENAL_MAX_RATE, "channels", G_TYPE_INT, chans[i].count, NULL);
457       if (chans[i].count > 2) {
458         gst_audio_channel_positions_to_mask (chans[i].positions, chans[i].count,
459             FALSE, &channel_mask);
460         gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK,
461             channel_mask, NULL);
462       }
463       gst_caps_append_structure (caps, structure);
464     }
465     for (i = 0; fmt8[i]; i++) {
466       ALenum value = alGetEnumValue (fmt8[i]);
467       if (checkALError () != AL_NO_ERROR || value == 0 || value == -1)
468         continue;
469 
470       structure =
471           gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING,
472           G_STRINGIFY (U8), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE,
473           OPENAL_MAX_RATE, "channels", G_TYPE_INT, chans[i].count, NULL);
474       if (chans[i].count > 2) {
475         gst_audio_channel_positions_to_mask (chans[i].positions, chans[i].count,
476             FALSE, &channel_mask);
477         gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK,
478             channel_mask, NULL);
479       }
480       gst_caps_append_structure (caps, structure);
481     }
482   } else {
483     if (alIsExtensionPresent ("AL_EXT_FLOAT32")) {
484       structure =
485           gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING,
486           GST_AUDIO_NE (F32), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE,
487           OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
488       gst_caps_append_structure (caps, structure);
489     }
490 
491     structure =
492         gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING,
493         GST_AUDIO_NE (S16), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE,
494         OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
495     gst_caps_append_structure (caps, structure);
496 
497     structure =
498         gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING,
499         G_STRINGIFY (U8), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE,
500         OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
501     gst_caps_append_structure (caps, structure);
502   }
503 
504   if (alIsExtensionPresent ("AL_EXT_double")) {
505     structure =
506         gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING,
507         GST_AUDIO_NE (F64), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE,
508         OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
509     gst_caps_append_structure (caps, structure);
510   }
511 
512   if (alIsExtensionPresent ("AL_EXT_IMA4")) {
513     structure =
514         gst_structure_new ("audio/x-adpcm", "layout", G_TYPE_STRING, "ima",
515         "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE,
516         "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
517     gst_caps_append_structure (caps, structure);
518   }
519 
520   if (alIsExtensionPresent ("AL_EXT_ALAW")) {
521     structure =
522         gst_structure_new ("audio/x-alaw", "rate", GST_TYPE_INT_RANGE,
523         OPENAL_MIN_RATE, OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2,
524         NULL);
525     gst_caps_append_structure (caps, structure);
526   }
527 
528   if (alIsExtensionPresent ("AL_EXT_MULAW_MCFORMATS")) {
529     const char *fmtmulaw[] = {
530       "AL_FORMAT_MONO_MULAW",
531       "AL_FORMAT_STEREO_MULAW",
532       "AL_FORMAT_QUAD_MULAW",
533       "AL_FORMAT_51CHN_MULAW",
534       "AL_FORMAT_61CHN_MULAW",
535       "AL_FORMAT_71CHN_MULAW",
536       NULL
537     };
538     int i;
539 
540     for (i = 0; fmtmulaw[i]; i++) {
541       ALenum value = alGetEnumValue (fmtmulaw[i]);
542       if (checkALError () != AL_NO_ERROR || value == 0 || value == -1)
543         continue;
544 
545       structure =
546           gst_structure_new ("audio/x-mulaw", "rate", GST_TYPE_INT_RANGE,
547           OPENAL_MIN_RATE, OPENAL_MAX_RATE, "channels", G_TYPE_INT,
548           chans[i].count, NULL);
549       if (chans[i].count > 2) {
550         gst_audio_channel_positions_to_mask (chans[i].positions, chans[i].count,
551             FALSE, &channel_mask);
552         gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK,
553             channel_mask, NULL);
554       }
555       gst_caps_append_structure (caps, structure);
556     }
557   } else if (alIsExtensionPresent ("AL_EXT_MULAW")) {
558     structure =
559         gst_structure_new ("audio/x-mulaw", "rate", GST_TYPE_INT_RANGE,
560         OPENAL_MIN_RATE, OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2,
561         NULL);
562     gst_caps_append_structure (caps, structure);
563   }
564 
565   popContext (old, context);
566 
567   return caps;
568 }
569 
570 static GstCaps *
gst_openal_sink_getcaps(GstBaseSink * basesink,GstCaps * filter)571 gst_openal_sink_getcaps (GstBaseSink * basesink, GstCaps * filter)
572 {
573   GstOpenALSink *sink = GST_OPENAL_SINK (basesink);
574   GstCaps *caps;
575 
576   if (sink->default_device == NULL) {
577     GstPad *pad = GST_BASE_SINK_PAD (basesink);
578     GstCaps *tcaps = gst_pad_get_pad_template_caps (pad);
579     caps = gst_caps_copy (tcaps);
580     gst_caps_unref (tcaps);
581   } else if (sink->probed_caps)
582     caps = gst_caps_copy (sink->probed_caps);
583   else {
584     if (sink->default_context)
585       caps = gst_openal_helper_probe_caps (sink->default_context);
586     else if (sink->user_context)
587       caps = gst_openal_helper_probe_caps (sink->user_context);
588     else {
589       ALCcontext *context = alcCreateContext (sink->default_device, NULL);
590       if (context) {
591         caps = gst_openal_helper_probe_caps (context);
592         alcDestroyContext (context);
593       } else {
594         GST_ELEMENT_WARNING (sink, RESOURCE, FAILED,
595             ("Could not create temporary context."),
596             GST_ALC_ERROR (sink->default_device));
597         caps = NULL;
598       }
599     }
600 
601     if (caps && !gst_caps_is_empty (caps))
602       sink->probed_caps = gst_caps_copy (caps);
603   }
604 
605   if (filter) {
606     GstCaps *intersection;
607 
608     intersection =
609         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
610     return intersection;
611   } else {
612     return caps;
613   }
614 }
615 
616 static gboolean
gst_openal_sink_open(GstAudioSink * audiosink)617 gst_openal_sink_open (GstAudioSink * audiosink)
618 {
619   GstOpenALSink *sink = GST_OPENAL_SINK (audiosink);
620 
621   if (sink->user_device) {
622     ALCint value = -1;
623     alcGetIntegerv (sink->user_device, ALC_ATTRIBUTES_SIZE, 1, &value);
624     if (value > 0) {
625       if (!sink->user_context
626           || alcGetContextsDevice (sink->user_context) == sink->user_device)
627         sink->default_device = sink->user_device;
628     }
629   } else if (sink->user_context)
630     sink->default_device = alcGetContextsDevice (sink->user_context);
631   else
632     sink->default_device = alcOpenDevice (sink->device_name);
633   if (!sink->default_device) {
634     GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
635         ("Could not open device."), GST_ALC_ERROR (sink->default_device));
636     return FALSE;
637   }
638 
639   return TRUE;
640 }
641 
642 static gboolean
gst_openal_sink_close(GstAudioSink * audiosink)643 gst_openal_sink_close (GstAudioSink * audiosink)
644 {
645   GstOpenALSink *sink = GST_OPENAL_SINK (audiosink);
646 
647   if (!sink->user_device && !sink->user_context) {
648     if (alcCloseDevice (sink->default_device) == ALC_FALSE) {
649       GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
650           ("Could not close device."), GST_ALC_ERROR (sink->default_device));
651       return FALSE;
652     }
653   }
654   sink->default_device = NULL;
655 
656   if (sink->probed_caps)
657     gst_caps_unref (sink->probed_caps);
658   sink->probed_caps = NULL;
659 
660   return TRUE;
661 }
662 
663 static void
gst_openal_sink_parse_spec(GstOpenALSink * sink,const GstAudioRingBufferSpec * spec)664 gst_openal_sink_parse_spec (GstOpenALSink * sink,
665     const GstAudioRingBufferSpec * spec)
666 {
667   ALuint format = AL_NONE;
668 
669   GST_DEBUG_OBJECT (sink,
670       "looking up format for type %d, gst-format %d, and %d channels",
671       spec->type, GST_AUDIO_INFO_FORMAT (&spec->info),
672       GST_AUDIO_INFO_CHANNELS (&spec->info));
673 
674   /* Don't need to verify supported formats, since the probed caps will only
675    * report what was detected and we shouldn't get anything different */
676   switch (spec->type) {
677     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW:
678       switch (GST_AUDIO_INFO_FORMAT (&spec->info)) {
679         case GST_AUDIO_FORMAT_U8:
680           switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) {
681             case 1:
682               format = AL_FORMAT_MONO8;
683               break;
684             case 2:
685               format = AL_FORMAT_STEREO8;
686               break;
687             case 4:
688               format = AL_FORMAT_QUAD8;
689               break;
690             case 6:
691               format = AL_FORMAT_51CHN8;
692               break;
693             case 7:
694               format = AL_FORMAT_61CHN8;
695               break;
696             case 8:
697               format = AL_FORMAT_71CHN8;
698               break;
699             default:
700               break;
701           }
702           break;
703 
704         case GST_AUDIO_FORMAT_S16:
705           switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) {
706             case 1:
707               format = AL_FORMAT_MONO16;
708               break;
709             case 2:
710               format = AL_FORMAT_STEREO16;
711               break;
712             case 4:
713               format = AL_FORMAT_QUAD16;
714               break;
715             case 6:
716               format = AL_FORMAT_51CHN16;
717               break;
718             case 7:
719               format = AL_FORMAT_61CHN16;
720               break;
721             case 8:
722               format = AL_FORMAT_71CHN16;
723               break;
724             default:
725               break;
726           }
727           break;
728 
729         case GST_AUDIO_FORMAT_F32:
730           switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) {
731             case 1:
732               format = AL_FORMAT_MONO_FLOAT32;
733               break;
734             case 2:
735               format = AL_FORMAT_STEREO_FLOAT32;
736               break;
737             case 4:
738               format = AL_FORMAT_QUAD32;
739               break;
740             case 6:
741               format = AL_FORMAT_51CHN32;
742               break;
743             case 7:
744               format = AL_FORMAT_61CHN32;
745               break;
746             case 8:
747               format = AL_FORMAT_71CHN32;
748               break;
749             default:
750               break;
751           }
752           break;
753 
754         case GST_AUDIO_FORMAT_F64:
755           switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) {
756             case 1:
757               format = AL_FORMAT_MONO_DOUBLE_EXT;
758               break;
759             case 2:
760               format = AL_FORMAT_STEREO_DOUBLE_EXT;
761               break;
762             default:
763               break;
764           }
765           break;
766         default:
767           break;
768       }
769       break;
770 
771     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IMA_ADPCM:
772       switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) {
773         case 1:
774           format = AL_FORMAT_MONO_IMA4;
775           break;
776         case 2:
777           format = AL_FORMAT_STEREO_IMA4;
778           break;
779         default:
780           break;
781       }
782       break;
783 
784     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW:
785       switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) {
786         case 1:
787           format = AL_FORMAT_MONO_ALAW_EXT;
788           break;
789         case 2:
790           format = AL_FORMAT_STEREO_ALAW_EXT;
791           break;
792         default:
793           break;
794       }
795       break;
796 
797     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW:
798       switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) {
799         case 1:
800           format = AL_FORMAT_MONO_MULAW;
801           break;
802         case 2:
803           format = AL_FORMAT_STEREO_MULAW;
804           break;
805         case 4:
806           format = AL_FORMAT_QUAD_MULAW;
807           break;
808         case 6:
809           format = AL_FORMAT_51CHN_MULAW;
810           break;
811         case 7:
812           format = AL_FORMAT_61CHN_MULAW;
813           break;
814         case 8:
815           format = AL_FORMAT_71CHN_MULAW;
816           break;
817         default:
818           break;
819       }
820       break;
821 
822     default:
823       break;
824   }
825 
826   sink->bytes_per_sample = GST_AUDIO_INFO_BPS (&spec->info);
827   sink->rate = GST_AUDIO_INFO_RATE (&spec->info);
828   sink->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
829   sink->format = format;
830   sink->buffer_count = spec->segtotal;
831   sink->buffer_length = spec->segsize;
832 }
833 
834 static gboolean
gst_openal_sink_prepare(GstAudioSink * audiosink,GstAudioRingBufferSpec * spec)835 gst_openal_sink_prepare (GstAudioSink * audiosink,
836     GstAudioRingBufferSpec * spec)
837 {
838   GstOpenALSink *sink = GST_OPENAL_SINK (audiosink);
839   ALCcontext *context, *old;
840 
841   if (sink->default_context && !gst_openal_sink_unprepare (audiosink))
842     return FALSE;
843 
844   if (sink->user_context)
845     context = sink->user_context;
846   else {
847     ALCint attribs[3] = { 0, 0, 0 };
848 
849     /* Don't try to change the playback frequency of an app's device */
850     if (!sink->user_device) {
851       attribs[0] = ALC_FREQUENCY;
852       attribs[1] = GST_AUDIO_INFO_RATE (&spec->info);
853       attribs[2] = 0;
854     }
855 
856     context = alcCreateContext (sink->default_device, attribs);
857     if (!context) {
858       GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
859           ("Unable to prepare device."), GST_ALC_ERROR (sink->default_device));
860       return FALSE;
861     }
862   }
863 
864   old = pushContext (context);
865 
866   if (sink->user_source) {
867     if (!sink->user_context || !alIsSource (sink->user_source)) {
868       GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, (NULL),
869           ("Invalid source specified for context"));
870       goto fail;
871     }
872     sink->default_source = sink->user_source;
873   } else {
874     ALuint source;
875 
876     alGenSources (1, &source);
877     if (checkALError () != AL_NO_ERROR) {
878       GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL),
879           ("Unable to generate source"));
880       goto fail;
881     }
882     sink->default_source = source;
883   }
884 
885   gst_openal_sink_parse_spec (sink, spec);
886   if (sink->format == AL_NONE) {
887     GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
888         ("Unable to get type %d, format %d, and %d channels", spec->type,
889             GST_AUDIO_INFO_FORMAT (&spec->info),
890             GST_AUDIO_INFO_CHANNELS (&spec->info)));
891     goto fail;
892   }
893 
894   sink->buffers = g_malloc (sink->buffer_count * sizeof (*sink->buffers));
895   if (!sink->buffers) {
896     GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, ("Out of memory."),
897         ("Unable to allocate buffers"));
898     goto fail;
899   }
900 
901   alGenBuffers (sink->buffer_count, sink->buffers);
902   if (checkALError () != AL_NO_ERROR) {
903     GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL),
904         ("Unable to generate %d buffers", sink->buffer_count));
905     goto fail;
906   }
907   sink->buffer_idx = 0;
908 
909   popContext (old, context);
910   sink->default_context = context;
911   return TRUE;
912 
913 fail:
914   if (!sink->user_source && sink->default_source)
915     alDeleteSources (1, &sink->default_source);
916   sink->default_source = 0;
917 
918   g_free (sink->buffers);
919   sink->buffers = NULL;
920   sink->buffer_count = 0;
921   sink->buffer_length = 0;
922 
923   popContext (old, context);
924   if (!sink->user_context)
925     alcDestroyContext (context);
926   return FALSE;
927 }
928 
929 static gboolean
gst_openal_sink_unprepare(GstAudioSink * audiosink)930 gst_openal_sink_unprepare (GstAudioSink * audiosink)
931 {
932   GstOpenALSink *sink = GST_OPENAL_SINK (audiosink);
933   ALCcontext *old;
934 
935   if (!sink->default_context)
936     return TRUE;
937 
938   old = pushContext (sink->default_context);
939 
940   alSourceStop (sink->default_source);
941   alSourcei (sink->default_source, AL_BUFFER, 0);
942 
943   if (!sink->user_source)
944     alDeleteSources (1, &sink->default_source);
945   sink->default_source = 0;
946 
947   alDeleteBuffers (sink->buffer_count, sink->buffers);
948   g_free (sink->buffers);
949   sink->buffers = NULL;
950   sink->buffer_idx = 0;
951   sink->buffer_count = 0;
952   sink->buffer_length = 0;
953 
954   checkALError ();
955   popContext (old, sink->default_context);
956   if (!sink->user_context)
957     alcDestroyContext (sink->default_context);
958   sink->default_context = NULL;
959 
960   return TRUE;
961 }
962 
963 static gint
gst_openal_sink_write(GstAudioSink * audiosink,gpointer data,guint length)964 gst_openal_sink_write (GstAudioSink * audiosink, gpointer data, guint length)
965 {
966   GstOpenALSink *sink = GST_OPENAL_SINK (audiosink);
967   ALint processed, queued, state;
968   ALCcontext *old;
969   gulong rest_us;
970 
971   g_assert (length == sink->buffer_length);
972 
973   old = pushContext (sink->default_context);
974 
975   rest_us =
976       (guint64) (sink->buffer_length / sink->bytes_per_sample) *
977       G_USEC_PER_SEC / sink->rate / sink->channels;
978   do {
979     alGetSourcei (sink->default_source, AL_SOURCE_STATE, &state);
980     alGetSourcei (sink->default_source, AL_BUFFERS_QUEUED, &queued);
981     alGetSourcei (sink->default_source, AL_BUFFERS_PROCESSED, &processed);
982     if (checkALError () != AL_NO_ERROR) {
983       GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
984           ("Source state error detected"));
985       length = 0;
986       goto out_nolock;
987     }
988 
989     if (processed > 0 || queued < sink->buffer_count)
990       break;
991     if (state != AL_PLAYING)
992       alSourcePlay (sink->default_source);
993     g_usleep (rest_us);
994   }
995   while (1);
996 
997   GST_OPENAL_SINK_LOCK (sink);
998   if (sink->write_reset != AL_FALSE) {
999     sink->write_reset = AL_FALSE;
1000     length = 0;
1001     goto out;
1002   }
1003 
1004   queued -= processed;
1005   while (processed-- > 0) {
1006     ALuint bid;
1007     alSourceUnqueueBuffers (sink->default_source, 1, &bid);
1008   }
1009   if (state == AL_STOPPED) {
1010     /* "Restore" from underruns (not actually needed, but it keeps delay
1011      * calculations correct while rebuffering) */
1012     alSourceRewind (sink->default_source);
1013   }
1014 
1015   alBufferData (sink->buffers[sink->buffer_idx], sink->format,
1016       data, sink->buffer_length, sink->rate);
1017   alSourceQueueBuffers (sink->default_source, 1,
1018       &sink->buffers[sink->buffer_idx]);
1019   sink->buffer_idx = (sink->buffer_idx + 1) % sink->buffer_count;
1020   queued++;
1021 
1022   if (state != AL_PLAYING && queued == sink->buffer_count)
1023     alSourcePlay (sink->default_source);
1024 
1025   if (checkALError () != AL_NO_ERROR) {
1026     GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
1027         ("Source queue error detected"));
1028     goto out;
1029   }
1030 
1031 out:
1032   GST_OPENAL_SINK_UNLOCK (sink);
1033 out_nolock:
1034   popContext (old, sink->default_context);
1035   return length;
1036 }
1037 
1038 static guint
gst_openal_sink_delay(GstAudioSink * audiosink)1039 gst_openal_sink_delay (GstAudioSink * audiosink)
1040 {
1041   GstOpenALSink *sink = GST_OPENAL_SINK (audiosink);
1042   ALint queued, state, offset, delay;
1043   ALCcontext *old;
1044 
1045   if (!sink->default_context)
1046     return 0;
1047 
1048   GST_OPENAL_SINK_LOCK (sink);
1049   old = pushContext (sink->default_context);
1050 
1051   delay = 0;
1052   alGetSourcei (sink->default_source, AL_BUFFERS_QUEUED, &queued);
1053   /* Order here is important. If the offset is queried after the state and an
1054    * underrun occurs in between the two calls, it can end up with a 0 offset
1055    * in a playing state, incorrectly reporting a len*queued/bps delay. */
1056   alGetSourcei (sink->default_source, AL_BYTE_OFFSET, &offset);
1057   alGetSourcei (sink->default_source, AL_SOURCE_STATE, &state);
1058 
1059   /* Note: state=stopped is an underrun, meaning all buffers are processed
1060    * and there's no delay when writing the next buffer. Pre-buffering is
1061    * state=initial, which will introduce a delay while writing. */
1062   if (checkALError () == AL_NO_ERROR && state != AL_STOPPED)
1063     delay =
1064         ((queued * sink->buffer_length) -
1065         offset) / sink->bytes_per_sample / sink->channels / GST_MSECOND;
1066 
1067   popContext (old, sink->default_context);
1068   GST_OPENAL_SINK_UNLOCK (sink);
1069 
1070   if (G_UNLIKELY (delay < 0)) {
1071     /* make sure we never return a negative delay */
1072     GST_WARNING_OBJECT (openal_debug, "negative delay");
1073     delay = 0;
1074   }
1075 
1076   return delay;
1077 }
1078 
1079 static void
gst_openal_sink_reset(GstAudioSink * audiosink)1080 gst_openal_sink_reset (GstAudioSink * audiosink)
1081 {
1082   GstOpenALSink *sink = GST_OPENAL_SINK (audiosink);
1083   ALCcontext *old;
1084 
1085   GST_OPENAL_SINK_LOCK (sink);
1086   old = pushContext (sink->default_context);
1087 
1088   sink->write_reset = AL_TRUE;
1089   alSourceStop (sink->default_source);
1090   alSourceRewind (sink->default_source);
1091   alSourcei (sink->default_source, AL_BUFFER, 0);
1092   checkALError ();
1093 
1094   popContext (old, sink->default_context);
1095   GST_OPENAL_SINK_UNLOCK (sink);
1096 }
1097