Takashi Iwai
8a90d87ca6
- backport from upstream tree: * lots of patches to support the new chmap API * fix segfault in rate plugin error path * add a couple of test programs * fix inifinte loop in htimestamp of dmix & co OBS-URL: https://build.opensuse.org/request/show/138456 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa?expand=0&rev=113
287 lines
7.1 KiB
Diff
287 lines
7.1 KiB
Diff
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;
|