From 3c2ca0cecc7f88fb94449605b7b33fbdbb855ed0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 20 Jan 2015 14:25:47 +0100 Subject: 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. --- audio/out/ao.c | 158 ++++++++++++++++++++++++++------------------------------- 1 file changed, 73 insertions(+), 85 deletions(-) diff --git a/audio/out/ao.c b/audio/out/ao.c index 26cfde212e..c749cd0701 100644 --- a/audio/out/ao.c +++ b/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; - } - - match_ao_driver(ao->driver->name, opts->audio_device, &ao->device); - ao->device = talloc_strdup(ao, ao->device); + if (ao->driver->encode != !!ao->encode_lavc_ctx) + goto fail; - 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; } -- cgit v1.2.3