The highlevel control layer was rewritten and updated.

Various fixes in mixer simple layer.
Added include/list.h (from the kernel tree).
This commit is contained in:
Jaroslav Kysela 2000-08-11 19:28:43 +00:00
parent b99128d8de
commit 82102903fe
7 changed files with 382 additions and 189 deletions

View file

@ -54,10 +54,25 @@ int snd_ctl_read(snd_ctl_t *handle, snd_ctl_callbacks_t * callbacks);
* Highlevel API for controls * Highlevel API for controls
*/ */
#define LIST_HEAD_IS_DEFINED
struct list_head {
struct list_head *next, *prev;
};
typedef struct snd_hcontrol_list_stru snd_hcontrol_list_t;
typedef struct snd_hcontrol_stru snd_hcontrol_t; typedef struct snd_hcontrol_stru snd_hcontrol_t;
struct snd_hcontrol_list_stru {
unsigned int controls_offset; /* W: first control ID to get */
unsigned int controls_request; /* W: count of control IDs to get */
unsigned int controls_count; /* R: count of available (set) controls */
unsigned int controls; /* R: count of all available controls */
snd_control_id_t *pids; /* W: IDs */
};
struct snd_hcontrol_stru { struct snd_hcontrol_stru {
snd_control_id_t id; /* must be always on top */ snd_control_id_t id; /* must be always on top */
struct list_head list; /* links for list of all hcontrols */
int change: 1, /* structure change */ int change: 1, /* structure change */
value: 1; /* value change */ value: 1; /* value change */
/* event callbacks */ /* event callbacks */
@ -71,18 +86,19 @@ struct snd_hcontrol_stru {
snd_ctl_t *handle; /* associated handle */ snd_ctl_t *handle; /* associated handle */
}; };
typedef int (snd_ctl_csort_t)(const snd_hcontrol_t *c1, const snd_hcontrol_t *c2); typedef int (snd_ctl_hsort_t)(const snd_hcontrol_t *c1, const snd_hcontrol_t *c2);
typedef int (snd_ctl_ccallback_rebuild_t)(snd_ctl_t *handle, void *private_data); typedef int (snd_ctl_hcallback_rebuild_t)(snd_ctl_t *handle, void *private_data);
typedef int (snd_ctl_ccallback_add_t)(snd_ctl_t *handle, void *private_data, snd_hcontrol_t *hcontrol); typedef int (snd_ctl_hcallback_add_t)(snd_ctl_t *handle, void *private_data, snd_hcontrol_t *hcontrol);
int snd_ctl_cbuild(snd_ctl_t *handle, snd_ctl_csort_t *csort); int snd_ctl_hbuild(snd_ctl_t *handle, snd_ctl_hsort_t *csort);
int snd_ctl_cfree(snd_ctl_t *handle); int snd_ctl_hfree(snd_ctl_t *handle);
snd_hcontrol_t *snd_ctl_cfind(snd_ctl_t *handle, snd_control_id_t *id); snd_hcontrol_t *snd_ctl_hfind(snd_ctl_t *handle, snd_control_id_t *id);
int snd_ctl_csort(const snd_hcontrol_t *c1, const snd_hcontrol_t *c2); int snd_ctl_hlist(snd_ctl_t *handle, snd_hcontrol_list_t *hlist);
int snd_ctl_cresort(snd_ctl_t *handle, snd_ctl_csort_t *csort); int snd_ctl_hsort(const snd_hcontrol_t *c1, const snd_hcontrol_t *c2);
int snd_ctl_ccallback_rebuild(snd_ctl_t *handle, snd_ctl_ccallback_rebuild_t *callback, void *private_data); int snd_ctl_hresort(snd_ctl_t *handle, snd_ctl_hsort_t *csort);
int snd_ctl_ccallback_add(snd_ctl_t *handle, snd_ctl_ccallback_add_t *callback, void *private_data); int snd_ctl_hcallback_rebuild(snd_ctl_t *handle, snd_ctl_hcallback_rebuild_t *callback, void *private_data);
int snd_ctl_cevent(snd_ctl_t *handle); int snd_ctl_hcallback_add(snd_ctl_t *handle, snd_ctl_hcallback_add_t *callback, void *private_data);
int snd_ctl_hevent(snd_ctl_t *handle);
#ifdef __cplusplus #ifdef __cplusplus
} }

