diff options
author | wm4 <wm4@nowhere> | 2014-11-24 19:40:24 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-11-24 19:44:26 +0100 |
commit | 2228d4737367fb0303bec263bc06ca90c9ff8757 (patch) | |
tree | 30231e75b7fedac3424711fb082c0b2f196f04c0 /audio | |
parent | 7561adb14da8ce5f2a742eea8506823500167ad5 (diff) |
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')
-rw-r--r-- | audio/chmap.h | 3 | ||||
-rw-r--r-- | audio/out/ao_alsa.c | 64 |
2 files changed, 66 insertions, 1 deletions
diff --git a/audio/chmap.h b/audio/chmap.h index 22cf6fb73b..c7851a8657 100644 --- a/audio/chmap.h +++ b/audio/chmap.h @@ -61,7 +61,8 @@ enum mp_speaker_id { MP_SPEAKER_ID_UNKNOWN0 = 64, MP_SPEAKER_ID_UNKNOWN_LAST = MP_SPEAKER_ID_UNKNOWN0 + MP_NUM_CHANNELS - 1, - // Including the unassigned IDs in between. This is not a valid ID anymore. + // Including the unassigned IDs in between. This is not a valid ID anymore, + // but is still within uint8_t. MP_SPEAKER_ID_COUNT, }; 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)); |