int snd_ctl_poll_descriptors_count(snd_ctl_t *ctl)
{
assert(ctl);
+ if (ctl->ops->poll_descriptors_count)
+ return ctl->ops->poll_descriptors_count(ctl);
+ if (ctl->poll_fd < 0)
+ return 0;
return 1;
}
int snd_ctl_poll_descriptors(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int space)
{
assert(ctl && pfds);
+ if (ctl->ops->poll_descriptors)
+ return ctl->ops->poll_descriptors(ctl, pfds, space);
+ if (ctl->poll_fd < 0)
+ return 0;
if (space > 0) {
pfds->fd = ctl->poll_fd;
pfds->events = POLLIN|POLLERR|POLLNVAL;
int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
{
assert(ctl && pfds && revents);
+ if (ctl->ops->poll_revents)
+ return ctl->ops->poll_revents(ctl, pfds, nfds, revents);
if (nfds == 1) {
*revents = pfds->revents;
return 0;
*/
int snd_ctl_wait(snd_ctl_t *ctl, int timeout)
{
- struct pollfd pfd;
- int err;
- err = snd_ctl_poll_descriptors(ctl, &pfd, 1);
- assert(err == 1);
- err = poll(&pfd, 1, timeout);
+ struct pollfd *pfd;
+ unsigned short *revents;
+ int i, npfds, pollio, err, err_poll;
+
+ npfds = snd_ctl_poll_descriptors_count(ctl);
+ if (npfds <= 0 || npfds >= 16) {
+ SNDERR("Invalid poll_fds %d\n", npfds);
+ return -EIO;
+ }
+ pfd = alloca(sizeof(*pfd) * npfds);
+ revents = alloca(sizeof(*revents) * npfds);
+ err = snd_ctl_poll_descriptors(ctl, pfd, npfds);
if (err < 0)
- return -errno;
- return 0;
+ return err;
+ if (err != npfds) {
+ SNDMSG("invalid poll descriptors %d\n", err);
+ return -EIO;
+ }
+ do {
+ err_poll = poll(pfd, npfds, timeout);
+ if (err_poll < 0)
+ return -errno;
+ if (! err_poll)
+ break;
+ err = snd_ctl_poll_descriptors_revents(ctl, pfd, npfds, revents);
+ if (err < 0)
+ return err;
+ pollio = 0;
+ for (i = 0; i < npfds; i++) {
+ if (revents[i] & (POLLERR | POLLNVAL))
+ return -EIO;
+ if ((revents[i] & (POLLIN | POLLOUT)) == 0)
+ continue;
+ pollio++;
+ }
+ } while (! pollio);
+
+ return err_poll > 0 ? 1 : 0;
}
/**
return handler->u.ctl;
}
+static const char *build_in_ctls[] = {
+ "hw", "shm", NULL
+};
+
static int snd_ctl_open_conf(snd_ctl_t **ctlp, const char *name,
snd_config_t *ctl_root, snd_config_t *ctl_conf, int mode)
{
const char *str;
- char buf[256];
+ char *buf = NULL, *buf1 = NULL;
int err;
snd_config_t *conf, *type_conf = NULL;
snd_config_iterator_t i, next;
}
}
if (!open_name) {
+ buf = malloc(strlen(str) + 32);
+ if (buf == NULL) {
+ err = -ENOMEM;
+ goto _err;
+ }
open_name = buf;
- snprintf(buf, sizeof(buf), "_snd_ctl_%s_open", str);
+ sprintf(buf, "_snd_ctl_%s_open", str);
+ }
+ if (!lib) {
+ const char **build_in = build_in_ctls;
+ while (*build_in) {
+ if (!strcmp(*build_in, str))
+ break;
+ build_in++;
+ }
+ if (*build_in == NULL) {
+ buf1 = malloc(strlen(str) + sizeof(PKGLIBDIR) + 32);
+ if (buf1 == NULL) {
+ err = -ENOMEM;
+ goto _err;
+ }
+ lib = buf1;
+ sprintf(buf1, "%s/libasound_module_ctl_%s.so", PKGLIBDIR, str);
+ }
}
#ifndef PIC
snd_control_open_symbols();
#endif
+ open_func = snd_dlobj_cache_lookup(open_name);
+ if (open_func) {
+ err = 0;
+ goto _err;
+ }
h = snd_dlopen(lib, RTLD_NOW);
if (h)
open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_CONTROL_DLSYM_VERSION));
if (err >= 0) {
err = open_func(ctlp, name, ctl_root, ctl_conf, mode);
if (err >= 0) {
+ if (h /*&& (mode & SND_CTL_KEEP_ALIVE)*/) {
+ snd_dlobj_cache_add(open_name, h, open_func);
+ h = NULL;
+ }
(*ctlp)->dl_handle = h;
- return 0;
+ err = 0;
} else {
- snd_dlclose(h);
+ if (h)
+ snd_dlclose(h);
}
}
+ free(buf);
+ free(buf1);
return err;
}