156
include/list.h Normal file
View file

@ -0,0 +1,156 @@
#ifndef _LIST_H
#define _LIST_H
/*
* This code was taken from the Linux 2.4.0 kernel. [jaroslav]
*/
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
#ifndef LIST_HEAD_IS_DEFINED
struct list_head {
struct list_head *next, *prev;
};
#endif
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head * new,
struct list_head * prev,
struct list_head * next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head * prev,
struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.n
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list, struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#endif /* _LIST_H */

View file

@ -64,6 +64,7 @@ int snd_ctl_open(snd_ctl_t **handle, int card)
} }
ctl->card = card; ctl->card = card;
ctl->fd = fd; ctl->fd = fd;
INIT_LIST_HEAD(&ctl->hlist);
*handle = ctl; *handle = ctl;
return 0; return 0;
} }
@ -101,7 +102,7 @@ int snd_ctl_clist(snd_ctl_t *handle, snd_control_list_t *list)
int snd_ctl_cinfo(snd_ctl_t *handle, snd_control_info_t *info) int snd_ctl_cinfo(snd_ctl_t *handle, snd_control_info_t *info)
{ {
assert(handle && info && info->id.name[0]); assert(handle && info && (info->id.name[0] || info->id.numid));
if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_INFO, info) < 0) if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_INFO, info) < 0)
return -errno; return -errno;
return 0; return 0;
@ -109,7 +110,7 @@ int snd_ctl_cinfo(snd_ctl_t *handle, snd_control_info_t *info)
int snd_ctl_cread(snd_ctl_t *handle, snd_control_t *control) int snd_ctl_cread(snd_ctl_t *handle, snd_control_t *control)
{ {
assert(handle && control && control->id.name[0]); assert(handle && control && (control->id.name[0] || control->id.numid));
if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_READ, control) < 0) if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_READ, control) < 0)
return -errno; return -errno;
return 0; return 0;
@ -117,7 +118,7 @@ int snd_ctl_cread(snd_ctl_t *handle, snd_control_t *control)
int snd_ctl_cwrite(snd_ctl_t *handle, snd_control_t *control) int snd_ctl_cwrite(snd_ctl_t *handle, snd_control_t *control)
{ {
assert(handle && control && control->id.name[0]); assert(handle && control && (control->id.name[0] || control->id.numid));
if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_WRITE, control) < 0) if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_WRITE, control) < 0)
return -errno; return -errno;
return 0; return 0;

View file

@ -19,16 +19,19 @@
* *
*/ */
#include "list.h"
struct snd_ctl { struct snd_ctl {
int card; int card;
int fd; int fd;
int ccount; int hcount;
int cerr; int herr;
void *croot; /* root of controls */ struct list_head hlist; /* list of all controls */
void *croot_new; /* new croot */ void *hroot; /* root of controls */
snd_ctl_csort_t *csort; void *hroot_new; /* new croot */
snd_ctl_ccallback_rebuild_t *callback_rebuild; snd_ctl_hsort_t *hsort;
snd_ctl_hcallback_rebuild_t *callback_rebuild;
void *callback_rebuild_private_data; void *callback_rebuild_private_data;
snd_ctl_ccallback_add_t *callback_add; snd_ctl_hcallback_add_t *callback_add;
void *callback_add_private_data; void *callback_add_private_data;
}; };

View file

