mirror of
https://github.com/mpv-player/mpv
synced 2024-12-19 05:15:12 +00:00
ao: refactor --audio-device selection code
This removes the slightly duplicated code for picking the required AO driver if --audio-device forces one. Now --audio-device reuses the same code as --ao for this. As a consequence, ao_alloc_pb() and ao_create() can be merged into ao_init(). Although the ao_init() argument list, which is already pretty big, grows by one, it's better than having all these similar sounding functions around. Actually, I just wanted to do the change the following commit will do, but I found this code was more of a mess than it had to be.
This commit is contained in:
parent
84928b049d
commit
3c2ca0cecc
158
audio/out/ao.c
158
audio/out/ao.c
@ -125,30 +125,6 @@ const struct m_obj_list ao_obj_list = {
|
||||
.allow_trailer = true,
|
||||
};
|
||||
|
||||
// Return true if the ao with the given name matches the opt (--audio-device
|
||||
// contents). If opt is empty, matching always succeeds. If out_device is not
|
||||
// NULL, it will be set to the implied audio device (or NULL).
|
||||
static bool match_ao_driver(const char *ao_name, char *opt, char **out_device)
|
||||
{
|
||||
bstr ao_nameb = bstr0(ao_name);
|
||||
bstr optb = bstr0(opt);
|
||||
|
||||
char *dummy;
|
||||
if (!out_device)
|
||||
out_device = &dummy;
|
||||
*out_device = NULL;
|
||||
|
||||
if (!optb.len || bstr_equals0(optb, "auto"))
|
||||
return true;
|
||||
if (!bstr_startswith(optb, ao_nameb))
|
||||
return false;
|
||||
if (optb.len > ao_nameb.len && optb.start[ao_nameb.len] != '/')
|
||||
return false;
|
||||
char *split = strchr(opt, '/');
|
||||
*out_device = split ? split + 1 : NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct ao *ao_alloc(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx, char *name, char **args)
|
||||
{
|
||||
@ -181,11 +157,11 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ao *ao_alloc_pb(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels,
|
||||
char *name, char **args)
|
||||
static struct ao *ao_init(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels,
|
||||
char *dev, char *name, char **args)
|
||||
{
|
||||
struct MPOpts *opts = global->opts;
|
||||
struct ao *ao = ao_alloc(probing, global, input_ctx, name, args);
|
||||
@ -195,32 +171,33 @@ static struct ao *ao_alloc_pb(bool probing, struct mpv_global *global,
|
||||
ao->channels = channels;
|
||||
ao->format = format;
|
||||
ao->encode_lavc_ctx = encode_lavc_ctx;
|
||||
if (ao->driver->encode != !!ao->encode_lavc_ctx) {
|
||||
talloc_free(ao);
|
||||
return NULL;
|
||||
}
|
||||
if (ao->driver->encode != !!ao->encode_lavc_ctx)
|
||||
goto fail;
|
||||
|
||||
match_ao_driver(ao->driver->name, opts->audio_device, &ao->device);
|
||||
ao->device = talloc_strdup(ao, ao->device);
|
||||
|
||||
ao->client_name = talloc_strdup(ao, opts->audio_client_name);
|
||||
|
||||
return ao;
|
||||
}
|
||||
|
||||
static int ao_init(struct ao *ao)
|
||||
{
|
||||
MP_VERBOSE(ao, "requested format: %d Hz, %s channels, %s\n",
|
||||
ao->samplerate, mp_chmap_to_str(&ao->channels),
|
||||
af_fmt_to_str(ao->format));
|
||||
|
||||
ao->device = talloc_strdup(ao, dev);
|
||||
ao->client_name = talloc_strdup(ao, opts->audio_client_name);
|
||||
|
||||
ao->api = ao->driver->play ? &ao_api_push : &ao_api_pull;
|
||||
ao->api_priv = talloc_zero_size(ao, ao->api->priv_size);
|
||||
assert(!ao->api->priv_defaults && !ao->api->options);
|
||||
|
||||
int r = ao->driver->init(ao);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r < 0) {
|
||||
// Silly exception for coreaudio spdif redirection
|
||||
if (ao->redirect) {
|
||||
char redirect[80], rdevice[80];
|
||||
snprintf(redirect, sizeof(redirect), "%s", ao->redirect);
|
||||
snprintf(rdevice, sizeof(rdevice), "%s", ao->device ? ao->device : "");
|
||||
talloc_free(ao);
|
||||
return ao_init(probing, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, rdevice, redirect, args);
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ao->sstride = af_fmt2bps(ao->format);
|
||||
ao->num_planes = 1;
|
||||
@ -238,79 +215,90 @@ static int ao_init(struct ao *ao)
|
||||
ao->buffer = MPMAX(ao->device_buffer, ao->def_buffer * ao->samplerate);
|
||||
MP_VERBOSE(ao, "using soft-buffer of %d samples.\n", ao->buffer);
|
||||
|
||||
return ao->api->init(ao);
|
||||
}
|
||||
if (ao->api->init(ao) < 0)
|
||||
goto fail;
|
||||
return ao;
|
||||
|
||||
static struct ao *ao_create(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels,
|
||||
char *name, char **args)
|
||||
{
|
||||
struct ao *ao = ao_alloc_pb(probing, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, name, args);
|
||||
if (ao && ao_init(ao) >= 0)
|
||||
return ao;
|
||||
// Silly exception for coreaudio spdif redirection
|
||||
if (ao && ao->redirect) {
|
||||
char redirect[80], device[80];
|
||||
snprintf(redirect, sizeof(redirect), "%s", ao->redirect);
|
||||
snprintf(device, sizeof(device), "%s", ao->device ? ao->device : "");
|
||||
talloc_free(ao);
|
||||
ao = ao_alloc_pb(probing, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, redirect, args);
|
||||
if (ao) {
|
||||
ao->device = talloc_strdup(ao, device);
|
||||
if (ao_init(ao) >= 0)
|
||||
return ao;
|
||||
}
|
||||
}
|
||||
fail:
|
||||
talloc_free(ao);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void split_ao_device(void *tmp, char *opt, char **out_ao, char **out_dev)
|
||||
{
|
||||
*out_ao = NULL;
|
||||
*out_dev = NULL;
|
||||
if (!opt)
|
||||
return;
|
||||
if (!opt[0] || strcmp(opt, "auto") == 0)
|
||||
return;
|
||||
// Split on "/". If there's no "/", leave out_device NULL.
|
||||
bstr b_dev, b_ao;
|
||||
if (bstr_split_tok(bstr0(opt), "/", &b_ao, &b_dev))
|
||||
*out_dev = bstrto0(tmp, b_dev);
|
||||
*out_ao = bstrto0(tmp, b_ao);
|
||||
}
|
||||
|
||||
struct ao *ao_init_best(struct mpv_global *global,
|
||||
struct input_ctx *input_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels)
|
||||
{
|
||||
struct MPOpts *opts = global->opts;
|
||||
struct mp_log *log = mp_log_new(NULL, global->log, "ao");
|
||||
void *tmp = talloc_new(NULL);
|
||||
struct mp_log *log = mp_log_new(tmp, global->log, "ao");
|
||||
struct ao *ao = NULL;
|
||||
struct m_obj_settings *ao_list = opts->audio_driver_list;
|
||||
|
||||
bool forced_dev = false;
|
||||
char *pref_ao, *pref_dev;
|
||||
split_ao_device(tmp, opts->audio_device, &pref_ao, &pref_dev);
|
||||
if (!(ao_list && ao_list[0].name) && pref_ao) {
|
||||
// Reuse the autoselection code
|
||||
ao_list = talloc_zero_array(tmp, struct m_obj_settings, 2);
|
||||
ao_list[0].name = pref_ao;
|
||||
forced_dev = true;
|
||||
}
|
||||
|
||||
if (ao_list && ao_list[0].name) {
|
||||
for (int n = 0; ao_list[n].name; n++) {
|
||||
if (strlen(ao_list[n].name) == 0)
|
||||
goto autoprobe;
|
||||
mp_verbose(log, "Trying preferred audio driver '%s'\n",
|
||||
ao_list[n].name);
|
||||
ao = ao_create(false, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels,
|
||||
ao_list[n].name, ao_list[n].attribs);
|
||||
char *dev = NULL;
|
||||
if (pref_ao && strcmp(ao_list[n].name, pref_ao) == 0)
|
||||
dev = pref_dev;
|
||||
if (dev)
|
||||
mp_verbose(log, "Using preferred device '%s'\n", dev);
|
||||
ao = ao_init(false, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, dev,
|
||||
ao_list[n].name, ao_list[n].attribs);
|
||||
if (ao)
|
||||
goto done;
|
||||
mp_warn(log, "Failed to initialize audio driver '%s'\n",
|
||||
ao_list[n].name);
|
||||
if (forced_dev) {
|
||||
mp_err(log, "This audio driver/device was forced with the "
|
||||
"--audio-device option.\n"
|
||||
"Try unsetting it.\n");
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
autoprobe: ;
|
||||
// now try the rest...
|
||||
bool matched_dev = false;
|
||||
for (int i = 0; audio_out_drivers[i]; i++) {
|
||||
char *name = (char *)audio_out_drivers[i]->name;
|
||||
if (!match_ao_driver(name, opts->audio_device, NULL))
|
||||
continue;
|
||||
matched_dev = true;
|
||||
ao = ao_create(true, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, name, NULL);
|
||||
const struct ao_driver *driver = audio_out_drivers[i];
|
||||
ao = ao_init(true, global, input_ctx, encode_lavc_ctx, samplerate,
|
||||
format, channels, NULL, (char *)driver->name, NULL);
|
||||
if (ao)
|
||||
goto done;
|
||||
}
|
||||
if (!matched_dev)
|
||||
mp_err(log, "--audio-device option refers to missing output driver.\n");
|
||||
|
||||
done:
|
||||
talloc_free(log);
|
||||
talloc_free(tmp);
|
||||
return ao;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user