mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Continued config implementation. Added incomplete support for pcm
This commit is contained in:
parent
c709eb8140
commit
244653df61
8 changed files with 329 additions and 19 deletions
|
|
@ -24,11 +24,14 @@ struct snd_config {
|
|||
snd_config_t *father;
|
||||
};
|
||||
|
||||
int snd_config_top(snd_config_t **config);
|
||||
|
||||
int snd_config_load(snd_config_t **config, FILE *fp);
|
||||
int snd_config_load(snd_config_t *config, FILE *fp);
|
||||
int snd_config_save(snd_config_t *config, FILE *fp);
|
||||
|
||||
int snd_config_search(snd_config_t *config, char *key, snd_config_t **result);
|
||||
int snd_config_searchv(snd_config_t *config,
|
||||
snd_config_t **result, ...);
|
||||
|
||||
int snd_config_add(snd_config_t *config, snd_config_t *leaf);
|
||||
int snd_config_delete(snd_config_t *config);
|
||||
|
|
@ -55,3 +58,15 @@ typedef struct list_head *snd_config_iterator_t;
|
|||
|
||||
#define snd_config_entry(iterator) list_entry(iterator, snd_config_t, list)
|
||||
|
||||
static inline snd_config_type_t snd_config_type(snd_config_t *config)
|
||||
{
|
||||
return config->type;
|
||||
}
|
||||
|
||||
static inline char *snd_config_id(snd_config_t *config)
|
||||
{
|
||||
return config->id;
|
||||
}
|
||||
|
||||
snd_config_t *snd_config;
|
||||
int snd_config_update();
|
||||
|
|
|
|||
|
|
@ -122,6 +122,9 @@ int snd_pcm_synchro(snd_pcm_synchro_cmd_t cmd,
|
|||
#endif
|
||||
|
||||
|
||||
int snd_pcm_open(snd_pcm_t **handle, char *name,
|
||||
int stream, int mode);
|
||||
|
||||
int snd_pcm_hw_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
|
||||
int snd_pcm_hw_open(snd_pcm_t **handle, int card, int device, int stream, int mode);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ libasound_la_SOURCES = error.c
|
|||
libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
|
||||
rawmidi/librawmidi.la timer/libtimer.la \
|
||||
hwdep/libhwdep.la seq/libseq.la instr/libinstr.la \
|
||||
compat/libcompat.la
|
||||
compat/libcompat.la conf/libconf.la
|
||||
|
||||
libasound_la_LDFLAGS = -version-info $(COMPATNUM)
|
||||
|
||||
|
|
@ -37,4 +37,7 @@ instr/libinstr.la:
|
|||
compat/libcompat.la:
|
||||
$(MAKE) -C compat libcompat.la
|
||||
|
||||
conf/libconf.la:
|
||||
$(MAKE) -C conf libconf.la
|
||||
|
||||
INCLUDES=-I$(top_srcdir)/include
|
||||
|
|
|
|||
152
src/conf/conf.c
152
src/conf/conf.c
|
|
@ -22,9 +22,13 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include "asoundlib.h"
|
||||
#include "list.h"
|
||||
|
||||
#define SYS_ASOUNDRC "/etc/asound.conf"
|
||||
#define USR_ASOUNDRC ".asoundrc"
|
||||
|
||||
typedef struct {
|
||||
FILE *fp;
|
||||
unsigned int line, column;
|
||||
|
|
@ -183,7 +187,7 @@ static int get_freestring(char **string, input_t *input)
|
|||
}
|
||||
if (idx >= alloc) {
|
||||
size_t old_alloc = alloc;
|
||||
alloc *= 2;
|
||||
alloc += bufsize;
|
||||
if (old_alloc == bufsize) {
|
||||
buf = malloc(alloc);
|
||||
memcpy(buf, _buf, old_alloc);
|
||||
|
|
@ -227,7 +231,7 @@ static int get_delimstring(char **string, int delim, input_t *input)
|
|||
}
|
||||
if (idx >= alloc) {
|
||||
size_t old_alloc = alloc;
|
||||
alloc *= 2;
|
||||
alloc += bufsize;
|
||||
if (old_alloc == bufsize) {
|
||||
buf = malloc(alloc);
|
||||
memcpy(buf, _buf, old_alloc);
|
||||
|
|
@ -507,30 +511,30 @@ static int parse_defs(snd_config_t *father, input_t *input)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int snd_config_top(snd_config_t **config)
|
||||
{
|
||||
assert(config);
|
||||
return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND);
|
||||
}
|
||||
|
||||
int snd_config_load(snd_config_t **config, FILE *fp)
|
||||
int snd_config_load(snd_config_t *config, FILE *fp)
|
||||
{
|
||||
int err;
|
||||
input_t input;
|
||||
snd_config_t *c;
|
||||
assert(config && fp);
|
||||
err = _snd_config_make(&c, 0, SND_CONFIG_TYPE_COMPOUND);
|
||||
if (err < 0)
|
||||
return err;
|
||||
input.fp = fp;
|
||||
input.line = 1;
|
||||
input.column = 0;
|
||||
input.unget = 0;
|
||||
err = parse_defs(c, &input);
|
||||
err = parse_defs(config, &input);
|
||||
if (err < 0) {
|
||||
snd_config_delete(c);
|
||||
snd_config_delete(config);
|
||||
return err;
|
||||
}
|
||||
if (get_char(&input) != EOF) {
|
||||
snd_config_delete(c);
|
||||
snd_config_delete(config);
|
||||
return -1;
|
||||
}
|
||||
*config = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -595,14 +599,18 @@ int snd_config_make(snd_config_t **config, char *id,
|
|||
|
||||
int snd_config_integer_set(snd_config_t *config, long value)
|
||||
{
|
||||
assert(config->type == SND_CONFIG_TYPE_INTEGER);
|
||||
assert(config);
|
||||
if (config->type != SND_CONFIG_TYPE_INTEGER)
|
||||
return -EINVAL;
|
||||
config->u.integer = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_config_real_set(snd_config_t *config, double value)
|
||||
{
|
||||
assert(config->type == SND_CONFIG_TYPE_REAL);
|
||||
assert(config);
|
||||
if (config->type != SND_CONFIG_TYPE_REAL)
|
||||
return -EINVAL;
|
||||
config->u.real = value;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -610,7 +618,8 @@ int snd_config_real_set(snd_config_t *config, double value)
|
|||
int snd_config_string_set(snd_config_t *config, char *value)
|
||||
{
|
||||
assert(config);
|
||||
assert(config->type == SND_CONFIG_TYPE_INTEGER);
|
||||
if (config->type != SND_CONFIG_TYPE_STRING)
|
||||
return -EINVAL;
|
||||
if (config->u.string)
|
||||
free(config->u.string);
|
||||
config->u.string = strdup(value);
|
||||
|
|
@ -645,7 +654,8 @@ int snd_config_set(snd_config_t *config, ...)
|
|||
int snd_config_integer_get(snd_config_t *config, long *ptr)
|
||||
{
|
||||
assert(config && ptr);
|
||||
assert(config->type == SND_CONFIG_TYPE_INTEGER);
|
||||
if (config->type != SND_CONFIG_TYPE_INTEGER)
|
||||
return -EINVAL;
|
||||
*ptr = config->u.integer;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -653,7 +663,8 @@ int snd_config_integer_get(snd_config_t *config, long *ptr)
|
|||
int snd_config_real_get(snd_config_t *config, double *ptr)
|
||||
{
|
||||
assert(config && ptr);
|
||||
assert(config->type == SND_CONFIG_TYPE_REAL);
|
||||
if (config->type != SND_CONFIG_TYPE_REAL)
|
||||
return -EINVAL;
|
||||
*ptr = config->u.real;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -661,7 +672,8 @@ int snd_config_real_get(snd_config_t *config, double *ptr)
|
|||
int snd_config_string_get(snd_config_t *config, char **ptr)
|
||||
{
|
||||
assert(config && ptr);
|
||||
assert(config->type == SND_CONFIG_TYPE_INTEGER);
|
||||
if (config->type != SND_CONFIG_TYPE_STRING)
|
||||
return -EINVAL;
|
||||
*ptr = config->u.string;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -860,4 +872,110 @@ int snd_config_search(snd_config_t *config, char *key, snd_config_t **result)
|
|||
return _snd_config_search(config, key, -1, result);
|
||||
}
|
||||
}
|
||||
|
||||
int snd_config_searchv(snd_config_t *config,
|
||||
snd_config_t **result, ...)
|
||||
{
|
||||
va_list arg;
|
||||
const size_t bufsize = 256;
|
||||
char _buf[bufsize];
|
||||
char *buf = _buf;
|
||||
size_t alloc = bufsize;
|
||||
size_t idx = 0;
|
||||
size_t dot = 0;
|
||||
assert(config && result);
|
||||
va_start(arg, result);
|
||||
while (1) {
|
||||
char *k = va_arg(arg, char *);
|
||||
size_t len;
|
||||
if (!k)
|
||||
break;
|
||||
len = strlen(k);
|
||||
if (idx + len + dot>= alloc) {
|
||||
size_t old_alloc = alloc;
|
||||
alloc = idx + len + dot;
|
||||
alloc += bufsize - alloc % bufsize;
|
||||
if (old_alloc == bufsize) {
|
||||
buf = malloc(alloc);
|
||||
memcpy(buf, _buf, old_alloc);
|
||||
} else
|
||||
buf = realloc(buf, alloc);
|
||||
}
|
||||
if (dot)
|
||||
buf[idx] = '.';
|
||||
memcpy(buf + idx + dot, k, len);
|
||||
idx += len + dot;
|
||||
if (dot == 0)
|
||||
dot = 1;
|
||||
}
|
||||
buf[idx] = '\0';
|
||||
return snd_config_search(config, buf, result);
|
||||
}
|
||||
|
||||
snd_config_t *snd_config = 0;
|
||||
static dev_t sys_asoundrc_device;
|
||||
static ino_t sys_asoundrc_inode;
|
||||
static time_t sys_asoundrc_mtime;
|
||||
static dev_t usr_asoundrc_device;
|
||||
static ino_t usr_asoundrc_inode;
|
||||
static time_t usr_asoundrc_mtime;
|
||||
|
||||
int snd_config_update()
|
||||
{
|
||||
int err;
|
||||
char *usr_asoundrc = NULL;
|
||||
char *home = getenv("HOME");
|
||||
struct stat st;
|
||||
int reload;
|
||||
FILE *fp;
|
||||
if (home) {
|
||||
size_t len = strlen(home);
|
||||
size_t len1 = strlen(USR_ASOUNDRC);
|
||||
usr_asoundrc = alloca(len + len1 + 2);
|
||||
memcpy(usr_asoundrc, home, len);
|
||||
usr_asoundrc[len] = '/';
|
||||
memcpy(usr_asoundrc + len + 1, USR_ASOUNDRC, len1);
|
||||
usr_asoundrc[len + 1 + len1] = '\0';
|
||||
}
|
||||
reload = (snd_config == NULL);
|
||||
if (!reload &&
|
||||
stat(usr_asoundrc, &st) == 0 &&
|
||||
(st.st_dev != usr_asoundrc_device ||
|
||||
st.st_ino != usr_asoundrc_inode ||
|
||||
st.st_mtime != usr_asoundrc_mtime))
|
||||
reload = 1;
|
||||
if (!reload &&
|
||||
stat(SYS_ASOUNDRC, &st) == 0 &&
|
||||
(st.st_dev != sys_asoundrc_device ||
|
||||
st.st_ino != sys_asoundrc_inode ||
|
||||
st.st_mtime != sys_asoundrc_mtime))
|
||||
reload = 1;
|
||||
if (!reload)
|
||||
return 0;
|
||||
if (snd_config == NULL) {
|
||||
err = snd_config_top(&snd_config);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
fp = fopen(SYS_ASOUNDRC, "r");
|
||||
if (fp) {
|
||||
err = snd_config_load(snd_config, fp);
|
||||
if (err < 0) {
|
||||
snd_config = NULL;
|
||||
fclose(fp);
|
||||
return err;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
fp = fopen(usr_asoundrc, "r");
|
||||
if (fp) {
|
||||
err = snd_config_load(snd_config, fp);
|
||||
if (err < 0) {
|
||||
snd_config = NULL;
|
||||
fclose(fp);
|
||||
return err;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
168
src/pcm/pcm.c
168
src/pcm/pcm.c
|
|
@ -27,6 +27,7 @@
|
|||
#include <sys/poll.h>
|
||||
#include <sys/uio.h>
|
||||
#include "pcm_local.h"
|
||||
#include "list.h"
|
||||
|
||||
snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle)
|
||||
{
|
||||
|
|
@ -501,3 +502,170 @@ ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *handle, ssize_t samples)
|
|||
return samples * handle->bits_per_sample / 8;
|
||||
}
|
||||
|
||||
static int _snd_pcm_open_hw(snd_pcm_t **handlep, snd_config_t *conf,
|
||||
int stream, int mode)
|
||||
{
|
||||
snd_config_iterator_t i;
|
||||
long card = -1, device = -1, subdevice = -1;
|
||||
char *str;
|
||||
int err;
|
||||
snd_config_foreach(i, conf) {
|
||||
snd_config_t *n = snd_config_entry(i);
|
||||
if (strcmp(n->id, "comment") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "type") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "stream") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "card") == 0) {
|
||||
err = snd_config_integer_get(n, &card);
|
||||
if (err < 0) {
|
||||
err = snd_config_string_get(n, &str);
|
||||
if (err < 0)
|
||||
return -EINVAL;
|
||||
card = snd_card_name(str);
|
||||
if (card < 0)
|
||||
return card;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(n->id, "device") == 0) {
|
||||
err = snd_config_integer_get(n, &device);
|
||||
if (err < 0)
|
||||
return err;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(n->id, "subdevice") == 0) {
|
||||
err = snd_config_integer_get(n, &subdevice);
|
||||
if (err < 0)
|
||||
return err;
|
||||
continue;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
if (card < 0 || device < 0)
|
||||
return -EINVAL;
|
||||
return snd_pcm_hw_open_subdevice(handlep, card, device, subdevice, stream, mode);
|
||||
}
|
||||
|
||||
static int _snd_pcm_open_plug(snd_pcm_t **handlep, snd_config_t *conf,
|
||||
int stream, int mode)
|
||||
{
|
||||
snd_config_iterator_t i;
|
||||
long card = -1, device = -1, subdevice = -1;
|
||||
char *str;
|
||||
int err;
|
||||
snd_config_foreach(i, conf) {
|
||||
snd_config_t *n = snd_config_entry(i);
|
||||
if (strcmp(n->id, "comment") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "type") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "stream") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "card") == 0) {
|
||||
err = snd_config_integer_get(n, &card);
|
||||
if (err < 0) {
|
||||
err = snd_config_string_get(n, &str);
|
||||
if (err < 0)
|
||||
return -EINVAL;
|
||||
card = snd_card_name(str);
|
||||
if (card < 0)
|
||||
return card;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(n->id, "device") == 0) {
|
||||
err = snd_config_integer_get(n, &device);
|
||||
if (err < 0)
|
||||
return err;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(n->id, "subdevice") == 0) {
|
||||
err = snd_config_integer_get(n, &subdevice);
|
||||
if (err < 0)
|
||||
return err;
|
||||
continue;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
if (card < 0 || device < 0)
|
||||
return -EINVAL;
|
||||
return snd_pcm_plug_open_subdevice(handlep, card, device, subdevice, stream, mode);
|
||||
}
|
||||
|
||||
static int _snd_pcm_open_multi(snd_pcm_t **handle, snd_config_t *conf,
|
||||
int stream, int mode)
|
||||
{
|
||||
snd_config_iterator_t i;
|
||||
char *str;
|
||||
int err;
|
||||
snd_config_foreach(i, conf) {
|
||||
snd_config_t *n = snd_config_entry(i);
|
||||
if (strcmp(n->id, "comment") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "type") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "stream") == 0)
|
||||
continue;
|
||||
if (strcmp(n->id, "slave") == 0) {
|
||||
if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
|
||||
return -EINVAL;
|
||||
/* Not yet implemented */
|
||||
continue;
|
||||
}
|
||||
if (strcmp(n->id, "binding") == 0) {
|
||||
if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
|
||||
return -EINVAL;
|
||||
/* Not yet implemented */
|
||||
continue;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int snd_pcm_open(snd_pcm_t **handlep, char *name,
|
||||
int stream, int mode)
|
||||
{
|
||||
char *str;
|
||||
int err;
|
||||
snd_config_t *pcm_conf, *conf;
|
||||
assert(handlep && name);
|
||||
err = snd_config_update();
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND)
|
||||
return -EINVAL;
|
||||
err = snd_config_search(pcm_conf, "stream", &conf);
|
||||
if (err >= 0) {
|
||||
err = snd_config_string_get(conf, &str);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (strcmp(str, "playback") == 0) {
|
||||
if (stream != SND_PCM_STREAM_PLAYBACK)
|
||||
return -EINVAL;
|
||||
} else if (strcmp(str, "capture") == 0) {
|
||||
if (stream != SND_PCM_STREAM_CAPTURE)
|
||||
return -EINVAL;
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
err = snd_config_search(pcm_conf, "type", &conf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_config_string_get(conf, &str);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (strcmp(str, "hw") == 0)
|
||||
return _snd_pcm_open_hw(handlep, pcm_conf, stream, mode);
|
||||
else if (strcmp(str, "plug") == 0)
|
||||
return _snd_pcm_open_plug(handlep, pcm_conf, stream, mode);
|
||||
else if (strcmp(str, "multi") == 0)
|
||||
return _snd_pcm_open_multi(handlep, pcm_conf, stream, mode);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -406,6 +406,7 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
|
|||
snd_pcm_t *handle;
|
||||
snd_pcm_hw_t *hw;
|
||||
|
||||
assert(handlep);
|
||||
*handlep = 0;
|
||||
|
||||
if ((ret = snd_ctl_open(&ctl, card)) < 0)
|
||||
|
|
|
|||
|
|
@ -737,6 +737,7 @@ int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
|
|||
char client_map[32] = { 0 };
|
||||
char slave_map[32][32] = { { 0 } };
|
||||
|
||||
assert(handlep);
|
||||
assert(slaves_count > 0 && slaves_handle && slaves_channels_count);
|
||||
assert(binds_count > 0 && binds_slave && binds_client_channel && binds_slave_channel);
|
||||
|
||||
|
|
|
|||
|
|
@ -789,6 +789,7 @@ int snd_pcm_plug_create(snd_pcm_t **handlep, snd_pcm_t *slave, int close_slave)
|
|||
{
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_plug_t *plug;
|
||||
assert(handlep && slave);
|
||||
handle = calloc(1, sizeof(snd_pcm_t));
|
||||
if (!handle)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue