summaryrefslogtreecommitdiffstats
path: root/audio/out
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-04-08 00:51:18 +0200
committerwm4 <wm4@nowhere>2013-05-12 21:24:56 +0200
commitbc03eb02958a942cb7db69cf87283431c7ea3fe8 (patch)
treef8aa0c5d452274a52b21b548fad3e07edf2095fe /audio/out
parent7828048d65753ce0400d119d8a35f5a1d90025b6 (diff)
downloadmpv-bc03eb02958a942cb7db69cf87283431c7ea3fe8.tar.bz2
mpv-bc03eb02958a942cb7db69cf87283431c7ea3fe8.tar.xz
ao_alsa: map to exact channel layout
This allows supporting 5 channel audio (which can be eother 5.0 or 4.1). Fallback doesn't work yet. It will do nonsense if the channel layout doesn't match perfectly, even though it's similar.
Diffstat (limited to 'audio/out')
-rw-r--r--audio/out/ao_alsa.c86
1 files changed, 48 insertions, 38 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index 85bd92650c..a63d3ed515 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -322,6 +322,39 @@ static int find_alsa_format(int af_format)
return SND_PCM_FORMAT_UNKNOWN;
}
+// 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
+// (Speaker names are slightly different from mpv's.)
+static const char *device_channel_layouts[][2] = {
+ {"default", "fc"},
+ {"default", "fl-fr"},
+ {"rear", "bl-br"},
+ {"center_lfe", "fc-lfe"},
+ {"side", "sl-sr"},
+ {"surround40", "fl-fr-fc-bc"},
+ {"surround50", "fl-fr-bl-br-fc"},
+ {"surround41", "fl-fr-bl-br-lfe"},
+ {"surround51", "fl-fr-bl-br-fc-lfe"},
+ {"surround71", "fl-fr-bl-br-fc-lfe-sl-sr"},
+ {0}
+};
+
+// Find a device that contains exactly all the requested speakers.
+// Set *request to the required channel order.
+static const char *find_device(struct mp_chmap *request)
+{
+ for (int n = 0; device_channel_layouts[n][0]; n++) {
+ struct mp_chmap map = {0};
+ mp_chmap_from_str(&map, bstr0(device_channel_layouts[n][1]));
+ if (mp_chmap_equals_reordered(&map, request)) {
+ *request = map;
+ return device_channel_layouts[n][0];
+ }
+ }
+ return NULL;
+}
+
static int try_open_device(const char *device, int open_mode, int try_ac3)
{
int err, len;
@@ -413,48 +446,27 @@ static int init(int rate_hz, const struct mp_chmap *channels, int format,
* while opening the abstract alias for the spdif subdevice
* 'iec958'
*/
+ device.str = NULL;
if (AF_FORMAT_IS_IEC61937(format)) {
device.str = "iec958";
mp_msg(MSGT_AO, MSGL_V,
"alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n",
ao_data.channels.num);
} else {
- /* in any case for multichannel playback we should select
- * appropriate device
- */
- switch (ao_data.channels.num) {
- case 1:
- case 2:
- device.str = "default";
- mp_msg(MSGT_AO, MSGL_V, "alsa-init: setup for 1/2 channel(s)\n");
- break;
- case 4:
- if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
- // hack - use the converter plugin
- device.str = "plug:surround40";
- else
- device.str = "surround40";
- mp_msg(MSGT_AO, MSGL_V, "alsa-init: device set to surround40\n");
- break;
- case 6:
- if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
- device.str = "plug:surround51";
- else
- device.str = "surround51";
- mp_msg(MSGT_AO, MSGL_V, "alsa-init: device set to surround51\n");
- break;
- case 8:
- if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
- device.str = "plug:surround71";
- else
- device.str = "surround71";
- mp_msg(MSGT_AO, MSGL_V, "alsa-init: device set to surround71\n");
- break;
- default:
+ device.str = find_device(&ao_data.channels);
+ if (!device.str) {
+ char *name = mp_chmap_to_str(&ao_data.channels);
device.str = "default";
+ mp_chmap_from_channels(&ao_data.channels, ao_data.channels.num);
mp_tmsg(MSGT_AO, MSGL_ERR,
- "[AO_ALSA] %d channels are not supported.\n",
- ao_data.channels.num);
+ "[AO_ALSA] channel layout %s (%d ch) not supported.\n",
+ name, ao_data.channels.num);
+ talloc_free(name);
+ }
+ if (strcmp(device.str, "default") != 0 && format == AF_FORMAT_FLOAT_NE)
+ {
+ // hack - use the converter plugin (why the heck?)
+ device.str = talloc_asprintf(global_ao, "plug:%s", device.str);
}
}
device.len = strlen(device.str);
@@ -528,10 +540,8 @@ static int init(int rate_hz, const struct mp_chmap *channels, int format,
(alsa_handler, alsa_hwparams, &num_channels);
CHECK_ALSA_ERROR("Unable to set channels");
- mp_chmap_from_channels(&ao_data.channels, num_channels);
- if (!AF_FORMAT_IS_IEC61937(format))
- mp_chmap_reorder_to_alsa(&ao_data.channels);
-
+ if (num_channels != ao_data.channels.num)
+ mp_chmap_from_channels(&ao_data.channels, num_channels);
/* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11)
prefer our own resampler, since that allows users to choose the resampler,