summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_alsa.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-11-24 19:40:24 +0100
committerwm4 <wm4@nowhere>2014-11-24 19:44:26 +0100
commit2228d4737367fb0303bec263bc06ca90c9ff8757 (patch)
tree30231e75b7fedac3424711fb082c0b2f196f04c0 /audio/out/ao_alsa.c
parent7561adb14da8ce5f2a742eea8506823500167ad5 (diff)
downloadmpv-2228d4737367fb0303bec263bc06ca90c9ff8757.tar.bz2
mpv-2228d4737367fb0303bec263bc06ca90c9ff8757.tar.xz
ao_alsa: try to use the channel map reported by ALSA
If ALSA reports a channel map, and it looks like it makes sense (i.e. could be converted to mpv channel map, and the channel count matches), then use that instead of the channel map we are assuming. This is based on code written by lachs0r (alsa_ng branch).
Diffstat (limited to 'audio/out/ao_alsa.c')
-rw-r--r--audio/out/ao_alsa.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index b857c8fcf4..910ac98437 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -45,6 +45,9 @@
#include <alsa/asoundlib.h>
+#define HAVE_CHMAP_API \
+ (defined(SND_CHMAP_API_VERSION) && SND_CHMAP_API_VERSION >= (1 << 16))
+
#include "ao.h"
#include "internal.h"
#include "audio/format.h"
@@ -237,6 +240,45 @@ static int find_alsa_format(int af_format)
return SND_PCM_FORMAT_UNKNOWN;
}
+#if HAVE_CHMAP_API
+
+static const int alsa_to_mp_channels[][2] = {
+ {SND_CHMAP_FL, MP_SP(FL)},
+ {SND_CHMAP_FR, MP_SP(FR)},
+ {SND_CHMAP_RL, MP_SP(BL)},
+ {SND_CHMAP_RR, MP_SP(BR)},
+ {SND_CHMAP_FC, MP_SP(FC)},
+ {SND_CHMAP_LFE, MP_SP(LFE)},
+ {SND_CHMAP_SL, MP_SP(SL)},
+ {SND_CHMAP_SR, MP_SP(SR)},
+ {SND_CHMAP_RC, MP_SP(BC)},
+ {SND_CHMAP_FLC, MP_SP(FLC)},
+ {SND_CHMAP_FRC, MP_SP(FRC)},
+ {SND_CHMAP_FLW, MP_SP(WL)},
+ {SND_CHMAP_FRW, MP_SP(WR)},
+ {SND_CHMAP_TC, MP_SP(TC)},
+ {SND_CHMAP_TFL, MP_SP(TFL)},
+ {SND_CHMAP_TFR, MP_SP(TFR)},
+ {SND_CHMAP_TFC, MP_SP(TFC)},
+ {SND_CHMAP_TRL, MP_SP(TBL)},
+ {SND_CHMAP_TRR, MP_SP(TBR)},
+ {SND_CHMAP_TRC, MP_SP(TBC)},
+ {SND_CHMAP_MONO, MP_SP(FC)},
+ {SND_CHMAP_LAST, MP_SPEAKER_ID_COUNT}
+};
+
+static int find_mp_channel(int alsa_channel)
+{
+ for (int i = 0; alsa_to_mp_channels[i][1] != MP_SPEAKER_ID_COUNT; i++) {
+ if (alsa_to_mp_channels[i][0] == alsa_channel)
+ return alsa_to_mp_channels[i][1];
+ }
+
+ return MP_SPEAKER_ID_COUNT;
+}
+
+#endif /* HAVE_CHMAP_API */
+
// Lists device names and their implied channel map.
// The second item must be resolvable with mp_chmap_from_str().
// Source: http://www.alsa-project.org/main/index.php/DeviceNames
@@ -534,6 +576,28 @@ static int init(struct ao *ao)
p->can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
+#if HAVE_CHMAP_API
+ snd_pcm_chmap_t *alsa_chmap = snd_pcm_get_chmap(p->alsa);
+ if (alsa_chmap) {
+ char tmp[128];
+ if (snd_pcm_chmap_print(alsa_chmap, sizeof(tmp), tmp) > 0)
+ MP_VERBOSE(ao, "attempting to set ALSA channel map: %s\n", tmp);
+
+ struct mp_chmap chmap = {.num = alsa_chmap->channels};
+ for (int c = 0; c < chmap.num; c++)
+ chmap.speaker[c] = find_mp_channel(alsa_chmap->pos[c]);
+
+ char *mp_map_str = mp_chmap_to_str(&chmap);
+ MP_VERBOSE(ao, "which we understand as: %s\n", mp_map_str);
+ talloc_free(mp_map_str);
+
+ if (mp_chmap_is_valid(&chmap) && chmap.num == ao->channels.num) {
+ MP_VERBOSE(ao, "using the ALSA channel map.\n");
+ ao->channels = chmap;
+ }
+ }
+#endif
+
MP_VERBOSE(ao, "opened: %d Hz/%d channels/%d bps/%d samples buffer/%s\n",
ao->samplerate, ao->channels.num, af_fmt2bits(ao->format),
p->buffersize, snd_pcm_format_description(p->alsa_fmt));