summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-05-06 21:46:11 +0200
committerDiogo Franco (Kovensky) <diogomfranco@gmail.com>2015-05-07 10:54:49 +0900
commit52ed30e9b80bc621bab06f0f930d4398fee1b55f (patch)
tree6a955829b1a9a37f0c16f35cc32bb4c70310fe84
parent76d2ba6283cac45a740a1dbb7f3a43326360d2c4 (diff)
downloadmpv-52ed30e9b80bc621bab06f0f930d4398fee1b55f.tar.bz2
mpv-52ed30e9b80bc621bab06f0f930d4398fee1b55f.tar.xz
ao_alsa: use new padding channels support
Sometimes, ALSA will return channel layouts with padded channels (NA speakers). Use them instead of failing. This still includes the old "braindeath" code to retry with a layout without NA channels. This might be helpful for performance, and also the padded channel layout string looks confusing. To be fair, I have not encountered a case yet which would really need this, and for which the old "braindeath" code did not fix it. (cherry picked from commit 85fc6b2a0569b24c5652f600d90d7a131b61eb07)
-rw-r--r--audio/out/ao_alsa.c47
1 files changed, 26 insertions, 21 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index 82494717cf..e31e8012f8 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -252,6 +252,7 @@ static const int alsa_to_mp_channels[][2] = {
{SND_CHMAP_TRR, MP_SP(TBR)},
{SND_CHMAP_TRC, MP_SP(TBC)},
{SND_CHMAP_MONO, MP_SP(FC)},
+ {SND_CHMAP_NA, MP_SPEAKER_ID_NA0},
{SND_CHMAP_LAST, MP_SPEAKER_ID_COUNT}
};
@@ -282,9 +283,14 @@ static int mp_chmap_from_alsa(struct mp_chmap *dst, snd_pcm_chmap_t *src)
if (src->channels > MP_NUM_CHANNELS)
return -1;
+ int next_na = MP_SPEAKER_ID_NA0;
+
dst->num = src->channels;
- for (int c = 0; c < dst->num; c++)
+ for (int c = 0; c < dst->num; c++) {
dst->speaker[c] = find_mp_channel(src->pos[c]);
+ if (dst->speaker[c] == MP_SPEAKER_ID_NA0)
+ dst->speaker[c] = next_na++;
+ }
return 0;
}
@@ -412,7 +418,7 @@ alsa_error: ;
#define INIT_OK 0
#define INIT_ERROR -1
#define INIT_BRAINDEATH -2
-static int init_device(struct ao *ao)
+static int init_device(struct ao *ao, bool second_try)
{
struct priv *p = ao->priv;
int err;
@@ -582,24 +588,14 @@ static int init_device(struct ao *ao)
} else if (AF_FORMAT_IS_IEC61937(ao->format)) {
MP_VERBOSE(ao, "using spdif passthrough; ignoring the channel map.\n");
} else if (mp_chmap_is_valid(&chmap)) {
- if (mp_chmap_equals(&chmap, &ao->channels)) {
- MP_VERBOSE(ao, "which is what we requested.\n");
- } else if (chmap.num == ao->channels.num) {
- MP_VERBOSE(ao, "using the ALSA channel map.\n");
- ao->channels = chmap;
- } else {
- MP_WARN(ao, "ALSA channel map conflicts with channel count!\n");
- }
- } else {
// Is it one that contains NA channels?
- struct mp_chmap chmap2 = {0};
- for (int c = 0; c < alsa_chmap->channels; c++) {
- int alsa_ch = alsa_chmap->pos[c];
- if (alsa_ch != SND_CHMAP_NA)
- chmap2.speaker[chmap2.num++] = find_mp_channel(alsa_ch);
- }
+ struct mp_chmap without_na = chmap;
+ mp_chmap_remove_na(&without_na);
- if (mp_chmap_is_valid(&chmap2)) {
+ if (mp_chmap_is_valid(&without_na) &&
+ !mp_chmap_equals(&without_na, &chmap) &&
+ !second_try)
+ {
// Sometimes, ALSA will advertise certain chmaps, but it's not
// possible to set them. This can happen with dmix: as of
// alsa 1.0.28, dmix can do stereo only, but advertises the
@@ -616,10 +612,19 @@ static int init_device(struct ao *ao)
err = snd_pcm_close(p->alsa);
p->alsa = NULL;
CHECK_ALSA_ERROR("pcm close error");
- ao->channels = chmap2;
+ ao->channels = without_na;
return INIT_BRAINDEATH;
}
+ if (mp_chmap_equals(&chmap, &ao->channels)) {
+ MP_VERBOSE(ao, "which is what we requested.\n");
+ } else if (chmap.num == ao->channels.num) {
+ MP_VERBOSE(ao, "using the ALSA channel map.\n");
+ ao->channels = chmap;
+ } else {
+ MP_WARN(ao, "ALSA channel map conflicts with channel count!\n");
+ }
+ } else {
MP_WARN(ao, "Got unknown channel map from ALSA.\n");
}
@@ -690,9 +695,9 @@ static int init(struct ao *ao)
MP_VERBOSE(ao, "using ALSA version: %s\n", snd_asoundlib_version());
- int r = init_device(ao);
+ int r = init_device(ao, false);
if (r == INIT_BRAINDEATH)
- r = init_device(ao); // retry with normalized channel layout
+ r = init_device(ao, true); // retry with normalized channel layout
return r == INIT_OK ? 0 : -1;
}