Takashi Iwai
f84c139643
- Backport upstream fixes: a few fixes for chmap support, alsaconf updates, a new monitor command for alsactl, etc: 0006-amixer-fix-indentation-when-printing-container-TLV-c.patch 0007-alsaloop-pcmjob.c-use-portable-way-to-initialize-rec.patch 0008-speaker-test-Fix-chmapped-channel-selection-without-.patch 0009-speaker-test-Always-show-chmap-channel-names-if-avai.patch 0010-speaker-test-Show-out-of-chmap-channels-as-Unknown.patch 0011-alsaconf-support-newer-m-i-t-and-kmod.patch 0012-alsaconf-update-gentoo-to-use-modprobe.d-method-as-e.patch 0013-configure-detect-udevdir-via-pkg-config-fallback-to-.patch 0014-alsactl-Add-monitor-command.patch 0015-alsactl-Fix-REMOVE-event-handling-in-monitor-command.patch 0016-alsactl-monitor-all-cards-as-default.patch OBS-URL: https://build.opensuse.org/request/show/208681 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa-utils?expand=0&rev=94
233 lines
6.9 KiB
Diff
233 lines
6.9 KiB
Diff
From a1992044d5813371ce71f5252187942f943b198d Mon Sep 17 00:00:00 2001
|
|
From: Anssi Hannula <anssi.hannula@iki.fi>
|
|
Date: Tue, 12 Nov 2013 00:04:02 +0200
|
|
Subject: [PATCH] speaker-test: Fix chmapped channel selection without
|
|
specified chmap
|
|
|
|
The channel selection currently does not work properly when there is a
|
|
driver-provided non-ALSA-traditional channel map but no manual channel
|
|
map was explicitely requested with "-m".
|
|
|
|
For example, the CEA/HDMI 8ch map is FL,FR,RLC,RRC,FC,LFE,RL,RR. Note
|
|
that it is otherwise the same as the traditional ALSA channel map,
|
|
except that the traditional rear speakers are considered
|
|
rear-center speakers and the traditional side speakers are considered
|
|
rear speakers.
|
|
|
|
Speaker-test tries to play back channels in this following order:
|
|
0, /* Front Left */
|
|
4, /* Center */
|
|
1, /* Front Right */
|
|
7, /* Side Right */
|
|
3, /* Rear Right */
|
|
2, /* Rear Left */
|
|
6, /* Side Left */
|
|
5, /* LFE */
|
|
|
|
When it is the time to play back Side Left/Right, speaker-test tries to
|
|
look for SL/SR in the chmap, but doesn't find it, so it just plays back
|
|
channels 6/7 (which indeed are the side speakers, or RL/RR in this
|
|
channel map - so the correct channels are selected).
|
|
|
|
When it becomes the time to playback Rear Left/Right, speaker-test again
|
|
tries to find RL/RR in the chmap, and this time it does find them in the
|
|
chmap positions 6/7.
|
|
|
|
So the channels 6/7 are tested twice and 2/3 are never tested.
|
|
|
|
To fix this, define a generic playback order channel_order[] to be used
|
|
when the channel map is present (but not user-defined) and generate a
|
|
(speaker/playback number => channel number) mapping with the channels
|
|
ordered in the following order:
|
|
1. regular channels found in channel_order[] in the defined order,
|
|
2. channels not found in channel_order[] ordered by channel number.
|
|
3. UNKNOWN channels ordered by channel number.
|
|
4. NA channels ordered by channel number.
|
|
For channels outside the channel map just use their channel numbers (so
|
|
they will be last after all of the above).
|
|
|
|
For example, if the playback device has a fictional default channel map
|
|
of FR,FL,UNKNOWN1,FOO,BAR,RR,RL,UNKNOWN2, the playback order will be
|
|
FL,FR,RR,RL,FOO,BAR,UNKNOWN1,UNKNOWN2(,any_extra_channels).
|
|
|
|
When the channel mapping is specified manually, the specified order is
|
|
used for playback as before.
|
|
|
|
Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
|
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
---
|
|
speaker-test/speaker-test.c | 113 +++++++++++++++++++++++++++++++++++---------
|
|
1 file changed, 91 insertions(+), 22 deletions(-)
|
|
|
|
diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c
|
|
index d35065f73a7a..25b08dcee70b 100644
|
|
--- a/speaker-test/speaker-test.c
|
|
+++ b/speaker-test/speaker-test.c
|
|
@@ -88,6 +88,8 @@ enum {
|
|
#define BE_INT(v) (v)
|
|
#endif
|
|
|
|
+#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x[0]))
|
|
+
|
|
static char *device = "default"; /* playback device */
|
|
static snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */
|
|
static unsigned int rate = 48000; /* stream rate */
|
|
@@ -110,6 +112,7 @@ static snd_pcm_t *pcm_handle = NULL;
|
|
#ifdef CONFIG_SUPPORT_CHMAP
|
|
static snd_pcm_chmap_t *channel_map;
|
|
static int channel_map_set;
|
|
+static unsigned int *ordered_channels;
|
|
#endif
|
|
|
|
static const char *const channel_name[MAX_CHANNELS] = {
|
|
@@ -156,36 +159,94 @@ static const int channels8[] = {
|
|
5, /* LFE */
|
|
};
|
|
|
|
-static int get_mapped_channel(int chn)
|
|
-{
|
|
#ifdef CONFIG_SUPPORT_CHMAP
|
|
- static const int maps[MAX_CHANNELS] = {
|
|
- SND_CHMAP_FL,
|
|
- SND_CHMAP_FR,
|
|
- SND_CHMAP_RL,
|
|
- SND_CHMAP_RR,
|
|
- SND_CHMAP_FC,
|
|
- SND_CHMAP_LFE,
|
|
- SND_CHMAP_SL,
|
|
- SND_CHMAP_SR,
|
|
- };
|
|
+/* circular clockwise and bottom-to-top order */
|
|
+static const int channel_order[] = {
|
|
+ [SND_CHMAP_FLW] = 10,
|
|
+ [SND_CHMAP_FL] = 20,
|
|
+ [SND_CHMAP_TFL] = 30,
|
|
+ [SND_CHMAP_FLC] = 40,
|
|
+ [SND_CHMAP_TFLC] = 50,
|
|
+ [SND_CHMAP_FC] = 60,
|
|
+ [SND_CHMAP_TFC] = 70,
|
|
+ [SND_CHMAP_FRC] = 80,
|
|
+ [SND_CHMAP_TFRC] = 90,
|
|
+ [SND_CHMAP_FR] = 100,
|
|
+ [SND_CHMAP_TFR] = 110,
|
|
+ [SND_CHMAP_FRW] = 120,
|
|
+ [SND_CHMAP_SR] = 130,
|
|
+ [SND_CHMAP_TSR] = 140,
|
|
+ [SND_CHMAP_RR] = 150,
|
|
+ [SND_CHMAP_TRR] = 160,
|
|
+ [SND_CHMAP_RRC] = 170,
|
|
+ [SND_CHMAP_RC] = 180,
|
|
+ [SND_CHMAP_TRC] = 190,
|
|
+ [SND_CHMAP_RLC] = 200,
|
|
+ [SND_CHMAP_RL] = 210,
|
|
+ [SND_CHMAP_TRL] = 220,
|
|
+ [SND_CHMAP_SL] = 230,
|
|
+ [SND_CHMAP_TSL] = 240,
|
|
+ [SND_CHMAP_BC] = 250,
|
|
+ [SND_CHMAP_TC] = 260,
|
|
+ [SND_CHMAP_LLFE] = 270,
|
|
+ [SND_CHMAP_LFE] = 280,
|
|
+ [SND_CHMAP_RLFE] = 290,
|
|
+ /* not in table = 10000 */
|
|
+ [SND_CHMAP_UNKNOWN] = 20000,
|
|
+ [SND_CHMAP_NA] = 30000,
|
|
+};
|
|
|
|
- if (channel_map && maps[chn]) {
|
|
- int i;
|
|
- for (i = 0; i < channel_map->channels; i++) {
|
|
- if (channel_map->pos[i] == maps[chn])
|
|
- return i;
|
|
- }
|
|
+static int chpos_cmp(const void *chnum1p, const void *chnum2p)
|
|
+{
|
|
+ int chnum1 = *(int *)chnum1p;
|
|
+ int chnum2 = *(int *)chnum2p;
|
|
+ int chpos1 = channel_map->pos[chnum1];
|
|
+ int chpos2 = channel_map->pos[chnum2];
|
|
+ int weight1 = 10000;
|
|
+ int weight2 = 10000;
|
|
+
|
|
+ if (chpos1 < ARRAY_SIZE(channel_order) && channel_order[chpos1])
|
|
+ weight1 = channel_order[chpos1];
|
|
+ if (chpos2 < ARRAY_SIZE(channel_order) && channel_order[chpos2])
|
|
+ weight2 = channel_order[chpos2];
|
|
+
|
|
+ if (weight1 == weight2) {
|
|
+ /* order by channel number if both have the same position (e.g. UNKNOWN)
|
|
+ * or if neither is in channel_order[] */
|
|
+ return chnum1 - chnum2;
|
|
}
|
|
-#endif
|
|
- return chn;
|
|
+
|
|
+ /* order according to channel_order[] */
|
|
+ return weight1 - weight2;
|
|
+}
|
|
+
|
|
+static int *order_channels(void)
|
|
+{
|
|
+ /* create a (playback order => channel number) table with channels ordered
|
|
+ * according to channel_order[] values */
|
|
+ int i;
|
|
+ int *ordered_chs;
|
|
+
|
|
+ ordered_chs = calloc(channel_map->channels, sizeof(*ordered_chs));
|
|
+ if (!ordered_chs)
|
|
+ return NULL;
|
|
+
|
|
+ for (i = 0; i < channel_map->channels; i++)
|
|
+ ordered_chs[i] = i;
|
|
+
|
|
+ qsort(ordered_chs, channel_map->channels, sizeof(*ordered_chs), chpos_cmp);
|
|
+
|
|
+ return ordered_chs;
|
|
}
|
|
+#endif
|
|
|
|
static int get_speaker_channel(int chn)
|
|
{
|
|
#ifdef CONFIG_SUPPORT_CHMAP
|
|
- if (channel_map_set)
|
|
+ if (channel_map_set || (ordered_channels && chn >= channel_map->channels))
|
|
return chn;
|
|
+ if (ordered_channels)
|
|
+ return ordered_channels[chn];
|
|
#endif
|
|
|
|
switch (channels) {
|
|
@@ -200,7 +261,7 @@ static int get_speaker_channel(int chn)
|
|
break;
|
|
}
|
|
|
|
- return get_mapped_channel(chn);
|
|
+ return chn;
|
|
}
|
|
|
|
static const char *get_channel_name(int chn)
|
|
@@ -611,6 +672,11 @@ static int config_chmap(snd_pcm_t *handle, const char *mapstr)
|
|
}
|
|
|
|
channel_map = snd_pcm_get_chmap(handle);
|
|
+
|
|
+ /* create a channel order table for default layouts */
|
|
+ if (channel_map)
|
|
+ ordered_channels = order_channels();
|
|
+
|
|
return 0;
|
|
}
|
|
#endif
|
|
@@ -1230,6 +1296,9 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
|
free(frames);
|
|
+#ifdef CONFIG_SUPPORT_CHMAP
|
|
+ free(ordered_channels);
|
|
+#endif
|
|
|
|
return prg_exit(EXIT_SUCCESS);
|
|
}
|
|
--
|
|
1.8.4.3
|
|
|