From 6ad93ac89216a0659209aebd2d7df7b418c926f0 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 3 Sep 2003 19:25:08 +0000 Subject: added snd_user_file() function alisp extensions - added nth, include, path commands - added auto-exec functionality - added helpers for C<->lisp interoperability --- alsalisp/hctl.lisp | 5 + include/alisp.h | 19 +- include/global.h | 5 +- include/mixer_ordinary.h | 3 +- src/Makefile.am | 2 +- src/Versions | 8 + src/alisp/alisp.c | 491 +++++++++++++++++++++++++++++++++--- src/conf.c | 41 +-- src/ordinary_mixer/ordinary_mixer.c | 114 ++++++++- test/Makefile.am | 3 +- test/control.c | 2 + test/omixer.c | 64 +++++ test/pcm.c | 2 +- 13 files changed, 667 insertions(+), 92 deletions(-) create mode 100644 test/omixer.c diff --git a/alsalisp/hctl.lisp b/alsalisp/hctl.lisp index 2d040411..6348d7bb 100644 --- a/alsalisp/hctl.lisp +++ b/alsalisp/hctl.lisp @@ -88,3 +88,8 @@ (&stat-memory) (&dump-memory "memory.dump") + +(defun autotest () (princ "abcd\n")) +(setq auto-exec 'autotest) + +(princ (path 'data) "\n") diff --git a/include/alisp.h b/include/alisp.h index 1bc88a77..f8423d34 100644 --- a/include/alisp.h +++ b/include/alisp.h @@ -32,9 +32,22 @@ struct alisp_cfg { }; struct alisp_instance; +struct alisp_object; +struct alisp_seq_iterator; +struct alisp_cfg *alsa_lisp_default_cfg(snd_input_t *input); +void alsa_lisp_default_cfg_free(struct alisp_cfg *cfg); int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **instance); void alsa_lisp_free(struct alisp_instance *instance); - -extern struct alisp_object alsa_lisp_nil; -extern struct alisp_object alsa_lisp_t; +int alsa_lisp_function(struct alisp_instance *instance, struct alisp_seq_iterator **result, + const char *id, const char *args, ...) +#ifndef DOC_HIDDEN + __attribute__ ((format (printf, 4, 5))) +#endif + ; +int alsa_lisp_seq_first(struct alisp_instance *instance, const char *id, + struct alisp_seq_iterator **seq); +int alsa_lisp_seq_next(struct alisp_seq_iterator **seq); +int alsa_lisp_seq_count(struct alisp_seq_iterator *seq); +int alsa_lisp_seq_integer(struct alisp_seq_iterator *seq, long *val); +int alsa_lisp_seq_pointer(struct alisp_seq_iterator *seq, const char *ptr_id, void **ptr); diff --git a/include/global.h b/include/global.h index 60a6737d..f6b5fc3e 100644 --- a/include/global.h +++ b/include/global.h @@ -119,13 +119,12 @@ int snd_async_handler_get_fd(snd_async_handler_t *handler); int snd_async_handler_get_signo(snd_async_handler_t *handler); void *snd_async_handler_get_callback_private(snd_async_handler_t *handler); -/** - * \brief Internal structure for an IPC shm area manager. - */ struct snd_shm_area *snd_shm_area_create(int shmid, void *ptr); struct snd_shm_area *snd_shm_area_share(struct snd_shm_area *area); int snd_shm_area_destroy(struct snd_shm_area *area); +int snd_user_file(const char *file, char **result); + /** Timestamp */ typedef struct timeval snd_timestamp_t; /** Hi-res timestamp */ diff --git a/include/mixer_ordinary.h b/include/mixer_ordinary.h index e8dd0db2..940d7ac9 100644 --- a/include/mixer_ordinary.h +++ b/include/mixer_ordinary.h @@ -95,6 +95,7 @@ enum sndo_mixer_io_type { }; typedef struct sndo_mixer sndo_mixer_t; +struct alisp_cfg; #ifdef __cplusplus extern "C" { @@ -106,7 +107,7 @@ extern "C" { * \{ */ -int sndo_mixer_open(sndo_mixer_t **pmixer, const char *playback_name, const char *capture_name, snd_config_t *lconf); +int sndo_mixer_open(sndo_mixer_t **pmixer, const char *playback_name, const char *capture_name, struct alisp_cfg *lconf); int sndo_mixer_close(sndo_mixer_t *mixer); int sndo_mixer_poll_descriptors_count(sndo_mixer_t *mixer); int sndo_mixer_poll_descriptors(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int space); diff --git a/src/Makefile.am b/src/Makefile.am index 2851d222..da73e6ca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,7 @@ VSYMS = endif lib_LTLIBRARIES = libasound.la -libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c +libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c userfile.c libasound_la_LIBADD = control/libcontrol.la \ mixer/libmixer.la ordinary_mixer/libordinarymixer.la \ pcm/libpcm.la ordinary_pcm/libordinarypcm.la \ diff --git a/src/Versions b/src/Versions index 62a20bc8..4e6a7eab 100644 --- a/src/Versions +++ b/src/Versions @@ -126,3 +126,11 @@ ALSA_0.9.6 { snd_seq_port_info_set_timestamp_real; snd_seq_port_info_set_timestamp_queue; } ALSA_0.9.5; + +ALSA_0.9.7 { + global: + + snd_user_file; + sndo_*; + alsa_lisp_*; +} ALSA_0.9.6; diff --git a/src/alisp/alisp.c b/src/alisp/alisp.c index e13ff53d..2321c7f3 100644 --- a/src/alisp/alisp.c +++ b/src/alisp/alisp.c @@ -30,11 +30,15 @@ #include #include #include +#include + +#define alisp_seq_iterator alisp_object #include "local.h" #include "alisp.h" #include "alisp_local.h" + #define ALISP_FREE_OBJ_POOL 500 /* free objects above this pool */ #define ALISP_AUTO_GC_THRESHOLD 200 /* run automagically garbage-collect when this threshold is reached */ #define ALISP_MAIN_ID "---alisp---main---" @@ -52,6 +56,9 @@ static struct alisp_object * eval(struct alisp_instance *instance, struct alisp_ static struct alisp_object *F_eval(struct alisp_instance *instance, struct alisp_object *); static struct alisp_object *F_progn(struct alisp_instance *instance, struct alisp_object *); +/* others */ +static int alisp_include_file(struct alisp_instance *instance, const char *filename); + /* * object handling */ @@ -655,13 +662,13 @@ static struct alisp_object_pair * set_object(struct alisp_instance *instance, st return p; } -static void unset_object(struct alisp_instance *instance, struct alisp_object * name) +static void unset_object1(struct alisp_instance *instance, const char *id) { struct alisp_object_pair *p, *p1; for (p = instance->setobjs_list, p1 = NULL; p != NULL; p1 = p, p = p->next) { if (p->name->value.id != NULL && - !strcmp(name->value.id, p->name->value.id)) { + !strcmp(id, p->name->value.id)) { if (p1) p1->next = p->next; else @@ -672,18 +679,28 @@ static void unset_object(struct alisp_instance *instance, struct alisp_object * } } -static struct alisp_object * get_object(struct alisp_instance *instance, struct alisp_object * name) +static inline void unset_object(struct alisp_instance *instance, struct alisp_object * name) +{ + return unset_object1(instance, name->value.id); +} + +static struct alisp_object * get_object1(struct alisp_instance *instance, const char *id) { struct alisp_object_pair *p; for (p = instance->setobjs_list; p != NULL; p = p->next) if (p->name->value.id != NULL && - !strcmp(name->value.id, p->name->value.id)) + !strcmp(id, p->name->value.id)) return p->value; return &alsa_lisp_nil; } +static inline struct alisp_object * get_object(struct alisp_instance *instance, struct alisp_object * name) +{ + return get_object1(instance, name->value.id); +} + static void dump_objects(struct alisp_instance *instance, const char *fname) { struct alisp_object_pair *p; @@ -910,32 +927,60 @@ static struct alisp_object * F_cdr(struct alisp_instance *instance, struct alisp static struct alisp_object * F_add(struct alisp_instance *instance, struct alisp_object * args) { struct alisp_object * p = args, * p1; - long v = 0; - double f = 0; - int type = ALISP_OBJ_INTEGER; - do { - p1 = eval(instance, car(p)); - if (p1->type == ALISP_OBJ_INTEGER) { - if (type == ALISP_OBJ_FLOAT) - f += p1->value.i; - else - v += p1->value.i; - } else if (p1->type == ALISP_OBJ_FLOAT) { - f += p1->value.f + v; - v = 0; - type = ALISP_OBJ_FLOAT; + p1 = eval(instance, car(p)); + if (p1->type == ALISP_OBJ_INTEGER || p1->type == ALISP_OBJ_FLOAT) { + long v = 0; + double f = 0; + int type = ALISP_OBJ_INTEGER; + for (;;) { + if (p1->type == ALISP_OBJ_INTEGER) { + if (type == ALISP_OBJ_FLOAT) + f += p1->value.i; + else + v += p1->value.i; + } else if (p1->type == ALISP_OBJ_FLOAT) { + f += p1->value.f + v; + v = 0; + type = ALISP_OBJ_FLOAT; + } else { + lisp_warn(instance, "sum with a non integer or float operand"); + } + p = cdr(p); + if (p == &alsa_lisp_nil) + break; + p1 = eval(instance, car(p)); + } + if (type == ALISP_OBJ_INTEGER) { + return new_integer(instance, v); } else { - lisp_warn(instance, "sum with a non integer or float operand"); + return new_float(instance, f); } - p = cdr(p); - } while (p != &alsa_lisp_nil); - - if (type == ALISP_OBJ_INTEGER) { - return new_integer(instance, v); - } else { - return new_float(instance, f); + } else if (p1->type == ALISP_OBJ_STRING || p1->type == ALISP_OBJ_IDENTIFIER) { + char *str = NULL, *str1; + for (;;) { + if (p1->type == ALISP_OBJ_STRING || p1->type == ALISP_OBJ_IDENTIFIER) { + str1 = realloc(str, strlen(str) + strlen(p1->value.s) + 1); + if (str1 == NULL) { + nomem(); + if (str) + free(str); + return NULL; + } + strcat(str, p1->value.s); + } else { + lisp_warn(instance, "concat with a non string or identifier operand"); + } + p = cdr(p); + if (p == &alsa_lisp_nil) + break; + p1 = eval(instance, car(p)); + } + p = new_string(instance, str); + free(str); + return p; } + return &alsa_lisp_nil; } /* @@ -1753,7 +1798,7 @@ static struct alisp_object * F_defun(struct alisp_instance *instance, struct ali static struct alisp_object * eval_func(struct alisp_instance *instance, struct alisp_object * p, struct alisp_object * args) { struct alisp_object * p1, * p2, * p3, * p4, * p5; - struct alisp_object * eval_objs[64], * save_objs[64]; + struct alisp_object ** eval_objs, ** save_objs; int i; p1 = car(p); @@ -1761,33 +1806,40 @@ static struct alisp_object * eval_func(struct alisp_instance *instance, struct a p2 = car(cdr(p)); p3 = args; - if (count_list(p2) != count_list(p3)) { + if ((i = count_list(p2)) != count_list(p3)) { lisp_warn(instance, "wrong number of parameters"); return &alsa_lisp_nil; } + eval_objs = malloc(2 * i * sizeof(struct alisp_object *)); + if (eval_objs == NULL) { + nomem(); + goto _err; + } + save_objs = eval_objs + i; + /* * Save the new variable values. */ i = 0; - do { + while (p3 != &alsa_lisp_nil) { p5 = eval(instance, car(p3)); eval_objs[i++] = p5; p3 = cdr(p3); - } while (p3 != &alsa_lisp_nil); + } /* * Save the old variable values and set the new ones. */ i = 0; - do { + while (p2 != &alsa_lisp_nil) { p4 = car(p2); save_objs[i] = get_object(instance, p4); if (set_object(instance, p4, eval_objs[i]) == NULL) - return NULL; + goto _err; p2 = cdr(p2); ++i; - } while (p2 != &alsa_lisp_nil); + } p5 = F_progn(instance, cdr(cdr(p))); @@ -1796,17 +1848,25 @@ static struct alisp_object * eval_func(struct alisp_instance *instance, struct a */ p2 = car(cdr(p)); i = 0; - do { + while (p2 != &alsa_lisp_nil) { p4 = car(p2); if (set_object(instance, p4, save_objs[i++]) == NULL) return NULL; p2 = cdr(p2); - } while (p2 != &alsa_lisp_nil); + } + + if (eval_objs) + free(eval_objs); return p5; } return &alsa_lisp_nil; + + _err: + if (eval_objs) + free(eval_objs); + return NULL; } struct alisp_object * F_gc(struct alisp_instance *instance, struct alisp_object * args ATTRIBUTE_UNUSED) @@ -1816,6 +1876,39 @@ struct alisp_object * F_gc(struct alisp_instance *instance, struct alisp_object return &alsa_lisp_t; } +/* + * Syntax: (path what) + * what is string ('data') + */ +struct alisp_object * F_path(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1; + + p1 = eval(instance, car(p)); + if (p1->type != ALISP_STRING && p1->type != ALISP_IDENTIFIER) + return &alsa_lisp_nil; + if (!strcmp(p1->value.s, "data")) + return new_string(instance, DATADIR); + return &alsa_lisp_nil; +} + +/* + * Syntax: (include filename...) + */ +struct alisp_object * F_include(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1; + + do { + p1 = eval(instance, car(p)); + if (p1->type == ALISP_STRING && p1->type == ALISP_IDENTIFIER) + alisp_include_file(instance, p1->value.s); + p = cdr(p); + } while (p != &alsa_lisp_nil); + + return p1; +} + /* * Syntax: (int value) * 'value' can be integer or float type @@ -1931,6 +2024,27 @@ struct alisp_object * F_assq(struct alisp_instance *instance, struct alisp_objec return &alsa_lisp_nil; } +/* + * Syntax: (nth index alist) + */ +struct alisp_object * F_nth(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + long idx; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + + if (p1->type != ALISP_OBJ_INTEGER) + return &alsa_lisp_nil; + if (p2->type != ALISP_OBJ_CONS) + return &alsa_lisp_nil; + idx = p1->value.i; + while (idx-- > 0) + p2 = cdr(p2); + return car(p2); +} + /* * Syntax: (rassq value alist) */ @@ -2031,10 +2145,13 @@ static struct intrinsic intrinsics[] = { { "gc", F_gc }, { "if", F_if }, { "int", F_int }, + { "include", F_include }, { "list", F_list }, { "not", F_not }, + { "nth", F_nth }, { "null", F_not }, { "or", F_or }, + { "path", F_path }, { "princ", F_princ }, { "prog1", F_prog1 }, { "prog2", F_prog2 }, @@ -2087,7 +2204,6 @@ static struct alisp_object * eval_cons(struct alisp_instance *instance, struct a sizeof snd_intrinsics[0], compar)) != NULL) return item->func(instance, p2); - if ((p3 = get_object(instance, p1)) != &alsa_lisp_nil) return eval_func(instance, p3, p2); else @@ -2120,12 +2236,91 @@ static struct alisp_object * F_eval(struct alisp_instance *instance, struct alis /* * main routine */ + +static int alisp_include_file(struct alisp_instance *instance, const char *filename) +{ + snd_input_t *old_in; + struct alisp_object *p, *p1, *omain; + struct alisp_object_pair *pmain; + char *name, *uname; + int retval = 0, err; + + err = snd_user_file(filename, &name); + if (err < 0) + return err; + old_in = instance->in; + err = snd_input_stdio_open(&instance->in, name, "r"); + if (err < 0) { + retval = err; + goto _err; + } + if (instance->verbose) + lisp_verbose(instance, "** include filename '%s'", name); + uname = malloc(sizeof(ALISP_MAIN_ID) + strlen(name) + 2); + if (uname == NULL) { + retval = -ENOMEM; + goto _err; + } + strcpy(uname, ALISP_MAIN_ID); + strcat(uname, "-"); + strcat(uname, name); + omain = new_identifier(instance, uname); + free(uname); + if (omain == NULL) { + retval = -ENOMEM; + goto _err; + } + pmain = set_object(instance, omain, &alsa_lisp_t); + if (pmain == NULL) { + retval = -ENOMEM; + goto _err; + } + + for (;;) { + if ((p = parse_object(instance, 0)) == NULL) + break; + if (instance->verbose) { + lisp_verbose(instance, "** code"); + princ_object(instance->vout, p); + snd_output_putc(instance->vout, '\n'); + } + pmain->value = p; /* protect the code tree from garbage-collect */ + p1 = eval(instance, p); + if (p1 == NULL) { + retval = -ENOMEM; + break; + } + if (instance->verbose) { + lisp_verbose(instance, "** result"); + princ_object(instance->vout, p1); + snd_output_putc(instance->vout, '\n'); + } + if (instance->debug) { + lisp_debug(instance, "** objects before collection"); + print_obj_lists(instance, instance->dout); + } + pmain->value = &alsa_lisp_t; /* let garbage-collect working */ + garbage_collect(instance); + if (instance->debug) { + lisp_debug(instance, "** objects after collection"); + print_obj_lists(instance, instance->dout); + } + } + + unset_object(instance, omain); + + _err: + free(name); + instance->in = old_in; + return retval; +} int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance) { struct alisp_instance *instance; struct alisp_object *p, *p1, *omain; struct alisp_object_pair *pmain; + int retval = 0; instance = (struct alisp_instance *)malloc(sizeof(struct alisp_instance)); if (instance == NULL) { @@ -2167,7 +2362,10 @@ int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance) } pmain->value = p; /* protect the code tree from garbage-collect */ p1 = eval(instance, p); - pmain->value = &alsa_lisp_t; /* let garbage-collect working */ + if (p1 == NULL) { + retval = -ENOMEM; + break; + } if (instance->verbose) { lisp_verbose(instance, "** result"); princ_object(instance->vout, p1); @@ -2177,6 +2375,7 @@ int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance) lisp_debug(instance, "** objects before collection"); print_obj_lists(instance, instance->dout); } + pmain->value = &alsa_lisp_t; /* let garbage-collect working */ garbage_collect(instance); if (instance->debug) { lisp_debug(instance, "** objects after collection"); @@ -2186,6 +2385,22 @@ int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance) unset_object(instance, omain); + for (;;) { + p = get_object1(instance, "auto-exec"); + if (p == &alsa_lisp_nil) + break; + p = get_object(instance, p); + if (p == &alsa_lisp_nil) + break; + unset_object1(instance, "auto-exec"); + p1 = eval_func(instance, p, &alsa_lisp_nil); + if (p1 == NULL) { + retval = -ENOMEM; + break; + } + garbage_collect(instance); + } + done_lex(instance); if (_instance) *_instance = instance; @@ -2202,3 +2417,205 @@ void alsa_lisp_free(struct alisp_instance *instance) free_objects(instance); free(instance); } + +struct alisp_cfg *alsa_lisp_default_cfg(snd_input_t *input) +{ + snd_output_t *output, *eoutput; + struct alisp_cfg *cfg; + int err; + + err = snd_output_stdio_attach(&output, stdout, 0); + if (err < 0) + return NULL; + err = snd_output_stdio_attach(&eoutput, stderr, 0); + if (err < 0) { + snd_output_close(output); + return NULL; + } + cfg = calloc(1, sizeof(struct alisp_cfg)); + if (cfg == NULL) { + snd_output_close(eoutput); + snd_output_close(output); + return NULL; + } + cfg->out = output; + cfg->wout = eoutput; + cfg->eout = eoutput; + cfg->dout = eoutput; + cfg->in = input; + return cfg; +} + +void alsa_lisp_default_cfg_free(struct alisp_cfg *cfg) +{ + snd_input_close(cfg->in); + snd_output_close(cfg->out); + snd_output_close(cfg->dout); + free(cfg); +} + +int alsa_lisp_function(struct alisp_instance *instance, struct alisp_seq_iterator **result, + const char *id, const char *args, ...) +{ + int err = 0; + struct alisp_object *aargs = NULL, *p3, *res; + + if (args && *args != 'n') { + va_list ap; + struct alisp_object *p, *obj; + p = NULL; + va_start(ap, args); + while (*args) { + if (*args++ != '%') { + err = -EINVAL; + break; + } + if (*args == '\0') { + err = -EINVAL; + break; + } + obj = NULL; + err = 0; + switch (*args++) { + case 's': + obj = new_string(instance, va_arg(ap, char *)); + break; + case 'i': + obj = new_integer(instance, va_arg(ap, int)); + break; + case 'l': + obj = new_integer(instance, va_arg(ap, long)); + break; + case 'f': + case 'd': + obj = new_integer(instance, va_arg(ap, double)); + break; + default: + err = -EINVAL; + break; + } + if (err < 0) + goto __args_end; + if (obj == NULL) { + err = -ENOMEM; + goto __args_end; + } + if (p == NULL) { + p = aargs = new_object(instance, ALISP_OBJ_CONS); + } else { + p->value.c.cdr = new_object(instance, ALISP_OBJ_CONS); + p = p->value.c.cdr; + } + if (p == NULL) { + err = -ENOMEM; + goto __args_end; + } + p->value.c.car = obj; + } + __args_end: + va_end(ap); + if (err < 0) + return err; +#if 0 + snd_output_printf(instance->wout, ">>>"); + princ_object(instance->wout, aargs); + snd_output_printf(instance->wout, "<<<\n"); +#endif + } + + err = -ENOENT; + if (aargs == NULL) + aargs = &alsa_lisp_nil; + if ((p3 = get_object1(instance, id)) != &alsa_lisp_nil) { + res = eval_func(instance, p3, aargs); + err = 0; + } else { + struct intrinsic key, *item; + key.name = id; + if ((item = bsearch(&key, intrinsics, + sizeof intrinsics / sizeof intrinsics[0], + sizeof intrinsics[0], compar)) != NULL) { + res = item->func(instance, aargs); + err = 0; + } else if ((item = bsearch(&key, snd_intrinsics, + sizeof snd_intrinsics / sizeof snd_intrinsics[0], + sizeof snd_intrinsics[0], compar)) != NULL) { + res = item->func(instance, aargs); + err = 0; + } else { + res = &alsa_lisp_nil; + } + } + if (res == NULL) + err = -ENOMEM; + if (err == 0 && result) + *result = res; + + return 0; +} + +int alsa_lisp_seq_first(struct alisp_instance *instance, const char *id, + struct alisp_seq_iterator **seq) +{ + struct alisp_object * p1; + + p1 = get_object1(instance, id); + if (p1 == NULL) + return -ENOMEM; + *seq = p1; + return 0; +} + +int alsa_lisp_seq_next(struct alisp_seq_iterator **seq) +{ + struct alisp_object * p1 = *seq; + + p1 = cdr(p1); + if (p1 == &alsa_lisp_nil) + return -ENOENT; + *seq = p1; + return 0; +} + +int alsa_lisp_seq_count(struct alisp_seq_iterator *seq) +{ + int count = 0; + + while (seq != &alsa_lisp_nil) { + count++; + seq = cdr(seq); + } + return count; +} + +int alsa_lisp_seq_integer(struct alisp_seq_iterator *seq, long *val) +{ + if (seq->type == ALISP_OBJ_CONS) + seq = seq->value.c.cdr; + if (seq->type == ALISP_OBJ_INTEGER) + *val = seq->value.i; + else + return -EINVAL; + return 0; +} + +int alsa_lisp_seq_pointer(struct alisp_seq_iterator *seq, const char *ptr_id, void **ptr) +{ + struct alisp_object * p2; + + if (seq->type == ALISP_OBJ_CONS && seq->value.c.cdr->type == ALISP_OBJ_CONS) + seq = seq->value.c.cdr; + if (seq->type == ALISP_OBJ_CONS) { + p2 = seq->value.c.car; + if (p2->type != ALISP_OBJ_STRING && p2->type != ALISP_OBJ_IDENTIFIER) + return -EINVAL; + if (strcmp(p2->value.s, ptr_id)) + return -EINVAL; + p2 = seq->value.c.cdr; + if (p2->type != ALISP_OBJ_POINTER) + return -EINVAL; + *ptr = (void *)seq->value.ptr; + } else + return -EINVAL; + return 0; +} diff --git a/src/conf.c b/src/conf.c index 54798f0c..7c5f9935 100644 --- a/src/conf.c +++ b/src/conf.c @@ -2780,30 +2780,12 @@ int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t goto _err; } if (i == idx) { - wordexp_t we; char *name; if ((err = snd_config_get_ascii(n, &name)) < 0) goto _err; - err = wordexp(name, &we, WRDE_NOCMD); - switch (err) { - case WRDE_NOSPACE: - err = -ENOMEM; + if ((err = snd_user_file(name, &fi[idx].name)) < 0) goto _err; - case 0: - if (we.we_wordc == 1) - break; - /* Fall through */ - default: - err = -EINVAL; - goto _err; - } - fi[idx].name = strdup(we.we_wordv[0]); - wordfree(&we); free(name); - if (fi[idx].name == NULL) { - err = -ENOMEM; - goto _err; - } idx++; hit = 1; } @@ -2924,7 +2906,6 @@ int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, cons int err; const char *configs, *c; unsigned int k; - wordexp_t we; size_t l; snd_config_update_t *local; snd_config_update_t *update; @@ -2963,25 +2944,9 @@ int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, cons char name[l + 1]; memcpy(name, c, l); name[l] = 0; - err = wordexp(name, &we, WRDE_NOCMD); - switch (err) { - case WRDE_NOSPACE: - err = -ENOMEM; - goto _end; - case 0: - if (we.we_wordc == 1) - break; - /* Fall through */ - default: - err = -EINVAL; - goto _end; - } - local->finfo[k].name = strdup(we.we_wordv[0]); - wordfree(&we); - if (!local->finfo[k].name) { - err = -ENOMEM; + err = snd_user_file(name, &local->finfo[k].name); + if (err < 0) goto _end; - } c += l; k++; if (!*c) diff --git a/src/ordinary_mixer/ordinary_mixer.c b/src/ordinary_mixer/ordinary_mixer.c index 0e8490bf..a005aac1 100644 --- a/src/ordinary_mixer/ordinary_mixer.c +++ b/src/ordinary_mixer/ordinary_mixer.c @@ -56,10 +56,15 @@ Write something here #include #include #include "local.h" +#include "alisp.h" #include "mixer_ordinary.h" struct sndo_mixer { - snd_mixer_t *mixer; + struct alisp_cfg *cfg; + struct alisp_instance *alisp; + int hctl_count; + snd_hctl_t **hctl; + int _free_cfg; }; /** @@ -73,10 +78,78 @@ struct sndo_mixer { int sndo_mixer_open(sndo_mixer_t **pmixer, const char *playback_name, const char *capture_name, - snd_config_t *lconf) + struct alisp_cfg *lconf) { + struct alisp_cfg *cfg = lconf; + struct alisp_instance *alisp; + struct alisp_seq_iterator *iterator; + sndo_mixer_t *mixer; + int err, count; + long val; + *pmixer = NULL; - return -ENODEV; + if (cfg == NULL) { + char *file; + snd_input_t *input; + file = getenv("ALSA_ORDINARY_MIXER"); + if (!file) + file = DATADIR "/alsa/sndo-mixer.alisp"; + if ((err = snd_input_stdio_open(&input, file, "r")) < 0) { + SNDERR("unable to open alisp file '%s'", file); + return err; + } + cfg = alsa_lisp_default_cfg(input); + if (cfg == NULL) + return -ENOMEM; + } + err = alsa_lisp(cfg, &alisp); + if (err < 0) + goto __error; + err = alsa_lisp_function(alisp, &iterator, "open", "%s%s", playback_name, capture_name); + if (err < 0) { + alsa_lisp_free(alisp); + goto __error; + } + err = alsa_lisp_seq_integer(iterator, &val); + if (err == 0 && val < 0) + err = val; + if (err < 0) { + alsa_lisp_free(alisp); + goto __error; + } + count = 0; + if (alsa_lisp_seq_first(alisp, "hctls", &iterator) == 0) { + count = alsa_lisp_seq_count(iterator); + if (count < 0) + count = 0; + } + mixer = malloc(sizeof(sndo_mixer_t) + count * sizeof(snd_hctl_t *)); + if (mixer == NULL) { + alsa_lisp_free(alisp); + err = -ENOMEM; + goto __error; + } + memset(mixer, 0, sizeof(sndo_mixer_t)); + if (count > 0) { + mixer->hctl = (snd_hctl_t **)(mixer + 1); + do { + if (alsa_lisp_seq_pointer(iterator, "hctl", (void **)&mixer->hctl[mixer->hctl_count++])) + break; + } while (mixer->hctl_count < count && alsa_lisp_seq_next(&iterator) == 0); + if (mixer->hctl_count < count) { + mixer->hctl = NULL; + mixer->hctl_count = 0; + } + } + mixer->alisp = alisp; + mixer->cfg = cfg; + mixer->_free_cfg = cfg != lconf; + *pmixer = mixer; + return 0; + __error: + if (cfg != lconf) + alsa_lisp_default_cfg_free(cfg); + return err; } /** @@ -86,7 +159,14 @@ int sndo_mixer_open(sndo_mixer_t **pmixer, */ int sndo_mixer_close(sndo_mixer_t *mixer) { - return -ENODEV; + int res; + + res = alsa_lisp_function(mixer->alisp, NULL, "close", "n"); + alsa_lisp_free(mixer->alisp); + if (mixer->_free_cfg) + alsa_lisp_default_cfg_free(mixer->cfg); + free(mixer); + return res; } /** @@ -96,7 +176,25 @@ int sndo_mixer_close(sndo_mixer_t *mixer) */ int sndo_mixer_poll_descriptors_count(sndo_mixer_t *mixer) { - return snd_mixer_poll_descriptors_count(mixer->mixer); + int idx, err, res = -EIO; + + if (mixer->hctl_count > 0) { + for (idx = 0; idx < mixer->hctl_count; idx++) { + err = snd_hctl_poll_descriptors_count(mixer->hctl[idx]); + if (err < 0) + return err; + res += err; + } + } else { + struct alisp_seq_iterator *result; + long val; + err = alsa_lisp_function(mixer->alisp, &result, "poll_descriptors_count", "n"); + if (err < 0) + return err; + err = alsa_lisp_seq_integer(result, &val); + return err < 0 ? err : val; + } + return res; } /** @@ -108,7 +206,8 @@ int sndo_mixer_poll_descriptors_count(sndo_mixer_t *mixer) */ int sndo_mixer_poll_descriptors(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int space) { - return snd_mixer_poll_descriptors(mixer->mixer, pfds, space); + //return snd_mixer_poll_descriptors(mixer->mixer, pfds, space); + return -ENODEV; } /** @@ -121,7 +220,8 @@ int sndo_mixer_poll_descriptors(sndo_mixer_t *mixer, struct pollfd *pfds, unsign */ int sndo_mixer_poll_descriptors_revents(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) { - return snd_mixer_poll_descriptors_revents(mixer->mixer, pfds, nfds, revents); + //return snd_mixer_poll_descriptors_revents(mixer->mixer, pfds, nfds, revents); + return -ENODEV; } /** diff --git a/test/Makefile.am b/test/Makefile.am index ac354c07..3ce04041 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,6 @@ check_PROGRAMS=control pcm latency seq \ playmidi1 timer rawmidi midiloop \ - code + omixer code control_LDADD=../src/libasound.la pcm_LDADD=../src/libasound.la @@ -10,6 +10,7 @@ playmidi1_LDADD=../src/libasound.la timer_LDADD=../src/libasound.la rawmidi_LDADD=../src/libasound.la midiloop_LDADD=../src/libasound.la +omixer_LDADD=../src/libasound.la code_CFLAGS=-Wall -pipe -g -O2 INCLUDES=-I$(top_srcdir)/include diff --git a/test/control.c b/test/control.c index 9fec0ea7..f4b437ee 100644 --- a/test/control.c +++ b/test/control.c @@ -100,5 +100,7 @@ int main(void) } snd_ctl_close(handle); } + + snd_config_update_free_global(); return 0; } diff --git a/test/omixer.c b/test/omixer.c new file mode 100644 index 00000000..f4ffabf4 --- /dev/null +++ b/test/omixer.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include +#include "../include/mixer_ordinary.h" +#include +#include + +static void help(void) +{ + printf( +"Usage: omixer [OPTION]...\n" +"-h,--help help\n" +"-P,--pname playback device\n" +"-C,--cname capture device\n" +"\n"); +} + +int main(int argc, char *argv[]) +{ + struct option long_option[] = + { + {"help", 0, NULL, 'h'}, + {"pname", 1, NULL, 'P'}, + {"cname", 1, NULL, 'C'}, + {NULL, 0, NULL, 0}, + }; + int err, morehelp; + char *pname = "default", *cname = "default"; + sndo_mixer_t *handle; + + morehelp = 0; + while (1) { + int c; + if ((c = getopt_long(argc, argv, "hP:C:", long_option, NULL)) < 0) + break; + switch (c) { + case 'h': + morehelp++; + break; + case 'P': + pname = strdup(optarg); + break; + case 'C': + cname = strdup(optarg); + break; + } + } + + if (morehelp) { + help(); + return 0; + } + + err = sndo_mixer_open(&handle, pname, cname, NULL); + if (err < 0) { + fprintf(stderr, "mixer open error: %s\n", snd_strerror(err)); + return EXIT_FAILURE; + } + sndo_mixer_close(handle); + return EXIT_SUCCESS; +} diff --git a/test/pcm.c b/test/pcm.c index c9185ffa..2c8e1b97 100644 --- a/test/pcm.c +++ b/test/pcm.c @@ -691,7 +691,7 @@ static void help(void) { int k; printf( -"Usage: latency [OPTION]... [FILE]...\n" +"Usage: pcm [OPTION]... [FILE]...\n" "-h,--help help\n" "-D,--device playback device\n" "-r,--rate stream rate in Hz\n" -- cgit v1.2.3