From a93fb460cdea2951bae039b8e004b5042c337d05 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 6 May 2016 17:20:02 +0200 Subject: ao_alsa: add more shitty workarounds This reportedly makes it work on ODROID-C2. The idea for this hack is taken from kodi; they unconditionally set some or all of those flags. I don't trust ALSA enough to hope that setting these flags couldn't break something else, so we try without them first. It's not clear whether this is a driver bug or a bug in the ALSA libs. There is no ALSA bug tracker (the ALSA website has had a dead link to a deleted bug tracker fo years). There's not much we can do other than piling up ridiculous hacks. At least I think that at this point invalid API usage by mpv can be excluded as a cause. ALSA might be the worst audio API ever. --- audio/out/ao_alsa.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'audio') diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 47ff51f83d..d09f5fc499 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -538,7 +538,7 @@ static char *append_params(void *ta_parent, const char *device, const char *p) abort(); } -static int try_open_device(struct ao *ao, const char *device) +static int try_open_device(struct ao *ao, const char *device, int mode) { struct priv *p = ao->priv; int err; @@ -552,7 +552,7 @@ static int try_open_device(struct ao *ao, const char *device) map_iec958_srate(ao->samplerate)); const char *ac3_device = append_params(tmp, device, params); MP_VERBOSE(ao, "opening device '%s' => '%s'\n", device, ac3_device); - err = snd_pcm_open(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, 0); + err = snd_pcm_open(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, mode); if (err < 0) { // Some spdif-capable devices do not accept the AES0 parameter, // and instead require the iec958 pseudo-device (they will play @@ -565,13 +565,13 @@ static int try_open_device(struct ao *ao, const char *device) MP_VERBOSE(ao, "got error %d; opening iec fallback device '%s'\n", err, ac3_device); err = snd_pcm_open - (&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, 0); + (&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, mode); } } talloc_free(tmp); } else { MP_VERBOSE(ao, "opening device '%s'\n", device); - err = snd_pcm_open(&p->alsa, device, SND_PCM_STREAM_PLAYBACK, 0); + err = snd_pcm_open(&p->alsa, device, SND_PCM_STREAM_PLAYBACK, mode); } return err; @@ -596,9 +596,12 @@ static void uninit(struct ao *ao) alsa_error: ; } -static int init_device(struct ao *ao) +#define INIT_DEVICE_ERR_GENERIC -1 +#define INIT_DEVICE_ERR_HWPARAMS -2 +static int init_device(struct ao *ao, int mode) { struct priv *p = ao->priv; + int ret = INIT_DEVICE_ERR_GENERIC; char *tmp; size_t tmp_s; int err; @@ -612,7 +615,7 @@ static int init_device(struct ao *ao) if (p->cfg_device && p->cfg_device[0]) device = p->cfg_device; - err = try_open_device(ao, device); + err = try_open_device(ao, device, mode); CHECK_ALSA_ERROR("Playback open error"); err = snd_pcm_dump(p->alsa, p->output); @@ -727,7 +730,9 @@ static int init_device(struct ao *ao) /* finally install hardware parameters */ err = snd_pcm_hw_params(p->alsa, alsa_hwparams); + ret = INIT_DEVICE_ERR_HWPARAMS; CHECK_ALSA_ERROR("Unable to set hw-parameters"); + ret = INIT_DEVICE_ERR_GENERIC; dump_hw_params(ao, MSGL_DEBUG, "Final HW params:\n", alsa_hwparams); if (set_chmap(ao, &dev_chmap, num_channels) < 0) @@ -784,7 +789,7 @@ static int init_device(struct ao *ao) alsa_error: uninit(ao); - return -1; + return ret; } static int init(struct ao *ao) @@ -795,7 +800,18 @@ static int init(struct ao *ao) MP_VERBOSE(ao, "using ALSA version: %s\n", snd_asoundlib_version()); - int r = init_device(ao); + int mode = 0; + int r = init_device(ao, mode); + if (r == INIT_DEVICE_ERR_HWPARAMS) { + // With some drivers, ALSA appears to be unable to set valid hwparams, + // but they work if at least SND_PCM_NO_AUTO_FORMAT is set. Also, it + // appears you can set this flag only on opening a device, thus there + // is the need to retry opening the device. + MP_WARN(ao, "Attempting to work around even more ALSA bugs...\n"); + mode |= SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT | + SND_PCM_NO_AUTO_RESAMPLE; + r = init_device(ao, mode); + } // Sometimes, ALSA will advertise certain chmaps, but it's not possible to // set them. This can happen with dmix: as of alsa 1.0.29, dmix can do @@ -817,7 +833,7 @@ static int init(struct ao *ao) MP_VERBOSE(ao, "Working around braindead dmix multichannel behavior.\n"); uninit(ao); ao->channels = without_na; - r = init_device(ao); + r = init_device(ao, mode); } } -- cgit v1.2.3