summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_alsa.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-11-04 13:50:22 +0100
committerwm4 <wm4@nowhere>2015-11-04 21:48:37 +0100
commitbe49da72ea245e2b5227ce4b96b6c2c8f360cfaf (patch)
treefe5637e5874bb9fec414a3b150930012bc8b5212 /audio/out/ao_alsa.c
parent46f59f25c23bf9fc4c73fd56b29cc39812bb42a5 (diff)
downloadmpv-be49da72ea245e2b5227ce4b96b6c2c8f360cfaf.tar.bz2
mpv-be49da72ea245e2b5227ce4b96b6c2c8f360cfaf.tar.xz
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.
Diffstat (limited to 'audio/out/ao_alsa.c')
-rw-r--r--audio/out/ao_alsa.c26
1 files changed, 26 insertions, 0 deletions
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);
}