File 0013-PCM-Add-string-conversion-helper-functions-for-chmap.patch of Package alsa

From b4c64e815a051e711798be1d772f123d19c1ff6e Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 10 Sep 2012 18:07:36 +0200
Subject: [PATCH 13/30] PCM: Add string conversion helper functions for chmap

Added a few helper functions between chmap and string.
  snd_pcm_chmap_type_name() -- a string of the given chmap type
  snd_pcm_chmap_name() -- a string of the given channel position
  snd_pcm_chmap_print() -- print channel map on the given buffer
  snd_pcm_chmap_from_string() -- get a channel position from string
  snd_pcm_parse_string() -- parse the whole channel map from string

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/pcm.h |    6 ++
 src/pcm/pcm.c |  142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/chmap.c  |   69 ++++------------------------
 3 files changed, 160 insertions(+), 57 deletions(-)

--- a/include/pcm.h
+++ b/include/pcm.h
@@ -534,6 +534,12 @@ void snd_pcm_free_chmaps(snd_pcm_chmap_q
 snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm);
 int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
 
+const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val);
+const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val);
+int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf);
+unsigned int snd_pcm_chmap_from_string(const char *str);
+snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str);
+
 //int snd_pcm_mixer_element(snd_pcm_t *pcm, snd_mixer_t *mixer, snd_mixer_elem_t **elem);
 
 /*
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -633,6 +633,7 @@ playback devices.
 #include <malloc.h>
 #include <stdarg.h>
 #include <signal.h>
+#include <ctype.h>
 #include <sys/poll.h>
 #include <sys/shm.h>
 #include <sys/mman.h>
@@ -7356,6 +7357,147 @@ int snd_pcm_set_chmap(snd_pcm_t *pcm, co
 	return pcm->ops->set_chmap(pcm, map);
 }
 
+/*
+ */
+#define _NAME(n) [SND_CHMAP_TYPE_##n] = #n
+static const char *chmap_type_names[SND_CHMAP_TYPE_LAST + 1] = {
+	_NAME(NONE), _NAME(FIXED), _NAME(VAR), _NAME(PAIRED),
+};
+#undef _NAME
+
+const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val)
+{
+	if (val <= SND_CHMAP_TYPE_LAST)
+		return chmap_type_names[val];
+	else
+		return NULL;
+}
+
+#define _NAME(n) [SND_CHMAP_##n] = #n
+static const char *chmap_names[SND_CHMAP_LAST + 1] = {
+	_NAME(UNKNOWN),
+	_NAME(FL), _NAME(FR),
+	_NAME(RL), _NAME(RR),
+	_NAME(FC), _NAME(LFE),
+	_NAME(SL), _NAME(SR),
+	_NAME(RC), _NAME(FLC), _NAME(FRC), _NAME(RLC), _NAME(RRC),
+	_NAME(FLW), _NAME(FRW),
+	_NAME(FLH), _NAME(FCH), _NAME(FRH), _NAME(TC),
+	_NAME(NA),
+};
+#undef _NAME
+
+const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val)
+{
+	if (val <= SND_CHMAP_LAST)
+		return chmap_names[val];
+	else
+		return NULL;
+}
+
+int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf)
+{
+	unsigned int i, len = 0;
+
+	for (i = 0; i < map->channels; i++) {
+		unsigned int p = map->pos[i] & SND_CHMAP_POSITION_MASK;
+		if (i > 0) {
+			len += snprintf(buf + len, maxlen - len, " ");
+			if (len >= maxlen)
+				return -ENOMEM;
+		}
+		if (map->pos[i] & SND_CHMAP_DRIVER_SPEC)
+			len += snprintf(buf + len, maxlen, "%d", p);
+		else {
+			const char *name = chmap_names[p];
+			if (name)
+				len += snprintf(buf + len, maxlen - len,
+						"%s", name);
+			else
+				len += snprintf(buf + len, maxlen - len,
+						"Ch%d", p);
+		}
+		if (len >= maxlen)
+			return -ENOMEM;
+		if (map->pos[i] & SND_CHMAP_PHASE_INVERSE) {
+			len += snprintf(buf + len, maxlen - len, "[INV]");
+			if (len >= maxlen)
+				return -ENOMEM;
+		}
+	}
+	return len;
+}
+
+static int str_to_chmap(const char *str, int len)
+{
+	int val;
+
+	if (isdigit(*str)) {
+		val = atoi(str);
+		if (val < 0)
+			return -1;
+		return val | SND_CHMAP_DRIVER_SPEC;
+	} else if (str[0] == 'C' && str[1] == 'h') {
+		val = atoi(str + 2);
+		if (val < 0)
+			return -1;
+		return val;
+	} else {
+		for (val = 0; val <= SND_CHMAP_LAST; val++) {
+			if (!strncmp(str, chmap_names[val], len))
+				return val;
+		}
+		return -1;
+	}
+}
+
+unsigned int snd_pcm_chmap_from_string(const char *str)
+{
+	return str_to_chmap(str, strlen(str));
+}
+
+snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str)
+{
+	int i, ch = 0;
+	int tmp_map[64];
+	snd_pcm_chmap_t *map;
+
+	for (;;) {
+		const char *p;
+		int len, val;
+
+		if (ch >= (int)(sizeof(tmp_map) / sizeof(tmp_map[0])))
+			return NULL;
+		for (p = str; *p && isalnum(*p); p++)
+			;
+		len = p - str;
+		if (!len)
+			return NULL;
+		val = str_to_chmap(str, len);
+		if (val < 0)
+			return NULL;
+		str += len;
+		if (*str == '[') {
+			if (!strncmp(str, "[INV]", 5)) {
+				val |= SND_CHMAP_PHASE_INVERSE;
+				str += 5;
+			}
+		}
+		tmp_map[ch] = val;
+		ch++;
+		for (; *str && !isalnum(*str); str++)
+			;
+		if (!*str)
+			break;
+	}
+	map = malloc(sizeof(*map) + ch * sizeof(int));
+	if (!map)
+		return NULL;
+	map->channels = ch;
+	for (i = 0; i < ch; i++)
+		map->pos[i] = tmp_map[i];
+	return map;
+}
 
 /*
  * basic helpers
--- a/test/chmap.c
+++ b/test/chmap.c
@@ -21,62 +21,11 @@ static void usage(void)
 	       "  -r rate       Sample rate\n");
 }
 
-static const char * const chname[] = {
-	"Unknown",
-	"FL", "FR", "RL", "RR", "FC", "LFE", "SL", "SR", "RC",
-	"FLC", "FRC", "RLC", "RRC", "FLW", "FRW", "FLH",
-	"FCH", "FRH", "TC",
-	"N/A",
-};
-
-#define ARRAY_SIZE(x)	(sizeof(x) / sizeof(x[0]))
-
 static void print_channels(const snd_pcm_chmap_t *map)
 {
-	unsigned int i;
-
-	printf("  ");
-	for (i = 0; i < map->channels; i++) {
-		unsigned int c = map->pos[i];
-		unsigned int p = c & SND_CHMAP_POSITION_MASK;
-		if (c & SND_CHMAP_DRIVER_SPEC)
-			printf(" %d", p);
-		else if (p >= ARRAY_SIZE(chname))
-			printf(" Ch%d", p);
-		else
-			printf(" %s", chname[p]);
-		if (c & SND_CHMAP_PHASE_INVERSE)
-			printf("[INV]");
-	}
-	printf("\n");
-}
-
-static int to_channel(const char *name)
-{
-	unsigned int i;
-
-	if (isdigit(*name))
-		return atoi(name);
-	for (i = 0; i < ARRAY_SIZE(chname); i++)
-		if (!strcmp(chname[i], name))
-			return i;
-	return SND_CHMAP_UNKNOWN;
-}
-
-static const char *chmap_type(int type)
-{
-	switch (type) {
-	case SND_CHMAP_NONE:
-		return "None";
-	case SND_CHMAP_FIXED:
-		return "Fixed";
-	case SND_CHMAP_VAR:
-		return "Variable";
-	case SND_CHMAP_PAIRED:
-		return "Paired";
-	default:
-		return "Unknown";
-	}
+	char tmp[128];
+	if (snd_pcm_chmap_print(map, sizeof(tmp), tmp) > 0)
+		printf("  %s\n", tmp);
 }
 
 static int query_chmaps(snd_pcm_t *pcm)
@@ -89,7 +38,9 @@ static int query_chmaps(snd_pcm_t *pcm)
 		return 1;
 	}
 	for (p = maps; (v = *p) != NULL; p++) {
-		printf("Type = %s, Channels = %d\n", chmap_type(v->type), v->map.channels);
+		printf("Type = %s, Channels = %d\n",
+		       snd_pcm_chmap_type_name(v->type),
+		       v->map.channels);
 		print_channels(&v->map);
 	}
 	snd_pcm_free_chmaps(maps);
@@ -173,8 +124,12 @@ static int set_chmap(snd_pcm_t *pcm, int
 		return 1;
 	}
 	map->channels = channels;
-	for (i = 0; i < channels; i++)
-		map->pos[i] = to_channel(arg[i]);
+	for (i = 0; i < channels; i++) {
+		int val = snd_pcm_chmap_from_string(arg[i]);
+		if (val < 0)
+			val = SND_CHMAP_UNKNOWN;
+		map->pos[i] = val;
+	}
 	if (snd_pcm_set_chmap(pcm, map) < 0) {
 		printf("Cannot set chmap\n");
 		return 1;
openSUSE Build Service is sponsored by