summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-09-10 18:07:36 +0200
committerTakashi Iwai <tiwai@suse.de>2012-09-13 08:24:58 +0200
commitb4c64e815a051e711798be1d772f123d19c1ff6e (patch)
tree2f2723d458475a61d5ded94016382bd7592e1286
parent6950a1030c4f878b51104268e3cd13401d56bf60 (diff)
downloadalsa-lib-b4c64e815a051e711798be1d772f123d19c1ff6e.tar.gz
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>
-rw-r--r--include/pcm.h6
-rw-r--r--src/pcm/pcm.c142
-rw-r--r--test/chmap.c69
3 files changed, 160 insertions, 57 deletions
diff --git a/include/pcm.h b/include/pcm.h
index 838809c0..7ec1af2a 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -534,6 +534,12 @@ void snd_pcm_free_chmaps(snd_pcm_chmap_query_t **maps);
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);
/*
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index a2d9daa7..2c30e574 100644
--- 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, const snd_pcm_chmap_t *map)
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
diff --git a/test/chmap.c b/test/chmap.c
index 7e440597..a566b1cf 100644
--- 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 format, int channels, int rate,
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;