From be49da72ea245e2b5227ce4b96b6c2c8f360cfaf Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 4 Nov 2015 13:50:22 +0100 Subject: ao_alsa: fix 7.1 over HDMI We need to effectively swap the last channel pair. See commit 4e358a96 and 5a18c5ea for details. Doing this seems rather strange, as 7.1 just extends 5.1 with 2 new speakers, and 5.1 doesn't need this change. Going by the HDMI standard and the Intel HDA sources (cited in the referenced commits), it also looks like 7.1 should simply append two channels to 5.1 as well. But swapping them is apparently correct. This is also what XBMC does. (I didn't find any other applications doing 7.1 PCM using the ALSA channel map API. VLC seems to ignore the 7.1 case.) Testing reveals that at least the end result is correct. "Normal" ALSA 7.1 is unaffected by this, as it reports a different (and saner) channel layout. --- audio/out/ao_alsa.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'audio/out/ao_alsa.c') diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 3ee39d71de..6c34d6bcc1 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -284,6 +284,28 @@ static int find_mp_channel(int alsa_channel) return MP_SPEAKER_ID_COUNT; } +#define CHMAP(n, ...) &(struct mp_chmap) MP_CONCAT(MP_CHMAP, n) (__VA_ARGS__) + +// Replace each channel in a with b (a->num == b->num) +static void replace_submap(struct mp_chmap *dst, struct mp_chmap *a, + struct mp_chmap *b) +{ + struct mp_chmap t = *dst; + if (!mp_chmap_is_valid(&t) || mp_chmap_diffn(a, &t) != 0) + return; + assert(a->num == b->num); + for (int n = 0; n < t.num; n++) { + for (int i = 0; i < a->num; i++) { + if (t.speaker[n] == a->speaker[i]) { + t.speaker[n] = b->speaker[i]; + break; + } + } + } + if (mp_chmap_is_valid(&t)) + *dst = t; +} + static bool mp_chmap_from_alsa(struct mp_chmap *dst, snd_pcm_chmap_t *src) { *dst = (struct mp_chmap) {0}; @@ -299,6 +321,10 @@ static bool mp_chmap_from_alsa(struct mp_chmap *dst, snd_pcm_chmap_t *src) if (dst->num == 1) dst->speaker[0] = MP_SP(FC); + // Remap weird Intel HDA HDMI 7.1 layouts correctly. + replace_submap(dst, CHMAP(6, FL, FR, BL, BR, SDL, SDR), + CHMAP(6, FL, FR, SL, SR, BL, BR)); + return mp_chmap_is_valid(dst); } -- cgit v1.2.3