summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-05-06 17:20:02 +0200
committerwm4 <wm4@nowhere>2016-05-06 17:20:02 +0200
commita93fb460cdea2951bae039b8e004b5042c337d05 (patch)
tree9123088335ca7c5355b5ef9bad0967fe9eba31c5 /audio
parenteef271c8f491c8a1de4e5f2b505582e786fe3690 (diff)
downloadmpv-a93fb460cdea2951bae039b8e004b5042c337d05.tar.bz2
mpv-a93fb460cdea2951bae039b8e004b5042c337d05.tar.xz
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.
Diffstat (limited to 'audio')
-rw-r--r--audio/out/ao_alsa.c34
1 files changed, 25 insertions, 9 deletions
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);
}
}