summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/out/ao_alsa.c93
1 files changed, 54 insertions, 39 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index daf744deec..3ee39d71de 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -284,28 +284,22 @@ static int find_mp_channel(int alsa_channel)
return MP_SPEAKER_ID_COUNT;
}
-static int find_alsa_channel(int mp_channel)
-{
- for (int i = 0; alsa_to_mp_channels[i][1] != MP_SPEAKER_ID_COUNT; i++) {
- if (alsa_to_mp_channels[i][1] == mp_channel)
- return alsa_to_mp_channels[i][0];
- }
-
- return SND_CHMAP_UNKNOWN;
-}
-
-static int mp_chmap_from_alsa(struct mp_chmap *dst, snd_pcm_chmap_t *src)
+static bool mp_chmap_from_alsa(struct mp_chmap *dst, snd_pcm_chmap_t *src)
{
*dst = (struct mp_chmap) {0};
if (src->channels > MP_NUM_CHANNELS)
- return -1;
+ return false;
dst->num = src->channels;
for (int c = 0; c < dst->num; c++)
dst->speaker[c] = find_mp_channel(src->pos[c]);
- return 0;
+ // Assume anything with 1 channel is mono.
+ if (dst->num == 1)
+ dst->speaker[0] = MP_SP(FC);
+
+ return mp_chmap_is_valid(dst);
}
static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
@@ -323,8 +317,7 @@ static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
aname[0] = '\0';
struct mp_chmap entry;
- mp_chmap_from_alsa(&entry, &maps[i]->map);
- if (mp_chmap_is_valid(&entry)) {
+ if (mp_chmap_from_alsa(&entry, &maps[i]->map)) {
struct mp_chmap reorder = entry;
if (maps[i]->type == SND_CHMAP_TYPE_VAR)
mp_chmap_reorder_norm(&reorder);
@@ -342,26 +335,57 @@ static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
return ao_chmap_sel_adjust(ao, &chmap_sel, chmap);
}
-static int set_chmap(struct ao *ao, struct mp_chmap *dev_chmap, int num_channels)
+// Map back our selected channel layout to an ALSA one. This is done this way so
+// that our ALSA->mp_chmap mapping function only has to go one way.
+// The return value is to be freed with free().
+static snd_pcm_chmap_t *map_back_chmap(struct ao *ao, struct mp_chmap *chmap)
{
struct priv *p = ao->priv;
- int err;
+ if (!mp_chmap_is_valid(chmap))
+ return NULL;
- if (mp_chmap_is_valid(dev_chmap)) {
- snd_pcm_chmap_t *alsa_chmap =
- calloc(1, sizeof(*alsa_chmap) +
- sizeof(alsa_chmap->pos[0]) * dev_chmap->num);
- if (!alsa_chmap)
- goto alsa_error;
+ snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps(p->alsa);
+ if (!maps)
+ return NULL;
+
+ snd_pcm_chmap_t *alsa_chmap = NULL;
+
+ for (int i = 0; maps[i] != NULL; i++) {
+ struct mp_chmap entry;
+ if (!mp_chmap_from_alsa(&entry, &maps[i]->map))
+ continue;
- alsa_chmap->channels = dev_chmap->num;
- for (int c = 0; c < dev_chmap->num; c++)
- alsa_chmap->pos[c] = find_alsa_channel(dev_chmap->speaker[c]);
+ if (mp_chmap_equals(chmap, &entry) ||
+ (mp_chmap_equals_reordered(chmap, &entry) &&
+ maps[i]->type == SND_CHMAP_TYPE_VAR))
+ {
+ alsa_chmap = calloc(1, sizeof(*alsa_chmap) +
+ sizeof(alsa_chmap->pos[0]) * entry.num);
+ if (!alsa_chmap)
+ break;
+ alsa_chmap->channels = entry.num;
+
+ // Undo if mp_chmap_reorder() was called on the result.
+ int reorder[MP_NUM_CHANNELS];
+ mp_chmap_get_reorder(reorder, chmap, &entry);
+ for (int n = 0; n < entry.num; n++)
+ alsa_chmap->pos[n] = maps[i]->map.pos[reorder[n]];
+ break;
+ }
+ }
- // mpv and ALSA use different conventions for mono
- if (dev_chmap->num == 1 && dev_chmap->speaker[0] == MP_SP(FC))
- alsa_chmap->pos[0] = SND_CHMAP_MONO;
+ snd_pcm_free_chmaps(maps);
+ return alsa_chmap;
+}
+
+
+static int set_chmap(struct ao *ao, struct mp_chmap *dev_chmap, int num_channels)
+{
+ struct priv *p = ao->priv;
+ int err;
+ snd_pcm_chmap_t *alsa_chmap = map_back_chmap(ao, dev_chmap);
+ if (alsa_chmap) {
char tmp[128];
if (snd_pcm_chmap_print(alsa_chmap, sizeof(tmp), tmp) > 0)
MP_VERBOSE(ao, "trying to set ALSA channel map: %s\n", tmp);
@@ -381,7 +405,7 @@ static int set_chmap(struct ao *ao, struct mp_chmap *dev_chmap, int num_channels
free(alsa_chmap);
}
- snd_pcm_chmap_t *alsa_chmap = snd_pcm_get_chmap(p->alsa);
+ 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)
@@ -407,19 +431,10 @@ static int set_chmap(struct ao *ao, struct mp_chmap *dev_chmap, int num_channels
ao->channels = chmap;
}
- // mpv and ALSA use different conventions for mono
- if (ao->channels.num == 1) {
- MP_VERBOSE(ao, "assuming we actually got MONO from ALSA.\n");
- ao->channels.speaker[0] = MP_SP(FC);
- }
-
free(alsa_chmap);
}
return 0;
-
-alsa_error:
- return -1;
}
#else /* HAVE_CHMAP_API */