[alsa-devel] [PATCH 1/3] speaker-test: Fix chmapped channel selection without specified chmap

Anssi Hannula anssi.hannula at iki.fi
Sun Nov 10 19:29:17 CET 2013


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 to be used when a channel
map is present and assign the speaker numbers (i.e. playback order) in
the following order:
1. channels in map found in map_order[] in the map_order[] order,
2. channels in map not found in map_order[] in map order,
3. channels outside the map.

When the channel mapping is specified manually, the specified order is
used for playback as before.

Signed-off-by: Anssi Hannula <anssi.hannula at iki.fi>
---
 speaker-test/speaker-test.c | 86 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 67 insertions(+), 19 deletions(-)

diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c
index d35065f..274007d 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 */
@@ -156,36 +158,82 @@ static const int	channels8[] = {
   5, /* LFE         */
 };
 
+#ifdef CONFIG_SUPPORT_CHMAP
+/* generic version of the above channelsX[] */
+static const int map_order[] = {
+  SND_CHMAP_FLW,
+  SND_CHMAP_FL,
+  SND_CHMAP_TFL,
+  SND_CHMAP_FLC,
+  SND_CHMAP_TFLC,
+  SND_CHMAP_FC,
+  SND_CHMAP_TFC,
+  SND_CHMAP_FRC,
+  SND_CHMAP_TFRC,
+  SND_CHMAP_FR,
+  SND_CHMAP_TFR,
+  SND_CHMAP_FRW,
+  SND_CHMAP_SR,
+  SND_CHMAP_TSR,
+  SND_CHMAP_RR,
+  SND_CHMAP_TRR,
+  SND_CHMAP_RRC,
+  SND_CHMAP_RC,
+  SND_CHMAP_TRC,
+  SND_CHMAP_RLC,
+  SND_CHMAP_RL,
+  SND_CHMAP_TRL,
+  SND_CHMAP_SL,
+  SND_CHMAP_TSL,
+  SND_CHMAP_BC,
+  SND_CHMAP_TC,
+  SND_CHMAP_LLFE,
+  SND_CHMAP_LFE,
+  SND_CHMAP_RLFE,
+};
+
 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,
-  };
+  int found_count = 0;
+  int i, j;
+
+  if (chn >= channel_map->channels)
+    return chn; /* out of map */
 
-  if (channel_map && maps[chn]) {
-    int i;
-    for (i = 0; i < channel_map->channels; i++) {
-      if (channel_map->pos[i] == maps[chn])
-	return i;
+  for (i = 0; i < ARRAY_SIZE(map_order) && found_count <= chn; i++) {
+    for (j = 0; j < channel_map->channels; j++) {
+      if (channel_map->pos[j] == map_order[i]) {
+        found_count++;
+	break;
+      }
     }
   }
-#endif
-  return chn;
+
+  if (found_count == chn + 1)
+    return j;
+
+  /* chn is bigger than the amount of present map_order[] channels, find
+   * the non-map_order[] channels */
+  for (j = 0; j < channel_map->channels && found_count <= chn; j++) {
+    for (i = 0; i < ARRAY_SIZE(map_order); i++) {
+      if (channel_map->pos[j] == map_order[i])
+        break;
+    }
+    if (i == ARRAY_SIZE(map_order))
+      found_count++;
+  }
+
+  return j - 1;
 }
+#endif
 
 static int get_speaker_channel(int chn)
 {
 #ifdef CONFIG_SUPPORT_CHMAP
   if (channel_map_set)
     return chn;
+  if (channel_map)
+    return get_mapped_channel(chn);
 #endif
 
   switch (channels) {
@@ -200,7 +248,7 @@ static int get_speaker_channel(int chn)
     break;
   }
 
-  return get_mapped_channel(chn);
+  return chn;
 }
 
 static const char *get_channel_name(int chn)
-- 
1.8.1.5



More information about the Alsa-devel mailing list