diff options
Diffstat (limited to 'src/libasound.c')
-rw-r--r-- | src/libasound.c | 261 |
1 files changed, 218 insertions, 43 deletions
diff --git a/src/libasound.c b/src/libasound.c index 66cdf2c..d21f1b9 100644 --- a/src/libasound.c +++ b/src/libasound.c @@ -12,8 +12,28 @@ #include "stubs.h" #include "symversioning-hell.h" -struct _snd_config { char noop; } s_snd_config; -struct _snd_config *snd_config = &s_snd_config; +enum { + CARD_NONE = -1, + CARD_DEFAULT, +}; + +static const char *CARD_NAMES[] = { + "sndio", // CARD_DEFAULT // hw:0 +}; + +enum { + PCM_NONE = -1, + PCM_PLAYBACK, + PCM_CAPTURE +}; + +static const struct { + const char *name; + snd_pcm_stream_t stream; +} PCMS[] = { + { .name = "playback", .stream = SND_PCM_STREAM_PLAYBACK }, // PCM_PLAYBACK // hw:?,0 + { .name = "capture", .stream = SND_PCM_STREAM_CAPTURE }, // PCM_CAPTURE // hw:?,1 +}; const char* snd_asoundlib_version(void) @@ -47,7 +67,7 @@ int snd_card_next(int *card) { if (card) { - *card = (*card == -1 ? 0 : -1); + *card = (*card + 1 >= (int)ARRAY_SIZE(CARD_NAMES) ? CARD_NONE : *card + 1); return 0; } @@ -57,8 +77,13 @@ snd_card_next(int *card) int snd_card_get_index(const char *name) { - if (!strcmp(name, "default")) - return 0; + if (!strcmp(name, "default") || !strcmp(name, "hw:0")) + return CARD_DEFAULT; + + for (unsigned int i = 0; i < ARRAY_SIZE(CARD_NAMES); ++i) { + if (!strcmp(name, CARD_NAMES[i])) + return i; + } return -1; } @@ -66,22 +91,24 @@ snd_card_get_index(const char *name) int snd_card_get_name(int card, char **name) { - if (name) *name = c_strdup("default"); + if (card < 0 || (unsigned int)card >= ARRAY_SIZE(CARD_NAMES)) + return -1; + + if (name) *name = c_strdup(CARD_NAMES[card]); return 0; } int snd_card_get_longname(int card, char **name) { - if (name) *name = c_strdup("default"); - return 0; + return snd_card_get_name(card, name); } -struct device_name_hint { char *name, *ioid; }; +struct device_name_hint { int id; }; int snd_device_name_hint(int card, const char *iface, void ***hints) { - static struct device_name_hint defaults[] = { { .name = "default", .ioid = "Output" }, { .name = "capture", .ioid = "Input" } }; + static struct device_name_hint defaults[] = { {PCM_PLAYBACK}, {PCM_CAPTURE} }; static struct device_name_hint *array[] = { &defaults[0], &defaults[1], NULL }; *hints = (void**)array; return 0; @@ -92,10 +119,13 @@ snd_device_name_get_hint(const void *hint, const char *id) { const struct device_name_hint *shint = hint; + if (shint->id < 0 || (unsigned int)shint->id >= ARRAY_SIZE(PCMS)) + return NULL; + if (!strcmp(id, "NAME")) - return c_strdup(shint->name); + return c_strdup(PCMS[shint->id].name); else if (!strcmp(id, "IOID")) - return c_strdup(shint->ioid); + return c_strdup((PCMS[shint->id].stream == SND_PCM_STREAM_PLAYBACK ? "Output" : "Input")); return NULL; } @@ -106,8 +136,55 @@ snd_device_name_free_hint(void **hints) return 0; } +struct _snd_ctl { + int id; +}; + +int +snd_ctl_open(snd_ctl_t **ctl, const char *name, int mode) +{ + int id; + if ((id = snd_card_get_index(name)) < 0) + return -1; + + if (!(*ctl = calloc(1, sizeof(**ctl)))) { + WARNX1("calloc"); + return -1; + } + + (*ctl)->id = id; + return 0; +} + +int +snd_ctl_close(snd_ctl_t *ctl) +{ + free(ctl); + return 0; +} + +snd_ctl_t* +snd_hctl_ctl(snd_hctl_t *hctl) +{ + snd_ctl_t *ctl = NULL; + snd_ctl_open(&ctl, NULL, 0); + return ctl; +} + +int +snd_ctl_pcm_next_device(snd_ctl_t *ctl, int *device) +{ + if (device) { + *device = (*device + 1 >= (int)ARRAY_SIZE(PCMS) ? PCM_NONE : *device + 1); + return 0; + } + + return -1; +} + struct _snd_pcm_info { - const char *name; + int card, id, subdevice; + snd_pcm_stream_t stream; }; size_t @@ -133,54 +210,66 @@ snd_pcm_info_free(snd_pcm_info_t *obj) free(obj); } -const char* -snd_pcm_info_get_name(const snd_pcm_info_t *obj) +void +snd_pcm_info_set_device(snd_pcm_info_t *obj, unsigned int val) { - return obj->name; + obj->id = val; } -int -snd_ctl_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t *info) +void +snd_pcm_info_set_stream(snd_pcm_info_t *obj, snd_pcm_stream_t val) { - info->name = "sndio"; - return 0; + obj->stream = val; +} + +void +snd_pcm_info_set_subdevice(snd_pcm_info_t *obj, unsigned int val) +{ + obj->subdevice = val; } int -snd_ctl_pcm_next_device(snd_ctl_t *ctl, int *device) +snd_ctl_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t *info) { - if (device) { - *device = (*device == -1 ? 0 : -1); - return 0; - } + if (info->id < 0 || (unsigned int)info->id >= ARRAY_SIZE(PCMS) || info->subdevice != 0) + return -1; - return -1; + info->card = ctl->id; + return (PCMS[info->id].stream == info->stream ? 0 : -1); } -struct _snd_ctl { - char noop; -}; +const char* +snd_pcm_info_get_name(const snd_pcm_info_t *obj) +{ + assert(obj->id >= 0 && (unsigned int)obj->id < ARRAY_SIZE(PCMS)); + return PCMS[obj->id].name; +} -int -snd_ctl_open(snd_ctl_t **ctl, const char *name, int mode) +unsigned int +snd_pcm_info_get_device(const snd_pcm_info_t *obj) { - if (!(*ctl = calloc(1, sizeof(**ctl)))) { - WARNX1("calloc"); - return -1; - } + return obj->id; +} +unsigned int +snd_pcm_info_get_subdevice(const snd_pcm_info_t *obj) +{ return 0; } -int -snd_ctl_close(snd_ctl_t *ctl) +snd_pcm_stream_t +snd_pcm_info_get_stream(const snd_pcm_info_t *obj) { - free(ctl); - return 0; + return obj->stream; +} + +int snd_pcm_info_get_card(const snd_pcm_info_t *obj) +{ + return obj->card; } struct _snd_ctl_card_info { - const char *name; + int id; }; size_t @@ -207,20 +296,21 @@ snd_ctl_card_info_free(snd_ctl_card_info_t *obj) int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info) { - info->name = "sndio"; + *info = (snd_ctl_card_info_t){ ctl->id }; return 0; } const char* snd_ctl_card_info_get_name(const snd_ctl_card_info_t *obj) { - return obj->name; + assert(obj->id >= 0 && (unsigned int)obj->id < ARRAY_SIZE(CARD_NAMES)); + return CARD_NAMES[obj->id]; } const char* snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj) { - return obj->name; + return snd_ctl_card_info_get_name(obj); } int @@ -234,3 +324,88 @@ snd_seq_query_next_client(snd_seq_t *handle, snd_seq_client_info_t *info) { return -1; } + +// snd_config insanity is needed for portaudio (e.g. used by audacity) since it has buggy code + +struct _snd_config { + const char *path; + + union { + const char *id, *str; + } v; + + enum { + TYPE_NONE, + TYPE_ID, + TYPE_STR + } type; + + snd_config_t *next; +} s_snd_config; + +snd_config_t *snd_config = &s_snd_config; + +int +snd_config_search(snd_config_t *config, const char *key, snd_config_t **result) +{ + char path[255]; + const char *cp = (config->path ? config->path : "."); + snprintf(path, sizeof(path), "%s/%s", cp, key); + + if (!strcmp(path, "./pcm")) { + static snd_config_t res = { .path = "./pcm", .v.id = "default", .type = TYPE_ID }; + if (result) *result = &res; + return 0; + } else if (!strcmp(path, "./pcm/type")) { + static snd_config_t res = { .path = "./pcm/type", .v.str = "default", .type = TYPE_STR }; + if (result) *result = &res; + return 0; + } + + return -1; +} + +snd_config_iterator_t +snd_config_iterator_first(const snd_config_t *node) +{ + return (void*)node; +} + +snd_config_iterator_t +snd_config_iterator_next(const snd_config_iterator_t iterator) +{ + const snd_config_t *cfg = (void*)iterator; + return (cfg ? (void*)cfg->next : NULL); +} + +snd_config_iterator_t +snd_config_iterator_end(const snd_config_t *node) +{ + return NULL; +} + +snd_config_t* +snd_config_iterator_entry(const snd_config_iterator_t iterator) +{ + return (void*)iterator; +} + +int +snd_config_get_id(const snd_config_t *config, const char **value) +{ + if (config->type != TYPE_ID) + return -1; + + if (value) *value = config->v.id; + return 0; +} + +int +snd_config_get_string(const snd_config_t *config, const char **value) +{ + if (config->type != TYPE_STR) + return -1; + + if (value) *value = config->v.str; + return 0; +} |