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