From 60585e25fca3e31a2828f03170c8c1d6bb36c5fc Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 9 Sep 2003 19:24:35 +0000 Subject: [PATCH] added snd_hctl_ctl() function ordinary mixer: - revised Ordinary Mixer I/O type - sndo_mixer_open() take PCMs rather than strings to pass the real relationship - an initial version of toplevel alisp script more alisp development: - renamed a* functions to A* functions (acall -> Acall etc.) - many improvements (unset*, exfun, Acall pcm_info, Asnderr, Asyserr) --- alsalisp/hctl.lisp | 69 +++++----- configure.in | 3 +- include/control.h | 1 + include/mixer_ordinary.h | 160 +++++++++++++++++----- src/Versions | 1 + src/alisp/alisp.c | 170 ++++++++++++++++-------- src/alisp/alisp_snd.c | 115 ++++++++++++---- src/conf/Makefile.am | 3 +- src/conf/cards/Makefile.am | 15 ++- src/conf/cards/SI7018/sndoc-mixer.alisp | 4 + src/conf/cards/SI7018/sndop-mixer.alisp | 4 + src/conf/cards/aliases.alisp | 25 ++++ src/conf/sndo-mixer.alisp | 82 ++++++++++++ src/control/hcontrol.c | 11 +- src/ordinary_mixer/ordinary_mixer.c | 14 +- test/omixer.c | 27 +++- 16 files changed, 537 insertions(+), 167 deletions(-) create mode 100644 src/conf/cards/SI7018/sndoc-mixer.alisp create mode 100644 src/conf/cards/SI7018/sndop-mixer.alisp create mode 100644 src/conf/cards/aliases.alisp create mode 100644 src/conf/sndo-mixer.alisp diff --git a/alsalisp/hctl.lisp b/alsalisp/hctl.lisp index 6348d7bb..488d71f2 100644 --- a/alsalisp/hctl.lisp +++ b/alsalisp/hctl.lisp @@ -1,26 +1,26 @@ -(setq card (acall 'card_next -1)) -(setq card (aresult card)) +(setq card (Acall 'card_next -1)) +(setq card (Aresult card)) (while (>= card 0) (progn (princ "found card: " card "\n") - (princ " name : " (aresult (acall 'card_get_name card)) "\n") - (princ " longname: " (aresult (acall 'card_get_longname card)) "\n") - (setq card (acall 'card_next card)) - (setq card (aresult card)) + (princ " name : " (Aresult (Acall 'card_get_name card)) "\n") + (princ " longname: " (Aresult (Acall 'card_get_longname card)) "\n") + (setq card (Acall 'card_next card)) + (setq card (Aresult card)) ) ) (unsetq card) -(princ "card_get_index test (SI7018): " (acall 'card_get_index "SI7018") "\n") -(princ "card_get_index test (ABCD): " (acall 'card_get_index "ABCD") "\n") +(princ "card_get_index test (SI7018): " (Acall 'card_get_index "SI7018") "\n") +(princ "card_get_index test (ABCD): " (Acall 'card_get_index "ABCD") "\n") -(setq hctl (acall 'hctl_open 'default nil)) -(if (= (aerror hctl) 0) +(setq hctl (Acall 'hctl_open 'default nil)) +(if (= (Aerror hctl) 0) (progn (princ "open success: " hctl "\n") - (setq hctl (ahandle hctl)) + (setq hctl (Ahandle hctl)) (princ "open hctl: " hctl "\n") - (setq hctl (acall 'hctl_close hctl)) + (setq hctl (Acall 'hctl_close hctl)) (if (= hctl 0) (princ "close success\n") (princ "close failed: " hctl "\n") @@ -32,42 +32,42 @@ ) (unsetq hctl) -(setq ctl (acall 'ctl_open 'default nil)) -(if (= (aerror ctl) 0) +(setq ctl (Acall 'ctl_open 'default nil)) +(if (= (Aerror ctl) 0) (progn (princ "ctl open success: " ctl "\n") - (setq ctl (ahandle ctl)) - (setq info (aresult (acall 'ctl_card_info ctl))) + (setq ctl (Ahandle ctl)) + (setq info (Aresult (Acall 'ctl_card_info ctl))) (princ "ctl card info: " info "\n") (princ "ctl card info (mixername): " (cdr (assq "mixername" info)) "\n") (unsetq info) - (setq hctl (acall 'hctl_open_ctl ctl)) - (if (= (aerror hctl) 0) + (setq hctl (Acall 'hctl_open_ctl ctl)) + (if (= (Aerror hctl) 0) (progn (princ "hctl open success: " hctl "\n") - (setq hctl (ahandle hctl)) + (setq hctl (Ahandle hctl)) (princ "open hctl: " hctl "\n") - (princ "load hctl: " (acall 'hctl_load hctl) "\n") - (princ "first : " (acall 'hctl_first_elem hctl) "\n") - (princ "last : " (acall 'hctl_last_elem hctl) "\n") - (princ "next (first): " (acall 'hctl_elem_next (acall 'hctl_first_elem hctl)) "\n") - (princ "prev (last) : " (acall 'hctl_elem_prev (acall 'hctl_last_elem hctl)) "\n") - (setq elem (acall 'hctl_first_elem hctl)) + (princ "load hctl: " (Acall 'hctl_load hctl) "\n") + (princ "first : " (Acall 'hctl_first_elem hctl) "\n") + (princ "last : " (Acall 'hctl_last_elem hctl) "\n") + (princ "next (first): " (Acall 'hctl_elem_next (Acall 'hctl_first_elem hctl)) "\n") + (princ "prev (last) : " (Acall 'hctl_elem_prev (Acall 'hctl_last_elem hctl)) "\n") + (setq elem (Acall 'hctl_first_elem hctl)) (while elem (progn - (setq info (acall 'hctl_elem_info elem)) + (setq info (Acall 'hctl_elem_info elem)) (princ info "\n") - (setq value (acall 'hctl_elem_read elem)) + (setq value (Acall 'hctl_elem_read elem)) (princ value "\n") - (when (equal (cdr (assq "name" (car (cdr (assq "id" (aresult info)))))) "Master Playback Volume") - (princ "write Master: " (acall 'hctl_elem_write elem (20 20)) "\n") + (when (equal (cdr (assq "name" (car (cdr (assq "id" (Aresult info)))))) "Master Playback Volume") + (princ "write Master: " (Acall 'hctl_elem_write elem (20 20)) "\n") ) (unsetq info value) (gc) - (setq elem (acall 'hctl_elem_next elem)) + (setq elem (Acall 'hctl_elem_next elem)) ) ) - (setq hctl (acall 'hctl_close hctl)) + (setq hctl (Acall 'hctl_close hctl)) (if (= hctl 0) (princ "hctl close success\n") (princ "hctl close failed: " hctl "\n") @@ -75,7 +75,7 @@ ) (progn (princ "hctl open failed: " hctl "\n") - (acall 'ctl_close ctl) + (Acall 'ctl_close ctl) ) ) (unsetq hctl) @@ -88,8 +88,3 @@ (&stat-memory) (&dump-memory "memory.dump") - -(defun autotest () (princ "abcd\n")) -(setq auto-exec 'autotest) - -(princ (path 'data) "\n") diff --git a/configure.in b/configure.in index adc823d6..a29e2238 100644 --- a/configure.in +++ b/configure.in @@ -176,6 +176,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile include/Makefile src/rawmidi/Makefile src/timer/Makefile \ src/hwdep/Makefile src/seq/Makefile src/instr/Makefile \ src/compat/Makefile src/alisp/Makefile src/conf/Makefile \ - src/conf/cards/Makefile src/conf/pcm/Makefile \ + src/conf/cards/Makefile \ + src/conf/pcm/Makefile \ alsalisp/Makefile aserver/Makefile test/Makefile utils/Makefile \ utils/alsa-lib.spec utils/alsa.pc) diff --git a/include/control.h b/include/control.h index b26ab75c..a40c125e 100644 --- a/include/control.h +++ b/include/control.h @@ -468,6 +468,7 @@ int snd_hctl_free(snd_hctl_t *hctl); int snd_hctl_handle_events(snd_hctl_t *hctl); const char *snd_hctl_name(snd_hctl_t *hctl); int snd_hctl_wait(snd_hctl_t *hctl, int timeout); +snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl); snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem); snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem); diff --git a/include/mixer_ordinary.h b/include/mixer_ordinary.h index 940d7ac9..eebce24f 100644 --- a/include/mixer_ordinary.h +++ b/include/mixer_ordinary.h @@ -29,48 +29,137 @@ #include -/** Ordinary Mixer latency type */ +/** Ordinary Mixer I/O type */ enum sndo_mixer_io_type { /* * playback section */ - /** master volume - left (0-1000) */ + /** Master volume - left (0-1000) */ SNDO_MIO_MASTER_LVOL = 0, - /** master volume - right (0-1000) */ + /** Master volume - right (0-1000) */ SNDO_MIO_MASTER_RVOL, - /** master volume - left mute (0 = off, 1 = on) */ + /** Master volume - left surround (0-1000) */ + SNDO_MIO_MASTER_LSVOL = 0, + /** Master volume - right surround (0-1000) */ + SNDO_MIO_MASTER_RSVOL, + /** Master volume - center (0-1000) */ + SNDO_MIO_MASTER_CVOL = 0, + /** Master volume - LFE (0-1000) */ + SNDO_MIO_MASTER_LFEVOL, + /** Master volume - left mute (0 = off, 1 = on) */ SNDO_MIO_MASTER_LMUTE, - /** master volume - right mute (0 = off, 1 = on) */ + /** Master volume - right mute (0 = off, 1 = on) */ SNDO_MIO_MASTER_RMUTE, - - /** pcm volume - left (0-1000) */ - SNDO_MIO_Mixer_LVOL, - /** pcm volume - right (0-1000) */ - SNDO_MIO_Mixer_RVOL, - /** pcm volume - left mute (0 = off, 1 = on) */ - SNDO_MIO_Mixer_LMUTE, - /** pcm volume - right mute (0 = off, 1 = on) */ - SNDO_MIO_Mixer_RMUTE, + /** Master volume - left surround mute (0 = off, 1 = on) */ + SNDO_MIO_MASTER_LSMUTE, + /** Master volume - right surround mute (0 = off, 1 = on) */ + SNDO_MIO_MASTER_RSMUTE, + /** Master volume - center mute (0 = off, 1 = on) */ + SNDO_MIO_MASTER_CMUTE, + /** Master volume - LFE mute (0 = off, 1 = on) */ + SNDO_MIO_MASTER_LFEMUTE, + + /** PCM volume - left (0-1000) */ + SNDO_MIO_PCM_LVOL = 0, + /** PCM volume - right (0-1000) */ + SNDO_MIO_PCM_RVOL, + /** PCM volume - left surround (0-1000) */ + SNDO_MIO_PCM_LSVOL = 0, + /** PCM volume - right surround (0-1000) */ + SNDO_MIO_PCM_RSVOL, + /** PCM volume - center (0-1000) */ + SNDO_MIO_PCM_CVOL = 0, + /** PCM volume - LFE (0-1000) */ + SNDO_MIO_PCM_LFEVOL, + /** PCM volume - left mute (0 = off, 1 = on) */ + SNDO_MIO_PCM_LMUTE, + /** PCM volume - right mute (0 = off, 1 = on) */ + SNDO_MIO_PCM_RMUTE, + /** PCM volume - left surround mute (0 = off, 1 = on) */ + SNDO_MIO_PCM_LSMUTE, + /** PCM volume - right surround mute (0 = off, 1 = on) */ + SNDO_MIO_PCM_RSMUTE, + /** PCM volume - center mute (0 = off, 1 = on) */ + SNDO_MIO_PCM_CMUTE, + /** PCM volume - LFE mute (0 = off, 1 = on) */ + SNDO_MIO_PCM_LFEMUTE, + + /** LINE volume - left (0-1000) */ + SNDO_MIO_LINE_LVOL = 0, + /** LINE volume - right (0-1000) */ + SNDO_MIO_LINE_RVOL, + /** LINE volume - left surround (0-1000) */ + SNDO_MIO_LINE_LSVOL = 0, + /** LINE volume - right surround (0-1000) */ + SNDO_MIO_LINE_RSVOL, + /** LINE volume - center (0-1000) */ + SNDO_MIO_LINE_CVOL = 0, + /** LINE volume - LFE (0-1000) */ + SNDO_MIO_LINE_LFEVOL, + /** LINE volume - left mute (0 = off, 1 = on) */ + SNDO_MIO_LINE_LMUTE, + /** LINE volume - right mute (0 = off, 1 = on) */ + SNDO_MIO_LINE_RMUTE, + /** LINE volume - left surround mute (0 = off, 1 = on) */ + SNDO_MIO_LINE_LSMUTE, + /** LINE volume - right surround mute (0 = off, 1 = on) */ + SNDO_MIO_LINE_RSMUTE, + /** LINE volume - center mute (0 = off, 1 = on) */ + SNDO_MIO_LINE_CMUTE, + /** LINE volume - LFE mute (0 = off, 1 = on) */ + SNDO_MIO_LINE_LFEMUTE, + + /** MIC volume - left (0-1000) */ + SNDO_MIO_MIC_LVOL = 0, + /** MIC volume - right (0-1000) */ + SNDO_MIO_MIC_RVOL, + /** MIC volume - left surround (0-1000) */ + SNDO_MIO_MIC_LSVOL = 0, + /** MIC volume - right surround (0-1000) */ + SNDO_MIO_MIC_RSVOL, + /** MIC volume - center (0-1000) */ + SNDO_MIO_MIC_CVOL = 0, + /** MIC volume - LFE (0-1000) */ + SNDO_MIO_MIC_LFEVOL, + /** MIC volume - left mute (0 = off, 1 = on) */ + SNDO_MIO_MIC_LMUTE, + /** MIC volume - right mute (0 = off, 1 = on) */ + SNDO_MIO_MIC_RMUTE, + /** MIC volume - left surround mute (0 = off, 1 = on) */ + SNDO_MIO_MIC_LSMUTE, + /** MIC volume - right surround mute (0 = off, 1 = on) */ + SNDO_MIO_MIC_RSMUTE, + /** MIC volume - center mute (0 = off, 1 = on) */ + SNDO_MIO_MIC_CMUTE, + /** MIC volume - LFE mute (0 = off, 1 = on) */ + SNDO_MIO_MIC_LFEMUTE, /** CD volume - left (0-1000) */ - SNDO_MIO_CD_LVOL, + SNDO_MIO_CD_LVOL = 0, /** CD volume - right (0-1000) */ SNDO_MIO_CD_RVOL, + /** CD volume - left surround (0-1000) */ + SNDO_MIO_CD_LSVOL = 0, + /** CD volume - right surround (0-1000) */ + SNDO_MIO_CD_RSVOL, + /** CD volume - center (0-1000) */ + SNDO_MIO_CD_CVOL = 0, + /** CD volume - LFE (0-1000) */ + SNDO_MIO_CD_LFEVOL, /** CD volume - left mute (0 = off, 1 = on) */ SNDO_MIO_CD_LMUTE, /** CD volume - right mute (0 = off, 1 = on) */ SNDO_MIO_CD_RMUTE, - - /** AUX volume - left (0-1000) */ - SNDO_MIO_AUX_LVOL, - /** CD volume - right (0-1000) */ - SNDO_MIO_AUX_RVOL, - /** CD volume - left mute (0 = off, 1 = on) */ - SNDO_MIO_AUX_LMUTE, - /** CD volume - right mute (0 = off, 1 = on) */ - SNDO_MIO_AUX_RMUTE, + /** CD volume - left surround mute (0 = off, 1 = on) */ + SNDO_MIO_CD_LSMUTE, + /** CD volume - right surround mute (0 = off, 1 = on) */ + SNDO_MIO_CD_RSMUTE, + /** CD volume - center mute (0 = off, 1 = on) */ + SNDO_MIO_CD_CMUTE, + /** CD volume - LFE mute (0 = off, 1 = on) */ + SNDO_MIO_CD_LFEMUTE, /* * capture section @@ -80,17 +169,24 @@ enum sndo_mixer_io_type { SNDO_MIO_CGAIN_LVOL = 0x1000, /** capture gain - right (0-1000) */ SNDO_MIO_CGAIN_RVOL, - - - /** capture source - mic switch (0 = off, 1 = on) */ + /** capture gain - left surround (0-1000) */ + SNDO_MIO_CGAIN_LSVOL, + /** capture gain - right surround (0-1000) */ + SNDO_MIO_CGAIN_RSVOL, + /** capture gain - center (0-1000) */ + SNDO_MIO_CGAIN_CVOL, + /** capture gain - LFE (0-1000) */ + SNDO_MIO_CGAIN_LFEVOL, + + /** capture source - MIC exclusive switch (0 = off, 1 = on) */ SNDO_MIO_CSOURCE_MIC = 0x1100, - /** capture source - line switch (0 = off, 1 = on)*/ + /** capture source - LINE exclusive switch (0 = off, 1 = on) */ SNDO_MIO_CSOURCE_LINE, - /** capture source - CD switch (0 = off, 1 = on) */ + /** capture source - CD exclusive switch (0 = off, 1 = on) */ SNDO_MIO_CSOURCE_CD, - /** capture source - AUX switch (0 = off, 1 = on) */ + /** capture source - AUX exclusive switch (0 = off, 1 = on) */ SNDO_MIO_CSOURCE_AUX, - /** capture source - mix switch (0 = off, 1 = on) */ + /** capture source - MIX exclusive switch (0 = off, 1 = on) */ SNDO_MIO_CSOURCE_MIX }; @@ -107,7 +203,7 @@ extern "C" { * \{ */ -int sndo_mixer_open(sndo_mixer_t **pmixer, const char *playback_name, const char *capture_name, struct alisp_cfg *lconf); +int sndo_mixer_open(sndo_mixer_t **pmixer, snd_pcm_t *playback_pcm, snd_pcm_t *capture_pcm, 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/Versions b/src/Versions index 4e6a7eab..d9919cf5 100644 --- a/src/Versions +++ b/src/Versions @@ -131,6 +131,7 @@ ALSA_0.9.7 { global: snd_user_file; + snd_hctl_ctl; sndo_*; alsa_lisp_*; } ALSA_0.9.6; diff --git a/src/alisp/alisp.c b/src/alisp/alisp.c index 2321c7f3..4e8b2bf0 100644 --- a/src/alisp/alisp.c +++ b/src/alisp/alisp.c @@ -309,6 +309,24 @@ static struct alisp_object * new_pointer(struct alisp_instance *instance, const return obj; } +static struct alisp_object * new_cons_pointer(struct alisp_instance * instance, const char *ptr_id, void *ptr) +{ + struct alisp_object * lexpr; + + if (ptr == NULL) + return &alsa_lisp_nil; + lexpr = new_object(instance, ALISP_OBJ_CONS); + if (lexpr == NULL) + return NULL; + lexpr->value.c.car = new_string(instance, ptr_id); + if (lexpr->value.c.car == NULL) + return NULL; + lexpr->value.c.cdr = new_pointer(instance, ptr); + if (lexpr->value.c.cdr == NULL) + return NULL; + return lexpr; +} + void alsa_lisp_init_objects(void) __attribute__ ((constructor)); void alsa_lisp_init_objects(void) @@ -563,10 +581,13 @@ static struct alisp_object * parse_form(struct alisp_instance *instance) return first; } -static struct alisp_object * parse_quote(struct alisp_instance *instance) +static struct alisp_object * quote_object(struct alisp_instance *instance, struct alisp_object * obj) { struct alisp_object * p; + if (obj == NULL) + return NULL; + p = new_object(instance, ALISP_OBJ_CONS); if (p == NULL) return NULL; @@ -577,13 +598,16 @@ static struct alisp_object * parse_quote(struct alisp_instance *instance) p->value.c.cdr = new_object(instance, ALISP_OBJ_CONS); if (p->value.c.cdr == NULL) return NULL; - p->value.c.cdr->value.c.car = parse_object(instance, 0); - if (p->value.c.cdr->value.c.car == NULL) - return NULL; + p->value.c.cdr->value.c.car = obj; return p; } +static inline struct alisp_object * parse_quote(struct alisp_instance *instance) +{ + return quote_object(instance, parse_object(instance, 0)); +} + static struct alisp_object * parse_object(struct alisp_instance *instance, int havetoken) { int thistoken; @@ -662,8 +686,9 @@ static struct alisp_object_pair * set_object(struct alisp_instance *instance, st return p; } -static void unset_object1(struct alisp_instance *instance, const char *id) +static struct alisp_object * unset_object1(struct alisp_instance *instance, const char *id) { + struct alisp_object * res; struct alisp_object_pair *p, *p1; for (p = instance->setobjs_list, p1 = NULL; p != NULL; p1 = p, p = p->next) { @@ -673,13 +698,16 @@ static void unset_object1(struct alisp_instance *instance, const char *id) p1->next = p->next; else instance->setobjs_list = p->next; + res = p->value; free(p); - return; + return res; } } + + return &alsa_lisp_nil; } -static inline void unset_object(struct alisp_instance *instance, struct alisp_object * name) +static inline struct alisp_object * unset_object(struct alisp_instance *instance, struct alisp_object * name) { return unset_object1(instance, name->value.id); } @@ -688,10 +716,11 @@ static struct alisp_object * get_object1(struct alisp_instance *instance, const { struct alisp_object_pair *p; - for (p = instance->setobjs_list; p != NULL; p = p->next) + for (p = instance->setobjs_list; p != NULL; p = p->next) { if (p->name->value.id != NULL && !strcmp(id, p->name->value.id)) return p->value; + } return &alsa_lisp_nil; } @@ -956,18 +985,22 @@ static struct alisp_object * F_add(struct alisp_instance *instance, struct alisp } else { return new_float(instance, f); } - } else if (p1->type == ALISP_OBJ_STRING || p1->type == ALISP_OBJ_IDENTIFIER) { + } else if (p1->type == ALISP_OBJ_STRING) { 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 (p1->type == ALISP_OBJ_STRING) { + str1 = realloc(str, (str ? strlen(str) : 0) + strlen(p1->value.s) + 1); if (str1 == NULL) { nomem(); if (str) free(str); return NULL; } - strcat(str, p1->value.s); + if (str == NULL) + strcpy(str1, p1->value.s); + else + strcat(str1, p1->value.s); + str = str1; } else { lisp_warn(instance, "concat with a non string or identifier operand"); } @@ -1292,6 +1325,27 @@ static struct alisp_object * F_numeq(struct alisp_instance *instance, struct ali return &alsa_lisp_nil; } +/* + * Syntax: (exfun name) + * Test, if a function exists + */ +static struct alisp_object * F_exfun(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = car(args); + if (p1->type != ALISP_OBJ_STRING && p1->type != ALISP_OBJ_IDENTIFIER) + return &alsa_lisp_nil; + p2 = get_object(instance, p1); + if (p2 == &alsa_lisp_nil) + return &alsa_lisp_nil; + p2 = car(p2); + if (p2->type == ALISP_OBJ_IDENTIFIER && !strcmp(p2->value.id, "lambda")) + return &alsa_lisp_t; + + return &alsa_lisp_nil; +} + static void princ_string(snd_output_t *out, char *s) { char *p; @@ -1448,31 +1502,27 @@ static inline int eq(struct alisp_object * p1, struct alisp_object * p2) static int equal(struct alisp_object * p1, struct alisp_object * p2) { + int type1, type2; + if (eq(p1, p2)) return 1; - if (p1->type == ALISP_OBJ_CONS || p2->type == ALISP_OBJ_CONS) + type1 = p1->type; + type2 = p2->type; + + if (type1 == ALISP_OBJ_CONS || type2 == ALISP_OBJ_CONS) return 0; - if (p1->type == p2->type) - switch (p1->type) { - case ALISP_OBJ_IDENTIFIER: - if (!strcmp(p1->value.id, p2->value.id)) - return 1; - return 0; + if (type1 == type2) { + switch (type1) { case ALISP_OBJ_STRING: - if (!strcmp(p1->value.s, p2->value.s)) - return 1; - return 0; + return !strcmp(p1->value.s, p2->value.s); case ALISP_OBJ_INTEGER: - if (p1->value.i == p2->value.i) - return 1; - return 0; + return p1->value.i == p2->value.i; case ALISP_OBJ_FLOAT: - if (p1->value.i == p2->value.i) - return 1; - return 0; + return p1->value.i == p2->value.i; } + } return 0; } @@ -1727,7 +1777,7 @@ static struct alisp_object * F_unset(struct alisp_instance *instance, struct ali struct alisp_object * p1 = eval(instance, car(args)); unset_object(instance, p1); - return &alsa_lisp_nil; + return p1; } /* @@ -1757,15 +1807,15 @@ static struct alisp_object * F_setq(struct alisp_instance *instance, struct alis */ static struct alisp_object * F_unsetq(struct alisp_instance *instance, struct alisp_object * args) { - struct alisp_object * p = args, * p1; + struct alisp_object * p = args, * p1, * res; do { p1 = car(p); - unset_object(instance, p1); + res = unset_object(instance, p1); p = cdr(p); } while (p != &alsa_lisp_nil); - return &alsa_lisp_nil; + return res; } /* @@ -1885,7 +1935,7 @@ struct alisp_object * F_path(struct alisp_instance *instance, struct alisp_objec struct alisp_object * p = args, * p1; p1 = eval(instance, car(p)); - if (p1->type != ALISP_STRING && p1->type != ALISP_IDENTIFIER) + if (p1->type != ALISP_OBJ_STRING) return &alsa_lisp_nil; if (!strcmp(p1->value.s, "data")) return new_string(instance, DATADIR); @@ -1898,15 +1948,16 @@ struct alisp_object * F_path(struct alisp_instance *instance, struct alisp_objec struct alisp_object * F_include(struct alisp_instance *instance, struct alisp_object * args) { struct alisp_object * p = args, * p1; + int res = -ENOENT; do { p1 = eval(instance, car(p)); - if (p1->type == ALISP_STRING && p1->type == ALISP_IDENTIFIER) - alisp_include_file(instance, p1->value.s); + if (p1->type == ALISP_OBJ_STRING) + res = alisp_include_file(instance, p1->value.s); p = cdr(p); } while (p != &alsa_lisp_nil); - return p1; + return new_integer(instance, res); } /* @@ -2140,12 +2191,13 @@ static struct intrinsic intrinsics[] = { { "eq", F_eq }, { "equal", F_equal }, { "eval", F_eval }, + { "exfun", F_exfun }, { "float", F_float }, { "garbage-collect", F_gc }, { "gc", F_gc }, { "if", F_if }, - { "int", F_int }, { "include", F_include }, + { "int", F_int }, { "list", F_list }, { "not", F_not }, { "nth", F_nth }, @@ -2219,7 +2271,9 @@ static struct alisp_object * eval(struct alisp_instance *instance, struct alisp_ case ALISP_OBJ_IDENTIFIER: return get_object(instance, p); case ALISP_OBJ_INTEGER: + case ALISP_OBJ_FLOAT: case ALISP_OBJ_STRING: + case ALISP_OBJ_POINTER: return p; case ALISP_OBJ_CONS: return eval_cons(instance, p); @@ -2385,23 +2439,6 @@ 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; else @@ -2414,6 +2451,7 @@ void alsa_lisp_free(struct alisp_instance *instance) { if (instance == NULL) return; + done_lex(instance); free_objects(instance); free(instance); } @@ -2458,11 +2496,11 @@ int alsa_lisp_function(struct alisp_instance *instance, struct alisp_seq_iterato const char *id, const char *args, ...) { int err = 0; - struct alisp_object *aargs = NULL, *p3, *res; + struct alisp_object *aargs = NULL, *obj, *res; if (args && *args != 'n') { va_list ap; - struct alisp_object *p, *obj; + struct alisp_object *p; p = NULL; va_start(ap, args); while (*args) { @@ -2490,6 +2528,20 @@ int alsa_lisp_function(struct alisp_instance *instance, struct alisp_seq_iterato case 'd': obj = new_integer(instance, va_arg(ap, double)); break; + case 'p': { + char _ptrid[24]; + char *ptrid = _ptrid; + while (*args && *args != '%') + *ptrid++ = *args++; + *ptrid = 0; + if (ptrid == _ptrid) { + err = -EINVAL; + break; + } + obj = new_cons_pointer(instance, _ptrid, va_arg(ap, void *)); + obj = quote_object(instance, obj); + break; + } default: err = -EINVAL; break; @@ -2526,8 +2578,8 @@ int alsa_lisp_function(struct alisp_instance *instance, struct alisp_seq_iterato err = -ENOENT; if (aargs == NULL) aargs = &alsa_lisp_nil; - if ((p3 = get_object1(instance, id)) != &alsa_lisp_nil) { - res = eval_func(instance, p3, aargs); + if ((obj = get_object1(instance, id)) != &alsa_lisp_nil) { + res = eval_func(instance, obj, aargs); err = 0; } else { struct intrinsic key, *item; @@ -2607,7 +2659,7 @@ int alsa_lisp_seq_pointer(struct alisp_seq_iterator *seq, const char *ptr_id, vo 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) + if (p2->type != ALISP_OBJ_STRING) return -EINVAL; if (strcmp(p2->value.s, ptr_id)) return -EINVAL; diff --git a/src/alisp/alisp_snd.c b/src/alisp/alisp_snd.c index c26c4a32..6c12c9cc 100644 --- a/src/alisp/alisp_snd.c +++ b/src/alisp/alisp_snd.c @@ -243,24 +243,6 @@ static struct alisp_object * new_result3(struct alisp_instance * instance, int e return lexpr; } -static struct alisp_object * new_result4(struct alisp_instance * instance, const char *ptr_id, void *ptr) -{ - struct alisp_object * lexpr; - - if (ptr == NULL) - return &alsa_lisp_nil; - lexpr = new_object(instance, ALISP_OBJ_CONS); - if (lexpr == NULL) - return NULL; - lexpr->value.c.car = new_string(instance, ptr_id); - if (lexpr->value.c.car == NULL) - return NULL; - lexpr->value.c.cdr = new_pointer(instance, ptr); - if (lexpr->value.c.cdr == NULL) - return NULL; - return lexpr; -} - /* * macros */ @@ -326,6 +308,8 @@ static struct alisp_object * FA_p_p(struct alisp_instance * instance, struct aca item->xfunc == &snd_hctl_elem_next || item->xfunc == &snd_hctl_elem_prev) prefix1 = "hctl_elem"; + else if (item->xfunc == &snd_hctl_ctl) + prefix1 = "ctl"; else return &alsa_lisp_nil; args = eval(instance, car(args)); @@ -333,7 +317,7 @@ static struct alisp_object * FA_p_p(struct alisp_instance * instance, struct aca if (handle == NULL) return &alsa_lisp_nil; handle = ((snd_p_p_t)item->xfunc)(handle); - return new_result4(instance, prefix1, handle); + return new_cons_pointer(instance, prefix1, handle); } static struct alisp_object * FA_int_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) @@ -466,7 +450,7 @@ static struct alisp_object * FA_hctl_find_elem(struct alisp_instance * instance, snd_ctl_elem_id_alloca(&id); if (parse_ctl_elem_id(eval(instance, car(cdr(args))), id) < 0) return &alsa_lisp_nil; - return new_result4(instance, "hctl_elem", snd_hctl_find_elem(handle, id)); + return new_cons_pointer(instance, "hctl_elem", snd_hctl_find_elem(handle, id)); } static struct alisp_object * FA_hctl_elem_info(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) @@ -660,6 +644,36 @@ static struct alisp_object * FA_hctl_elem_write(struct alisp_instance * instance return new_result(instance, err); } +static struct alisp_object * FA_pcm_info(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + snd_pcm_t *handle; + struct alisp_object * lexpr, * p1; + snd_pcm_info_t *info; + int err; + + args = eval(instance, car(args)); + handle = (snd_pcm_t *)get_ptr(args, item->prefix); + if (handle == NULL) + return &alsa_lisp_nil; + snd_pcm_info_alloca(&info); + err = snd_pcm_info(handle, info); + lexpr = new_lexpr(instance, err); + if (err < 0) + return lexpr; + p1 = add_cons(instance, lexpr->value.c.cdr, 0, "card", new_integer(instance, snd_pcm_info_get_card(info))); + p1 = add_cons(instance, p1, 1, "device", new_integer(instance, snd_pcm_info_get_device(info))); + p1 = add_cons(instance, p1, 1, "subdevice", new_integer(instance, snd_pcm_info_get_subdevice(info))); + p1 = add_cons(instance, p1, 1, "id", new_string(instance, snd_pcm_info_get_id(info))); + p1 = add_cons(instance, p1, 1, "name", new_string(instance, snd_pcm_info_get_name(info))); + p1 = add_cons(instance, p1, 1, "subdevice_name", new_string(instance, snd_pcm_info_get_subdevice_name(info))); + p1 = add_cons(instance, p1, 1, "class", new_integer(instance, snd_pcm_info_get_class(info))); + p1 = add_cons(instance, p1, 1, "subclass", new_integer(instance, snd_pcm_info_get_subclass(info))); + p1 = add_cons(instance, p1, 1, "subdevices_count", new_integer(instance, snd_pcm_info_get_subdevices_count(info))); + p1 = add_cons(instance, p1, 1, "subdevices_avail", new_integer(instance, snd_pcm_info_get_subdevices_avail(info))); + //p1 = add_cons(instance, p1, 1, "sync", new_string(instance, snd_pcm_info_get_sync(info))); + return lexpr; +} + /* * main code */ @@ -673,6 +687,7 @@ static struct acall_table acall_table[] = { { "ctl_close", &FA_int_p, (void *)&snd_ctl_close, "ctl" }, { "ctl_open", &FA_int_pp_strp_int, (void *)&snd_ctl_open, "ctl" }, { "hctl_close", &FA_int_p, (void *)&snd_hctl_close, "hctl" }, + { "hctl_ctl", &FA_p_p, (void *)&snd_hctl_ctl, "hctl" }, { "hctl_elem_info", &FA_hctl_elem_info, (void *)&snd_hctl_elem_info, "hctl_elem" }, { "hctl_elem_next", &FA_p_p, (void *)&snd_hctl_elem_next, "hctl_elem" }, { "hctl_elem_prev", &FA_p_p, (void *)&snd_hctl_elem_prev, "hctl_elem" }, @@ -685,6 +700,7 @@ static struct acall_table acall_table[] = { { "hctl_load", &FA_int_p, (void *)&snd_hctl_load, "hctl" }, { "hctl_open", &FA_int_pp_strp_int, (void *)&snd_hctl_open, "hctl" }, { "hctl_open_ctl", &FA_int_pp_p, (void *)&snd_hctl_open_ctl, "hctl" }, + { "pcm_info", &FA_pcm_info, NULL, "pcm" }, }; static int acall_compar(const void *p1, const void *p2) @@ -724,9 +740,60 @@ static struct alisp_object * F_aerror(struct alisp_instance *instance, struct al return args; } +static int common_error(snd_output_t **rout, struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1; + snd_output_t *out; + int err; + + err = snd_output_buffer_open(&out); + if (err < 0) + return err; + + do { + p1 = eval(instance, car(p)); + if (p1->type == ALISP_OBJ_STRING) + snd_output_printf(out, "%s", p1->value.s); + else + princ_object(out, p1); + p = cdr(p); + } while (p != &alsa_lisp_nil); + + *rout = out; + return 0; +} + +static struct alisp_object * F_snderr(struct alisp_instance *instance, struct alisp_object * args) +{ + snd_output_t *out; + char *str; + + if (common_error(&out, instance, args) < 0) + return &alsa_lisp_nil; + snd_output_buffer_string(out, &str); + SNDERR(str); + snd_output_close(out); + return &alsa_lisp_t; +} + +static struct alisp_object * F_syserr(struct alisp_instance *instance, struct alisp_object * args) +{ + snd_output_t *out; + char *str; + + if (common_error(&out, instance, args) < 0) + return &alsa_lisp_nil; + snd_output_buffer_string(out, &str); + SYSERR(str); + snd_output_close(out); + return &alsa_lisp_t; +} + static struct intrinsic snd_intrinsics[] = { - { "acall", F_acall }, - { "aerror", F_aerror }, - { "ahandle", F_ahandle }, - { "aresult", F_ahandle }, + { "Acall", F_acall }, + { "Aerror", F_aerror }, + { "Ahandle", F_ahandle }, + { "Aresult", F_ahandle }, + { "Asnderr", F_snderr }, + { "Asyserr", F_syserr } }; diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am index ff9108a4..ab812f93 100644 --- a/src/conf/Makefile.am +++ b/src/conf/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS=cards pcm -cfg_files = alsa.conf +cfg_files = alsa.conf \ + sndo-mixer.alisp EXTRA_DIST = $(cfg_files) diff --git a/src/conf/cards/Makefile.am b/src/conf/cards/Makefile.am index bf0ec173..0c5821bd 100644 --- a/src/conf/cards/Makefile.am +++ b/src/conf/cards/Makefile.am @@ -23,7 +23,18 @@ cfg_files = aliases.conf \ VIA8233A.conf \ VX222.conf \ VXPocket.conf \ - VXPocket440.conf + VXPocket440.conf \ +\ + aliases.alisp -EXTRA_DIST = $(cfg_files) alsa_DATA = $(cfg_files) + +SI7018dir = $(datadir)/alsa/cards/SI7018 +SI7018_files = \ + SI7018/sndoc-mixer.alisp \ + SI7018/sndop-mixer.alisp +SI7018_DATA = $(SI7018_files) + +EXTRA_DIST = + $(cfg_files) \ + $(SI7018_files) diff --git a/src/conf/cards/SI7018/sndoc-mixer.alisp b/src/conf/cards/SI7018/sndoc-mixer.alisp new file mode 100644 index 00000000..2bea45c0 --- /dev/null +++ b/src/conf/cards/SI7018/sndoc-mixer.alisp @@ -0,0 +1,4 @@ +(defun sndoc_mixer_open (hctl) + (princ "sndoc_mixer_open\n") + 0 +) diff --git a/src/conf/cards/SI7018/sndop-mixer.alisp b/src/conf/cards/SI7018/sndop-mixer.alisp new file mode 100644 index 00000000..26dc9ad9 --- /dev/null +++ b/src/conf/cards/SI7018/sndop-mixer.alisp @@ -0,0 +1,4 @@ +(defun sndop_mixer_open (hctl) + (princ "sndop_mixer_open\n") + 0 +) diff --git a/src/conf/cards/aliases.alisp b/src/conf/cards/aliases.alisp new file mode 100644 index 00000000..3ab21e76 --- /dev/null +++ b/src/conf/cards/aliases.alisp @@ -0,0 +1,25 @@ +(setq snd_card_aliases_array + ( + ("YMF724" . "YMF744") + ("YMF724F" . "YMF744") + ("YMF740" . "YMF744") + ("YMF740C" . "YMF744") + ("YMF754" . "YMF744") + ("CMIPCI" . "CMI8338") + ("CMI8738" . "CMI8338") + ("CMI8738-MC4" . "CMI8738-MC6") + ("E-mu APS" . "EMU10K1") + ("GUS Max" . "GUS") + ("GUS ACE" . "GUS") + ("GUS Extreme" . "GUS") + ("AMD InterWave" . "GUS") + ("Dynasonic 3-D" . "GUS") + ("InterWave STB" . "GUS") + ) +) + +(defun snd_card_alias (cardname) + (setq r (assq cardname snd_card_aliases_array)) + (setq r (if (null r) cardname r)) + (unsetq r) +) diff --git a/src/conf/sndo-mixer.alisp b/src/conf/sndo-mixer.alisp new file mode 100644 index 00000000..8342ad05 --- /dev/null +++ b/src/conf/sndo-mixer.alisp @@ -0,0 +1,82 @@ +(defun sndo_include (hctl stream) + (setq info (Acall "ctl_card_info" (Acall "hctl_ctl" hctl))) + (if (= (Aerror info) 0) + (progn + (setq info (Aresult info)) + (setq driver (cdr (assq "driver" (unsetq info)))) + (setq file (+ (path "data") "/alsa/cards/" (snd_card_alias driver) "/sndo" stream "-mixer.alisp")) + (setq r (include file)) + (when (= r -2) (Asyserr "unable to find file " file)) + (unsetq driver file r) + ) + (setq r (Aerror info)) + (unsetq info r) + ) +) + +(defun sndo_mixer_open1 (pcm stream) + (setq info (Acall "pcm_info" pcm)) + (setq r (Aerror info)) + (when (= r 0) + (progn + (setq info (Aresult info)) + (setq card (cdr (assq "card" info))) + (setq r + (if (< card 0) + (+ (Acall "pcm_name" pcm) stream) + (+ "hw:" (str card)) + ) + ) + (unsetq card) + ) + ) + (unsetq info r) +) + +(defun sndo_mixer_open (ppcm cpcm) + (setq pname (sndo_mixer_open1 ppcm "p")) + (setq cname (sndo_mixer_open1 cpcm "c")) + (setq phctl (Acall "hctl_open" pname nil)) + (if (= (Aerror phctl) 0) + (progn + (setq phctl (Aresult phctl)) + (setq chctl (Acall "hctl_open" cname nil)) + (if (= (Aerror chctl) 0) + (progn + (setq chctl (Aresult chctl)) + (setq hctls (cons phctl (cons chctl))) + (setq r (sndo_include phctl "p")) + (when (= r 0) (setq r (sndo_include chctl "c"))) + (when (= r 0) (setq r (if (exfun sndop_mixer_open) (sndop_mixer_open phctl) 0))) + (when (= r 0) + (progn + (setq r (if (exfun sndoc_mixer_open) (sndoc_mixer_open chctl) 0)) + (unless (= r 0) (sndop_close phctl)) + ) + ) + (unless (= r 0) (sndo_close)) + (unsetq phctl chctl) + (gc) + (unsetq r) + ) + (progn + (Acall "hctl_close" (Aresult phctl)) + (setq r (Aerror chctl)) + (unsetq r) + ) + ) + ) + (setq r (Aerror phctl)) + (unsetq r) + ) +) + +(defun sndo_mixer_close nil + (cond (exfun sndop_close) (sndop_close (nth 0 hctls))) + (cond (exfun sndoc_close) (sndoc_close (nth 1 hctls))) + (Acall "hctl_close" (nth 0 hctls)) + (Acall "hctl_close" (nth 1 hctls)) + (unsetq hctls) +) + +(include (+ (path "data") "/alsa/cards/aliases.alisp")) diff --git a/src/control/hcontrol.c b/src/control/hcontrol.c index 889bde5c..b1d5ac42 100644 --- a/src/control/hcontrol.c +++ b/src/control/hcontrol.c @@ -89,7 +89,6 @@ int snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode) int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl) { snd_hctl_t *hctl; - int err; assert(hctlp); *hctlp = NULL; @@ -649,6 +648,16 @@ int snd_hctl_wait(snd_hctl_t *hctl, int timeout) return 0; } +/** + * \brief Get a ctl handle associated to the given hctl handle + * \param hctl HCTL handle + * \return a ctl handle otherwise NULL + */ +snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl) +{ + return hctl->ctl; +} + static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event) { snd_hctl_elem_t *elem; diff --git a/src/ordinary_mixer/ordinary_mixer.c b/src/ordinary_mixer/ordinary_mixer.c index a005aac1..63042923 100644 --- a/src/ordinary_mixer/ordinary_mixer.c +++ b/src/ordinary_mixer/ordinary_mixer.c @@ -70,14 +70,14 @@ struct sndo_mixer { /** * \brief Opens a ordinary mixer instance * \param pmixer Returned ordinary mixer handle - * \param playback_name ASCII identifier of the ordinary mixer handle (playback controls) - * \param capture_name ASCII identifier of the ordinary mixer handle (capture controls) + * \param playback_pcm handle of the playback PCM + * \param capture_pcm handle of the capture PCM * \param lconf Local configuration (might be NULL - use global configuration) * \return 0 on success otherwise a negative error code */ int sndo_mixer_open(sndo_mixer_t **pmixer, - const char *playback_name, - const char *capture_name, + snd_pcm_t *playback_pcm, + snd_pcm_t *capture_pcm, struct alisp_cfg *lconf) { struct alisp_cfg *cfg = lconf; @@ -105,7 +105,7 @@ int sndo_mixer_open(sndo_mixer_t **pmixer, err = alsa_lisp(cfg, &alisp); if (err < 0) goto __error; - err = alsa_lisp_function(alisp, &iterator, "open", "%s%s", playback_name, capture_name); + err = alsa_lisp_function(alisp, &iterator, "sndo_mixer_open", "%ppcm%ppcm", playback_pcm, capture_pcm); if (err < 0) { alsa_lisp_free(alisp); goto __error; @@ -161,7 +161,7 @@ int sndo_mixer_close(sndo_mixer_t *mixer) { int res; - res = alsa_lisp_function(mixer->alisp, NULL, "close", "n"); + res = alsa_lisp_function(mixer->alisp, NULL, "sndo_mixer_close", "n"); alsa_lisp_free(mixer->alisp); if (mixer->_free_cfg) alsa_lisp_default_cfg_free(mixer->cfg); @@ -188,7 +188,7 @@ int sndo_mixer_poll_descriptors_count(sndo_mixer_t *mixer) } else { struct alisp_seq_iterator *result; long val; - err = alsa_lisp_function(mixer->alisp, &result, "poll_descriptors_count", "n"); + err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_poll_descriptors_count", "n"); if (err < 0) return err; err = alsa_lisp_seq_integer(result, &val); diff --git a/test/omixer.c b/test/omixer.c index f4ffabf4..0512b7eb 100644 --- a/test/omixer.c +++ b/test/omixer.c @@ -13,8 +13,8 @@ static void help(void) printf( "Usage: omixer [OPTION]...\n" "-h,--help help\n" -"-P,--pname playback device\n" -"-C,--cname capture device\n" +"-P,--pname playback PCM device\n" +"-C,--cname capture PCM device\n" "\n"); } @@ -29,6 +29,7 @@ int main(int argc, char *argv[]) }; int err, morehelp; char *pname = "default", *cname = "default"; + snd_pcm_t *phandle = NULL, *chandle = NULL; sndo_mixer_t *handle; morehelp = 0; @@ -54,11 +55,31 @@ int main(int argc, char *argv[]) return 0; } - err = sndo_mixer_open(&handle, pname, cname, NULL); + if (strcmp(pname, "-")) { + err = snd_pcm_open(&phandle, pname, SND_PCM_STREAM_PLAYBACK, 0); + if (err < 0) { + fprintf(stderr, "Playback PCM open error: %s\n", snd_strerror(err)); + return EXIT_FAILURE; + } + } + + if (strcmp(cname, "-")) { + err = snd_pcm_open(&chandle, cname, SND_PCM_STREAM_CAPTURE, 0); + if (err < 0) { + if (phandle) + snd_pcm_close(phandle); + fprintf(stderr, "Capture PCM open error: %s\n", snd_strerror(err)); + return EXIT_FAILURE; + } + } + + err = sndo_mixer_open(&handle, phandle, chandle, NULL); if (err < 0) { fprintf(stderr, "mixer open error: %s\n", snd_strerror(err)); return EXIT_FAILURE; } sndo_mixer_close(handle); + snd_pcm_close(chandle); + snd_pcm_close(phandle); return EXIT_SUCCESS; } -- 2.47.1