@ -32,21 +32,20 @@
#include "asoundlib.h" #include "asoundlib.h"
#include "control_local.h" #include "control_local.h"
static void snd_ctl_cfree1(snd_hcontrol_t *hcontrol); static void snd_ctl_hfree1(snd_hcontrol_t *hcontrol);
int snd_ctl_cbuild(snd_ctl_t *handle, snd_ctl_csort_t *csort) int snd_ctl_hbuild(snd_ctl_t *handle, snd_ctl_hsort_t *hsort)
{ {
snd_control_list_t list; snd_control_list_t list;
snd_hcontrol_t *hcontrol, *prev; snd_hcontrol_t *hcontrol, *prev;
int err; int err;
unsigned int idx; unsigned int idx;
printf("cbuild - start\n");
assert(handle != NULL); assert(handle != NULL);
if ((err = snd_ctl_cfree(handle)) < 0) if ((err = snd_ctl_hfree(handle)) < 0)
return err; return err;
if (csort == NULL) if (hsort == NULL)
csort = snd_ctl_csort; hsort = snd_ctl_hsort;
memset(&list, 0, sizeof(list)); memset(&list, 0, sizeof(list));
do { do {
if (list.pids != NULL) if (list.pids != NULL)
@ -67,132 +66,171 @@ int snd_ctl_cbuild(snd_ctl_t *handle, snd_ctl_csort_t *csort)
} while (list.controls != list.controls_count); } while (list.controls != list.controls_count);
for (idx = 0, prev = NULL; idx < list.controls_count; idx++) { for (idx = 0, prev = NULL; idx < list.controls_count; idx++) {
hcontrol = (snd_hcontrol_t *)calloc(1, sizeof(snd_hcontrol_t)); hcontrol = (snd_hcontrol_t *)calloc(1, sizeof(snd_hcontrol_t));
if (hcontrol == NULL) { if (hcontrol == NULL)
snd_ctl_cfree(handle); goto __nomem;
hcontrol->id = list.pids[idx];
hcontrol->handle = handle;
if (tsearch(hcontrol, &handle->hroot, (__compar_fn_t)hsort) == NULL) {
__nomem:
if (handle->hroot != NULL) {
tdestroy(handle->hroot, (__free_fn_t)snd_ctl_hfree1);
handle->hroot = NULL;
}
handle->hroot = NULL;
if (hcontrol != NULL)
free(hcontrol);
free(list.pids); free(list.pids);
return -ENOMEM; return -ENOMEM;
} }
hcontrol->id = list.pids[idx]; list_add_tail(&hcontrol->list, &handle->hlist);
hcontrol->handle = handle; handle->hcount++;
if (tsearch(hcontrol, &handle->croot, (__compar_fn_t)csort) == NULL) {
tdestroy(&handle->croot, (__free_fn_t)snd_ctl_cfree1);
handle->croot = NULL;
}
handle->ccount++;
} }
if (list.pids != NULL) if (list.pids != NULL)
free(list.pids); free(list.pids);
handle->csort = csort; if ((err = snd_ctl_hresort(handle, hsort)) < 0) {
tdestroy(handle->hroot, (__free_fn_t)snd_ctl_hfree1);
handle->hroot = NULL;
}
return 0; return 0;
} }
static void snd_ctl_cfree1(snd_hcontrol_t *hcontrol) static void snd_ctl_hfree1(snd_hcontrol_t *hcontrol)
{ {
snd_ctl_t *handle; snd_ctl_t *handle;
assert(hcontrol != NULL); assert(hcontrol != NULL);
handle = hcontrol->handle; handle = hcontrol->handle;
assert(handle != NULL); assert(handle != NULL);
assert(handle->ccount > 0); assert(handle->hcount > 0);
if (hcontrol->event_remove) if (hcontrol->event_remove)
hcontrol->event_remove(handle, hcontrol); hcontrol->event_remove(handle, hcontrol);
if (hcontrol->private_free) if (hcontrol->private_free)
hcontrol->private_free(hcontrol->private_data); hcontrol->private_free(hcontrol->private_data);
list_del(&hcontrol->list);
free(hcontrol); free(hcontrol);
handle->ccount--; handle->hcount--;
} }
int snd_ctl_cfree(snd_ctl_t *handle) int snd_ctl_hfree(snd_ctl_t *handle)
{ {
handle->csort = NULL; handle->hsort = NULL;
handle->cerr = 0; handle->herr = 0;
if (handle->croot != NULL) { if (handle->hroot != NULL) {
tdestroy(handle->croot, (__free_fn_t)snd_ctl_cfree1); tdestroy(handle->hroot, (__free_fn_t)snd_ctl_hfree1);
handle->croot = NULL; handle->hroot = NULL;
} }
assert(handle->ccount == 0); assert(list_empty(&handle->hlist));
assert(handle->hcount == 0);
return 0; return 0;
} }
int snd_ctl_csort(const snd_hcontrol_t *c1, const snd_hcontrol_t *c2) int snd_ctl_hsort(const snd_hcontrol_t *c1, const snd_hcontrol_t *c2)
{ {
int res; int res;
res = strcmp(c1->id.name, c2->id.name); if (c1->id.iface < c2->id.iface)
if (res == 0) { return -1;
if (c1->id.index < c2->id.index) if (c1->id.iface > c2->id.iface)
return -1; return 1;
if (c1->id.index > c2->id.index) if ((res = strcmp(c1->id.name, c2->id.name)) != 0)
return 1; return res;
return 0; if (c1->id.index < c2->id.index)
} return -1;
return res; if (c1->id.index > c2->id.index)
} return 1;
static void snd_ctl_cresort_action(snd_hcontrol_t *hcontrol, VISIT which, int level)
{
snd_ctl_t *handle;
level = 0; /* to keep GCC happy */
assert(hcontrol != NULL);
handle = hcontrol->handle;
assert(handle != NULL);
if (handle->cerr < 0)
return;
switch (which) {
case preorder: break;
case postorder: break;
case endorder:
case leaf:
if (tsearch(hcontrol, &handle->croot, (__compar_fn_t)handle->csort) == NULL)
handle->cerr = -ENOMEM;
break;
}
}
static void snd_ctl_cresort_free(snd_hcontrol_t *hcontrol)
{
hcontrol = NULL; /* to keep GCC happy */
/* nothing */
}
int snd_ctl_cresort(snd_ctl_t *handle, snd_ctl_csort_t *csort)
{
int result;
snd_ctl_csort_t *csort_old;
assert(handle != NULL && csort != NULL);
if (handle->ccount == 0)
return 0;
if (handle->cerr < 0)
return handle->cerr;
assert(handle->croot_new == NULL);
csort_old = handle->csort;
handle->csort = csort;
twalk(handle->croot, (__action_fn_t)snd_ctl_cresort_action);
if (handle->cerr < 0) {
result = handle->cerr;
handle->cerr = 0;
handle->csort = csort_old;
tdestroy(handle->croot_new, (__free_fn_t)snd_ctl_cresort_free);
handle->croot_new = NULL;
return result;
}
tdestroy(handle->croot, (__free_fn_t)snd_ctl_cresort_free);
handle->croot = handle->croot_new;
handle->croot_new = NULL;
return 0; return 0;
} }
snd_hcontrol_t *snd_ctl_cfind(snd_ctl_t *handle, snd_control_id_t *id) static void snd_ctl_hresort_free(snd_hcontrol_t *hcontrol ATTRIBUTE_UNUSED)
{ {
assert(handle != NULL); /* nothing */
if (handle->croot == NULL)
return NULL;
return (snd_hcontrol_t *)tfind(id, &handle->croot, (__compar_fn_t)handle->csort);
} }
int snd_ctl_ccallback_rebuild(snd_ctl_t *handle, snd_ctl_ccallback_rebuild_t *callback, void *private_data) int snd_ctl_hresort(snd_ctl_t *handle, snd_ctl_hsort_t *hsort)
{
struct list_head *list;
snd_hcontrol_t *hcontrol;
snd_control_id_t *ids, *pids;
int idx;
assert(handle != NULL && hsort != NULL);
if (handle->hcount == 0)
return 0;
if (handle->herr < 0)
return handle->herr;
assert(handle->hroot_new == NULL);
ids = pids = (snd_control_id_t *)malloc(sizeof(snd_control_id_t) * handle->hcount);
if (ids == NULL)
return -ENOMEM;
/* first step - update search engine */
list_for_each(list, &handle->hlist) {
hcontrol = list_entry(list, snd_hcontrol_t, list);
*pids++ = hcontrol->id;
if (tsearch(hcontrol, &handle->hroot_new, (__compar_fn_t)hsort) == NULL) {
if (handle->hroot_new != NULL)
tdestroy(handle->hroot_new, (__free_fn_t)snd_ctl_hresort_free);
handle->hroot_new = NULL;
free(ids);
return -ENOMEM;
}
}
if (handle->hroot != NULL)
tdestroy(handle->hroot, (__free_fn_t)snd_ctl_hresort_free);
handle->hsort = hsort;
handle->hroot = handle->hroot_new;
handle->hroot_new = NULL;
/* second step - perform qsort and save results */
qsort(ids, handle->hcount, sizeof(snd_control_id_t), (int (*)(const void *, const void *))hsort);
INIT_LIST_HEAD(&handle->hlist);
for (idx = 0; idx < handle->hcount; idx++) {
hcontrol = snd_ctl_hfind(handle, ids + idx);
list_add_tail(&hcontrol->list, &handle->hlist);
}
free(ids);
return 0;
}
snd_hcontrol_t *snd_ctl_hfind(snd_ctl_t *handle, snd_control_id_t *id)
{
void *res;
assert(handle != NULL);
if (handle->hroot == NULL)
return NULL;
res = tfind(id, &handle->hroot, (__compar_fn_t)handle->hsort);
return res == NULL ? NULL : *(snd_hcontrol_t **)res;
}
int snd_ctl_hlist(snd_ctl_t *handle, snd_hcontrol_list_t *hlist)
{
struct list_head *list;
snd_hcontrol_t *hcontrol;
unsigned int idx;
assert(hlist != NULL);
if (hlist->controls_offset >= (unsigned int)handle->hcount)
return -EINVAL;
hlist->controls_count = 0;
hlist->controls = handle->hcount;
if (hlist->controls_request > 0) {
if (hlist->pids == NULL)
return -EINVAL;
idx = 0;
list_for_each(list, &handle->hlist) {
hcontrol = list_entry(list, snd_hcontrol_t, list);
if (idx >= hlist->controls_offset + hlist->controls_request)
break;
if (idx >= hlist->controls_offset) {
hlist->pids[idx] = hcontrol->id;
hlist->controls_count++;
}
idx++;
}
}
return 0;
}
int snd_ctl_hcallback_rebuild(snd_ctl_t *handle, snd_ctl_hcallback_rebuild_t *callback, void *private_data)
{ {
assert(handle != NULL); assert(handle != NULL);
handle->callback_rebuild = callback; handle->callback_rebuild = callback;
@ -200,7 +238,7 @@ int snd_ctl_ccallback_rebuild(snd_ctl_t *handle, snd_ctl_ccallback_rebuild_t *ca
return 0; return 0;
} }
int snd_ctl_ccallback_add(snd_ctl_t *handle, snd_ctl_ccallback_add_t *callback, void *private_data) int snd_ctl_hcallback_add(snd_ctl_t *handle, snd_ctl_hcallback_add_t *callback, void *private_data)
{ {
assert(handle != NULL); assert(handle != NULL);
handle->callback_add = callback; handle->callback_add = callback;
@ -208,110 +246,85 @@ int snd_ctl_ccallback_add(snd_ctl_t *handle, snd_ctl_ccallback_add_t *callback,
return 0; return 0;
} }
static void callback_rebuild(snd_ctl_t *handle, void *private_data) static void callback_rebuild(snd_ctl_t *handle, void *private_data ATTRIBUTE_UNUSED)
{ {
private_data = NULL; /* to keep GCC happy */ handle->herr = snd_ctl_hbuild(handle, handle->hsort);
handle->cerr = snd_ctl_cbuild(handle, handle->csort); if (handle->herr >= 0 && handle->callback_rebuild)
if (handle->cerr >= 0 && handle->callback_rebuild)
handle->callback_rebuild(handle, handle->callback_rebuild_private_data); handle->callback_rebuild(handle, handle->callback_rebuild_private_data);
} }
static void callback_change(snd_ctl_t *handle, void *private_data, snd_control_id_t *id) static void callback_change(snd_ctl_t *handle, void *private_data ATTRIBUTE_UNUSED, snd_control_id_t *id)
{ {
snd_hcontrol_t *hcontrol; snd_hcontrol_t *hcontrol;
private_data = NULL; /* to keep GCC happy */ if (handle->herr < 0)
if (handle->cerr < 0)
return; return;
hcontrol = snd_ctl_cfind(handle, id); hcontrol = snd_ctl_hfind(handle, id);
if (hcontrol == NULL) { if (hcontrol == NULL) {
handle->cerr = -ENOENT; handle->herr = -ENOENT;
return; return;
} }
hcontrol->change = 1; hcontrol->change = 1;
} }
static void callback_value(snd_ctl_t *handle, void *private_data, snd_control_id_t *id) static void callback_value(snd_ctl_t *handle, void *private_data ATTRIBUTE_UNUSED, snd_control_id_t *id)
{ {
snd_hcontrol_t *hcontrol; snd_hcontrol_t *hcontrol;
private_data = NULL; /* to keep GCC happy */ if (handle->herr < 0)
if (handle->cerr < 0)
return; return;
hcontrol = snd_ctl_cfind(handle, id); hcontrol = snd_ctl_hfind(handle, id);
if (hcontrol == NULL) { if (hcontrol == NULL) {
handle->cerr = -ENOENT; handle->herr = -ENOENT;
return; return;
} }
hcontrol->value = 1; hcontrol->value = 1;
} }
static void callback_add(snd_ctl_t *handle, void *private_data, snd_control_id_t *id) static void callback_add(snd_ctl_t *handle, void *private_data ATTRIBUTE_UNUSED, snd_control_id_t *id)
{ {
snd_hcontrol_t *hcontrol, *icontrol; snd_hcontrol_t *hcontrol, *icontrol;
private_data = NULL; /* to keep GCC happy */ if (handle->herr < 0)
if (handle->cerr < 0)
return; return;
hcontrol = (snd_hcontrol_t *)calloc(1, sizeof(snd_hcontrol_t)); hcontrol = (snd_hcontrol_t *)calloc(1, sizeof(snd_hcontrol_t));
if (hcontrol == NULL) { if (hcontrol == NULL) {
handle->cerr = -ENOMEM; handle->herr = -ENOMEM;
return; return;
} }
hcontrol->id = *id; hcontrol->id = *id;
hcontrol->handle = handle; hcontrol->handle = handle;
icontrol = tsearch(hcontrol, &handle->croot, (__compar_fn_t)handle->csort); icontrol = tsearch(hcontrol, &handle->hroot, (__compar_fn_t)handle->hsort);
if (icontrol == NULL) { if (icontrol == NULL) {
free(hcontrol); free(hcontrol);
handle->cerr = -ENOMEM; handle->herr = -ENOMEM;
return; return;
} }
if (icontrol != hcontrol) { /* double hit */ if (icontrol != hcontrol) { /* double hit */
free(hcontrol); free(hcontrol);
return; return;
} }
list_add_tail(&hcontrol->list, &handle->hlist);
if (handle->callback_add) if (handle->callback_add)
handle->callback_add(handle, handle->callback_add_private_data, hcontrol); handle->callback_add(handle, handle->callback_add_private_data, hcontrol);
} }
static void callback_remove(snd_ctl_t *handle, void *private_data, snd_control_id_t *id) static void callback_remove(snd_ctl_t *handle, void *private_data ATTRIBUTE_UNUSED, snd_control_id_t *id)
{ {
snd_hcontrol_t *hcontrol; snd_hcontrol_t *hcontrol;
private_data = NULL; /* to keep GCC happy */ if (handle->herr < 0)
if (handle->cerr < 0)
return; return;
hcontrol = snd_ctl_cfind(handle, id); hcontrol = snd_ctl_hfind(handle, id);
if (hcontrol == NULL) { if (hcontrol == NULL) {
handle->cerr = -ENOENT; handle->herr = -ENOENT;
return; return;
} }
if (tdelete(hcontrol, &handle->croot, (__compar_fn_t)handle->csort) != NULL) if (tdelete(hcontrol, &handle->hroot, (__compar_fn_t)handle->hsort) != NULL)
snd_ctl_cfree1(hcontrol); snd_ctl_hfree1(hcontrol);
} }
static void snd_ctl_cevent_walk1(snd_hcontrol_t *hcontrol, VISIT which, int level) int snd_ctl_hevent(snd_ctl_t *handle)
{
level = 0; /* to keep GCC happy */
assert(hcontrol != NULL);
switch (which) {
case preorder: break;
case postorder: break;
case endorder:
case leaf:
if (hcontrol->change && hcontrol->event_change) {
hcontrol->event_change(hcontrol->handle, hcontrol);
hcontrol->change = 0;
}
if (hcontrol->value && hcontrol->event_value) {
hcontrol->event_value(hcontrol->handle, hcontrol);
hcontrol->value = 0;
}
break;
}
}
int snd_ctl_cevent(snd_ctl_t *handle)
{ {
static snd_ctl_callbacks_t callbacks = { static snd_ctl_callbacks_t callbacks = {
rebuild: callback_rebuild, rebuild: callback_rebuild,
@ -322,15 +335,27 @@ int snd_ctl_cevent(snd_ctl_t *handle)
private_data: NULL, private_data: NULL,
reserved: { NULL, } reserved: { NULL, }
}; };
struct list_head *list;
snd_hcontrol_t *hcontrol;
int res; int res;
assert(handle != NULL); assert(handle != NULL);
handle->cerr = 0; handle->herr = 0;
res = snd_ctl_read(handle, &callbacks); res = snd_ctl_read(handle, &callbacks);
if (res < 0) if (res < 0)
return res; return res;
if (handle->cerr < 0) if (handle->herr < 0)
return handle->cerr; return handle->herr;
twalk(handle->croot, (__action_fn_t)snd_ctl_cevent_walk1); list_for_each(list, &handle->hlist) {
hcontrol = list_entry(list, snd_hcontrol_t, list);
if (hcontrol->change && hcontrol->event_change) {
hcontrol->event_change(hcontrol->handle, hcontrol);
hcontrol->change = 0;
}
if (hcontrol->value && hcontrol->event_value) {
hcontrol->event_value(hcontrol->handle, hcontrol);
hcontrol->value = 0;
}
}
return res; return res;
} }

View file

@ -214,7 +214,7 @@ int snd_mixer_simple_read(snd_mixer_t *handle, snd_mixer_simple_callbacks_t *cal
snd_mixer_simple_build(handle); snd_mixer_simple_build(handle);
handle->callbacks = callbacks; handle->callbacks = callbacks;
handle->simple_changes = 0; handle->simple_changes = 0;
if ((err = snd_ctl_cevent(handle->ctl_handle)) <= 0) { if ((err = snd_ctl_hevent(handle->ctl_handle)) <= 0) {
handle->callbacks = NULL; handle->callbacks = NULL;
return err; return err;
} }

View file

@ -38,9 +38,8 @@ static int test_mixer_id(snd_mixer_t *handle, const char *name, int index)
id.iface = SND_CONTROL_IFACE_MIXER; id.iface = SND_CONTROL_IFACE_MIXER;
strcpy(id.name, name); strcpy(id.name, name);
id.index = index; id.index = index;
printf("look\n"); hcontrol = snd_ctl_hfind(handle->ctl_handle, &id);
hcontrol = snd_ctl_cfind(handle->ctl_handle, &id); // fprintf(stderr, "Looking for control: '%s', %i (0x%lx)\n", name, index, (long)hcontrol);
fprintf(stderr, "Looking for control: '%s', %i (0x%lx)\n", name, index, (long)hcontrol);
return hcontrol != NULL; return hcontrol != NULL;
} }
@ -339,19 +338,15 @@ static int build_input(snd_mixer_t *handle, const char *sname)
memset(&gvolume_info, 0, sizeof(gvolume_info)); memset(&gvolume_info, 0, sizeof(gvolume_info));
memset(&pvolume_info, 0, sizeof(pvolume_info)); memset(&pvolume_info, 0, sizeof(pvolume_info));
memset(&cvolume_info, 0, sizeof(cvolume_info)); memset(&cvolume_info, 0, sizeof(cvolume_info));
printf("b (1)\n"); while (1) {
do {
index++; index++;
voices = 0; voices = 0;
present = caps = capture_item = 0; present = caps = capture_item = 0;
min = max = 0; min = max = 0;
sprintf(str, "%s Switch", sname); sprintf(str, "%s Switch", sname);
printf("b (2)\n");
if (test_mixer_id(handle, str, index)) { if (test_mixer_id(handle, str, index)) {
printf("b (3)\n");
if ((err = get_mixer_info(handle, str, index, &gswitch_info)) < 0) if ((err = get_mixer_info(handle, str, index, &gswitch_info)) < 0)
return err; return err;
printf("b (4)\n");
if (gswitch_info.type == SND_CONTROL_TYPE_BOOLEAN) { if (gswitch_info.type == SND_CONTROL_TYPE_BOOLEAN) {
if (voices < gswitch_info.values_count) if (voices < gswitch_info.values_count)
voices = gswitch_info.values_count; voices = gswitch_info.values_count;
@ -359,7 +354,6 @@ static int build_input(snd_mixer_t *handle, const char *sname)
present |= MIXER_PRESENT_GLOBAL_SWITCH; present |= MIXER_PRESENT_GLOBAL_SWITCH;
} }
} }
printf("b (3)\n");
sprintf(str, "%s Volume", sname); sprintf(str, "%s Volume", sname);
if (test_mixer_id(handle, str, index)) { if (test_mixer_id(handle, str, index)) {
if ((err = get_mixer_info(handle, str, index, &gvolume_info)) < 0) if ((err = get_mixer_info(handle, str, index, &gvolume_info)) < 0)
@ -483,7 +477,8 @@ static int build_input(snd_mixer_t *handle, const char *sname)
caps &= ~SND_MIXER_SCTCAP_JOINTLY_VOLUME; caps &= ~SND_MIXER_SCTCAP_JOINTLY_VOLUME;
} }
} }
printf("b (4)\n"); if (present == 0)
break;
simple = build_input_scontrol(handle, sname, index); simple = build_input_scontrol(handle, sname, index);
if (simple == NULL) if (simple == NULL)
return -ENOMEM; return -ENOMEM;
@ -500,8 +495,8 @@ static int build_input(snd_mixer_t *handle, const char *sname)
simple->voices = voices; simple->voices = voices;
simple->min = min; simple->min = min;
simple->max = max; simple->max = max;
fprintf(stderr, "sname = '%s', index = %i, present = 0x%x, voices = %i\n", sname, index, present, voices); // fprintf(stderr, "sname = '%s', index = %i, present = 0x%x, voices = %i\n", sname, index, present, voices);
} while (present != 0); };
return 0; return 0;
} }
@ -527,11 +522,9 @@ int snd_mixer_simple_build(snd_mixer_t *handle)
char **input = inputs; char **input = inputs;
int err; int err;
printf("simple build - start\n"); if ((err = snd_ctl_hbuild(handle->ctl_handle, snd_ctl_hsort)) < 0)
if ((err = snd_ctl_cbuild(handle->ctl_handle, snd_ctl_csort)) < 0)
return err; return err;
while (*input) { while (*input) {
printf("simple build - input '%s'\n", *input);
if ((err = build_input(handle, *input)) < 0) { if ((err = build_input(handle, *input)) < 0) {
snd_mixer_simple_destroy(handle); snd_mixer_simple_destroy(handle);
return err; return err;
@ -539,7 +532,6 @@ int snd_mixer_simple_build(snd_mixer_t *handle)
input++; input++;
} }
handle->simple_valid = 1; handle->simple_valid = 1;
printf("simple build - end\n");
return 0; return 0;
} }
@ -548,6 +540,6 @@ int snd_mixer_simple_destroy(snd_mixer_t *handle)
while (handle->simple_first) while (handle->simple_first)
simple_remove(handle, handle->simple_first); simple_remove(handle, handle->simple_first);
handle->simple_valid = 0; handle->simple_valid = 0;
snd_ctl_cfree(handle->ctl_handle); snd_ctl_hfree(handle->ctl_handle);
return 0; return 0;
} }