1 /*
2  * This file is part of mpv.
3  *
4  * mpv is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * mpv is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with mpv.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <math.h>
22 #include <assert.h>
23 
24 #include "mpv_talloc.h"
25 
26 #include "config.h"
27 #include "ao.h"
28 #include "internal.h"
29 #include "audio/format.h"
30 
31 #include "options/options.h"
32 #include "options/m_config_frontend.h"
33 #include "osdep/endian.h"
34 #include "common/msg.h"
35 #include "common/common.h"
36 #include "common/global.h"
37 
38 extern const struct ao_driver audio_out_oss;
39 extern const struct ao_driver audio_out_audiotrack;
40 extern const struct ao_driver audio_out_audiounit;
41 extern const struct ao_driver audio_out_coreaudio;
42 extern const struct ao_driver audio_out_coreaudio_exclusive;
43 extern const struct ao_driver audio_out_rsound;
44 extern const struct ao_driver audio_out_sndio;
45 extern const struct ao_driver audio_out_pulse;
46 extern const struct ao_driver audio_out_jack;
47 extern const struct ao_driver audio_out_openal;
48 extern const struct ao_driver audio_out_opensles;
49 extern const struct ao_driver audio_out_null;
50 extern const struct ao_driver audio_out_alsa;
51 extern const struct ao_driver audio_out_wasapi;
52 extern const struct ao_driver audio_out_pcm;
53 extern const struct ao_driver audio_out_lavc;
54 extern const struct ao_driver audio_out_sdl;
55 
56 static const struct ao_driver * const audio_out_drivers[] = {
57 // native:
58 #if HAVE_ANDROID
59     &audio_out_audiotrack,
60 #endif
61 #if HAVE_AUDIOUNIT
62     &audio_out_audiounit,
63 #endif
64 #if HAVE_COREAUDIO
65     &audio_out_coreaudio,
66 #endif
67 #if HAVE_PULSE
68     &audio_out_pulse,
69 #endif
70 #if HAVE_ALSA
71     &audio_out_alsa,
72 #endif
73 #if HAVE_WASAPI
74     &audio_out_wasapi,
75 #endif
76 #if HAVE_OSS_AUDIO
77     &audio_out_oss,
78 #endif
79     // wrappers:
80 #if HAVE_JACK
81     &audio_out_jack,
82 #endif
83 #if HAVE_OPENAL
84     &audio_out_openal,
85 #endif
86 #if HAVE_OPENSLES
87     &audio_out_opensles,
88 #endif
89 #if HAVE_SDL2_AUDIO
90     &audio_out_sdl,
91 #endif
92 #if HAVE_SNDIO
93     &audio_out_sndio,
94 #endif
95     &audio_out_null,
96 #if HAVE_COREAUDIO
97     &audio_out_coreaudio_exclusive,
98 #endif
99     &audio_out_pcm,
100     &audio_out_lavc,
101     NULL
102 };
103 
get_desc(struct m_obj_desc * dst,int index)104 static bool get_desc(struct m_obj_desc *dst, int index)
105 {
106     if (index >= MP_ARRAY_SIZE(audio_out_drivers) - 1)
107         return false;
108     const struct ao_driver *ao = audio_out_drivers[index];
109     *dst = (struct m_obj_desc) {
110         .name = ao->name,
111         .description = ao->description,
112         .priv_size = ao->priv_size,
113         .priv_defaults = ao->priv_defaults,
114         .options = ao->options,
115         .options_prefix = ao->options_prefix,
116         .global_opts = ao->global_opts,
117         .hidden = ao->encode,
118         .p = ao,
119     };
120     return true;
121 }
122 
123 // For the ao option
124 static const struct m_obj_list ao_obj_list = {
125     .get_desc = get_desc,
126     .description = "audio outputs",
127     .allow_unknown_entries = true,
128     .allow_trailer = true,
129     .disallow_positional_parameters = true,
130     .use_global_options = true,
131 };
132 
133 #define OPT_BASE_STRUCT struct ao_opts
134 const struct m_sub_options ao_conf = {
135     .opts = (const struct m_option[]) {
136         {"ao", OPT_SETTINGSLIST(audio_driver_list, &ao_obj_list),
137             .flags = UPDATE_AUDIO},
138         {"audio-device", OPT_STRING(audio_device), .flags = UPDATE_AUDIO},
139         {"audio-client-name", OPT_STRING(audio_client_name), .flags = UPDATE_AUDIO},
140         {"audio-buffer", OPT_DOUBLE(audio_buffer),
141             .flags = UPDATE_AUDIO, M_RANGE(0, 10)},
142         {0}
143     },
144     .size = sizeof(OPT_BASE_STRUCT),
145     .defaults = &(const OPT_BASE_STRUCT){
146         .audio_buffer = 0.2,
147         .audio_device = "auto",
148         .audio_client_name = "mpv",
149     },
150 };
151 
ao_alloc(bool probing,struct mpv_global * global,void (* wakeup_cb)(void * ctx),void * wakeup_ctx,char * name)152 static struct ao *ao_alloc(bool probing, struct mpv_global *global,
153                            void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
154                            char *name)
155 {
156     assert(wakeup_cb);
157 
158     struct mp_log *log = mp_log_new(NULL, global->log, "ao");
159     struct m_obj_desc desc;
160     if (!m_obj_list_find(&desc, &ao_obj_list, bstr0(name))) {
161         mp_msg(log, MSGL_ERR, "Audio output %s not found!\n", name);
162         talloc_free(log);
163         return NULL;
164     };
165     struct ao_opts *opts = mp_get_config_group(NULL, global, &ao_conf);
166     struct ao *ao = talloc_ptrtype(NULL, ao);
167     talloc_steal(ao, log);
168     *ao = (struct ao) {
169         .driver = desc.p,
170         .probing = probing,
171         .global = global,
172         .wakeup_cb = wakeup_cb,
173         .wakeup_ctx = wakeup_ctx,
174         .log = mp_log_new(ao, log, name),
175         .def_buffer = opts->audio_buffer,
176         .client_name = talloc_strdup(ao, opts->audio_client_name),
177     };
178     talloc_free(opts);
179     ao->priv = m_config_group_from_desc(ao, ao->log, global, &desc, name);
180     if (!ao->priv)
181         goto error;
182     ao_set_gain(ao, 1.0f);
183     return ao;
184 error:
185     talloc_free(ao);
186     return NULL;
187 }
188 
ao_init(bool probing,struct mpv_global * global,void (* wakeup_cb)(void * ctx),void * wakeup_ctx,struct encode_lavc_context * encode_lavc_ctx,int flags,int samplerate,int format,struct mp_chmap channels,char * dev,char * name)189 static struct ao *ao_init(bool probing, struct mpv_global *global,
190                           void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
191                           struct encode_lavc_context *encode_lavc_ctx, int flags,
192                           int samplerate, int format, struct mp_chmap channels,
193                           char *dev, char *name)
194 {
195     struct ao *ao = ao_alloc(probing, global, wakeup_cb, wakeup_ctx, name);
196     if (!ao)
197         return NULL;
198     ao->samplerate = samplerate;
199     ao->channels = channels;
200     ao->format = format;
201     ao->encode_lavc_ctx = encode_lavc_ctx;
202     ao->init_flags = flags;
203     if (ao->driver->encode != !!ao->encode_lavc_ctx)
204         goto fail;
205 
206     MP_VERBOSE(ao, "requested format: %d Hz, %s channels, %s\n",
207                ao->samplerate, mp_chmap_to_str(&ao->channels),
208                af_fmt_to_str(ao->format));
209 
210     ao->device = talloc_strdup(ao, dev);
211     ao->stream_silence = flags & AO_INIT_STREAM_SILENCE;
212 
213     init_buffer_pre(ao);
214 
215     int r = ao->driver->init(ao);
216     if (r < 0) {
217         // Silly exception for coreaudio spdif redirection
218         if (ao->redirect) {
219             char redirect[80], rdevice[80];
220             snprintf(redirect, sizeof(redirect), "%s", ao->redirect);
221             snprintf(rdevice, sizeof(rdevice), "%s", ao->device ? ao->device : "");
222             ao_uninit(ao);
223             return ao_init(probing, global, wakeup_cb, wakeup_ctx,
224                            encode_lavc_ctx, flags, samplerate, format, channels,
225                            rdevice, redirect);
226         }
227         goto fail;
228     }
229     ao->driver_initialized = true;
230 
231     ao->sstride = af_fmt_to_bytes(ao->format);
232     ao->num_planes = 1;
233     if (af_fmt_is_planar(ao->format)) {
234         ao->num_planes = ao->channels.num;
235     } else {
236         ao->sstride *= ao->channels.num;
237     }
238     ao->bps = ao->samplerate * ao->sstride;
239 
240     if (ao->device_buffer <= 0 && ao->driver->write) {
241         MP_ERR(ao, "Device buffer size not set.\n");
242         goto fail;
243     }
244     if (ao->device_buffer)
245         MP_VERBOSE(ao, "device buffer: %d samples.\n", ao->device_buffer);
246     ao->buffer = MPMAX(ao->device_buffer, ao->def_buffer * ao->samplerate);
247     ao->buffer = MPMAX(ao->buffer, 1);
248 
249     int align = af_format_sample_alignment(ao->format);
250     ao->buffer = (ao->buffer + align - 1) / align * align;
251     MP_VERBOSE(ao, "using soft-buffer of %d samples.\n", ao->buffer);
252 
253     if (!init_buffer_post(ao))
254         goto fail;
255     return ao;
256 
257 fail:
258     ao_uninit(ao);
259     return NULL;
260 }
261 
split_ao_device(void * tmp,char * opt,char ** out_ao,char ** out_dev)262 static void split_ao_device(void *tmp, char *opt, char **out_ao, char **out_dev)
263 {
264     *out_ao = NULL;
265     *out_dev = NULL;
266     if (!opt)
267         return;
268     if (!opt[0] || strcmp(opt, "auto") == 0)
269         return;
270     // Split on "/". If "/" is the final character, or absent, out_dev is NULL.
271     bstr b_dev, b_ao;
272     bstr_split_tok(bstr0(opt), "/", &b_ao, &b_dev);
273     if (b_dev.len > 0)
274         *out_dev = bstrto0(tmp, b_dev);
275     *out_ao = bstrto0(tmp, b_ao);
276 }
277 
ao_init_best(struct mpv_global * global,int init_flags,void (* wakeup_cb)(void * ctx),void * wakeup_ctx,struct encode_lavc_context * encode_lavc_ctx,int samplerate,int format,struct mp_chmap channels)278 struct ao *ao_init_best(struct mpv_global *global,
279                         int init_flags,
280                         void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
281                         struct encode_lavc_context *encode_lavc_ctx,
282                         int samplerate, int format, struct mp_chmap channels)
283 {
284     void *tmp = talloc_new(NULL);
285     struct ao_opts *opts = mp_get_config_group(tmp, global, &ao_conf);
286     struct mp_log *log = mp_log_new(tmp, global->log, "ao");
287     struct ao *ao = NULL;
288     struct m_obj_settings *ao_list = NULL;
289     int ao_num = 0;
290 
291     for (int n = 0; opts->audio_driver_list && opts->audio_driver_list[n].name; n++)
292         MP_TARRAY_APPEND(tmp, ao_list, ao_num, opts->audio_driver_list[n]);
293 
294     bool forced_dev = false;
295     char *pref_ao, *pref_dev;
296     split_ao_device(tmp, opts->audio_device, &pref_ao, &pref_dev);
297     if (!ao_num && pref_ao) {
298         // Reuse the autoselection code
299         MP_TARRAY_APPEND(tmp, ao_list, ao_num,
300             (struct m_obj_settings){.name = pref_ao});
301         forced_dev = true;
302     }
303 
304     bool autoprobe = ao_num == 0;
305 
306     // Something like "--ao=a,b," means do autoprobing after a and b fail.
307     if (ao_num && strlen(ao_list[ao_num - 1].name) == 0) {
308         ao_num -= 1;
309         autoprobe = true;
310     }
311 
312     if (autoprobe) {
313         for (int n = 0; audio_out_drivers[n]; n++) {
314             const struct ao_driver *driver = audio_out_drivers[n];
315             if (driver == &audio_out_null)
316                 break;
317             MP_TARRAY_APPEND(tmp, ao_list, ao_num,
318                 (struct m_obj_settings){.name = (char *)driver->name});
319         }
320     }
321 
322     if (init_flags & AO_INIT_NULL_FALLBACK) {
323         MP_TARRAY_APPEND(tmp, ao_list, ao_num,
324             (struct m_obj_settings){.name = "null"});
325     }
326 
327     for (int n = 0; n < ao_num; n++) {
328         struct m_obj_settings *entry = &ao_list[n];
329         bool probing = n + 1 != ao_num;
330         mp_verbose(log, "Trying audio driver '%s'\n", entry->name);
331         char *dev = NULL;
332         if (pref_ao && pref_dev && strcmp(entry->name, pref_ao) == 0) {
333             dev = pref_dev;
334             mp_verbose(log, "Using preferred device '%s'\n", dev);
335         }
336         ao = ao_init(probing, global, wakeup_cb, wakeup_ctx, encode_lavc_ctx,
337                      init_flags, samplerate, format, channels, dev, entry->name);
338         if (ao)
339             break;
340         if (!probing)
341             mp_err(log, "Failed to initialize audio driver '%s'\n", entry->name);
342         if (dev && forced_dev) {
343             mp_err(log, "This audio driver/device was forced with the "
344                         "--audio-device option.\nTry unsetting it.\n");
345         }
346     }
347 
348     talloc_free(tmp);
349     return ao;
350 }
351 
352 // Query the AO_EVENT_*s as requested by the events parameter, and return them.
ao_query_and_reset_events(struct ao * ao,int events)353 int ao_query_and_reset_events(struct ao *ao, int events)
354 {
355     return atomic_fetch_and(&ao->events_, ~(unsigned)events) & events;
356 }
357 
358 // Returns events that were set by this calls.
ao_add_events(struct ao * ao,int events)359 int ao_add_events(struct ao *ao, int events)
360 {
361     unsigned prev_events = atomic_fetch_or(&ao->events_, events);
362     unsigned new = events & ~prev_events;
363     if (new)
364         ao->wakeup_cb(ao->wakeup_ctx);
365     return new;
366 }
367 
368 // Request that the player core destroys and recreates the AO. Fully thread-safe.
ao_request_reload(struct ao * ao)369 void ao_request_reload(struct ao *ao)
370 {
371     ao_add_events(ao, AO_EVENT_RELOAD);
372 }
373 
374 // Notify the player that the device list changed. Fully thread-safe.
ao_hotplug_event(struct ao * ao)375 void ao_hotplug_event(struct ao *ao)
376 {
377     ao_add_events(ao, AO_EVENT_HOTPLUG);
378 }
379 
ao_chmap_sel_adjust(struct ao * ao,const struct mp_chmap_sel * s,struct mp_chmap * map)380 bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
381                          struct mp_chmap *map)
382 {
383     MP_VERBOSE(ao, "Channel layouts:\n");
384     mp_chmal_sel_log(s, ao->log, MSGL_V);
385     bool r = mp_chmap_sel_adjust(s, map);
386     if (r)
387         MP_VERBOSE(ao, "result: %s\n", mp_chmap_to_str(map));
388     return r;
389 }
390 
391 // safe_multichannel=true behaves like ao_chmap_sel_adjust.
392 // safe_multichannel=false is a helper for callers which do not support safe
393 // handling of arbitrary channel layouts. If the multichannel layouts are not
394 // considered "always safe" (e.g. HDMI), then allow only stereo or mono, if
395 // they are part of the list in *s.
ao_chmap_sel_adjust2(struct ao * ao,const struct mp_chmap_sel * s,struct mp_chmap * map,bool safe_multichannel)396 bool ao_chmap_sel_adjust2(struct ao *ao, const struct mp_chmap_sel *s,
397                           struct mp_chmap *map, bool safe_multichannel)
398 {
399     if (!safe_multichannel && (ao->init_flags & AO_INIT_SAFE_MULTICHANNEL_ONLY)) {
400         struct mp_chmap res = *map;
401         if (mp_chmap_sel_adjust(s, &res)) {
402             if (!mp_chmap_equals(&res, &(struct mp_chmap)MP_CHMAP_INIT_MONO) &&
403                 !mp_chmap_equals(&res, &(struct mp_chmap)MP_CHMAP_INIT_STEREO))
404             {
405                 MP_VERBOSE(ao, "Disabling multichannel output.\n");
406                 *map = (struct mp_chmap)MP_CHMAP_INIT_STEREO;
407             }
408         }
409     }
410 
411     return ao_chmap_sel_adjust(ao, s, map);
412 }
413 
ao_chmap_sel_get_def(struct ao * ao,const struct mp_chmap_sel * s,struct mp_chmap * map,int num)414 bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
415                           struct mp_chmap *map, int num)
416 {
417     return mp_chmap_sel_get_def(s, map, num);
418 }
419 
420 // --- The following functions just return immutable information.
421 
ao_get_format(struct ao * ao,int * samplerate,int * format,struct mp_chmap * channels)422 void ao_get_format(struct ao *ao,
423                    int *samplerate, int *format, struct mp_chmap *channels)
424 {
425     *samplerate = ao->samplerate;
426     *format = ao->format;
427     *channels = ao->channels;
428 }
429 
ao_get_name(struct ao * ao)430 const char *ao_get_name(struct ao *ao)
431 {
432     return ao->driver->name;
433 }
434 
ao_get_description(struct ao * ao)435 const char *ao_get_description(struct ao *ao)
436 {
437     return ao->driver->description;
438 }
439 
ao_untimed(struct ao * ao)440 bool ao_untimed(struct ao *ao)
441 {
442     return ao->untimed;
443 }
444 
445 // ---
446 
447 struct ao_hotplug {
448     struct mpv_global *global;
449     void (*wakeup_cb)(void *ctx);
450     void *wakeup_ctx;
451     // A single AO instance is used to listen to hotplug events. It wouldn't
452     // make much sense to allow multiple AO drivers; all sane platforms have
453     // a single such audio API.
454     // This is _not_ the same AO instance as used for playing audio.
455     struct ao *ao;
456     // cached
457     struct ao_device_list *list;
458     bool needs_update;
459 };
460 
ao_hotplug_create(struct mpv_global * global,void (* wakeup_cb)(void * ctx),void * wakeup_ctx)461 struct ao_hotplug *ao_hotplug_create(struct mpv_global *global,
462                                      void (*wakeup_cb)(void *ctx),
463                                      void *wakeup_ctx)
464 {
465     struct ao_hotplug *hp = talloc_ptrtype(NULL, hp);
466     *hp = (struct ao_hotplug){
467         .global = global,
468         .wakeup_cb = wakeup_cb,
469         .wakeup_ctx = wakeup_ctx,
470         .needs_update = true,
471     };
472     return hp;
473 }
474 
get_devices(struct ao * ao,struct ao_device_list * list)475 static void get_devices(struct ao *ao, struct ao_device_list *list)
476 {
477     if (ao->driver->list_devs) {
478         ao->driver->list_devs(ao, list);
479     } else {
480         ao_device_list_add(list, ao, &(struct ao_device_desc){"", ""});
481     }
482 }
483 
ao_hotplug_check_update(struct ao_hotplug * hp)484 bool ao_hotplug_check_update(struct ao_hotplug *hp)
485 {
486     if (hp->ao && ao_query_and_reset_events(hp->ao, AO_EVENT_HOTPLUG)) {
487         hp->needs_update = true;
488         return true;
489     }
490     return false;
491 }
492 
493 // The return value is valid until the next call to this API.
ao_hotplug_get_device_list(struct ao_hotplug * hp)494 struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp)
495 {
496     if (hp->list && !hp->needs_update)
497         return hp->list;
498 
499     talloc_free(hp->list);
500     struct ao_device_list *list = talloc_zero(hp, struct ao_device_list);
501     hp->list = list;
502 
503     MP_TARRAY_APPEND(list, list->devices, list->num_devices,
504         (struct ao_device_desc){"auto", "Autoselect device"});
505 
506     for (int n = 0; audio_out_drivers[n]; n++) {
507         const struct ao_driver *d = audio_out_drivers[n];
508         if (d == &audio_out_null)
509             break; // don't add unsafe/special entries
510 
511         struct ao *ao = ao_alloc(true, hp->global, hp->wakeup_cb, hp->wakeup_ctx,
512                                  (char *)d->name);
513         if (!ao)
514             continue;
515 
516         if (ao->driver->hotplug_init) {
517             if (!hp->ao && ao->driver->hotplug_init(ao) >= 0)
518                 hp->ao = ao; // keep this one
519             if (hp->ao && hp->ao->driver == d)
520                 get_devices(hp->ao, list);
521         } else {
522             get_devices(ao, list);
523         }
524         if (ao != hp->ao)
525             talloc_free(ao);
526     }
527     hp->needs_update = false;
528     return list;
529 }
530 
ao_device_list_add(struct ao_device_list * list,struct ao * ao,struct ao_device_desc * e)531 void ao_device_list_add(struct ao_device_list *list, struct ao *ao,
532                         struct ao_device_desc *e)
533 {
534     struct ao_device_desc c = *e;
535     const char *dname = ao->driver->name;
536     char buf[80];
537     if (!c.desc || !c.desc[0]) {
538         if (c.name && c.name[0]) {
539             c.desc = c.name;
540         } else if (list->num_devices) {
541             // Assume this is the default device.
542             snprintf(buf, sizeof(buf), "Default (%s)", dname);
543             c.desc = buf;
544         } else {
545             // First default device (and maybe the only one).
546             c.desc = "Default";
547         }
548     }
549     c.name = (c.name && c.name[0]) ? talloc_asprintf(list, "%s/%s", dname, c.name)
550                                    : talloc_strdup(list, dname);
551     c.desc = talloc_strdup(list, c.desc);
552     MP_TARRAY_APPEND(list, list->devices, list->num_devices, c);
553 }
554 
ao_hotplug_destroy(struct ao_hotplug * hp)555 void ao_hotplug_destroy(struct ao_hotplug *hp)
556 {
557     if (!hp)
558         return;
559     if (hp->ao && hp->ao->driver->hotplug_uninit)
560         hp->ao->driver->hotplug_uninit(hp->ao);
561     talloc_free(hp->ao);
562     talloc_free(hp);
563 }
564 
dummy_wakeup(void * ctx)565 static void dummy_wakeup(void *ctx)
566 {
567 }
568 
ao_print_devices(struct mpv_global * global,struct mp_log * log)569 void ao_print_devices(struct mpv_global *global, struct mp_log *log)
570 {
571     struct ao_hotplug *hp = ao_hotplug_create(global, dummy_wakeup, NULL);
572     struct ao_device_list *list = ao_hotplug_get_device_list(hp);
573     mp_info(log, "List of detected audio devices:\n");
574     for (int n = 0; n < list->num_devices; n++) {
575         struct ao_device_desc *desc = &list->devices[n];
576         mp_info(log, "  '%s' (%s)\n", desc->name, desc->desc);
577     }
578     ao_hotplug_destroy(hp);
579 }
580 
ao_set_gain(struct ao * ao,float gain)581 void ao_set_gain(struct ao *ao, float gain)
582 {
583     atomic_store(&ao->gain, gain);
584 }
585 
586 #define MUL_GAIN_i(d, num_samples, gain, low, center, high)                     \
587     for (int n = 0; n < (num_samples); n++)                                     \
588         (d)[n] = MPCLAMP(                                                       \
589             ((((int64_t)((d)[n]) - (center)) * (gain) + 128) >> 8) + (center),  \
590             (low), (high))
591 
592 #define MUL_GAIN_f(d, num_samples, gain)                                        \
593     for (int n = 0; n < (num_samples); n++)                                     \
594         (d)[n] = MPCLAMP(((d)[n]) * (gain), -1.0, 1.0)
595 
process_plane(struct ao * ao,void * data,int num_samples)596 static void process_plane(struct ao *ao, void *data, int num_samples)
597 {
598     float gain = atomic_load_explicit(&ao->gain, memory_order_relaxed);
599     int gi = lrint(256.0 * gain);
600     if (gi == 256)
601         return;
602     switch (af_fmt_from_planar(ao->format)) {
603     case AF_FORMAT_U8:
604         MUL_GAIN_i((uint8_t *)data, num_samples, gi, 0, 128, 255);
605         break;
606     case AF_FORMAT_S16:
607         MUL_GAIN_i((int16_t *)data, num_samples, gi, INT16_MIN, 0, INT16_MAX);
608         break;
609     case AF_FORMAT_S32:
610         MUL_GAIN_i((int32_t *)data, num_samples, gi, INT32_MIN, 0, INT32_MAX);
611         break;
612     case AF_FORMAT_FLOAT:
613         MUL_GAIN_f((float *)data, num_samples, gain);
614         break;
615     case AF_FORMAT_DOUBLE:
616         MUL_GAIN_f((double *)data, num_samples, gain);
617         break;
618     default:;
619         // all other sample formats are simply not supported
620     }
621 }
622 
ao_post_process_data(struct ao * ao,void ** data,int num_samples)623 void ao_post_process_data(struct ao *ao, void **data, int num_samples)
624 {
625     bool planar = af_fmt_is_planar(ao->format);
626     int planes = planar ? ao->channels.num : 1;
627     int plane_samples = num_samples * (planar ? 1: ao->channels.num);
628     for (int n = 0; n < planes; n++)
629         process_plane(ao, data[n], plane_samples);
630 }
631 
get_conv_type(struct ao_convert_fmt * fmt)632 static int get_conv_type(struct ao_convert_fmt *fmt)
633 {
634     if (af_fmt_to_bytes(fmt->src_fmt) * 8 == fmt->dst_bits && !fmt->pad_msb)
635         return 0; // passthrough
636     if (fmt->src_fmt == AF_FORMAT_S32 && fmt->dst_bits == 24 && !fmt->pad_msb)
637         return 1; // simple 32->24 bit conversion
638     if (fmt->src_fmt == AF_FORMAT_S32 && fmt->dst_bits == 32 && fmt->pad_msb == 8)
639         return 2; // simple 32->24 bit conversion, with MSB padding
640     return -1; // unsupported
641 }
642 
643 // Check whether ao_convert_inplace() can be called. As an exception, the
644 // planar-ness of the sample format and the number of channels is ignored.
645 // All other parameters must be as passed to ao_convert_inplace().
ao_can_convert_inplace(struct ao_convert_fmt * fmt)646 bool ao_can_convert_inplace(struct ao_convert_fmt *fmt)
647 {
648     return get_conv_type(fmt) >= 0;
649 }
650 
ao_need_conversion(struct ao_convert_fmt * fmt)651 bool ao_need_conversion(struct ao_convert_fmt *fmt)
652 {
653     return get_conv_type(fmt) != 0;
654 }
655 
656 // The LSB is always ignored.
657 #if BYTE_ORDER == BIG_ENDIAN
658 #define SHIFT24(x) ((3-(x))*8)
659 #else
660 #define SHIFT24(x) (((x)+1)*8)
661 #endif
662 
convert_plane(int type,void * data,int num_samples)663 static void convert_plane(int type, void *data, int num_samples)
664 {
665     switch (type) {
666     case 0:
667         break;
668     case 1: /* fall through */
669     case 2: {
670         int bytes = type == 1 ? 3 : 4;
671         for (int s = 0; s < num_samples; s++) {
672             uint32_t val = *((uint32_t *)data + s);
673             uint8_t *ptr = (uint8_t *)data + s * bytes;
674             ptr[0] = val >> SHIFT24(0);
675             ptr[1] = val >> SHIFT24(1);
676             ptr[2] = val >> SHIFT24(2);
677             if (type == 2)
678                 ptr[3] = 0;
679         }
680         break;
681     }
682     default:
683         abort();
684     }
685 }
686 
687 // data[n] contains the pointer to the first sample of the n-th plane, in the
688 // format implied by fmt->src_fmt. src_fmt also controls whether the data is
689 // all in one plane, or if there is a plane per channel.
ao_convert_inplace(struct ao_convert_fmt * fmt,void ** data,int num_samples)690 void ao_convert_inplace(struct ao_convert_fmt *fmt, void **data, int num_samples)
691 {
692     int type = get_conv_type(fmt);
693     bool planar = af_fmt_is_planar(fmt->src_fmt);
694     int planes = planar ? fmt->channels : 1;
695     int plane_samples = num_samples * (planar ? 1: fmt->channels);
696     for (int n = 0; n < planes; n++)
697         convert_plane(type, data[n], plane_samples);
698 }
699