1 /*
2  * OpenAL audio output driver for MPlayer
3  *
4  * Copyleft 2006 by Reimar Döffinger (Reimar.Doeffinger@stud.uni-karlsruhe.de)
5  *
6  * This file is part of mpv.
7  *
8  * mpv is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * mpv is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with mpv.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <inttypes.h>
27 #ifdef OPENAL_AL_H
28 #include <OpenAL/alc.h>
29 #include <OpenAL/al.h>
30 #include <OpenAL/alext.h>
31 #else
32 #include <AL/alc.h>
33 #include <AL/al.h>
34 #include <AL/alext.h>
35 #endif
36 
37 #include "common/msg.h"
38 
39 #include "ao.h"
40 #include "internal.h"
41 #include "audio/format.h"
42 #include "osdep/timer.h"
43 #include "options/m_option.h"
44 
45 #define MAX_CHANS MP_NUM_CHANNELS
46 #define MAX_BUF 128
47 #define MAX_SAMPLES 32768
48 static ALuint buffers[MAX_BUF];
49 static ALuint buffer_size[MAX_BUF];
50 static ALuint source;
51 
52 static int cur_buf;
53 static int unqueue_buf;
54 
55 static struct ao *ao_data;
56 
57 struct priv {
58     ALenum al_format;
59     int num_buffers;
60     int num_samples;
61     int direct_channels;
62 };
63 
control(struct ao * ao,enum aocontrol cmd,void * arg)64 static int control(struct ao *ao, enum aocontrol cmd, void *arg)
65 {
66     switch (cmd) {
67     case AOCONTROL_GET_VOLUME:
68     case AOCONTROL_SET_VOLUME: {
69         ALfloat volume;
70         ao_control_vol_t *vol = (ao_control_vol_t *)arg;
71         if (cmd == AOCONTROL_SET_VOLUME) {
72             volume = (vol->left + vol->right) / 200.0;
73             alListenerf(AL_GAIN, volume);
74         }
75         alGetListenerf(AL_GAIN, &volume);
76         vol->left = vol->right = volume * 100;
77         return CONTROL_TRUE;
78     }
79     case AOCONTROL_GET_MUTE:
80     case AOCONTROL_SET_MUTE: {
81         bool mute = *(bool *)arg;
82 
83         // openal has no mute control, only gain.
84         // Thus reverse the muted state to get required gain
85         ALfloat al_mute = (ALfloat)(!mute);
86         if (cmd == AOCONTROL_SET_MUTE) {
87             alSourcef(source, AL_GAIN, al_mute);
88         }
89         alGetSourcef(source, AL_GAIN, &al_mute);
90         *(bool *)arg = !((bool)al_mute);
91         return CONTROL_TRUE;
92     }
93 
94     }
95     return CONTROL_UNKNOWN;
96 }
97 
get_supported_format(int format)98 static enum af_format get_supported_format(int format)
99 {
100     switch (format) {
101     case AF_FORMAT_U8:
102         if (alGetEnumValue((ALchar*)"AL_FORMAT_MONO8"))
103             return AF_FORMAT_U8;
104         break;
105 
106     case AF_FORMAT_S16:
107         if (alGetEnumValue((ALchar*)"AL_FORMAT_MONO16"))
108             return AF_FORMAT_S16;
109         break;
110 
111     case AF_FORMAT_S32:
112         if (strstr(alGetString(AL_RENDERER), "X-Fi") != NULL)
113             return AF_FORMAT_S32;
114         break;
115 
116     case AF_FORMAT_FLOAT:
117         if (alIsExtensionPresent((ALchar*)"AL_EXT_float32") == AL_TRUE)
118             return AF_FORMAT_FLOAT;
119         break;
120     }
121     return AL_FALSE;
122 }
123 
get_supported_layout(int format,int channels)124 static ALenum get_supported_layout(int format, int channels)
125 {
126     const char *channel_str[] = {
127         [1] = "MONO",
128         [2] = "STEREO",
129         [4] = "QUAD",
130         [6] = "51CHN",
131         [7] = "61CHN",
132         [8] = "71CHN",
133     };
134     const char *format_str[] = {
135         [AF_FORMAT_U8] = "8",
136         [AF_FORMAT_S16] = "16",
137         [AF_FORMAT_S32] = "32",
138         [AF_FORMAT_FLOAT] = "_FLOAT32",
139     };
140     if (channel_str[channels] == NULL || format_str[format] == NULL)
141         return AL_FALSE;
142 
143     char enum_name[32];
144     // AF_FORMAT_FLOAT uses same enum name as AF_FORMAT_S32 for multichannel
145     // playback, while it is different for mono and stereo.
146     // OpenAL Soft does not support AF_FORMAT_S32 and seems to reuse the names.
147     if (channels > 2 && format == AF_FORMAT_FLOAT)
148         format = AF_FORMAT_S32;
149     snprintf(enum_name, sizeof(enum_name), "AL_FORMAT_%s%s", channel_str[channels],
150              format_str[format]);
151 
152     if (alGetEnumValue((ALchar*)enum_name)) {
153         return alGetEnumValue((ALchar*)enum_name);
154     }
155     return AL_FALSE;
156 }
157 
158 // close audio device
uninit(struct ao * ao)159 static void uninit(struct ao *ao)
160 {
161     struct priv *p = ao->priv;
162     alSourceStop(source);
163     alSourcei(source, AL_BUFFER, 0);
164 
165     alDeleteBuffers(p->num_buffers, buffers);
166     alDeleteSources(1, &source);
167 
168     ALCcontext *ctx = alcGetCurrentContext();
169     ALCdevice *dev = alcGetContextsDevice(ctx);
170     alcMakeContextCurrent(NULL);
171     alcDestroyContext(ctx);
172     alcCloseDevice(dev);
173     ao_data = NULL;
174 }
175 
init(struct ao * ao)176 static int init(struct ao *ao)
177 {
178     float position[3] = {0, 0, 0};
179     float direction[6] = {0, 0, -1, 0, 1, 0};
180     ALCdevice *dev = NULL;
181     ALCcontext *ctx = NULL;
182     ALCint freq = 0;
183     ALCint attribs[] = {ALC_FREQUENCY, ao->samplerate, 0, 0};
184     struct priv *p = ao->priv;
185     if (ao_data) {
186         MP_FATAL(ao, "Not reentrant!\n");
187         return -1;
188     }
189     ao_data = ao;
190     char *dev_name = ao->device;
191     dev = alcOpenDevice(dev_name && dev_name[0] ? dev_name : NULL);
192     if (!dev) {
193         MP_FATAL(ao, "could not open device\n");
194         goto err_out;
195     }
196     ctx = alcCreateContext(dev, attribs);
197     alcMakeContextCurrent(ctx);
198     alListenerfv(AL_POSITION, position);
199     alListenerfv(AL_ORIENTATION, direction);
200 
201     alGenSources(1, &source);
202     if (p->direct_channels && alGetEnumValue((ALchar*)"AL_DIRECT_CHANNELS_SOFT")) {
203         alSourcei(source, alGetEnumValue((ALchar*)"AL_DIRECT_CHANNELS_SOFT"), AL_TRUE);
204     }
205 
206     cur_buf = 0;
207     unqueue_buf = 0;
208     for (int i = 0; i < p->num_buffers; ++i) {
209         buffer_size[i] = 0;
210     }
211 
212     alGenBuffers(p->num_buffers, buffers);
213 
214     alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq);
215     if (alcGetError(dev) == ALC_NO_ERROR && freq)
216         ao->samplerate = freq;
217 
218     // Check sample format
219     int try_formats[AF_FORMAT_COUNT + 1];
220     enum af_format sample_format = 0;
221     af_get_best_sample_formats(ao->format, try_formats);
222     for (int n = 0; try_formats[n]; n++) {
223         sample_format = get_supported_format(try_formats[n]);
224         if (sample_format != AF_FORMAT_UNKNOWN) {
225             ao->format = try_formats[n];
226             break;
227         }
228     }
229 
230     if (sample_format == AF_FORMAT_UNKNOWN) {
231         MP_FATAL(ao, "Can't find appropriate sample format.\n");
232         uninit(ao);
233         goto err_out;
234     }
235 
236     // Check if OpenAL driver supports the desired number of channels.
237     int num_channels = ao->channels.num;
238     do {
239         p->al_format = get_supported_layout(sample_format, num_channels);
240         if (p->al_format == AL_FALSE) {
241             num_channels = num_channels - 1;
242         }
243     } while (p->al_format == AL_FALSE && num_channels > 1);
244 
245     // Request number of speakers for output from ao.
246     const struct mp_chmap possible_layouts[] = {
247         {0},                                        // empty
248         MP_CHMAP_INIT_MONO,                         // mono
249         MP_CHMAP_INIT_STEREO,                       // stereo
250         {0},                                        // 2.1
251         MP_CHMAP4(FL, FR, BL, BR),                  // 4.0
252         {0},                                        // 5.0
253         MP_CHMAP6(FL, FR, FC, LFE, BL, BR),         // 5.1
254         MP_CHMAP7(FL, FR, FC, LFE, SL, SR, BC),     // 6.1
255         MP_CHMAP8(FL, FR, FC, LFE, BL, BR, SL, SR), // 7.1
256     };
257     ao->channels = possible_layouts[num_channels];
258     if (!ao->channels.num)
259         mp_chmap_set_unknown(&ao->channels, num_channels);
260 
261     if (p->al_format == AL_FALSE || !mp_chmap_is_valid(&ao->channels)) {
262         MP_FATAL(ao, "Can't find appropriate channel layout.\n");
263         uninit(ao);
264         goto err_out;
265     }
266 
267     ao->device_buffer = p->num_buffers * p->num_samples;
268     return 0;
269 
270 err_out:
271     ao_data = NULL;
272     return -1;
273 }
274 
unqueue_buffers(struct ao * ao)275 static void unqueue_buffers(struct ao *ao)
276 {
277     struct priv *q = ao->priv;
278     ALint p;
279     int till_wrap = q->num_buffers - unqueue_buf;
280     alGetSourcei(source, AL_BUFFERS_PROCESSED, &p);
281     if (p >= till_wrap) {
282         alSourceUnqueueBuffers(source, till_wrap, &buffers[unqueue_buf]);
283         unqueue_buf = 0;
284         p -= till_wrap;
285     }
286     if (p) {
287         alSourceUnqueueBuffers(source, p, &buffers[unqueue_buf]);
288         unqueue_buf += p;
289     }
290 }
291 
reset(struct ao * ao)292 static void reset(struct ao *ao)
293 {
294     alSourceStop(source);
295     unqueue_buffers(ao);
296 }
297 
audio_set_pause(struct ao * ao,bool pause)298 static bool audio_set_pause(struct ao *ao, bool pause)
299 {
300     if (pause) {
301         alSourcePause(source);
302     } else {
303         alSourcePlay(source);
304     }
305     return true;
306 }
307 
audio_write(struct ao * ao,void ** data,int samples)308 static bool audio_write(struct ao *ao, void **data, int samples)
309 {
310     struct priv *p = ao->priv;
311 
312     int num = (samples + p->num_samples - 1) / p->num_samples;
313 
314     for (int i = 0; i < num; i++) {
315         char *d = *data;
316         buffer_size[cur_buf] =
317             MPMIN(samples - i * p->num_samples, p->num_samples);
318         d += i * buffer_size[cur_buf] * ao->sstride;
319         alBufferData(buffers[cur_buf], p->al_format, d,
320             buffer_size[cur_buf] * ao->sstride, ao->samplerate);
321         alSourceQueueBuffers(source, 1, &buffers[cur_buf]);
322         cur_buf = (cur_buf + 1) % p->num_buffers;
323     }
324 
325     return true;
326 }
327 
audio_start(struct ao * ao)328 static void audio_start(struct ao *ao)
329 {
330     alSourcePlay(source);
331 }
332 
get_state(struct ao * ao,struct mp_pcm_state * state)333 static void get_state(struct ao *ao, struct mp_pcm_state *state)
334 {
335     struct priv *p = ao->priv;
336 
337     ALint queued;
338     unqueue_buffers(ao);
339     alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
340 
341     double source_offset = 0;
342     if(alIsExtensionPresent("AL_SOFT_source_latency")) {
343         ALdouble offsets[2];
344         LPALGETSOURCEDVSOFT alGetSourcedvSOFT = alGetProcAddress("alGetSourcedvSOFT");
345         alGetSourcedvSOFT(source, AL_SEC_OFFSET_LATENCY_SOFT, offsets);
346         // Additional latency to the play buffer, the remaining seconds to be
347         // played minus the offset (seconds already played)
348         source_offset = offsets[1] - offsets[0];
349     } else {
350         float offset = 0;
351         alGetSourcef(source, AL_SEC_OFFSET, &offset);
352         source_offset = -offset;
353     }
354 
355     int queued_samples = 0;
356     for (int i = 0, index = cur_buf; i < queued; ++i) {
357         queued_samples += buffer_size[index];
358         index = (index + 1) % p->num_buffers;
359     }
360 
361     state->delay = queued_samples / (double)ao->samplerate + source_offset;
362 
363     state->queued_samples = queued_samples;
364     state->free_samples = MPMAX(p->num_buffers - queued, 0) * p->num_samples;
365 
366     ALint source_state = 0;
367     alGetSourcei(source, AL_SOURCE_STATE, &source_state);
368     state->playing = source_state == AL_PLAYING;
369 }
370 
371 #define OPT_BASE_STRUCT struct priv
372 
373 const struct ao_driver audio_out_openal = {
374     .description = "OpenAL audio output",
375     .name      = "openal",
376     .init      = init,
377     .uninit    = uninit,
378     .control   = control,
379     .get_state = get_state,
380     .write     = audio_write,
381     .start     = audio_start,
382     .set_pause = audio_set_pause,
383     .reset     = reset,
384     .priv_size = sizeof(struct priv),
385     .priv_defaults = &(const struct priv) {
386         .num_buffers = 4,
387         .num_samples = 8192,
388         .direct_channels = 0,
389     },
390     .options = (const struct m_option[]) {
391         {"num-buffers", OPT_INT(num_buffers), M_RANGE(2, MAX_BUF)},
392         {"num-samples", OPT_INT(num_samples), M_RANGE(256, MAX_SAMPLES)},
393         {"direct-channels", OPT_FLAG(direct_channels)},
394         {0}
395     },
396     .options_prefix = "openal",
397 };
398