From 9d6a0ea016f6e5c30fb212288af3b1b38784bd1f Mon Sep 17 00:00:00 2001 From: Packit Service Date: Dec 09 2020 07:34:44 +0000 Subject: Prepare for a new update Reverting patches so we can apply the latest update and changes can be seen in the spec file and sources. --- diff --git a/aserver/aserver.c b/aserver/aserver.c index c2c7f91..2838702 100644 --- a/aserver/aserver.c +++ b/aserver/aserver.c @@ -35,8 +35,6 @@ #include "aserver.h" -#undef open - char *command; #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) diff --git a/aserver/aserver.c.glibc-open b/aserver/aserver.c.glibc-open deleted file mode 100644 index 2838702..0000000 --- a/aserver/aserver.c.glibc-open +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * ALSA server - * Copyright (c) by Abramo Bagnara - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aserver.h" - -char *command; - -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) -#define ERROR(...) do {\ - fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __func__); \ - fprintf(stderr, __VA_ARGS__); \ - putc('\n', stderr); \ -} while (0) -#else -#define ERROR(args...) do {\ - fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __func__); \ - fprintf(stderr, ##args); \ - putc('\n', stderr); \ -} while (0) -#endif - -#define SYSERROR(string) ERROR(string ": %s", strerror(errno)) - -static int make_local_socket(const char *filename) -{ - size_t l = strlen(filename); - size_t size = offsetof(struct sockaddr_un, sun_path) + l; - struct sockaddr_un *addr = alloca(size); - int sock; - - sock = socket(PF_LOCAL, SOCK_STREAM, 0); - if (sock < 0) { - int result = -errno; - SYSERROR("socket failed"); - return result; - } - - unlink(filename); - - addr->sun_family = AF_LOCAL; - memcpy(addr->sun_path, filename, l); - - if (bind(sock, (struct sockaddr *) addr, size) < 0) { - int result = -errno; - SYSERROR("bind failed"); - close(sock); - return result; - } - - return sock; -} - -static int make_inet_socket(int port) -{ - struct sockaddr_in addr; - int sock; - - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock < 0) { - int result = -errno; - SYSERROR("socket failed"); - return result; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = INADDR_ANY; - - if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - int result = -errno; - SYSERROR("bind failed"); - close(sock); - return result; - } - - return sock; -} - -struct pollfd *pollfds; -unsigned int pollfds_count = 0; -typedef struct waiter waiter_t; -typedef int (*waiter_handler_t)(waiter_t *waiter, unsigned short events); -struct waiter { - int fd; - void *private_data; - waiter_handler_t handler; -}; -waiter_t *waiters; - -static void add_waiter(int fd, unsigned short events, waiter_handler_t handler, - void *data) -{ - waiter_t *w = &waiters[fd]; - struct pollfd *pfd = &pollfds[pollfds_count]; - assert(!w->handler); - pfd->fd = fd; - pfd->events = events; - pfd->revents = 0; - w->fd = fd; - w->private_data = data; - w->handler = handler; - pollfds_count++; -} - -static void del_waiter(int fd) -{ - waiter_t *w = &waiters[fd]; - unsigned int k; - assert(w->handler); - w->handler = 0; - for (k = 0; k < pollfds_count; ++k) { - if (pollfds[k].fd == fd) - break; - } - assert(k < pollfds_count); - pollfds_count--; - memmove(&pollfds[k], &pollfds[k + 1], pollfds_count - k); -} - -typedef struct client client_t; - -typedef struct { - int (*open)(client_t *client, int *cookie); - int (*cmd)(client_t *client); - int (*close)(client_t *client); -} transport_ops_t; - -struct client { - struct list_head list; - int poll_fd; - int ctrl_fd; - int local; - int transport_type; - int dev_type; - char name[256]; - int stream; - int mode; - transport_ops_t *ops; - snd_async_handler_t *async_handler; - int async_sig; - pid_t async_pid; - union { - struct { - snd_pcm_t *handle; - int fd; - } pcm; - struct { - snd_ctl_t *handle; - int fd; - } ctl; -#if 0 - struct { - snd_rawmidi_t *handle; - } rawmidi; - struct { - snd_timer_open_t *handle; - } timer; - struct { - snd_hwdep_t *handle; - } hwdep; - struct { - snd_seq_t *handle; - } seq; -#endif - } device; - int polling; - int open; - int cookie; - union { - struct { - int ctrl_id; - void *ctrl; - } shm; - } transport; -}; - -LIST_HEAD(clients); - -typedef struct { - struct list_head list; - int fd; - uint32_t cookie; -} inet_pending_t; -LIST_HEAD(inet_pendings); - -#if 0 -static int pcm_handler(waiter_t *waiter, unsigned short events) -{ - client_t *client = waiter->private_data; - char buf[1]; - ssize_t n; - if (events & POLLIN) { - n = write(client->poll_fd, buf, 1); - if (n != 1) { - SYSERROR("write failed"); - return -errno; - } - } else if (events & POLLOUT) { - n = read(client->poll_fd, buf, 1); - if (n != 1) { - SYSERROR("read failed"); - return -errno; - } - } - del_waiter(waiter->fd); - client->polling = 0; - return 0; -} -#endif - -static void pcm_shm_hw_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED) -{ - client_t *client = pcm->hw.private_data; - volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; - snd_pcm_t *loop; - - ctrl->hw.changed = 1; - if (pcm->hw.fd >= 0) { - ctrl->hw.use_mmap = 1; - ctrl->hw.offset = pcm->hw.offset; - return; - } - ctrl->hw.use_mmap = 0; - ctrl->hw.ptr = pcm->hw.ptr ? *pcm->hw.ptr : 0; - for (loop = pcm->hw.master; loop; loop = loop->hw.master) - loop->hw.ptr = &ctrl->hw.ptr; - pcm->hw.ptr = &ctrl->hw.ptr; -} - -static void pcm_shm_appl_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED) -{ - client_t *client = pcm->appl.private_data; - volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; - snd_pcm_t *loop; - - ctrl->appl.changed = 1; - if (pcm->appl.fd >= 0) { - ctrl->appl.use_mmap = 1; - ctrl->appl.offset = pcm->appl.offset; - return; - } - ctrl->appl.use_mmap = 0; - ctrl->appl.ptr = pcm->appl.ptr ? *pcm->appl.ptr : 0; - for (loop = pcm->appl.master; loop; loop = loop->appl.master) - loop->appl.ptr = &ctrl->appl.ptr; - pcm->appl.ptr = &ctrl->appl.ptr; -} - -static int pcm_shm_open(client_t *client, int *cookie) -{ - int shmid; - snd_pcm_t *pcm; - int err; - int result; - err = snd_pcm_open(&pcm, client->name, client->stream, SND_PCM_NONBLOCK); - if (err < 0) - return err; - client->device.pcm.handle = pcm; - client->device.pcm.fd = _snd_pcm_poll_descriptor(pcm); - pcm->hw.private_data = client; - pcm->hw.changed = pcm_shm_hw_ptr_changed; - pcm->appl.private_data = client; - pcm->appl.changed = pcm_shm_appl_ptr_changed; - - shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666); - if (shmid < 0) { - result = -errno; - SYSERROR("shmget failed"); - goto _err; - } - client->transport.shm.ctrl_id = shmid; - client->transport.shm.ctrl = shmat(shmid, 0, 0); - if (client->transport.shm.ctrl == (void*) -1) { - result = -errno; - shmctl(shmid, IPC_RMID, 0); - SYSERROR("shmat failed"); - goto _err; - } - *cookie = shmid; - return 0; - - _err: - snd_pcm_close(pcm); - return result; - -} - -static int pcm_shm_close(client_t *client) -{ - int err; - snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; - if (client->polling) { - del_waiter(client->device.pcm.fd); - client->polling = 0; - } - err = snd_pcm_close(client->device.pcm.handle); - ctrl->result = err; - if (err < 0) - ERROR("snd_pcm_close"); - if (client->transport.shm.ctrl) { - err = shmdt((void *)client->transport.shm.ctrl); - if (err < 0) - SYSERROR("shmdt failed"); - err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0); - if (err < 0) - SYSERROR("shmctl IPC_RMID failed"); - client->transport.shm.ctrl = 0; - } - client->open = 0; - return 0; -} - -static int shm_ack(client_t *client) -{ - struct pollfd pfd; - int err; - char buf[1]; - pfd.fd = client->ctrl_fd; - pfd.events = POLLHUP; - if (poll(&pfd, 1, 0) == 1) - return -EBADFD; - err = write(client->ctrl_fd, buf, 1); - if (err != 1) - return -EBADFD; - return 0; -} - -static int shm_ack_fd(client_t *client, int fd) -{ - struct pollfd pfd; - int err; - char buf[1]; - pfd.fd = client->ctrl_fd; - pfd.events = POLLHUP; - if (poll(&pfd, 1, 0) == 1) - return -EBADFD; - err = snd_send_fd(client->ctrl_fd, buf, 1, fd); - if (err != 1) - return -EBADFD; - return 0; -} - -static int shm_rbptr_fd(client_t *client, snd_pcm_rbptr_t *rbptr) -{ - if (rbptr->fd < 0) - return -EINVAL; - return shm_ack_fd(client, rbptr->fd); -} - -static void async_handler(snd_async_handler_t *handler) -{ - client_t *client = snd_async_handler_get_callback_private(handler); - /* FIXME: use sigqueue */ - kill(client->async_pid, client->async_sig); -} - -static int pcm_shm_cmd(client_t *client) -{ - volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; - char buf[1]; - int err; - int cmd; - snd_pcm_t *pcm; - err = read(client->ctrl_fd, buf, 1); - if (err != 1) - return -EBADFD; - cmd = ctrl->cmd; - ctrl->cmd = 0; - pcm = client->device.pcm.handle; - switch (cmd) { - case SND_PCM_IOCTL_ASYNC: - ctrl->result = snd_pcm_async(pcm, ctrl->u.async.sig, ctrl->u.async.pid); - if (ctrl->result < 0) - break; - if (ctrl->u.async.sig >= 0) { - assert(client->async_sig < 0); - ctrl->result = snd_async_add_pcm_handler(&client->async_handler, pcm, async_handler, client); - if (ctrl->result < 0) - break; - } else { - assert(client->async_sig >= 0); - snd_async_del_handler(client->async_handler); - } - client->async_sig = ctrl->u.async.sig; - client->async_pid = ctrl->u.async.pid; - break; - case SNDRV_PCM_IOCTL_INFO: - ctrl->result = snd_pcm_info(pcm, (snd_pcm_info_t *) &ctrl->u.info); - break; - case SNDRV_PCM_IOCTL_HW_REFINE: - ctrl->result = snd_pcm_hw_refine(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_refine); - break; - case SNDRV_PCM_IOCTL_HW_PARAMS: - ctrl->result = snd_pcm_hw_params(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_params); - break; - case SNDRV_PCM_IOCTL_HW_FREE: - ctrl->result = snd_pcm_hw_free(pcm); - break; - case SNDRV_PCM_IOCTL_SW_PARAMS: - ctrl->result = snd_pcm_sw_params(pcm, (snd_pcm_sw_params_t *) &ctrl->u.sw_params); - break; - case SNDRV_PCM_IOCTL_STATUS: - ctrl->result = snd_pcm_status(pcm, (snd_pcm_status_t *) &ctrl->u.status); - break; - case SND_PCM_IOCTL_STATE: - ctrl->result = snd_pcm_state(pcm); - break; - case SND_PCM_IOCTL_HWSYNC: - ctrl->result = snd_pcm_hwsync(pcm); - break; - case SNDRV_PCM_IOCTL_DELAY: - ctrl->result = snd_pcm_delay(pcm, (snd_pcm_sframes_t *) &ctrl->u.delay.frames); - break; - case SND_PCM_IOCTL_AVAIL_UPDATE: - ctrl->result = snd_pcm_avail_update(pcm); - break; - case SNDRV_PCM_IOCTL_PREPARE: - ctrl->result = snd_pcm_prepare(pcm); - break; - case SNDRV_PCM_IOCTL_RESET: - ctrl->result = snd_pcm_reset(pcm); - break; - case SNDRV_PCM_IOCTL_START: - ctrl->result = snd_pcm_start(pcm); - break; - case SNDRV_PCM_IOCTL_DRAIN: - ctrl->result = snd_pcm_drain(pcm); - break; - case SNDRV_PCM_IOCTL_DROP: - ctrl->result = snd_pcm_drop(pcm); - break; - case SNDRV_PCM_IOCTL_PAUSE: - ctrl->result = snd_pcm_pause(pcm, ctrl->u.pause.enable); - break; - case SNDRV_PCM_IOCTL_CHANNEL_INFO: - ctrl->result = snd_pcm_channel_info(pcm, (snd_pcm_channel_info_t *) &ctrl->u.channel_info); - if (ctrl->result >= 0 && - ctrl->u.channel_info.type == SND_PCM_AREA_MMAP) - return shm_ack_fd(client, ctrl->u.channel_info.u.mmap.fd); - break; - case SNDRV_PCM_IOCTL_REWIND: - ctrl->result = snd_pcm_rewind(pcm, ctrl->u.rewind.frames); - break; - case SND_PCM_IOCTL_FORWARD: - ctrl->result = snd_pcm_forward(pcm, ctrl->u.forward.frames); - break; - case SNDRV_PCM_IOCTL_LINK: - { - /* FIXME */ - ctrl->result = -ENOSYS; - break; - } - case SNDRV_PCM_IOCTL_UNLINK: - ctrl->result = snd_pcm_unlink(pcm); - break; - case SNDRV_PCM_IOCTL_RESUME: - ctrl->result = snd_pcm_resume(pcm); - break; - case SND_PCM_IOCTL_MMAP: - { - ctrl->result = snd_pcm_mmap(pcm); - break; - } - case SND_PCM_IOCTL_MUNMAP: - { - ctrl->result = snd_pcm_munmap(pcm); - break; - } - case SND_PCM_IOCTL_MMAP_COMMIT: - ctrl->result = snd_pcm_mmap_commit(pcm, - ctrl->u.mmap_commit.offset, - ctrl->u.mmap_commit.frames); - break; - case SND_PCM_IOCTL_POLL_DESCRIPTOR: - ctrl->result = 0; - return shm_ack_fd(client, _snd_pcm_poll_descriptor(pcm)); - case SND_PCM_IOCTL_CLOSE: - client->ops->close(client); - break; - case SND_PCM_IOCTL_HW_PTR_FD: - return shm_rbptr_fd(client, &pcm->hw); - case SND_PCM_IOCTL_APPL_PTR_FD: - return shm_rbptr_fd(client, &pcm->appl); - default: - ERROR("Bogus cmd: %x", ctrl->cmd); - ctrl->result = -ENOSYS; - } - return shm_ack(client); -} - -transport_ops_t pcm_shm_ops = { - .open = pcm_shm_open, - .cmd = pcm_shm_cmd, - .close = pcm_shm_close, -}; - -static int ctl_handler(waiter_t *waiter, unsigned short events) -{ - client_t *client = waiter->private_data; - char buf[1]; - ssize_t n; - if (events & POLLIN) { - n = write(client->poll_fd, buf, 1); - if (n != 1) { - SYSERROR("write failed"); - return -errno; - } - } - del_waiter(waiter->fd); - client->polling = 0; - return 0; -} - -static int ctl_shm_open(client_t *client, int *cookie) -{ - int shmid; - snd_ctl_t *ctl; - int err; - int result; - err = snd_ctl_open(&ctl, client->name, SND_CTL_NONBLOCK); - if (err < 0) - return err; - client->device.ctl.handle = ctl; - client->device.ctl.fd = _snd_ctl_poll_descriptor(ctl); - - shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666); - if (shmid < 0) { - result = -errno; - SYSERROR("shmget failed"); - goto _err; - } - client->transport.shm.ctrl_id = shmid; - client->transport.shm.ctrl = shmat(shmid, 0, 0); - if (!client->transport.shm.ctrl) { - result = -errno; - shmctl(shmid, IPC_RMID, 0); - SYSERROR("shmat failed"); - goto _err; - } - *cookie = shmid; - add_waiter(client->device.ctl.fd, POLLIN, ctl_handler, client); - client->polling = 1; - return 0; - - _err: - snd_ctl_close(ctl); - return result; - -} - -static int ctl_shm_close(client_t *client) -{ - int err; - snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl; - if (client->polling) { - del_waiter(client->device.ctl.fd); - client->polling = 0; - } - err = snd_ctl_close(client->device.ctl.handle); - ctrl->result = err; - if (err < 0) - ERROR("snd_ctl_close"); - if (client->transport.shm.ctrl) { - err = shmdt((void *)client->transport.shm.ctrl); - if (err < 0) - SYSERROR("shmdt failed"); - err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0); - if (err < 0) - SYSERROR("shmctl failed"); - client->transport.shm.ctrl = 0; - } - client->open = 0; - return 0; -} - -static int ctl_shm_cmd(client_t *client) -{ - snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl; - char buf[1]; - int err; - int cmd; - snd_ctl_t *ctl; - err = read(client->ctrl_fd, buf, 1); - if (err != 1) - return -EBADFD; - cmd = ctrl->cmd; - ctrl->cmd = 0; - ctl = client->device.ctl.handle; - switch (cmd) { - case SND_CTL_IOCTL_ASYNC: - ctrl->result = snd_ctl_async(ctl, ctrl->u.async.sig, ctrl->u.async.pid); - if (ctrl->result < 0) - break; - if (ctrl->u.async.sig >= 0) { - assert(client->async_sig < 0); - ctrl->result = snd_async_add_ctl_handler(&client->async_handler, ctl, async_handler, client); - if (ctrl->result < 0) - break; - } else { - assert(client->async_sig >= 0); - snd_async_del_handler(client->async_handler); - } - client->async_sig = ctrl->u.async.sig; - client->async_pid = ctrl->u.async.pid; - break; - break; - case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: - ctrl->result = snd_ctl_subscribe_events(ctl, ctrl->u.subscribe_events); - break; - case SNDRV_CTL_IOCTL_CARD_INFO: - ctrl->result = snd_ctl_card_info(ctl, &ctrl->u.card_info); - break; - case SNDRV_CTL_IOCTL_ELEM_LIST: - { - size_t maxsize = CTL_SHM_DATA_MAXLEN; - if (ctrl->u.element_list.space * sizeof(*ctrl->u.element_list.pids) > maxsize) { - ctrl->result = -EFAULT; - break; - } - ctrl->u.element_list.pids = (snd_ctl_elem_id_t*) ctrl->data; - ctrl->result = snd_ctl_elem_list(ctl, &ctrl->u.element_list); - break; - } - case SNDRV_CTL_IOCTL_ELEM_INFO: - ctrl->result = snd_ctl_elem_info(ctl, &ctrl->u.element_info); - break; - case SNDRV_CTL_IOCTL_ELEM_READ: - ctrl->result = snd_ctl_elem_read(ctl, &ctrl->u.element_read); - break; - case SNDRV_CTL_IOCTL_ELEM_WRITE: - ctrl->result = snd_ctl_elem_write(ctl, &ctrl->u.element_write); - break; - case SNDRV_CTL_IOCTL_ELEM_LOCK: - ctrl->result = snd_ctl_elem_lock(ctl, &ctrl->u.element_lock); - break; - case SNDRV_CTL_IOCTL_ELEM_UNLOCK: - ctrl->result = snd_ctl_elem_unlock(ctl, &ctrl->u.element_unlock); - break; - case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE: - ctrl->result = snd_ctl_hwdep_next_device(ctl, &ctrl->u.device); - break; - case SNDRV_CTL_IOCTL_HWDEP_INFO: - ctrl->result = snd_ctl_hwdep_info(ctl, &ctrl->u.hwdep_info); - break; - case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE: - ctrl->result = snd_ctl_pcm_next_device(ctl, &ctrl->u.device); - break; - case SNDRV_CTL_IOCTL_PCM_INFO: - ctrl->result = snd_ctl_pcm_info(ctl, &ctrl->u.pcm_info); - break; - case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE: - ctrl->result = snd_ctl_pcm_prefer_subdevice(ctl, ctrl->u.pcm_prefer_subdevice); - break; - case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE: - ctrl->result = snd_ctl_rawmidi_next_device(ctl, &ctrl->u.device); - break; - case SNDRV_CTL_IOCTL_RAWMIDI_INFO: - ctrl->result = snd_ctl_rawmidi_info(ctl, &ctrl->u.rawmidi_info); - break; - case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: - ctrl->result = snd_ctl_rawmidi_prefer_subdevice(ctl, ctrl->u.rawmidi_prefer_subdevice); - break; - case SNDRV_CTL_IOCTL_POWER: - ctrl->result = snd_ctl_set_power_state(ctl, ctrl->u.power_state); - break; - case SNDRV_CTL_IOCTL_POWER_STATE: - ctrl->result = snd_ctl_get_power_state(ctl, &ctrl->u.power_state); - break; - case SND_CTL_IOCTL_READ: - ctrl->result = snd_ctl_read(ctl, &ctrl->u.read); - break; - case SND_CTL_IOCTL_CLOSE: - client->ops->close(client); - break; - case SND_CTL_IOCTL_POLL_DESCRIPTOR: - ctrl->result = 0; - return shm_ack_fd(client, _snd_ctl_poll_descriptor(ctl)); - default: - ERROR("Bogus cmd: %x", ctrl->cmd); - ctrl->result = -ENOSYS; - } - return shm_ack(client); -} - -transport_ops_t ctl_shm_ops = { - .open = ctl_shm_open, - .cmd = ctl_shm_cmd, - .close = ctl_shm_close, -}; - -static int snd_client_open(client_t *client) -{ - int err; - snd_client_open_request_t req; - snd_client_open_answer_t ans; - char *name; - memset(&ans, 0, sizeof(ans)); - err = read(client->ctrl_fd, &req, sizeof(req)); - if (err < 0) { - SYSERROR("read failed"); - exit(1); - } - if (err != sizeof(req)) { - ans.result = -EINVAL; - goto _answer; - } - name = alloca(req.namelen); - err = read(client->ctrl_fd, name, req.namelen); - if (err < 0) { - SYSERROR("read failed"); - exit(1); - } - if (err != req.namelen) { - ans.result = -EINVAL; - goto _answer; - } - - switch (req.transport_type) { - case SND_TRANSPORT_TYPE_SHM: - if (!client->local) { - ans.result = -EINVAL; - goto _answer; - } - switch (req.dev_type) { - case SND_DEV_TYPE_PCM: - client->ops = &pcm_shm_ops; - break; - case SND_DEV_TYPE_CONTROL: - client->ops = &ctl_shm_ops; - break; - default: - ans.result = -EINVAL; - goto _answer; - } - break; - default: - ans.result = -EINVAL; - goto _answer; - } - - name[req.namelen] = '\0'; - - client->transport_type = req.transport_type; - strcpy(client->name, name); - client->stream = req.stream; - client->mode = req.mode; - - err = client->ops->open(client, &ans.cookie); - if (err < 0) { - ans.result = err; - } else { - client->open = 1; - ans.result = 0; - } - - _answer: - err = write(client->ctrl_fd, &ans, sizeof(ans)); - if (err != sizeof(ans)) { - SYSERROR("write failed"); - exit(1); - } - return 0; -} - -static int client_poll_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) -{ - client_t *client = waiter->private_data; - if (client->open) - client->ops->close(client); - close(client->poll_fd); - close(client->ctrl_fd); - del_waiter(client->poll_fd); - del_waiter(client->ctrl_fd); - list_del(&client->list); - free(client); - return 0; -} - -static int client_ctrl_handler(waiter_t *waiter, unsigned short events) -{ - client_t *client = waiter->private_data; - if (events & POLLHUP) { - if (client->open) - client->ops->close(client); - close(client->ctrl_fd); - del_waiter(client->ctrl_fd); - list_del(&client->list); - free(client); - return 0; - } - if (client->open) - return client->ops->cmd(client); - else - return snd_client_open(client); -} - -static int inet_pending_handler(waiter_t *waiter, unsigned short events) -{ - inet_pending_t *pending = waiter->private_data; - inet_pending_t *pdata; - client_t *client; - uint32_t cookie; - struct list_head *item; - int remove = 0; - if (events & POLLHUP) - remove = 1; - else { - int err = read(waiter->fd, &cookie, sizeof(cookie)); - if (err != sizeof(cookie)) - remove = 1; - else { - err = write(waiter->fd, &cookie, sizeof(cookie)); - if (err != sizeof(cookie)) - remove = 1; - } - } - del_waiter(waiter->fd); - if (remove) { - close(waiter->fd); - list_del(&pending->list); - free(pending); - return 0; - } - - list_for_each(item, &inet_pendings) { - pdata = list_entry(item, inet_pending_t, list); - if (pdata->cookie == cookie) - goto found; - } - pending->cookie = cookie; - return 0; - - found: - client = calloc(1, sizeof(*client)); - client->local = 0; - client->poll_fd = pdata->fd; - client->ctrl_fd = waiter->fd; - add_waiter(client->ctrl_fd, POLLIN | POLLHUP, client_ctrl_handler, client); - add_waiter(client->poll_fd, POLLHUP, client_poll_handler, client); - client->open = 0; - list_add_tail(&client->list, &clients); - list_del(&pending->list); - list_del(&pdata->list); - free(pending); - free(pdata); - return 0; -} - -static int local_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) -{ - int sock; - sock = accept(waiter->fd, 0, 0); - if (sock < 0) { - int result = -errno; - SYSERROR("accept failed"); - return result; - } else { - client_t *client = calloc(1, sizeof(*client)); - client->ctrl_fd = sock; - client->local = 1; - client->open = 0; - add_waiter(sock, POLLIN | POLLHUP, client_ctrl_handler, client); - list_add_tail(&client->list, &clients); - } - return 0; -} - -static int inet_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) -{ - int sock; - sock = accept(waiter->fd, 0, 0); - if (sock < 0) { - int result = -errno; - SYSERROR("accept failed"); - return result; - } else { - inet_pending_t *pending = calloc(1, sizeof(*pending)); - pending->fd = sock; - pending->cookie = 0; - add_waiter(sock, POLLIN, inet_pending_handler, pending); - list_add_tail(&pending->list, &inet_pendings); - } - return 0; -} - -static int server(const char *sockname, int port) -{ - int err, result, sockn = -1, socki = -1; - unsigned int k; - long open_max; - - if (!sockname && port < 0) - return -EINVAL; - open_max = sysconf(_SC_OPEN_MAX); - if (open_max < 0) { - result = -errno; - SYSERROR("sysconf failed"); - return result; - } - pollfds = calloc((size_t) open_max, sizeof(*pollfds)); - waiters = calloc((size_t) open_max, sizeof(*waiters)); - - if (sockname) { - sockn = make_local_socket(sockname); - if (sockn < 0) - return sockn; - if (fcntl(sockn, F_SETFL, O_NONBLOCK) < 0) { - result = -errno; - SYSERROR("fcntl O_NONBLOCK failed"); - goto _end; - } - if (listen(sockn, 4) < 0) { - result = -errno; - SYSERROR("listen failed"); - goto _end; - } - add_waiter(sockn, POLLIN, local_handler, NULL); - } - if (port >= 0) { - socki = make_inet_socket(port); - if (socki < 0) - return socki; - if (fcntl(socki, F_SETFL, O_NONBLOCK) < 0) { - result = -errno; - SYSERROR("fcntl failed"); - goto _end; - } - if (listen(socki, 4) < 0) { - result = -errno; - SYSERROR("listen failed"); - goto _end; - } - add_waiter(socki, POLLIN, inet_handler, NULL); - } - - while (1) { - struct pollfd pfds[open_max]; - size_t pfds_count; - do { - err = poll(pollfds, pollfds_count, -1); - } while (err == 0); - if (err < 0) { - SYSERROR("poll failed"); - continue; - } - - pfds_count = pollfds_count; - memcpy(pfds, pollfds, sizeof(*pfds) * pfds_count); - for (k = 0; k < pfds_count; k++) { - struct pollfd *pfd = &pfds[k]; - if (pfd->revents) { - waiter_t *w = &waiters[pfd->fd]; - if (!w->handler) - continue; - err = w->handler(w, pfd->revents); - if (err < 0) - ERROR("waiter handler failed"); - } - } - } - _end: - if (sockn >= 0) - close(sockn); - if (socki >= 0) - close(socki); - free(pollfds); - free(waiters); - return result; -} - - -static void usage(void) -{ - fprintf(stderr, - "Usage: %s [OPTIONS] server\n" - "--help help\n", - command); -} - -int main(int argc, char **argv) -{ - static const struct option long_options[] = { - {"help", 0, 0, 'h'}, - { 0 , 0 , 0, 0 } - }; - int c; - snd_config_t *conf; - snd_config_iterator_t i, next; - const char *sockname = NULL; - long port = -1; - int err; - char *srvname; - - command = argv[0]; - while ((c = getopt_long(argc, argv, "h", long_options, 0)) != -1) { - switch (c) { - case 'h': - usage(); - return 0; - default: - fprintf(stderr, "Try `%s --help' for more information\n", command); - return 1; - } - } - if (argc - optind != 1) { - ERROR("you need to specify server name"); - return 1; - } - err = snd_config_update(); - if (err < 0) { - ERROR("cannot read configuration file"); - return 1; - } - srvname = argv[optind]; - err = snd_config_search_definition(snd_config, "server", srvname, &conf); - if (err < 0) { - ERROR("Missing definition for server %s", srvname); - return 1; - } - if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) { - SNDERR("Invalid type for server %s definition", srvname); - return -EINVAL; - } - snd_config_for_each(i, next, conf) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id; - if (snd_config_get_id(n, &id) < 0) - continue; - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "host") == 0) - continue; - if (strcmp(id, "socket") == 0) { - err = snd_config_get_string(n, &sockname); - if (err < 0) { - ERROR("Invalid type for %s", id); - return 1; - } - continue; - } - if (strcmp(id, "port") == 0) { - err = snd_config_get_integer(n, &port); - if (err < 0) { - ERROR("Invalid type for %s", id); - return 1; - } - continue; - } - ERROR("Unknown field %s", id); - return 1; - } - if (!sockname && port < 0) { - ERROR("either socket or port need to be defined"); - return 1; - } - server(sockname, port); - return 0; -} diff --git a/include/use-case.h b/include/use-case.h index 134303a..8e7e838 100644 --- a/include/use-case.h +++ b/include/use-case.h @@ -114,22 +114,10 @@ extern "C" { * * Physical system devices the render and capture audio. Devices can be OR'ed * together to support audio on simultaneous devices. - * - * If multiple devices with the same name exists, the number suffixes should - * be added to these names like HDMI1,HDMI2,HDMI3 etc. No number gaps are - * allowed. The names with numbers must be continuous. - * - * If EnableSequence/DisableSequence controls independent paths in the hardware - * it is also recommended to split playback and capture UCM devices and use - * the number suffixes. Example use case: Use the integrated microphone - * in the laptop instead the microphone in headphones. - * - * The preference of the devices is determined by the priority value. */ #define SND_USE_CASE_DEV_NONE "None" /**< None Device */ #define SND_USE_CASE_DEV_SPEAKER "Speaker" /**< Speaker Device */ #define SND_USE_CASE_DEV_LINE "Line" /**< Line Device */ -#define SND_USE_CASE_DEV_MIC "Mic" /**< Microphone Device */ #define SND_USE_CASE_DEV_HEADPHONES "Headphones" /**< Headphones Device */ #define SND_USE_CASE_DEV_HEADSET "Headset" /**< Headset Device */ #define SND_USE_CASE_DEV_HANDSET "Handset" /**< Handset Device */ @@ -218,7 +206,6 @@ int snd_use_case_free_list(const char *list[], int items); * - _enadevs - get list of enabled devices * - _enamods - get list of enabled modifiers * - * - _identifiers/{modifier}|{device}[/{verb}] - list of value identifiers * - _supporteddevs/{modifier}|{device}[/{verb}] - list of supported devices * - _conflictingdevs/{modifier}|{device}[/{verb}] - list of conflicting devices * @@ -274,10 +261,6 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * Recommended names for values: * - TQ * - Tone Quality - * - Priority - * - priority value (1-10000), higher value means higher priority - * - valid only for verbs - * - for devices - PlaybackPriority and CapturePriority * - PlaybackPCM * - full PCM playback device name * - PlaybackPCMIsDummy @@ -305,7 +288,7 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * - playback control switch identifier string * - can be parsed using snd_use_case_parse_ctl_elem_id() * - PlaybackPriority - * - priority value (1-10000), higher value means higher priority + * - priority value (1-10000), default value is 100, higher value means lower priority * - CaptureRate * - capture device sample rate * - CaptureChannels @@ -319,7 +302,7 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * - capture control switch identifier string * - can be parsed using snd_use_case_parse_ctl_elem_id() * - CapturePriority - * - priority value (1-10000), higher value means higher priority + * - priority value (1-10000), default value is 100, higher value means lower priority * - PlaybackMixer * - name of playback mixer * - PlaybackMixerElem @@ -327,7 +310,6 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * - can be parsed using snd_use_case_parse_selem_id() * - PlaybackMasterElem * - mixer element playback identifier for the master control - * - can be parsed using snd_use_case_parse_selem_id() * - PlaybackMasterType * - type of the master volume control * - Valid values: "soft" (software attenuation) @@ -338,38 +320,30 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * - can be parsed using snd_use_case_parse_selem_id() * - CaptureMasterElem * - mixer element playback identifier for the master control - * - can be parsed using snd_use_case_parse_selem_id() * - CaptureMasterType * - type of the master volume control * - Valid values: "soft" (software attenuation) * - EDIDFile * - Path to EDID file for HDMI devices - * - JackCTL - * - jack control device name - * - JackControl - * - jack control identificator - * - can be parsed using snd_use_case_parse_ctl_elem_id() - * - UCM configuration files should contain both JackControl and JackDev - * when possible, because applications are likely to support only one - * or the other - * - JackDev - * - the input device id of the jack (if the full input device path is - * /dev/input/by-id/foo, the JackDev value should be "foo") - * - UCM configuration files should contain both JackControl and JackDev - * when possible, because applications are likely to support only one - * or the other - * - JackHWMute - * If this value is set, it indicates that when the jack is plugged - * in, the hardware automatically mutes some other device(s). The - * value is a space-separated list of device names. If the device - * name contains space, it must be enclosed to ' or ", e.g.: - * JackHWMute "'Dock Headphone' Headphone" - * Note that JackHWMute should be used only when the hardware enforces - * the automatic muting. If the hardware doesn't enforce any muting, it - * may still be tempting to set JackHWMute to trick upper software layers - * to e.g. automatically mute speakers when headphones are plugged in, - * but that's application policy configuration that doesn't belong - * to UCM configuration files. + * - JackControl, JackDev, JackHWMute + * - Jack information for a device. The jack status can be reported via + * a kcontrol and/or via an input device. **JackControl** is the + * kcontrol name of the jack, and **JackDev** is the input device id of + * the jack (if the full input device path is /dev/input/by-id/foo, the + * JackDev value should be "foo"). UCM configuration files should + * contain both JackControl and JackDev when possible, because + * applications are likely to support only one or the other. + * + * If **JackHWMute** is set, it indicates that when the jack is plugged + * in, the hardware automatically mutes some other device(s). The + * JackHWMute value is a space-separated list of device names (this + * isn't compatible with device names with spaces in them, so don't use + * such device names!). Note that JackHWMute should be used only when + * the hardware enforces the automatic muting. If the hardware doesn't + * enforce any muting, it may still be tempting to set JackHWMute to + * trick upper software layers to e.g. automatically mute speakers when + * headphones are plugged in, but that's application policy + * configuration that doesn't belong to UCM configuration files. * - MinBufferLevel * - This is used on platform where reported buffer level is not accurate. * E.g. "512", which holds 512 samples in device buffer. Note: this will diff --git a/include/use-case.h.alsa-git b/include/use-case.h.alsa-git deleted file mode 100644 index 8e7e838..0000000 --- a/include/use-case.h.alsa-git +++ /dev/null @@ -1,500 +0,0 @@ -/** - * \file include/use-case.h - * \brief use case interface for the ALSA driver - * \author Liam Girdwood - * \author Stefan Schmidt - * \author Jaroslav Kysela - * \author Justin Xu - * \date 2008-2010 - */ -/* - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Copyright (C) 2008-2010 SlimLogic Ltd - * Copyright (C) 2010 Wolfson Microelectronics PLC - * Copyright (C) 2010 Texas Instruments Inc. - * - * Support for the verb/device/modifier core logic and API, - * command line tool and file parser was kindly sponsored by - * Texas Instruments Inc. - * Support for multiple active modifiers and devices, - * transition sequences, multiple client access and user defined use - * cases was kindly sponsored by Wolfson Microelectronics PLC. - */ - -#ifndef __ALSA_USE_CASE_H -#define __ALSA_USE_CASE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - * \defgroup ucm Use Case Interface - * The ALSA Use Case manager interface. - * See \ref Usecase page for more details. - * \{ - */ - -/*! \page Usecase ALSA Use Case Interface - * - * The use case manager works by configuring the sound card ALSA kcontrols to - * change the hardware digital and analog audio routing to match the requested - * device use case. The use case manager kcontrol configurations are stored in - * easy to modify text files. - * - * An audio use case can be defined by a verb and device parameter. The verb - * describes the use case action i.e. a phone call, listening to music, recording - * a conversation etc. The device describes the physical audio capture and playback - * hardware i.e. headphones, phone handset, bluetooth headset, etc. - * - * It's intended clients will mostly only need to set the use case verb and - * device for each system use case change (as the verb and device parameters - * cover most audio use cases). - * - * However there are times when a use case has to be modified at runtime. e.g. - * - * + Incoming phone call when the device is playing music - * + Recording sections of a phone call - * + Playing tones during a call. - * - * In order to allow asynchronous runtime use case adaptations, we have a third - * optional modifier parameter that can be used to further configure - * the use case during live audio runtime. - * - * This interface allows clients to :- - * - * + Query the supported use case verbs, devices and modifiers for the machine. - * + Set and Get use case verbs, devices and modifiers for the machine. - * + Get the ALSA PCM playback and capture device PCMs for use case verb, - * use case device and modifier. - * + Get the TQ parameter for each use case verb, use case device and - * modifier. - * + Get the ALSA master playback and capture volume/switch kcontrols - * or mixer elements for each use case. - */ - - -/* - * Use Case Verb. - * - * The use case verb is the main device audio action. e.g. the "HiFi" use - * case verb will configure the audio hardware for HiFi Music playback - * and capture. - */ -#define SND_USE_CASE_VERB_INACTIVE "Inactive" /**< Inactive Verb */ -#define SND_USE_CASE_VERB_HIFI "HiFi" /**< HiFi Verb */ -#define SND_USE_CASE_VERB_HIFI_LOW_POWER "HiFi Low Power" /**< HiFi Low Power Verb */ -#define SND_USE_CASE_VERB_VOICE "Voice" /**< Voice Verb */ -#define SND_USE_CASE_VERB_VOICE_LOW_POWER "Voice Low Power" /**< Voice Low Power Verb */ -#define SND_USE_CASE_VERB_VOICECALL "Voice Call" /**< Voice Call Verb */ -#define SND_USE_CASE_VERB_IP_VOICECALL "Voice Call IP" /**< Voice Call IP Verb */ -#define SND_USE_CASE_VERB_ANALOG_RADIO "FM Analog Radio" /**< FM Analog Radio Verb */ -#define SND_USE_CASE_VERB_DIGITAL_RADIO "FM Digital Radio" /**< FM Digital Radio Verb */ -/* add new verbs to end of list */ - - -/* - * Use Case Device. - * - * Physical system devices the render and capture audio. Devices can be OR'ed - * together to support audio on simultaneous devices. - */ -#define SND_USE_CASE_DEV_NONE "None" /**< None Device */ -#define SND_USE_CASE_DEV_SPEAKER "Speaker" /**< Speaker Device */ -#define SND_USE_CASE_DEV_LINE "Line" /**< Line Device */ -#define SND_USE_CASE_DEV_HEADPHONES "Headphones" /**< Headphones Device */ -#define SND_USE_CASE_DEV_HEADSET "Headset" /**< Headset Device */ -#define SND_USE_CASE_DEV_HANDSET "Handset" /**< Handset Device */ -#define SND_USE_CASE_DEV_BLUETOOTH "Bluetooth" /**< Bluetooth Device */ -#define SND_USE_CASE_DEV_EARPIECE "Earpiece" /**< Earpiece Device */ -#define SND_USE_CASE_DEV_SPDIF "SPDIF" /**< SPDIF Device */ -#define SND_USE_CASE_DEV_HDMI "HDMI" /**< HDMI Device */ -/* add new devices to end of list */ - - -/* - * Use Case Modifiers. - * - * The use case modifier allows runtime configuration changes to deal with - * asynchronous events. - * - * e.g. to record a voice call :- - * 1. Set verb to SND_USE_CASE_VERB_VOICECALL (for voice call) - * 2. Set modifier SND_USE_CASE_MOD_CAPTURE_VOICE when capture required. - * 3. Call snd_use_case_get("CapturePCM") to get ALSA source PCM name - * with captured voice pcm data. - * - * e.g. to play a ring tone when listenin to MP3 Music :- - * 1. Set verb to SND_USE_CASE_VERB_HIFI (for MP3 playback) - * 2. Set modifier to SND_USE_CASE_MOD_PLAY_TONE when incoming call happens. - * 3. Call snd_use_case_get("PlaybackPCM") to get ALSA PCM sink name for - * ringtone pcm data. - */ -#define SND_USE_CASE_MOD_CAPTURE_VOICE "Capture Voice" /**< Capture Voice Modifier */ -#define SND_USE_CASE_MOD_CAPTURE_MUSIC "Capture Music" /**< Capture Music Modifier */ -#define SND_USE_CASE_MOD_PLAY_MUSIC "Play Music" /**< Play Music Modifier */ -#define SND_USE_CASE_MOD_PLAY_VOICE "Play Voice" /**< Play Voice Modifier */ -#define SND_USE_CASE_MOD_PLAY_TONE "Play Tone" /**< Play Tone Modifier */ -#define SND_USE_CASE_MOD_ECHO_REF "Echo Reference" /**< Echo Reference Modifier */ -/* add new modifiers to end of list */ - - -/** - * TQ - Tone Quality - * - * The interface allows clients to determine the audio TQ required for each - * use case verb and modifier. It's intended as an optional hint to the - * audio driver in order to lower power consumption. - * - */ -#define SND_USE_CASE_TQ_MUSIC "Music" /**< Music Tone Quality */ -#define SND_USE_CASE_TQ_VOICE "Voice" /**< Voice Tone Quality */ -#define SND_USE_CASE_TQ_TONES "Tones" /**< Tones Tone Quality */ - -/** use case container */ -typedef struct snd_use_case_mgr snd_use_case_mgr_t; - -/** - * \brief Create an identifier - * \param fmt Format (sprintf like) - * \param ... Optional arguments for sprintf like format - * \return Allocated string identifier or NULL on error - */ -char *snd_use_case_identifier(const char *fmt, ...); - -/** - * \brief Free a string list - * \param list The string list to free - * \param items Count of strings - * \return Zero if success, otherwise a negative error code - */ -int snd_use_case_free_list(const char *list[], int items); - -/** - * \brief Obtain a list of entries - * \param uc_mgr Use case manager (may be NULL - card list) - * \param identifier (may be NULL - card list) - * \param list Returned allocated list - * \return Number of list entries if success, otherwise a negative error code - * - * Defined identifiers: - * - NULL - get card list - * (in pair cardname+comment) - * - _verbs - get verb list - * (in pair verb+comment) - * - _devices[/{verb}] - get list of supported devices - * (in pair device+comment) - * - _modifiers[/{verb}] - get list of supported modifiers - * (in pair modifier+comment) - * - TQ[/{verb}] - get list of TQ identifiers - * - _enadevs - get list of enabled devices - * - _enamods - get list of enabled modifiers - * - * - _supporteddevs/{modifier}|{device}[/{verb}] - list of supported devices - * - _conflictingdevs/{modifier}|{device}[/{verb}] - list of conflicting devices - * - * Note that at most one of the supported/conflicting devs lists has - * any entries, and when neither is present, all devices are supported. - * - */ -int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char **list[]); - - -/** - * \brief Get current - string - * \param uc_mgr Use case manager - * \param identifier - * \param value Value pointer - * \return Zero if success, otherwise a negative error code - * - * Note: The returned string is dynamically allocated, use free() to - * deallocate this string. (Yes, the value parameter shouldn't be marked as - * "const", but it's too late to fix it, sorry about that.) - * - * Known identifiers: - * - NULL - return current card - * - _verb - return current verb - * - _file - return configuration file loaded for current card - * - * - [=]{NAME}[/[{modifier}|{/device}][/{verb}]] - * - value identifier {NAME} - * - Search starts at given modifier or device if any, - * else at a verb - * - Search starts at given verb if any, - * else current verb - * - Searches modifier/device, then verb, then defaults - * - Specify a leading "=" to search only the exact - * device/modifier/verb specified, and not search - * through each object in turn. - * - Examples: - * - "PlaybackPCM/Play Music" - * - "CapturePCM/SPDIF" - * - From ValueDefaults only: - * "=Variable" - * - From current active verb: - * "=Variable//" - * - From verb "Verb": - * "=Variable//Verb" - * - From "Modifier" in current active verb: - * "=Variable/Modifier/" - * - From "Modifier" in "Verb": - * "=Variable/Modifier/Verb" - * - * Recommended names for values: - * - TQ - * - Tone Quality - * - PlaybackPCM - * - full PCM playback device name - * - PlaybackPCMIsDummy - * - Valid values: "yes" and "no". If set to "yes", the PCM named by the - * PlaybackPCM value is a dummy device, meaning that opening it enables - * an audio path in the hardware, but writing to the PCM device has no - * effect. - * - CapturePCM - * - full PCM capture device name - * - CapturePCMIsDummy - * - Valid values: "yes" and "no". If set to "yes", the PCM named by the - * CapturePCM value is a dummy device, meaning that opening it enables - * an audio path in the hardware, but reading from the PCM device has no - * effect. - * - PlaybackRate - * - playback device sample rate - * - PlaybackChannels - * - playback device channel count - * - PlaybackCTL - * - playback control device name - * - PlaybackVolume - * - playback control volume identifier string - * - can be parsed using snd_use_case_parse_ctl_elem_id() - * - PlaybackSwitch - * - playback control switch identifier string - * - can be parsed using snd_use_case_parse_ctl_elem_id() - * - PlaybackPriority - * - priority value (1-10000), default value is 100, higher value means lower priority - * - CaptureRate - * - capture device sample rate - * - CaptureChannels - * - capture device channel count - * - CaptureCTL - * - capture control device name - * - CaptureVolume - * - capture control volume identifier string - * - can be parsed using snd_use_case_parse_ctl_elem_id() - * - CaptureSwitch - * - capture control switch identifier string - * - can be parsed using snd_use_case_parse_ctl_elem_id() - * - CapturePriority - * - priority value (1-10000), default value is 100, higher value means lower priority - * - PlaybackMixer - * - name of playback mixer - * - PlaybackMixerElem - * - mixer element playback identifier - * - can be parsed using snd_use_case_parse_selem_id() - * - PlaybackMasterElem - * - mixer element playback identifier for the master control - * - PlaybackMasterType - * - type of the master volume control - * - Valid values: "soft" (software attenuation) - * - CaptureMixer - * - name of capture mixer - * - CaptureMixerElem - * - mixer element capture identifier - * - can be parsed using snd_use_case_parse_selem_id() - * - CaptureMasterElem - * - mixer element playback identifier for the master control - * - CaptureMasterType - * - type of the master volume control - * - Valid values: "soft" (software attenuation) - * - EDIDFile - * - Path to EDID file for HDMI devices - * - JackControl, JackDev, JackHWMute - * - Jack information for a device. The jack status can be reported via - * a kcontrol and/or via an input device. **JackControl** is the - * kcontrol name of the jack, and **JackDev** is the input device id of - * the jack (if the full input device path is /dev/input/by-id/foo, the - * JackDev value should be "foo"). UCM configuration files should - * contain both JackControl and JackDev when possible, because - * applications are likely to support only one or the other. - * - * If **JackHWMute** is set, it indicates that when the jack is plugged - * in, the hardware automatically mutes some other device(s). The - * JackHWMute value is a space-separated list of device names (this - * isn't compatible with device names with spaces in them, so don't use - * such device names!). Note that JackHWMute should be used only when - * the hardware enforces the automatic muting. If the hardware doesn't - * enforce any muting, it may still be tempting to set JackHWMute to - * trick upper software layers to e.g. automatically mute speakers when - * headphones are plugged in, but that's application policy - * configuration that doesn't belong to UCM configuration files. - * - MinBufferLevel - * - This is used on platform where reported buffer level is not accurate. - * E.g. "512", which holds 512 samples in device buffer. Note: this will - * increase latency. - */ -int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char **value); - -/** - * \brief Get current - integer - * \param uc_mgr Use case manager - * \param identifier - * \param value result - * \return Zero if success, otherwise a negative error code - * - * Known identifiers: - * - _devstatus/{device} - return status for given device - * - _modstatus/{modifier} - return status for given modifier - */ -int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - long *value); - -/** - * \brief Set new - * \param uc_mgr Use case manager - * \param identifier - * \param value Value - * \return Zero if success, otherwise a negative error code - * - * Known identifiers: - * - _verb - set current verb = value - * - _enadev - enable given device = value - * - _disdev - disable given device = value - * - _swdev/{old_device} - new_device = value - * - disable old_device and then enable new_device - * - if old_device is not enabled just return - * - check transmit sequence firstly - * - _enamod - enable given modifier = value - * - _dismod - disable given modifier = value - * - _swmod/{old_modifier} - new_modifier = value - * - disable old_modifier and then enable new_modifier - * - if old_modifier is not enabled just return - * - check transmit sequence firstly - */ -int snd_use_case_set(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char *value); - -/** - * \brief Open and initialise use case core for sound card - * \param uc_mgr Returned use case manager pointer - * \param card_name Sound card name. - * \return zero if success, otherwise a negative error code - * - * By default only first card is used when the driver card - * name or long name is passed in the card_name argument. - * - * The "strict:" prefix in the card_name defines that - * there is no driver name / long name matching. The straight - * configuration is used. - * - * The "hw:" prefix in the card_name will load the configuration - * for the ALSA card specified by the card index (value) or - * the card string identificator. - * - * The sound card might be also composed from several physical - * sound cards (for the default and strict card_name). - * The application cannot expect that the device names will refer - * only one ALSA sound card in this case. - */ -int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, - const char *card_name); - - -/** - * \brief Reload and re-parse use case configuration files for sound card. - * \param uc_mgr Use case manager - * \return zero if success, otherwise a negative error code - */ -int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr); - -/** - * \brief Close use case manager - * \param uc_mgr Use case manager - * \return zero if success, otherwise a negative error code - */ -int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr); - -/** - * \brief Reset use case manager verb, device, modifier to deafult settings. - * \param uc_mgr Use case manager - * \return zero if success, otherwise a negative error code - */ -int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr); - -/* - * helper functions - */ - -/** - * \brief Obtain a list of cards - * \param list Returned allocated list - * \return Number of list entries if success, otherwise a negative error code - */ -static __inline__ int snd_use_case_card_list(const char **list[]) -{ - return snd_use_case_get_list(NULL, NULL, list); -} - -/** - * \brief Obtain a list of verbs - * \param uc_mgr Use case manager - * \param list Returned list of verbs - * \return Number of list entries if success, otherwise a negative error code - */ -static __inline__ int snd_use_case_verb_list(snd_use_case_mgr_t *uc_mgr, - const char **list[]) -{ - return snd_use_case_get_list(uc_mgr, "_verbs", list); -} - -/** - * \brief Parse control element identifier - * \param elem_id Element identifier - * \param ucm_id Use case identifier - * \param value String value to be parsed - * \return Zero if success, otherwise a negative error code - */ -int snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst, - const char *ucm_id, - const char *value); - -/** - * \brief Parse mixer element identifier - * \param dst Simple mixer element identifier - * \param ucm_id Use case identifier - * \param value String value to be parsed - * \return Zero if success, otherwise a negative error code - */ -int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst, - const char *ucm_id, - const char *value); - -/** - * \} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_USE_CASE_H */ diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf index c4525f0..0998058 100644 --- a/src/conf/alsa.conf +++ b/src/conf/alsa.conf @@ -67,7 +67,8 @@ defaults.pcm.nonblock 1 defaults.pcm.compat 0 defaults.pcm.minperiodtime 5000 # in us defaults.pcm.ipc_key 5678293 -defaults.pcm.ipc_perm 0600 +defaults.pcm.ipc_gid audio +defaults.pcm.ipc_perm 0660 defaults.pcm.dmix.max_periods 0 defaults.pcm.dmix.channels 2 defaults.pcm.dmix.rate 48000 diff --git a/src/conf/alsa.conf.config b/src/conf/alsa.conf.config deleted file mode 100644 index 0998058..0000000 --- a/src/conf/alsa.conf.config +++ /dev/null @@ -1,629 +0,0 @@ -# -# ALSA library configuration file -# - -# pre-load the configuration files - -@hooks [ - { - func load - files [ - "/etc/alsa/conf.d" - "/etc/asound.conf" - "~/.asoundrc" - ] - errors false - } -] - -# load card-specific configuration files (on request) - -cards.@hooks [ - { - func load - files [ - { - @func concat - strings [ - { @func datadir } - "/cards/aliases.conf" - ] - } - ] - } - { - func load_for_all_cards - files [ - { - @func concat - strings [ - { @func datadir } - "/cards/" - { @func private_string } - ".conf" - ] - } - ] - errors false - } -] - -# -# defaults -# - -# show all name hints also for definitions without hint {} section -defaults.namehint.showall off -# show just basic name hints -defaults.namehint.basic on -# show extended name hints -defaults.namehint.extended off -# -defaults.ctl.card 0 -defaults.pcm.card 0 -defaults.pcm.device 0 -defaults.pcm.subdevice -1 -defaults.pcm.nonblock 1 -defaults.pcm.compat 0 -defaults.pcm.minperiodtime 5000 # in us -defaults.pcm.ipc_key 5678293 -defaults.pcm.ipc_gid audio -defaults.pcm.ipc_perm 0660 -defaults.pcm.dmix.max_periods 0 -defaults.pcm.dmix.channels 2 -defaults.pcm.dmix.rate 48000 -defaults.pcm.dmix.format "unchanged" -defaults.pcm.dmix.card defaults.pcm.card -defaults.pcm.dmix.device defaults.pcm.device -defaults.pcm.dsnoop.card defaults.pcm.card -defaults.pcm.dsnoop.device defaults.pcm.device -defaults.pcm.front.card defaults.pcm.card -defaults.pcm.front.device defaults.pcm.device -defaults.pcm.rear.card defaults.pcm.card -defaults.pcm.rear.device defaults.pcm.device -defaults.pcm.center_lfe.card defaults.pcm.card -defaults.pcm.center_lfe.device defaults.pcm.device -defaults.pcm.side.card defaults.pcm.card -defaults.pcm.side.device defaults.pcm.device -defaults.pcm.surround21.card defaults.pcm.card -defaults.pcm.surround21.device defaults.pcm.device -defaults.pcm.surround40.card defaults.pcm.card -defaults.pcm.surround40.device defaults.pcm.device -defaults.pcm.surround41.card defaults.pcm.card -defaults.pcm.surround41.device defaults.pcm.device -defaults.pcm.surround50.card defaults.pcm.card -defaults.pcm.surround50.device defaults.pcm.device -defaults.pcm.surround51.card defaults.pcm.card -defaults.pcm.surround51.device defaults.pcm.device -defaults.pcm.surround71.card defaults.pcm.card -defaults.pcm.surround71.device defaults.pcm.device -defaults.pcm.iec958.card defaults.pcm.card -defaults.pcm.iec958.device defaults.pcm.device -defaults.pcm.modem.card defaults.pcm.card -defaults.pcm.modem.device defaults.pcm.device -# truncate files via file or tee PCM -defaults.pcm.file_format "raw" -defaults.pcm.file_truncate true -defaults.rawmidi.card 0 -defaults.rawmidi.device 0 -defaults.rawmidi.subdevice -1 -defaults.hwdep.card 0 -defaults.hwdep.device 0 -defaults.timer.class 2 -defaults.timer.sclass 0 -defaults.timer.card 0 -defaults.timer.device 0 -defaults.timer.subdevice 0 - -# -# PCM interface -# - -# redirect to load-on-demand extended pcm definitions -pcm.cards cards.pcm - -pcm.default cards.pcm.default -pcm.sysdefault cards.pcm.default -pcm.front cards.pcm.front -pcm.rear cards.pcm.rear -pcm.center_lfe cards.pcm.center_lfe -pcm.side cards.pcm.side -pcm.surround21 cards.pcm.surround21 -pcm.surround40 cards.pcm.surround40 -pcm.surround41 cards.pcm.surround41 -pcm.surround50 cards.pcm.surround50 -pcm.surround51 cards.pcm.surround51 -pcm.surround71 cards.pcm.surround71 -pcm.iec958 cards.pcm.iec958 -pcm.spdif iec958 -pcm.hdmi cards.pcm.hdmi -pcm.dmix cards.pcm.dmix -pcm.dsnoop cards.pcm.dsnoop -pcm.modem cards.pcm.modem -pcm.phoneline cards.pcm.phoneline - -pcm.hw { - @args [ CARD DEV SUBDEV ] - @args.CARD { - type string - default { - @func getenv - vars [ - ALSA_PCM_CARD - ALSA_CARD - ] - default { - @func refer - name defaults.pcm.card - } - } - } - @args.DEV { - type integer - default { - @func igetenv - vars [ - ALSA_PCM_DEVICE - ] - default { - @func refer - name defaults.pcm.device - } - } - } - @args.SUBDEV { - type integer - default { - @func refer - name defaults.pcm.subdevice - } - } - type hw - card $CARD - device $DEV - subdevice $SUBDEV - hint { - show { - @func refer - name defaults.namehint.extended - } - description "Direct hardware device without any conversions" - } -} - -pcm.plughw { - @args [ CARD DEV SUBDEV ] - @args.CARD { - type string - default { - @func getenv - vars [ - ALSA_PCM_CARD - ALSA_CARD - ] - default { - @func refer - name defaults.pcm.card - } - } - } - @args.DEV { - type integer - default { - @func igetenv - vars [ - ALSA_PCM_DEVICE - ] - default { - @func refer - name defaults.pcm.device - } - } - } - @args.SUBDEV { - type integer - default { - @func refer - name defaults.pcm.subdevice - } - } - type plug - slave.pcm { - type hw - card $CARD - device $DEV - subdevice $SUBDEV - } - hint { - show { - @func refer - name defaults.namehint.extended - } - description "Hardware device with all software conversions" - } -} - -pcm.plug { - @args [ SLAVE ] - @args.SLAVE { - type string - } - type plug - slave.pcm $SLAVE -} - -pcm.shm { - @args [ SOCKET PCM ] - @args.SOCKET { - type string - } - @args.PCM { - type string - } - type shm - server $SOCKET - pcm $PCM -} - -pcm.tee { - @args [ SLAVE FILE FORMAT ] - @args.SLAVE { - type string - } - @args.FILE { - type string - } - @args.FORMAT { - type string - default { - @func refer - name defaults.pcm.file_format - } - } - type file - slave.pcm $SLAVE - file $FILE - format $FORMAT - truncate { - @func refer - name defaults.pcm.file_truncate - } -} - -pcm.file { - @args [ FILE FORMAT ] - @args.FILE { - type string - } - @args.FORMAT { - type string - default { - @func refer - name defaults.pcm.file_format - } - } - type file - slave.pcm null - file $FILE - format $FORMAT - truncate { - @func refer - name defaults.pcm.file_truncate - } -} - -pcm.null { - type null - hint { - show { - @func refer - name defaults.namehint.basic - } - description "Discard all samples (playback) or generate zero samples (capture)" - } -} - -# -# Control interface -# - -ctl.sysdefault { - type hw - card { - @func getenv - vars [ - ALSA_CTL_CARD - ALSA_CARD - ] - default { - @func refer - name defaults.ctl.card - } - } - hint.description "Default control device" -} -ctl.default ctl.sysdefault - -ctl.hw { - @args [ CARD ] - @args.CARD { - type string - default { - @func getenv - vars [ - ALSA_CTL_CARD - ALSA_CARD - ] - default { - @func refer - name defaults.ctl.card - } - } - } - type hw - card $CARD - hint.description "Direct control device" -} - -ctl.shm { - @args [ SOCKET CTL ] - @args.SOCKET { - type string - } - @args.CTL { - type string - } - type shm - server $SOCKET - ctl $CTL -} - -# -# RawMidi interface -# - -rawmidi.default { - type hw - card { - @func getenv - vars [ - ALSA_RAWMIDI_CARD - ALSA_CARD - ] - default { - @func refer - name defaults.rawmidi.card - } - } - device { - @func igetenv - vars [ - ALSA_RAWMIDI_DEVICE - ] - default { - @func refer - name defaults.rawmidi.device - } - } - hint.description "Default raw MIDI device" -} - -rawmidi.hw { - @args [ CARD DEV SUBDEV ] - @args.CARD { - type string - default { - @func getenv - vars [ - ALSA_RAWMIDI_CARD - ALSA_CARD - ] - default { - @func refer - name defaults.rawmidi.card - } - } - } - @args.DEV { - type integer - default { - @func igetenv - vars [ - ALSA_RAWMIDI_DEVICE - ] - default { - @func refer - name defaults.rawmidi.device - } - } - } - @args.SUBDEV { - type integer - default -1 - } - type hw - card $CARD - device $DEV - subdevice $SUBDEV - hint { - description "Direct rawmidi driver device" - device $DEV - } -} - -rawmidi.virtual { - @args [ MERGE ] - @args.MERGE { - type string - default 1 - } - type virtual - merge $MERGE -} - -# -# Sequencer interface -# - -seq.default { - type hw - hint.description "Default sequencer device" -} - -seq.hw { - type hw -} - -# -# HwDep interface -# - -hwdep.default { - type hw - card { - @func getenv - vars [ - ALSA_HWDEP_CARD - ALSA_CARD - ] - default { - @func refer - name defaults.hwdep.card - } - } - device { - @func igetenv - vars [ - ALSA_HWDEP_DEVICE - ] - default { - @func refer - name defaults.hwdep.device - } - } - hint.description "Default hardware dependent device" -} - -hwdep.hw { - @args [ CARD DEV ] - @args.CARD { - type string - default { - @func getenv - vars [ - ALSA_HWDEP_CARD - ALSA_CARD - ] - default { - @func refer - name defaults.hwdep.card - } - } - } - @args.DEV { - type integer - default { - @func igetenv - vars [ - ALSA_HWDEP_DEVICE - ] - default { - @func refer - name defaults.hwdep.device - } - } - } - type hw - card $CARD - device $DEV - hint { - description "Direct hardware dependent device" - device $DEV - } -} - -# -# Timer interface -# - -timer_query.default { - type hw -} - -timer_query.hw { - type hw -} - -timer.default { - type hw - class { - @func refer - name defaults.timer.class - } - sclass { - @func refer - name defaults.timer.sclass - } - card { - @func refer - name defaults.timer.card - } - device { - @func refer - name defaults.timer.device - } - subdevice { - @func refer - name defaults.timer.subdevice - } - hint.description "Default timer device" -} - -timer.hw { - @args [ CLASS SCLASS CARD DEV SUBDEV ] - @args.CLASS { - type integer - default { - @func refer - name defaults.timer.class - } - } - @args.SCLASS { - type integer - default { - @func refer - name defaults.timer.sclass - } - } - @args.CARD { - type string - default { - @func refer - name defaults.timer.card - } - } - @args.DEV { - type integer - default { - @func refer - name defaults.timer.device - } - } - @args.SUBDEV { - type integer - default { - @func refer - name defaults.timer.subdevice - } - } - type hw - class $CLASS - sclass $SCLASS - card $CARD - device $DEV - subdevice $SUBDEV - hint { - description "Direct timer device" - device $DEV - } -} diff --git a/src/conf/pcm/dmix.conf b/src/conf/pcm/dmix.conf index 97936a8..7fa5c8b 100644 --- a/src/conf/pcm/dmix.conf +++ b/src/conf/pcm/dmix.conf @@ -48,6 +48,10 @@ pcm.!dmix { @func refer name defaults.pcm.ipc_key } + ipc_gid { + @func refer + name defaults.pcm.ipc_gid + } ipc_perm { @func refer name defaults.pcm.ipc_perm diff --git a/src/conf/pcm/dmix.conf.config b/src/conf/pcm/dmix.conf.config deleted file mode 100644 index 7fa5c8b..0000000 --- a/src/conf/pcm/dmix.conf.config +++ /dev/null @@ -1,123 +0,0 @@ -# -# dmix output -# - -pcm.!dmix { - @args [ CARD DEV SUBDEV FORMAT RATE CHANNELS ] - @args.CARD { - type string - default { - @func refer - name defaults.pcm.dmix.card - } - } - @args.DEV { - type integer - default { - @func refer - name defaults.pcm.dmix.device - } - } - @args.SUBDEV { - type integer - default 0 - } - @args.FORMAT { - type string - default { - @func refer - name defaults.pcm.dmix.format - } - } - @args.RATE { - type integer - default { - @func refer - name defaults.pcm.dmix.rate - } - } - @args.CHANNELS { - type integer - default { - @func refer - name defaults.pcm.dmix.channels - } - } - type dmix - ipc_key { - @func refer - name defaults.pcm.ipc_key - } - ipc_gid { - @func refer - name defaults.pcm.ipc_gid - } - ipc_perm { - @func refer - name defaults.pcm.ipc_perm - } - slave { - pcm { - type hw - card $CARD - device $DEV - subdevice $SUBDEV - } - format $FORMAT - rate $RATE - channels $CHANNELS - period_size { - @func refer - name { - @func concat - strings [ - "defaults.dmix." - { - @func card_driver - card $CARD - } - ".period_size" - ] - } - default 1024 - } - period_time { - @func refer - name { - @func concat - strings [ - "defaults.dmix." - { - @func card_driver - card $CARD - } - ".period_time" - ] - } - default -1 - } - periods { - @func refer - name { - @func concat - strings [ - "defaults.dmix." - { - @func card_driver - card $CARD - } - ".periods" - ] - } - default 16 - } - } - hint { - show { - @func refer - name defaults.namehint.extended - } - description "Direct sample mixing device" - device_output $DEV - } -} diff --git a/src/conf/pcm/dsnoop.conf b/src/conf/pcm/dsnoop.conf index 528fb6a..abbd44f 100644 --- a/src/conf/pcm/dsnoop.conf +++ b/src/conf/pcm/dsnoop.conf @@ -41,6 +41,10 @@ pcm.!dsnoop { @func refer name defaults.pcm.ipc_key } + ipc_gid { + @func refer + name defaults.pcm.ipc_gid + } ipc_perm { @func refer name defaults.pcm.ipc_perm diff --git a/src/conf/pcm/dsnoop.conf.config b/src/conf/pcm/dsnoop.conf.config deleted file mode 100644 index abbd44f..0000000 --- a/src/conf/pcm/dsnoop.conf.config +++ /dev/null @@ -1,115 +0,0 @@ -# -# dsnoop -# - -pcm.!dsnoop { - @args [ CARD DEV SUBDEV FORMAT RATE ] - @args.CARD { - type string - default { - @func refer - name defaults.pcm.dsnoop.card - } - } - @args.DEV { - type integer - default { - @func refer - name defaults.pcm.dsnoop.device - } - } - @args.SUBDEV { - type integer - default 0 - } - @args.FORMAT { - type string - default { - @func refer - name defaults.pcm.dmix.format - } - } - @args.RATE { - type integer - default { - @func refer - name defaults.pcm.dmix.rate - } - } - type dsnoop - ipc_key { - @func refer - name defaults.pcm.ipc_key - } - ipc_gid { - @func refer - name defaults.pcm.ipc_gid - } - ipc_perm { - @func refer - name defaults.pcm.ipc_perm - } - slave { - pcm { - type hw - card $CARD - device $DEV - subdevice $SUBDEV - } - format $FORMAT - rate $RATE - period_size { - @func refer - name { - @func concat - strings [ - "cards." - { - @func card_driver - card $CARD - } - ".pcm.dsnoop.period_size" - ] - } - default 1024 - } - period_time { - @func refer - name { - @func concat - strings [ - "cards." - { - @func card_driver - card $CARD - } - ".pcm.dsnoop.period_time" - ] - } - default -1 - } - periods { - @func refer - name { - @func concat - strings [ - "cards." - { - @func card_driver - card $CARD - } - ".pcm.dsnoop.periods" - ] - } - default 16 - } - } - hint { - show { - @func refer - name defaults.namehint.extended - } - description "Direct sample snooping device" - device_input $DEV - } -} diff --git a/src/control/namehint.c b/src/control/namehint.c index 60c48ae..808df6b 100644 --- a/src/control/namehint.c +++ b/src/control/namehint.c @@ -348,13 +348,6 @@ static int try_config(snd_config_t *config, goto __cleanup; if (snd_config_search(res, "@args", &cfg) >= 0) { snd_config_for_each(i, next, cfg) { - /* skip the argument list */ - if (snd_config_get_id(snd_config_iterator_entry(i), &str) < 0) - continue; - while (*str && *str >= '0' && *str <= '9') str++; - if (*str == '\0') - continue; - /* the argument definition must have the default */ if (snd_config_search(snd_config_iterator_entry(i), "default", NULL) < 0) { err = -EINVAL; diff --git a/src/control/namehint.c.alsa-git b/src/control/namehint.c.alsa-git deleted file mode 100644 index 808df6b..0000000 --- a/src/control/namehint.c.alsa-git +++ /dev/null @@ -1,706 +0,0 @@ -/** - * \file control/namehint.c - * \brief Give device name hints - * \author Jaroslav Kysela - * \date 2006 - */ -/* - * Give device name hints - main file - * Copyright (c) 2006 by Jaroslav Kysela - * - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "local.h" - -#ifndef DOC_HIDDEN -#define DEV_SKIP 9999 /* some non-existing device number */ -struct hint_list { - char **list; - unsigned int count; - unsigned int allocated; - const char *siface; - snd_ctl_elem_iface_t iface; - snd_ctl_t *ctl; - snd_ctl_card_info_t *info; - int card; - int device; - long device_input; - long device_output; - int stream; - int show_all; - char *cardname; -}; -#endif - -static int hint_list_add(struct hint_list *list, - const char *name, - const char *description) -{ - char *x; - - if (list->count + 1 >= list->allocated) { - char **n = realloc(list->list, (list->allocated + 10) * sizeof(char *)); - if (n == NULL) - return -ENOMEM; - memset(n + list->allocated, 0, 10 * sizeof(*n)); - list->allocated += 10; - list->list = n; - } - if (name == NULL) { - x = NULL; - } else { - x = malloc(4 + strlen(name) + (description != NULL ? (4 + strlen(description) + 1) : 0) + 1); - if (x == NULL) - return -ENOMEM; - memcpy(x, "NAME", 4); - strcpy(x + 4, name); - if (description != NULL) { - strcat(x, "|DESC"); - strcat(x, description); - } - } - list->list[list->count++] = x; - return 0; -} - -static void zero_handler(const char *file ATTRIBUTE_UNUSED, - int line ATTRIBUTE_UNUSED, - const char *function ATTRIBUTE_UNUSED, - int err ATTRIBUTE_UNUSED, - const char *fmt ATTRIBUTE_UNUSED, - va_list arg ATTRIBUTE_UNUSED) -{ -} - -static int get_dev_name1(struct hint_list *list, char **res, int device, - int stream) -{ - *res = NULL; - if (device < 0 || device == DEV_SKIP) - return 0; - switch (list->iface) { -#ifdef BUILD_HWDEP - case SND_CTL_ELEM_IFACE_HWDEP: - { - snd_hwdep_info_t info = {0}; - snd_hwdep_info_set_device(&info, device); - if (snd_ctl_hwdep_info(list->ctl, &info) < 0) - return 0; - *res = strdup(snd_hwdep_info_get_name(&info)); - return 0; - } -#endif -#ifdef BUILD_PCM - case SND_CTL_ELEM_IFACE_PCM: - { - snd_pcm_info_t info = {0}; - snd_pcm_info_set_device(&info, device); - snd_pcm_info_set_stream(&info, stream ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK); - if (snd_ctl_pcm_info(list->ctl, &info) < 0) - return 0; - switch (snd_pcm_info_get_class(&info)) { - case SND_PCM_CLASS_MODEM: - case SND_PCM_CLASS_DIGITIZER: - return -ENODEV; - default: - break; - } - *res = strdup(snd_pcm_info_get_name(&info)); - return 0; - } -#endif -#ifdef BUILD_RAWMIDI - case SND_CTL_ELEM_IFACE_RAWMIDI: - { - snd_rawmidi_info_t info = {0}; - snd_rawmidi_info_set_device(&info, device); - snd_rawmidi_info_set_stream(&info, stream ? SND_RAWMIDI_STREAM_INPUT : SND_RAWMIDI_STREAM_OUTPUT); - if (snd_ctl_rawmidi_info(list->ctl, &info) < 0) - return 0; - *res = strdup(snd_rawmidi_info_get_name(&info)); - return 0; - } -#endif - default: - return 0; - } -} - -static char *get_dev_name(struct hint_list *list) -{ - char *str1, *str2, *res; - int device; - - device = list->device_input >= 0 ? list->device_input : list->device; - if (get_dev_name1(list, &str1, device, 1) < 0) - return NULL; - device = list->device_output >= 0 ? list->device_output : list->device; - if (get_dev_name1(list, &str2, device, 0) < 0) { - if (str1) - free(str1); - return NULL; - } - if (str1 != NULL || str2 != NULL) { - if (str1 != NULL && str2 != NULL) { - if (strcmp(str1, str2) == 0) { - res = malloc(strlen(list->cardname) + strlen(str2) + 3); - if (res != NULL) { - strcpy(res, list->cardname); - strcat(res, ", "); - strcat(res, str2); - } - } else { - res = malloc(strlen(list->cardname) + strlen(str2) + strlen(str1) + 6); - if (res != NULL) { - strcpy(res, list->cardname); - strcat(res, ", "); - strcat(res, str2); - strcat(res, " / "); - strcat(res, str1); - } - } - free(str2); - free(str1); - return res; - } else { - if (str1 != NULL) { - str2 = "Input"; - } else { - str1 = str2; - str2 = "Output"; - } - res = malloc(strlen(list->cardname) + strlen(str1) + 19); - if (res == NULL) { - free(str1); - return NULL; - } - strcpy(res, list->cardname); - strcat(res, ", "); - strcat(res, str1); - strcat(res, "|IOID"); - strcat(res, str2); - free(str1); - return res; - } - } - /* if the specified device doesn't exist, skip this entry */ - if (list->device >= 0 || list->device_input >= 0 || list->device_output >= 0) - return NULL; - return strdup(list->cardname); -} - -#ifndef DOC_HIDDEN -#define BUF_SIZE 128 -#endif - -static int try_config(snd_config_t *config, - struct hint_list *list, - const char *base, - const char *name) -{ - snd_local_error_handler_t eh; - snd_config_t *res = NULL, *cfg, *cfg1, *n; - snd_config_iterator_t i, next; - char *buf, *buf1 = NULL, *buf2; - const char *str; - int err = 0, level; - long dev = list->device; - int cleanup_res = 0; - - list->device_input = -1; - list->device_output = -1; - buf = malloc(BUF_SIZE); - if (buf == NULL) - return -ENOMEM; - sprintf(buf, "%s.%s", base, name); - /* look for redirection */ - if (snd_config_search(config, buf, &cfg) >= 0 && - snd_config_get_string(cfg, &str) >= 0 && - ((strncmp(base, str, strlen(base)) == 0 && - str[strlen(base)] == '.') || strchr(str, '.') == NULL)) - goto __skip_add; - if (list->card >= 0 && list->device >= 0) - sprintf(buf, "%s:CARD=%s,DEV=%i", name, snd_ctl_card_info_get_id(list->info), list->device); - else if (list->card >= 0) - sprintf(buf, "%s:CARD=%s", name, snd_ctl_card_info_get_id(list->info)); - else - strcpy(buf, name); - eh = snd_lib_error_set_local(&zero_handler); - err = snd_config_search_definition(config, base, buf, &res); - snd_lib_error_set_local(eh); - if (err < 0) - goto __skip_add; - cleanup_res = 1; - err = -EINVAL; - if (snd_config_get_type(res) != SND_CONFIG_TYPE_COMPOUND) - goto __cleanup; - if (snd_config_search(res, "type", NULL) < 0) - goto __cleanup; - -#if 0 /* for debug purposes */ - { - snd_output_t *out; - fprintf(stderr, "********* PCM '%s':\n", buf); - snd_output_stdio_attach(&out, stderr, 0); - snd_config_save(res, out); - snd_output_close(out); - fprintf(stderr, "\n"); - } -#endif - - cfg1 = res; - level = 0; - __hint: - level++; - if (snd_config_search(cfg1, "type", &cfg) >= 0 && - snd_config_get_string(cfg, &str) >= 0 && - strcmp(str, "hw") == 0) { - list->device_input = -1; - list->device_output = -1; - if (snd_config_search(cfg1, "device", &cfg) >= 0) { - if (snd_config_get_integer(cfg, &dev) < 0) { - SNDERR("(%s) device must be an integer", buf); - err = -EINVAL; - goto __cleanup; - } - } - } - - if (snd_config_search(cfg1, "hint", &cfg) >= 0) { - if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { - SNDERR("hint (%s) must be a compound", buf); - err = -EINVAL; - goto __cleanup; - } - if (level == 1 && - snd_config_search(cfg, "show", &n) >= 0 && - snd_config_get_bool(n) <= 0) - goto __skip_add; - if (buf1 == NULL && - snd_config_search(cfg, "description", &n) >= 0 && - snd_config_get_string(n, &str) >= 0) { - buf1 = strdup(str); - if (buf1 == NULL) { - err = -ENOMEM; - goto __cleanup; - } - } - if (snd_config_search(cfg, "device", &n) >= 0) { - if (snd_config_get_integer(n, &dev) < 0) { - SNDERR("(%s) device must be an integer", buf); - err = -EINVAL; - goto __cleanup; - } - list->device_input = dev; - list->device_output = dev; - } - if (snd_config_search(cfg, "device_input", &n) >= 0) { - if (snd_config_get_integer(n, &list->device_input) < 0) { - SNDERR("(%s) device_input must be an integer", buf); - err = -EINVAL; - goto __cleanup; - } - /* skip the counterpart if only a single direction is defined */ - if (list->device_output < 0) - list->device_output = DEV_SKIP; - } - if (snd_config_search(cfg, "device_output", &n) >= 0) { - if (snd_config_get_integer(n, &list->device_output) < 0) { - SNDERR("(%s) device_output must be an integer", buf); - err = -EINVAL; - goto __cleanup; - } - /* skip the counterpart if only a single direction is defined */ - if (list->device_input < 0) - list->device_input = DEV_SKIP; - } - } else if (level == 1 && !list->show_all) - goto __skip_add; - if (snd_config_search(cfg1, "slave", &cfg) >= 0 && - snd_config_search(cfg, base, &cfg1) >= 0) - goto __hint; - snd_config_delete(res); - res = NULL; - cleanup_res = 0; - if (strchr(buf, ':') != NULL) - goto __ok; - /* find, if all parameters have a default, */ - /* otherwise filter this definition */ - eh = snd_lib_error_set_local(&zero_handler); - err = snd_config_search_alias_hooks(config, base, buf, &res); - snd_lib_error_set_local(eh); - if (err < 0) - goto __cleanup; - if (snd_config_search(res, "@args", &cfg) >= 0) { - snd_config_for_each(i, next, cfg) { - if (snd_config_search(snd_config_iterator_entry(i), - "default", NULL) < 0) { - err = -EINVAL; - goto __cleanup; - } - } - } - __ok: - err = 0; - __cleanup: - if (err >= 0) { - list->device = dev; - str = list->card >= 0 ? get_dev_name(list) : NULL; - if (str != NULL) { - level = (buf1 == NULL ? 0 : strlen(buf1)) + 1 + strlen(str); - buf2 = realloc((char *)str, level + 1); - if (buf2 != NULL) { - if (buf1 != NULL) { - str = strchr(buf2, '|'); - if (str != NULL) - memmove(buf2 + (level - strlen(str)), str, strlen(str)); - else - str = buf2 + strlen(buf2); - *(char *)str++ = '\n'; - memcpy((char *)str, buf1, strlen(buf1)); - buf2[level] = '\0'; - free(buf1); - } - buf1 = buf2; - } else { - free((char *)str); - } - } else if (list->device >= 0) - goto __skip_add; - err = hint_list_add(list, buf, buf1); - } - __skip_add: - if (res && cleanup_res) - snd_config_delete(res); - if (buf1) - free(buf1); - free(buf); - return err; -} - -#ifndef DOC_HIDDEN -#define IFACE(v, fcn) [SND_CTL_ELEM_IFACE_##v] = (next_devices_t)fcn - -typedef int (*next_devices_t)(snd_ctl_t *, int *); - -static const next_devices_t next_devices[] = { - IFACE(CARD, NULL), - IFACE(HWDEP, snd_ctl_hwdep_next_device), - IFACE(MIXER, NULL), - IFACE(PCM, snd_ctl_pcm_next_device), - IFACE(RAWMIDI, snd_ctl_rawmidi_next_device), - IFACE(TIMER, NULL), - IFACE(SEQUENCER, NULL) -}; -#endif - -static int add_card(snd_config_t *config, snd_config_t *rw_config, struct hint_list *list, int card) -{ - int err, ok; - snd_config_t *conf, *n; - snd_config_iterator_t i, next; - const char *str; - char ctl_name[16]; - snd_ctl_card_info_t info = {0}; - int device, max_device = 0; - - list->info = &info; - err = snd_config_search(config, list->siface, &conf); - if (err < 0) - return err; - sprintf(ctl_name, "hw:%i", card); - err = snd_ctl_open(&list->ctl, ctl_name, 0); - if (err < 0) - return err; - err = snd_ctl_card_info(list->ctl, &info); - if (err < 0) - goto __error; - snd_config_for_each(i, next, conf) { - n = snd_config_iterator_entry(i); - if (snd_config_get_id(n, &str) < 0) - continue; - - if (next_devices[list->iface] != NULL) { - list->card = card; - device = max_device = -1; - err = next_devices[list->iface](list->ctl, &device); - if (device < 0) - err = -EINVAL; - else - max_device = device; - while (err >= 0 && device >= 0) { - err = next_devices[list->iface](list->ctl, &device); - if (err >= 0 && device > max_device) - max_device = device; - } - ok = 0; - for (device = 0; err >= 0 && device <= max_device; device++) { - list->device = device; - err = try_config(rw_config, list, list->siface, str); - if (err < 0) - break; - ok++; - } - if (ok) - continue; - } else { - err = -EINVAL; - } - if (err == -EXDEV) - continue; - if (err < 0) { - list->card = card; - list->device = -1; - err = try_config(rw_config, list, list->siface, str); - } - if (err == -ENOMEM) - goto __error; - } - err = 0; - __error: - snd_ctl_close(list->ctl); - return err; -} - -static int get_card_name(struct hint_list *list, int card) -{ - char scard[16], *s; - int err; - - free(list->cardname); - list->cardname = NULL; - err = snd_card_get_name(card, &list->cardname); - if (err <= 0) - return 0; - sprintf(scard, " #%i", card); - s = realloc(list->cardname, strlen(list->cardname) + strlen(scard) + 1); - if (s == NULL) - return -ENOMEM; - list->cardname = s; - return 0; -} - -static int add_software_devices(snd_config_t *config, snd_config_t *rw_config, - struct hint_list *list) -{ - int err; - snd_config_t *conf, *n; - snd_config_iterator_t i, next; - const char *str; - - err = snd_config_search(config, list->siface, &conf); - if (err < 0) - return err; - snd_config_for_each(i, next, conf) { - n = snd_config_iterator_entry(i); - if (snd_config_get_id(n, &str) < 0) - continue; - list->card = -1; - list->device = -1; - err = try_config(rw_config, list, list->siface, str); - if (err == -ENOMEM) - return -ENOMEM; - } - return 0; -} - -/** - * \brief Get a set of device name hints - * \param card Card number or -1 (means all cards) - * \param iface Interface identification (like "pcm", "rawmidi", "timer", "seq") - * \param hints Result - array of device name hints - * \result zero if success, otherwise a negative error code - * - * hints will receive a NULL-terminated array of device name hints, - * which can be passed to #snd_device_name_get_hint to extract usable - * values. When no longer needed, hints should be passed to - * #snd_device_name_free_hint to release resources. - * - * User-defined hints are gathered from namehint.IFACE tree like: - * - * - * namehint.pcm {
- * myfile "file:FILE=/tmp/soundwave.raw|Save sound output to /tmp/soundwave.raw"
- * myplug "plug:front:Do all conversions for front speakers"
- * } - *
- * - * Note: The device description is separated with '|' char. - * - * Special variables: defaults.namehint.showall specifies if all device - * definitions are accepted (boolean type). - */ -int snd_device_name_hint(int card, const char *iface, void ***hints) -{ - struct hint_list list; - char ehints[24]; - const char *str; - snd_config_t *conf, *local_config = NULL, *local_config_rw = NULL; - snd_config_update_t *local_config_update = NULL; - snd_config_iterator_t i, next; - int err; - - if (hints == NULL) - return -EINVAL; - err = snd_config_update_r(&local_config, &local_config_update, NULL); - if (err < 0) - return err; - err = snd_config_copy(&local_config_rw, local_config); - if (err < 0) - return err; - list.list = NULL; - list.count = list.allocated = 0; - list.siface = iface; - list.show_all = 0; - list.cardname = NULL; - if (strcmp(iface, "card") == 0) - list.iface = SND_CTL_ELEM_IFACE_CARD; - else if (strcmp(iface, "pcm") == 0) - list.iface = SND_CTL_ELEM_IFACE_PCM; - else if (strcmp(iface, "rawmidi") == 0) - list.iface = SND_CTL_ELEM_IFACE_RAWMIDI; - else if (strcmp(iface, "timer") == 0) - list.iface = SND_CTL_ELEM_IFACE_TIMER; - else if (strcmp(iface, "seq") == 0) - list.iface = SND_CTL_ELEM_IFACE_SEQUENCER; - else if (strcmp(iface, "hwdep") == 0) - list.iface = SND_CTL_ELEM_IFACE_HWDEP; - else if (strcmp(iface, "ctl") == 0) - list.iface = SND_CTL_ELEM_IFACE_MIXER; - else { - err = -EINVAL; - goto __error; - } - - if (snd_config_search(local_config, "defaults.namehint.showall", &conf) >= 0) - list.show_all = snd_config_get_bool(conf) > 0; - if (card >= 0) { - err = get_card_name(&list, card); - if (err >= 0) - err = add_card(local_config, local_config_rw, &list, card); - } else { - add_software_devices(local_config, local_config_rw, &list); - err = snd_card_next(&card); - if (err < 0) - goto __error; - while (card >= 0) { - err = get_card_name(&list, card); - if (err < 0) - goto __error; - err = add_card(local_config, local_config_rw, &list, card); - if (err < 0) - goto __error; - err = snd_card_next(&card); - if (err < 0) - goto __error; - } - } - sprintf(ehints, "namehint.%s", list.siface); - err = snd_config_search(local_config, ehints, &conf); - if (err >= 0) { - snd_config_for_each(i, next, conf) { - if (snd_config_get_string(snd_config_iterator_entry(i), - &str) < 0) - continue; - err = hint_list_add(&list, str, NULL); - if (err < 0) - goto __error; - } - } - err = 0; - __error: - /* add an empty entry if nothing has been added yet; the caller - * expects non-NULL return - */ - if (!err && !list.list) - err = hint_list_add(&list, NULL, NULL); - if (err < 0) - snd_device_name_free_hint((void **)list.list); - else - *hints = (void **)list.list; - free(list.cardname); - if (local_config_rw) - snd_config_delete(local_config_rw); - if (local_config) - snd_config_delete(local_config); - if (local_config_update) - snd_config_update_free(local_config_update); - return err; -} - -/** - * \brief Free a list of device name hints. - * \param hints List to free - * \result zero if success, otherwise a negative error code - */ -int snd_device_name_free_hint(void **hints) -{ - char **h; - - if (hints == NULL) - return 0; - h = (char **)hints; - while (*h) { - free(*h); - h++; - } - free(hints); - return 0; -} - -/** - * \brief Extract a value from a hint - * \param hint A pointer to hint - * \param id Hint value to extract ("NAME", "DESC", or "IOID", see below) - * \result an allocated ASCII string if success, otherwise NULL - * - * List of valid IDs: - * NAME - name of device - * DESC - description of device - * IOID - input / output identification ("Input" or "Output"), NULL means both - * - * The return value should be freed when no longer needed. - */ -char *snd_device_name_get_hint(const void *hint, const char *id) -{ - const char *hint1 = (const char *)hint, *delim; - char *res; - unsigned size; - - if (strlen(id) != 4) - return NULL; - while (*hint1 != '\0') { - delim = strchr(hint1, '|'); - if (memcmp(id, hint1, 4) != 0) { - if (delim == NULL) - return NULL; - hint1 = delim + 1; - continue; - } - if (delim == NULL) - return strdup(hint1 + 4); - size = delim - hint1 - 4; - res = malloc(size + 1); - if (res != NULL) { - memcpy(res, hint1 + 4, size); - res[size] = '\0'; - } - return res; - } - return NULL; -} diff --git a/src/ucm/main.c b/src/ucm/main.c index 61922f1..b0b6ffb 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -61,13 +61,11 @@ static int check_identifier(const char *identifier, const char *prefix) { int len; + if (strcmp(identifier, prefix) == 0) + return 1; len = strlen(prefix); - if (strncmp(identifier, prefix, len) != 0) - return 0; - - if (identifier[len] == 0 || identifier[len] == '/') + if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/') return 1; - return 0; } @@ -1072,6 +1070,7 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr) /** * \brief Get list of verbs in pair verbname+comment * \param list Returned list + * \param verbname For verb (NULL = current) * \return Number of list entries if success, otherwise a negative error code */ static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[]) @@ -1159,10 +1158,8 @@ static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr, modifier = find_modifier(uc_mgr, verb, name, 0); if (modifier) { - if (modifier->dev_list.type != type) { - *list = NULL; + if (modifier->dev_list.type != type) return 0; - } return get_list(&modifier->dev_list.list, list, struct dev_list_node, list, name); @@ -1170,16 +1167,15 @@ static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr, device = find_device(uc_mgr, verb, name, 0); if (device) { - if (device->dev_list.type != type) { - *list = NULL; + if (device->dev_list.type != type) return 0; - } return get_list(&device->dev_list.list, list, struct dev_list_node, list, name); } return -ENOENT; + } /** @@ -1208,201 +1204,41 @@ static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr, #ifndef DOC_HIDDEN struct myvalue { - struct list_head list; - const char *text; + struct list_head list; + char *value; }; #endif -/** - * \brief Convert myvalue list string list - * \param list myvalue list - * \param res string list - * \retval Number of list entries if success, otherwise a negativer error code - */ -static int myvalue_to_str_list(struct list_head *list, char ***res) -{ - struct list_head *pos; - struct myvalue *value; - char **p; - int cnt; - - cnt = alloc_str_list(list, 1, res); - if (cnt < 0) - return cnt; - p = *res; - list_for_each(pos, list) { - value = list_entry(pos, struct myvalue, list); - *p = strdup(value->text); - if (*p == NULL) { - snd_use_case_free_list((const char **)p, cnt); - return -ENOMEM; - } - p++; - } - return cnt; -} - -/** - * \brief Free myvalue list - * \param list myvalue list - */ -static void myvalue_list_free(struct list_head *list) -{ - struct list_head *pos, *npos; - struct myvalue *value; - - list_for_each_safe(pos, npos, list) { - value = list_entry(pos, struct myvalue, list); - list_del(&value->list); - free(value); - } -} - -/** - * \brief Merge one value to the myvalue list - * \param list The list with values - * \param value The value to be merged (without duplicates) - * \return 1 if dup, 0 if success, otherwise a negative error code - */ -static int merge_value(struct list_head *list, const char *text) -{ - struct list_head *pos; - struct myvalue *value; - - list_for_each(pos, list) { - value = list_entry(pos, struct myvalue, list); - if (strcmp(value->text, text) == 0) - return 1; - } - value = malloc(sizeof(*value)); - if (value == NULL) - return -ENOMEM; - value->text = text; - list_add_tail(&value->list, list); - return 0; -} - -/** - * \brief Find all values for given identifier - * \param list Returned list - * \param source Source list with ucm_value structures - * \return Zero if success, otherwise a negative error code - */ -static int add_identifiers(struct list_head *list, - struct list_head *source) -{ - struct ucm_value *v; - struct list_head *pos; - int err; - - list_for_each(pos, source) { - v = list_entry(pos, struct ucm_value, list); - err = merge_value(list, v->name); - if (err < 0) - return err; - } - return 0; -} - -/** - * \brief Find all values for given identifier - * \param list Returned list - * \param identifier Identifier - * \param source Source list with ucm_value structures - */ static int add_values(struct list_head *list, const char *identifier, struct list_head *source) { - struct ucm_value *v; - struct list_head *pos; - int err; + struct ucm_value *v; + struct myvalue *val; + struct list_head *pos, *pos1; + int match; - list_for_each(pos, source) { - v = list_entry(pos, struct ucm_value, list); - if (check_identifier(identifier, v->name)) { - err = merge_value(list, v->data); - if (err < 0) - return err; - } - } - return 0; -} - -/** - * \brief compare two identifiers - */ -static int identifier_cmp(const void *_a, const void *_b) -{ - const char * const *a = _a; - const char * const *b = _b; - return strcmp(*a, *b); -} - -/** - * \brief Get list of available identifiers - * \param list Returned list - * \param name Name of verb or modifier to query - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_identifiers_list(snd_use_case_mgr_t *uc_mgr, - const char **list[], char *name) -{ - struct use_case_verb *verb; - struct use_case_modifier *modifier; - struct use_case_device *device; - struct list_head mylist; - struct list_head *value_list; - char *str, **res; - int err; - - if (!name) - return -ENOENT; - - str = strchr(name, '/'); - if (str) { - *str = '\0'; - verb = find_verb(uc_mgr, str + 1); - } - else { - verb = uc_mgr->active_verb; - } - if (!verb) - return -ENOENT; - - value_list = NULL; - modifier = find_modifier(uc_mgr, verb, name, 0); - if (modifier) { - value_list = &modifier->value_list; - } else { - device = find_device(uc_mgr, verb, name, 0); - if (device) - value_list = &device->value_list; - } - if (value_list == NULL) - return -ENOENT; - - INIT_LIST_HEAD(&mylist); - err = add_identifiers(&mylist, &uc_mgr->value_list); - if (err < 0) - goto __fail; - err = add_identifiers(&mylist, &verb->value_list); - if (err < 0) - goto __fail; - err = add_identifiers(&mylist, value_list); - if (err < 0) - goto __fail; - err = myvalue_to_str_list(&mylist, &res); - if (err > 0) - *list = (const char **)res; - else if (err == 0) - *list = NULL; -__fail: - myvalue_list_free(&mylist); - if (err <= 0) - return err; - qsort(*list, err, sizeof(char *), identifier_cmp); - return err; + list_for_each(pos, source) { + v = list_entry(pos, struct ucm_value, list); + if (check_identifier(identifier, v->name)) { + match = 0; + list_for_each(pos1, list) { + val = list_entry(pos1, struct myvalue, list); + if (strcmp(val->value, v->data) == 0) { + match = 1; + break; + } + } + if (!match) { + val = malloc(sizeof(struct myvalue)); + if (val == NULL) + return -ENOMEM; + val->value = v->data; + list_add_tail(&val->list, list); + } + } + } + return 0; } /** @@ -1416,7 +1252,8 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr, const char **list[], char *verbname) { - struct list_head mylist, *pos; + struct list_head mylist, *pos, *npos; + struct myvalue *val; struct use_case_verb *verb; struct use_case_device *dev; struct use_case_modifier *mod; @@ -1449,13 +1286,26 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr, if (err < 0) goto __fail; } - err = myvalue_to_str_list(&mylist, &res); - if (err > 0) + err = alloc_str_list(&mylist, 1, &res); + if (err >= 0) { *list = (const char **)res; - else if (err == 0) - *list = NULL; + list_for_each(pos, &mylist) { + val = list_entry(pos, struct myvalue, list); + *res = strdup(val->value); + if (*res == NULL) { + snd_use_case_free_list((const char **)res, err); + err = -ENOMEM; + goto __fail; + } + res++; + } + } __fail: - myvalue_list_free(&mylist); + list_for_each_safe(pos, npos, &mylist) { + val = list_entry(pos, struct myvalue, list); + list_del(&val->list); + free(val); + } return err; } @@ -1525,23 +1375,21 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, } else { str = NULL; } - if (check_identifier(identifier, "_devices")) - err = get_device_list(uc_mgr, list, str); + if (check_identifier(identifier, "_devices")) + err = get_device_list(uc_mgr, list, str); else if (check_identifier(identifier, "_modifiers")) - err = get_modifier_list(uc_mgr, list, str); - else if (check_identifier(identifier, "_identifiers")) - err = get_identifiers_list(uc_mgr, list, str); - else if (check_identifier(identifier, "_supporteddevs")) - err = get_supported_device_list(uc_mgr, list, str); - else if (check_identifier(identifier, "_conflictingdevs")) - err = get_conflicting_device_list(uc_mgr, list, str); + err = get_modifier_list(uc_mgr, list, str); + else if (check_identifier(identifier, "_supporteddevs")) + err = get_supported_device_list(uc_mgr, list, str); + else if (check_identifier(identifier, "_conflictingdevs")) + err = get_conflicting_device_list(uc_mgr, list, str); else if (identifier[0] == '_') err = -ENOENT; - else - err = get_value_list(uc_mgr, identifier, list, str); - if (str) - free(str); - } + else + err = get_value_list(uc_mgr, identifier, list, str); + if (str) + free(str); + } __end: pthread_mutex_unlock(&uc_mgr->mutex); return err; @@ -2115,10 +1963,8 @@ int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst, const char *ucm_id, const char *value) { -#ifdef BUILD_MIXER if (strcmp(ucm_id, "PlaybackMixerId") == 0 || strcmp(ucm_id, "CaptureMixerId") == 0) return snd_mixer_selem_id_parse(dst, value); -#endif return -EINVAL; } diff --git a/src/ucm/main.c.alsa-git b/src/ucm/main.c.alsa-git deleted file mode 100644 index b0b6ffb..0000000 --- a/src/ucm/main.c.alsa-git +++ /dev/null @@ -1,1970 +0,0 @@ -/* - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Support for the verb/device/modifier core logic and API, - * command line tool and file parser was kindly sponsored by - * Texas Instruments Inc. - * Support for multiple active modifiers and devices, - * transition sequences, multiple client access and user defined use - * cases was kindly sponsored by Wolfson Microelectronics PLC. - * - * Copyright (C) 2008-2010 SlimLogic Ltd - * Copyright (C) 2010 Wolfson Microelectronics PLC - * Copyright (C) 2010 Texas Instruments Inc. - * Copyright (C) 2010 Red Hat Inc. - * Authors: Liam Girdwood - * Stefan Schmidt - * Justin Xu - * Jaroslav Kysela - */ - -#include "ucm_local.h" -#include -#include -#include -#include -#include - -/* - * misc - */ - -static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, - struct list_head *value_list, const char *identifier); -static int get_value3(snd_use_case_mgr_t *uc_mgr, - char **value, - const char *identifier, - struct list_head *value_list1, - struct list_head *value_list2, - struct list_head *value_list3); - -static int execute_component_seq(snd_use_case_mgr_t *uc_mgr, - struct component_sequence *cmpt_seq, - struct list_head *value_list1, - struct list_head *value_list2, - struct list_head *value_list3, - char *cdev); - -static int check_identifier(const char *identifier, const char *prefix) -{ - int len; - - if (strcmp(identifier, prefix) == 0) - return 1; - len = strlen(prefix); - if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/') - return 1; - return 0; -} - -static int list_count(struct list_head *list) -{ - struct list_head *pos; - int count = 0; - - list_for_each(pos, list) { - count += 1; - } - return count; -} - -static int alloc_str_list(struct list_head *list, int mult, char **result[]) -{ - char **res; - int cnt; - - cnt = list_count(list) * mult; - if (cnt == 0) { - *result = NULL; - return cnt; - } - res = calloc(mult, cnt * sizeof(char *)); - if (res == NULL) - return -ENOMEM; - *result = res; - return cnt; -} - -/** - * \brief Create an identifier - * \param fmt Format (sprintf like) - * \param ... Optional arguments for sprintf like format - * \return Allocated string identifier or NULL on error - */ -char *snd_use_case_identifier(const char *fmt, ...) -{ - char *str, *res; - int size = strlen(fmt) + 512; - va_list args; - - str = malloc(size); - if (str == NULL) - return NULL; - va_start(args, fmt); - vsnprintf(str, size, fmt, args); - va_end(args); - str[size-1] = '\0'; - res = realloc(str, strlen(str) + 1); - if (res) - return res; - return str; -} - -/** - * \brief Free a string list - * \param list The string list to free - * \param items Count of strings - * \return Zero if success, otherwise a negative error code - */ -int snd_use_case_free_list(const char *list[], int items) -{ - int i; - if (list == NULL) - return 0; - for (i = 0; i < items; i++) - free((void *)list[i]); - free(list); - return 0; -} - -static int read_tlv_file(unsigned int **res, - const char *filepath) -{ - int err = 0; - int fd; - struct stat st; - size_t sz; - ssize_t sz_read; - struct snd_ctl_tlv *tlv; - - fd = open(filepath, O_RDONLY); - if (fd < 0) { - err = -errno; - return err; - } - if (fstat(fd, &st) == -1) { - err = -errno; - goto __fail; - } - sz = st.st_size; - if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) { - uc_error("File size should be less than 16 MB " - "and multiple of 4"); - err = -EINVAL; - goto __fail; - } - *res = malloc(sz); - if (res == NULL) { - err = -ENOMEM; - goto __fail; - } - sz_read = read(fd, *res, sz); - if (sz_read < 0 || (size_t)sz_read != sz) { - err = -EIO; - free(*res); - *res = NULL; - } - /* Check if the tlv file specifies valid size. */ - tlv = (struct snd_ctl_tlv *)(*res); - if (tlv->length + 2 * sizeof(unsigned int) != sz) { - uc_error("Invalid tlv size: %d", tlv->length); - err = -EINVAL; - free(*res); - *res = NULL; - } - -__fail: - close(fd); - return err; -} - -static int binary_file_parse(snd_ctl_elem_value_t *dst, - snd_ctl_elem_info_t *info, - const char *filepath) -{ - int err = 0; - int fd; - struct stat st; - size_t sz; - ssize_t sz_read; - char *res; - snd_ctl_elem_type_t type; - unsigned int idx, count; - - type = snd_ctl_elem_info_get_type(info); - if (type != SND_CTL_ELEM_TYPE_BYTES) { - uc_error("only support byte type!"); - err = -EINVAL; - return err; - } - fd = open(filepath, O_RDONLY); - if (fd < 0) { - err = -errno; - return err; - } - if (stat(filepath, &st) == -1) { - err = -errno; - goto __fail; - } - sz = st.st_size; - count = snd_ctl_elem_info_get_count(info); - if (sz != count || sz > sizeof(dst->value.bytes)) { - uc_error("invalid parameter size %d!", sz); - err = -EINVAL; - goto __fail; - } - res = malloc(sz); - if (res == NULL) { - err = -ENOMEM; - goto __fail; - } - sz_read = read(fd, res, sz); - if (sz_read < 0 || (size_t)sz_read != sz) { - err = -errno; - goto __fail_read; - } - for (idx = 0; idx < sz; idx++) - snd_ctl_elem_value_set_byte(dst, idx, *(res + idx)); - __fail_read: - free(res); - __fail: - close(fd); - return err; -} - -extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, - const char *str, - const char **ret_ptr); - -static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type) -{ - const char *pos; - int err; - snd_ctl_elem_id_t *id; - snd_ctl_elem_value_t *value; - snd_ctl_elem_info_t *info; - unsigned int *res = NULL; - - snd_ctl_elem_id_malloc(&id); - snd_ctl_elem_value_malloc(&value); - snd_ctl_elem_info_malloc(&info); - - err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos); - if (err < 0) - goto __fail; - while (*pos && isspace(*pos)) - pos++; - if (!*pos) { - uc_error("undefined value for cset >%s<", cset); - err = -EINVAL; - goto __fail; - } - snd_ctl_elem_info_set_id(info, id); - err = snd_ctl_elem_info(ctl, info); - if (err < 0) - goto __fail; - if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) { - if (!snd_ctl_elem_info_is_tlv_writable(info)) { - err = -EINVAL; - goto __fail; - } - err = read_tlv_file(&res, pos); - if (err < 0) - goto __fail; - err = snd_ctl_elem_tlv_write(ctl, id, res); - if (err < 0) - goto __fail; - } else { - snd_ctl_elem_value_set_id(value, id); - err = snd_ctl_elem_read(ctl, value); - if (err < 0) - goto __fail; - if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE) - err = binary_file_parse(value, info, pos); - else - err = snd_ctl_ascii_value_parse(ctl, value, info, pos); - if (err < 0) - goto __fail; - err = snd_ctl_elem_write(ctl, value); - if (err < 0) - goto __fail; - } - err = 0; - __fail: - if (id != NULL) - free(id); - if (value != NULL) - free(value); - if (info != NULL) - free(info); - if (res != NULL) - free(res); - - return err; -} - -/** - * \brief Execute the sequence - * \param uc_mgr Use case manager - * \param seq Sequence - * \return zero on success, otherwise a negative error code - */ -static int execute_sequence(snd_use_case_mgr_t *uc_mgr, - struct list_head *seq, - struct list_head *value_list1, - struct list_head *value_list2, - struct list_head *value_list3) -{ - struct list_head *pos; - struct sequence_element *s; - char *cdev = NULL; - snd_ctl_t *ctl = NULL; - int err = 0; - - list_for_each(pos, seq) { - s = list_entry(pos, struct sequence_element, list); - switch (s->type) { - case SEQUENCE_ELEMENT_TYPE_CDEV: - cdev = strdup(s->data.cdev); - if (cdev == NULL) - goto __fail_nomem; - break; - case SEQUENCE_ELEMENT_TYPE_CSET: - case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE: - case SEQUENCE_ELEMENT_TYPE_CSET_TLV: - if (cdev == NULL && uc_mgr->in_component_domain) { - /* For sequence of a component device, use - * its parent's cdev stored by ucm manager. - */ - if (uc_mgr->cdev == NULL) { - uc_error("cdev is not defined!"); - return err; - } - - cdev = strndup(uc_mgr->cdev, PATH_MAX); - if (!cdev) - return -ENOMEM; - } else if (cdev == NULL) { - char *playback_ctl = NULL; - char *capture_ctl = NULL; - - err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL", - value_list1, - value_list2, - value_list3); - if (err < 0 && err != -ENOENT) { - uc_error("cdev is not defined!"); - return err; - } - err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL", - value_list1, - value_list2, - value_list3); - if (err < 0 && err != -ENOENT) { - free(playback_ctl); - uc_error("cdev is not defined!"); - return err; - } - if (playback_ctl == NULL && - capture_ctl == NULL) { - uc_error("cdev is not defined!"); - return -EINVAL; - } - if (playback_ctl != NULL && - capture_ctl != NULL && - strcmp(playback_ctl, capture_ctl) != 0) { - free(playback_ctl); - free(capture_ctl); - uc_error("cdev is not equal for playback and capture!"); - return -EINVAL; - } - if (playback_ctl != NULL) { - cdev = playback_ctl; - free(capture_ctl); - } else { - cdev = capture_ctl; - } - } - if (ctl == NULL) { - err = uc_mgr_open_ctl(uc_mgr, &ctl, cdev); - if (err < 0) { - uc_error("unable to open ctl device '%s'", cdev); - goto __fail; - } - } - err = execute_cset(ctl, s->data.cset, s->type); - if (err < 0) { - uc_error("unable to execute cset '%s'", s->data.cset); - goto __fail; - } - break; - case SEQUENCE_ELEMENT_TYPE_SLEEP: - usleep(s->data.sleep); - break; - case SEQUENCE_ELEMENT_TYPE_EXEC: - err = system(s->data.exec); - if (err < 0) - goto __fail; - break; - case SEQUENCE_ELEMENT_TYPE_CMPT_SEQ: - /* Execute enable or disable sequence of a component - * device. Pass the cdev defined by the machine device. - */ - err = execute_component_seq(uc_mgr, - &s->data.cmpt_seq, - value_list1, - value_list2, - value_list3, - cdev); - if (err < 0) - goto __fail; - break; - default: - uc_error("unknown sequence command %i", s->type); - break; - } - } - free(cdev); - return 0; - __fail_nomem: - err = -ENOMEM; - __fail: - free(cdev); - return err; - -} - -/* Execute enable or disable sequence of a component device. - * - * For a component device (a codec or embedded DSP), its sequence doesn't - * specify the sound card device 'cdev', because a component can be reused - * by different sound cards (machines). So when executing its sequence, a - * parameter 'cdev' is used to pass cdev defined by the sequence of its - * parent, the machine device. UCM manger will store the cdev when entering - * the component domain. - */ -static int execute_component_seq(snd_use_case_mgr_t *uc_mgr, - struct component_sequence *cmpt_seq, - struct list_head *value_list1 ATTRIBUTE_UNUSED, - struct list_head *value_list2 ATTRIBUTE_UNUSED, - struct list_head *value_list3 ATTRIBUTE_UNUSED, - char *cdev) -{ - struct use_case_device *device = cmpt_seq->device; - struct list_head *seq; - int err; - - /* enter component domain and store cdev for the component */ - uc_mgr->in_component_domain = 1; - uc_mgr->cdev = cdev; - - /* choose enable or disable sequence of the component device */ - if (cmpt_seq->enable) - seq = &device->enable_list; - else - seq = &device->disable_list; - - /* excecute the sequence of the component dev */ - err = execute_sequence(uc_mgr, seq, - &device->value_list, - &uc_mgr->active_verb->value_list, - &uc_mgr->value_list); - - /* exit component domain and clear cdev */ - uc_mgr->in_component_domain = 0; - uc_mgr->cdev = NULL; - - return err; -} - -static int add_auto_value(snd_use_case_mgr_t *uc_mgr, const char *key, char *value) -{ - char *s; - int err; - - err = get_value1(uc_mgr, &value, &uc_mgr->value_list, key); - if (err == -ENOENT) { - s = strdup(value); - if (s == NULL) - return -ENOMEM; - return uc_mgr_add_value(&uc_mgr->value_list, key, s); - } else if (err < 0) { - return err; - } - free(value); - return 0; -} - -static int add_auto_values(snd_use_case_mgr_t *uc_mgr) -{ - struct ctl_list *ctl_list; - const char *id; - char buf[40]; - int err; - - ctl_list = uc_mgr_get_one_ctl(uc_mgr); - if (ctl_list) { - id = snd_ctl_card_info_get_id(ctl_list->ctl_info); - snprintf(buf, sizeof(buf), "hw:%s", id); - err = add_auto_value(uc_mgr, "PlaybackCTL", buf); - if (err < 0) - return err; - err = add_auto_value(uc_mgr, "CaptureCTL", buf); - if (err < 0) - return err; - } - return 0; -} - -/** - * \brief Import master config and execute the default sequence - * \param uc_mgr Use case manager - * \return zero on success, otherwise a negative error code - */ -static int import_master_config(snd_use_case_mgr_t *uc_mgr) -{ - int err; - - err = uc_mgr_import_master_config(uc_mgr); - if (err < 0) - return err; - err = add_auto_values(uc_mgr); - if (err < 0) - return err; - err = execute_sequence(uc_mgr, &uc_mgr->default_list, - &uc_mgr->value_list, NULL, NULL); - if (err < 0) - uc_error("Unable to execute default sequence"); - return err; -} - -/** - * \brief Universal find - string in a list - * \param list List of structures - * \param offset Offset of list structure - * \param soffset Offset of string structure - * \param match String to match - * \return structure on success, otherwise a NULL (not found) - */ -static void *find0(struct list_head *list, - unsigned long offset, - unsigned long soffset, - const char *match) -{ - struct list_head *pos; - char *ptr, *str; - - list_for_each(pos, list) { - ptr = list_entry_offset(pos, char, offset); - str = *((char **)(ptr + soffset)); - if (strcmp(str, match) == 0) - return ptr; - } - return NULL; -} - -#define find(list, type, member, value, match) \ - find0(list, (unsigned long)(&((type *)0)->member), \ - (unsigned long)(&((type *)0)->value), match) - -/** - * \brief Universal string list - * \param list List of structures - * \param result Result list - * \param offset Offset of list structure - * \param s1offset Offset of string structure - * \return count of items on success, otherwise a negative error code - */ -static int get_list0(struct list_head *list, - const char **result[], - unsigned long offset, - unsigned long s1offset) -{ - char **res; - int cnt; - struct list_head *pos; - char *ptr, *str1; - - cnt = alloc_str_list(list, 1, &res); - if (cnt <= 0) { - *result = NULL; - return cnt; - } - *result = (const char **)res; - list_for_each(pos, list) { - ptr = list_entry_offset(pos, char, offset); - str1 = *((char **)(ptr + s1offset)); - if (str1 != NULL) { - *res = strdup(str1); - if (*res == NULL) - goto __fail; - } else { - *res = NULL; - } - res++; - } - return cnt; - __fail: - snd_use_case_free_list((const char **)res, cnt); - return -ENOMEM; -} - -#define get_list(list, result, type, member, s1) \ - get_list0(list, result, \ - (unsigned long)(&((type *)0)->member), \ - (unsigned long)(&((type *)0)->s1)) - -/** - * \brief Universal string list - pair of strings - * \param list List of structures - * \param result Result list - * \param offset Offset of list structure - * \param s1offset Offset of string structure - * \param s1offset Offset of string structure - * \return count of items on success, otherwise a negative error code - */ -static int get_list20(struct list_head *list, - const char **result[], - unsigned long offset, - unsigned long s1offset, - unsigned long s2offset) -{ - char **res; - int cnt; - struct list_head *pos; - char *ptr, *str1, *str2; - - cnt = alloc_str_list(list, 2, &res); - if (cnt <= 0) { - *result = NULL; - return cnt; - } - *result = (const char **)res; - list_for_each(pos, list) { - ptr = list_entry_offset(pos, char, offset); - str1 = *((char **)(ptr + s1offset)); - if (str1 != NULL) { - *res = strdup(str1); - if (*res == NULL) - goto __fail; - } else { - *res = NULL; - } - res++; - str2 = *((char **)(ptr + s2offset)); - if (str2 != NULL) { - *res = strdup(str2); - if (*res == NULL) - goto __fail; - } else { - *res = NULL; - } - res++; - } - return cnt; - __fail: - snd_use_case_free_list((const char **)res, cnt); - return -ENOMEM; -} - -#define get_list2(list, result, type, member, s1, s2) \ - get_list20(list, result, \ - (unsigned long)(&((type *)0)->member), \ - (unsigned long)(&((type *)0)->s1), \ - (unsigned long)(&((type *)0)->s2)) - -/** - * \brief Find verb - * \param uc_mgr Use case manager - * \param verb_name verb to find - * \return structure on success, otherwise a NULL (not found) - */ -static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr, - const char *verb_name) -{ - return find(&uc_mgr->verb_list, - struct use_case_verb, list, name, - verb_name); -} - -static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr, - struct dev_list *dev_list) -{ - struct dev_list_node *device; - struct use_case_device *adev; - struct list_head *pos, *pos1; - int found_ret; - - switch (dev_list->type) { - case DEVLIST_NONE: - default: - return 1; - case DEVLIST_SUPPORTED: - found_ret = 1; - break; - case DEVLIST_CONFLICTING: - found_ret = 0; - break; - } - - list_for_each(pos, &dev_list->list) { - device = list_entry(pos, struct dev_list_node, list); - - list_for_each(pos1, &uc_mgr->active_devices) { - adev = list_entry(pos1, struct use_case_device, - active_list); - if (!strcmp(device->name, adev->name)) - return found_ret; - } - } - return 1 - found_ret; -} - -static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr, - struct use_case_modifier *modifier) -{ - return is_devlist_supported(uc_mgr, &modifier->dev_list); -} - -static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr, - struct use_case_device *device) -{ - return is_devlist_supported(uc_mgr, &device->dev_list); -} - -/** - * \brief Find device - * \param verb Use case verb - * \param device_name device to find - * \return structure on success, otherwise a NULL (not found) - */ -static inline struct use_case_device * - find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, - const char *device_name, int check_supported) -{ - struct use_case_device *device; - struct list_head *pos; - - list_for_each(pos, &verb->device_list) { - device = list_entry(pos, struct use_case_device, list); - - if (strcmp(device_name, device->name)) - continue; - - if (check_supported && - !is_device_supported(uc_mgr, device)) - continue; - - return device; - } - return NULL; -} - -/** - * \brief Find modifier - * \param verb Use case verb - * \param modifier_name modifier to find - * \return structure on success, otherwise a NULL (not found) - */ -static struct use_case_modifier * - find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, - const char *modifier_name, int check_supported) -{ - struct use_case_modifier *modifier; - struct list_head *pos; - - list_for_each(pos, &verb->modifier_list) { - modifier = list_entry(pos, struct use_case_modifier, list); - - if (strcmp(modifier->name, modifier_name)) - continue; - - if (check_supported && - !is_modifier_supported(uc_mgr, modifier)) - continue; - - return modifier; - } - return NULL; -} - -long device_status(snd_use_case_mgr_t *uc_mgr, - const char *device_name) -{ - struct use_case_device *dev; - struct list_head *pos; - - list_for_each(pos, &uc_mgr->active_devices) { - dev = list_entry(pos, struct use_case_device, active_list); - if (strcmp(dev->name, device_name) == 0) - return 1; - } - return 0; -} - -long modifier_status(snd_use_case_mgr_t *uc_mgr, - const char *modifier_name) -{ - struct use_case_modifier *mod; - struct list_head *pos; - - list_for_each(pos, &uc_mgr->active_modifiers) { - mod = list_entry(pos, struct use_case_modifier, active_list); - if (strcmp(mod->name, modifier_name) == 0) - return 1; - } - return 0; -} - -/** - * \brief Set verb - * \param uc_mgr Use case manager - * \param verb verb to set - * \param enable nonzero = enable, zero = disable - * \return zero on success, otherwise a negative error code - */ -static int set_verb(snd_use_case_mgr_t *uc_mgr, - struct use_case_verb *verb, - int enable) -{ - struct list_head *seq; - int err; - - if (enable) { - seq = &verb->enable_list; - } else { - seq = &verb->disable_list; - } - err = execute_sequence(uc_mgr, seq, - &verb->value_list, - &uc_mgr->value_list, - NULL); - if (enable && err >= 0) - uc_mgr->active_verb = verb; - return err; -} - -/** - * \brief Set modifier - * \param uc_mgr Use case manager - * \param modifier modifier to set - * \param enable nonzero = enable, zero = disable - * \return zero on success, otherwise a negative error code - */ -static int set_modifier(snd_use_case_mgr_t *uc_mgr, - struct use_case_modifier *modifier, - int enable) -{ - struct list_head *seq; - int err; - - if (modifier_status(uc_mgr, modifier->name) == enable) - return 0; - - if (enable) { - seq = &modifier->enable_list; - } else { - seq = &modifier->disable_list; - } - err = execute_sequence(uc_mgr, seq, - &modifier->value_list, - &uc_mgr->active_verb->value_list, - &uc_mgr->value_list); - if (enable && err >= 0) { - list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers); - } else if (!enable) { - list_del(&modifier->active_list); - } - return err; -} - -/** - * \brief Set device - * \param uc_mgr Use case manager - * \param device device to set - * \param enable nonzero = enable, zero = disable - * \return zero on success, otherwise a negative error code - */ -static int set_device(snd_use_case_mgr_t *uc_mgr, - struct use_case_device *device, - int enable) -{ - struct list_head *seq; - int err; - - if (device_status(uc_mgr, device->name) == enable) - return 0; - - if (enable) { - seq = &device->enable_list; - } else { - seq = &device->disable_list; - } - err = execute_sequence(uc_mgr, seq, - &device->value_list, - &uc_mgr->active_verb->value_list, - &uc_mgr->value_list); - if (enable && err >= 0) { - list_add_tail(&device->active_list, &uc_mgr->active_devices); - } else if (!enable) { - list_del(&device->active_list); - } - return err; -} - -/** - * \brief Init sound card use case manager. - * \param uc_mgr Returned use case manager pointer - * \param card_name name of card to open - * \return zero on success, otherwise a negative error code - */ -int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, - const char *card_name) -{ - snd_use_case_mgr_t *mgr; - int err; - - /* create a new UCM */ - mgr = calloc(1, sizeof(snd_use_case_mgr_t)); - if (mgr == NULL) - return -ENOMEM; - INIT_LIST_HEAD(&mgr->verb_list); - INIT_LIST_HEAD(&mgr->default_list); - INIT_LIST_HEAD(&mgr->value_list); - INIT_LIST_HEAD(&mgr->active_modifiers); - INIT_LIST_HEAD(&mgr->active_devices); - INIT_LIST_HEAD(&mgr->ctl_list); - pthread_mutex_init(&mgr->mutex, NULL); - - mgr->card_name = strdup(card_name); - if (mgr->card_name == NULL) { - free(mgr); - return -ENOMEM; - } - - /* get info on use_cases and verify against card */ - err = import_master_config(mgr); - if (err < 0) { - uc_error("error: failed to import %s use case configuration %d", - card_name, err); - goto err; - } - - *uc_mgr = mgr; - return 0; - -err: - uc_mgr_free(mgr); - return err; -} - -/** - * \brief Reload and reparse all use case files. - * \param uc_mgr Use case manager - * \return zero on success, otherwise a negative error code - */ -int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr) -{ - int err; - - pthread_mutex_lock(&uc_mgr->mutex); - - uc_mgr_free_verb(uc_mgr); - - /* reload all use cases */ - err = import_master_config(uc_mgr); - if (err < 0) { - uc_error("error: failed to reload use cases"); - pthread_mutex_unlock(&uc_mgr->mutex); - return -EINVAL; - } - - pthread_mutex_unlock(&uc_mgr->mutex); - return err; -} - -/** - * \brief Close use case manager. - * \param uc_mgr Use case manager - * \return zero on success, otherwise a negative error code - */ -int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr) -{ - uc_mgr_free(uc_mgr); - - return 0; -} - -/* - * Tear down current use case verb, device and modifier. - */ -static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr) -{ - struct list_head *pos, *npos; - struct use_case_modifier *modifier; - struct use_case_device *device; - int err; - - list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) { - modifier = list_entry(pos, struct use_case_modifier, - active_list); - err = set_modifier(uc_mgr, modifier, 0); - if (err < 0) - uc_error("Unable to disable modifier %s", modifier->name); - } - INIT_LIST_HEAD(&uc_mgr->active_modifiers); - - list_for_each_safe(pos, npos, &uc_mgr->active_devices) { - device = list_entry(pos, struct use_case_device, - active_list); - err = set_device(uc_mgr, device, 0); - if (err < 0) - uc_error("Unable to disable device %s", device->name); - } - INIT_LIST_HEAD(&uc_mgr->active_devices); - - err = set_verb(uc_mgr, uc_mgr->active_verb, 0); - if (err < 0) { - uc_error("Unable to disable verb %s", uc_mgr->active_verb->name); - return err; - } - uc_mgr->active_verb = NULL; - - err = execute_sequence(uc_mgr, &uc_mgr->default_list, - &uc_mgr->value_list, NULL, NULL); - - return err; -} - -/** - * \brief Reset sound card controls to default values. - * \param uc_mgr Use case manager - * \return zero on success, otherwise a negative error code - */ -int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr) -{ - int err; - - pthread_mutex_lock(&uc_mgr->mutex); - err = execute_sequence(uc_mgr, &uc_mgr->default_list, - &uc_mgr->value_list, NULL, NULL); - INIT_LIST_HEAD(&uc_mgr->active_modifiers); - INIT_LIST_HEAD(&uc_mgr->active_devices); - uc_mgr->active_verb = NULL; - pthread_mutex_unlock(&uc_mgr->mutex); - return err; -} - -/** - * \brief Get list of verbs in pair verbname+comment - * \param list Returned list - * \param verbname For verb (NULL = current) - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[]) -{ - return get_list2(&uc_mgr->verb_list, list, - struct use_case_verb, list, - name, comment); -} - -/** - * \brief Get list of devices in pair devicename+comment - * \param list Returned list - * \param verbname For verb (NULL = current) - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[], - char *verbname) -{ - struct use_case_verb *verb; - - if (verbname) { - verb = find_verb(uc_mgr, verbname); - } else { - verb = uc_mgr->active_verb; - } - if (verb == NULL) - return -ENOENT; - return get_list2(&verb->device_list, list, - struct use_case_device, list, - name, comment); -} - -/** - * \brief Get list of modifiers in pair devicename+comment - * \param list Returned list - * \param verbname For verb (NULL = current) - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[], - char *verbname) -{ - struct use_case_verb *verb; - - if (verbname) { - verb = find_verb(uc_mgr, verbname); - } else { - verb = uc_mgr->active_verb; - } - if (verb == NULL) - return -ENOENT; - return get_list2(&verb->modifier_list, list, - struct use_case_modifier, list, - name, comment); -} - -/** - * \brief Get list of supported/conflicting devices - * \param list Returned list - * \param name Name of modifier or verb to query - * \param type Type of device list entries to return - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr, - const char **list[], char *name, - enum dev_list_type type) -{ - char *str; - struct use_case_verb *verb; - struct use_case_modifier *modifier; - struct use_case_device *device; - - if (!name) - return -ENOENT; - - str = strchr(name, '/'); - if (str) { - *str = '\0'; - verb = find_verb(uc_mgr, str + 1); - } - else { - verb = uc_mgr->active_verb; - } - if (!verb) - return -ENOENT; - - modifier = find_modifier(uc_mgr, verb, name, 0); - if (modifier) { - if (modifier->dev_list.type != type) - return 0; - return get_list(&modifier->dev_list.list, list, - struct dev_list_node, list, - name); - } - - device = find_device(uc_mgr, verb, name, 0); - if (device) { - if (device->dev_list.type != type) - return 0; - return get_list(&device->dev_list.list, list, - struct dev_list_node, list, - name); - } - - return -ENOENT; - -} - -/** - * \brief Get list of supported devices - * \param list Returned list - * \param name Name of verb or modifier to query - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr, - const char **list[], char *name) -{ - return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED); -} - -/** - * \brief Get list of conflicting devices - * \param list Returned list - * \param name Name of verb or modifier to query - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr, - const char **list[], char *name) -{ - return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING); -} - -#ifndef DOC_HIDDEN -struct myvalue { - struct list_head list; - char *value; -}; -#endif - -static int add_values(struct list_head *list, - const char *identifier, - struct list_head *source) -{ - struct ucm_value *v; - struct myvalue *val; - struct list_head *pos, *pos1; - int match; - - list_for_each(pos, source) { - v = list_entry(pos, struct ucm_value, list); - if (check_identifier(identifier, v->name)) { - match = 0; - list_for_each(pos1, list) { - val = list_entry(pos1, struct myvalue, list); - if (strcmp(val->value, v->data) == 0) { - match = 1; - break; - } - } - if (!match) { - val = malloc(sizeof(struct myvalue)); - if (val == NULL) - return -ENOMEM; - val->value = v->data; - list_add_tail(&val->list, list); - } - } - } - return 0; -} - -/** - * \brief Get list of values - * \param list Returned list - * \param verbname For verb (NULL = current) - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_value_list(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char **list[], - char *verbname) -{ - struct list_head mylist, *pos, *npos; - struct myvalue *val; - struct use_case_verb *verb; - struct use_case_device *dev; - struct use_case_modifier *mod; - char **res; - int err; - - if (verbname) { - verb = find_verb(uc_mgr, verbname); - } else { - verb = uc_mgr->active_verb; - } - if (verb == NULL) - return -ENOENT; - INIT_LIST_HEAD(&mylist); - err = add_values(&mylist, identifier, &uc_mgr->value_list); - if (err < 0) - goto __fail; - err = add_values(&mylist, identifier, &verb->value_list); - if (err < 0) - goto __fail; - list_for_each(pos, &verb->device_list) { - dev = list_entry(pos, struct use_case_device, list); - err = add_values(&mylist, identifier, &dev->value_list); - if (err < 0) - goto __fail; - } - list_for_each(pos, &verb->modifier_list) { - mod = list_entry(pos, struct use_case_modifier, list); - err = add_values(&mylist, identifier, &mod->value_list); - if (err < 0) - goto __fail; - } - err = alloc_str_list(&mylist, 1, &res); - if (err >= 0) { - *list = (const char **)res; - list_for_each(pos, &mylist) { - val = list_entry(pos, struct myvalue, list); - *res = strdup(val->value); - if (*res == NULL) { - snd_use_case_free_list((const char **)res, err); - err = -ENOMEM; - goto __fail; - } - res++; - } - } - __fail: - list_for_each_safe(pos, npos, &mylist) { - val = list_entry(pos, struct myvalue, list); - list_del(&val->list); - free(val); - } - return err; -} - -/** - * \brief Get list of enabled devices - * \param list Returned list - * \param verbname For verb (NULL = current) - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr, - const char **list[]) -{ - if (uc_mgr->active_verb == NULL) - return -EINVAL; - return get_list(&uc_mgr->active_devices, list, - struct use_case_device, active_list, - name); -} - -/** - * \brief Get list of enabled modifiers - * \param list Returned list - * \param verbname For verb (NULL = current) - * \return Number of list entries if success, otherwise a negative error code - */ -static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr, - const char **list[]) -{ - if (uc_mgr->active_verb == NULL) - return -EINVAL; - return get_list(&uc_mgr->active_modifiers, list, - struct use_case_modifier, active_list, - name); -} - -/** - * \brief Obtain a list of entries - * \param uc_mgr Use case manager (may be NULL - card list) - * \param identifier (may be NULL - card list) - * \param list Returned allocated list - * \return Number of list entries if success, otherwise a negative error code - */ -int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char **list[]) -{ - char *str, *str1; - int err; - - if (uc_mgr == NULL || identifier == NULL) - return uc_mgr_scan_master_configs(list); - pthread_mutex_lock(&uc_mgr->mutex); - if (strcmp(identifier, "_verbs") == 0) - err = get_verb_list(uc_mgr, list); - else if (strcmp(identifier, "_enadevs") == 0) - err = get_enabled_device_list(uc_mgr, list); - else if (strcmp(identifier, "_enamods") == 0) - err = get_enabled_modifier_list(uc_mgr, list); - else { - str1 = strchr(identifier, '/'); - if (str1) { - str = strdup(str1 + 1); - if (str == NULL) { - err = -ENOMEM; - goto __end; - } - } else { - str = NULL; - } - if (check_identifier(identifier, "_devices")) - err = get_device_list(uc_mgr, list, str); - else if (check_identifier(identifier, "_modifiers")) - err = get_modifier_list(uc_mgr, list, str); - else if (check_identifier(identifier, "_supporteddevs")) - err = get_supported_device_list(uc_mgr, list, str); - else if (check_identifier(identifier, "_conflictingdevs")) - err = get_conflicting_device_list(uc_mgr, list, str); - else if (identifier[0] == '_') - err = -ENOENT; - else - err = get_value_list(uc_mgr, identifier, list, str); - if (str) - free(str); - } - __end: - pthread_mutex_unlock(&uc_mgr->mutex); - return err; -} - -static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, - struct list_head *value_list, const char *identifier) -{ - struct ucm_value *val; - struct list_head *pos; - - if (!value_list) - return -ENOENT; - - list_for_each(pos, value_list) { - val = list_entry(pos, struct ucm_value, list); - if (check_identifier(identifier, val->name)) { - if (uc_mgr->conf_format < 2) { - *value = strdup(val->data); - if (*value == NULL) - return -ENOMEM; - return 0; - } - return uc_mgr_get_substituted_value(uc_mgr, value, val->data); - } - } - return -ENOENT; -} - -static int get_value3(snd_use_case_mgr_t *uc_mgr, - char **value, - const char *identifier, - struct list_head *value_list1, - struct list_head *value_list2, - struct list_head *value_list3) -{ - int err; - - err = get_value1(uc_mgr, value, value_list1, identifier); - if (err >= 0 || err != -ENOENT) - return err; - err = get_value1(uc_mgr, value, value_list2, identifier); - if (err >= 0 || err != -ENOENT) - return err; - err = get_value1(uc_mgr, value, value_list3, identifier); - if (err >= 0 || err != -ENOENT) - return err; - return -ENOENT; -} - -/** - * \brief Get value - * \param uc_mgr Use case manager - * \param identifier Value identifier (string) - * \param value Returned value string - * \param item Modifier or Device name (string) - * \return Zero on success (value is filled), otherwise a negative error code - */ -static int get_value(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - char **value, - const char *mod_dev_name, - const char *verb_name, - int exact) -{ - struct use_case_verb *verb; - struct use_case_modifier *mod; - struct use_case_device *dev; - int err; - - if (mod_dev_name || verb_name || !exact) { - if (verb_name && strlen(verb_name)) { - verb = find_verb(uc_mgr, verb_name); - } else { - verb = uc_mgr->active_verb; - } - if (verb) { - if (mod_dev_name) { - mod = find_modifier(uc_mgr, verb, - mod_dev_name, 0); - if (mod) { - err = get_value1(uc_mgr, value, - &mod->value_list, - identifier); - if (err >= 0 || err != -ENOENT) - return err; - } - - dev = find_device(uc_mgr, verb, - mod_dev_name, 0); - if (dev) { - err = get_value1(uc_mgr, value, - &dev->value_list, - identifier); - if (err >= 0 || err != -ENOENT) - return err; - } - - if (exact) - return -ENOENT; - } - - err = get_value1(uc_mgr, value, &verb->value_list, identifier); - if (err >= 0 || err != -ENOENT) - return err; - } - - if (exact) - return -ENOENT; - } - - err = get_value1(uc_mgr, value, &uc_mgr->value_list, identifier); - if (err >= 0 || err != -ENOENT) - return err; - - return -ENOENT; -} - -/** - * \brief Get current - string - * \param uc_mgr Use case manager - * \param identifier - * \param value Value pointer - * \return Zero if success, otherwise a negative error code - * - * Note: String is dynamically allocated, use free() to - * deallocate this string. - */ -int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char **value) -{ - const char *slash1, *slash2, *mod_dev_after; - const char *ident, *mod_dev, *verb; - int exact = 0; - int err; - - pthread_mutex_lock(&uc_mgr->mutex); - if (identifier == NULL) { - *value = strdup(uc_mgr->card_name); - if (*value == NULL) { - err = -ENOMEM; - goto __end; - } - err = 0; - } else if (strcmp(identifier, "_verb") == 0) { - if (uc_mgr->active_verb == NULL) { - err = -ENOENT; - goto __end; - } - *value = strdup(uc_mgr->active_verb->name); - if (*value == NULL) { - err = -ENOMEM; - goto __end; - } - err = 0; - } else if (strcmp(identifier, "_file") == 0) { - /* get the conf file name of the opened card */ - if ((uc_mgr->card_name == NULL) - || (uc_mgr->conf_file_name[0] == '\0')) { - err = -ENOENT; - goto __end; - } - *value = strndup(uc_mgr->conf_file_name, MAX_FILE); - if (*value == NULL) { - err = -ENOMEM; - goto __end; - } - err = 0; - - } else if (identifier[0] == '_') { - err = -ENOENT; - goto __end; - } else { - if (identifier[0] == '=') { - exact = 1; - identifier++; - } - - slash1 = strchr(identifier, '/'); - if (slash1) { - ident = strndup(identifier, slash1 - identifier); - - slash2 = strchr(slash1 + 1, '/'); - if (slash2) { - mod_dev_after = slash2; - verb = slash2 + 1; - } - else { - mod_dev_after = slash1 + strlen(slash1); - verb = NULL; - } - - if (mod_dev_after == slash1 + 1) - mod_dev = NULL; - else - mod_dev = strndup(slash1 + 1, - mod_dev_after - (slash1 + 1)); - } - else { - ident = identifier; - mod_dev = NULL; - verb = NULL; - } - - err = get_value(uc_mgr, ident, (char **)value, mod_dev, verb, - exact); - if (ident != identifier) - free((void *)ident); - if (mod_dev) - free((void *)mod_dev); - } - __end: - pthread_mutex_unlock(&uc_mgr->mutex); - return err; -} - - -/** - * \brief Get current - integer - * \param uc_mgr Use case manager - * \param identifier - * \return Value if success, otherwise a negative error code - */ -int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - long *value) -{ - char *str, *str1; - long err; - - pthread_mutex_lock(&uc_mgr->mutex); - if (0) { - /* nothing here - prepared for fixed identifiers */ - } else { - str1 = strchr(identifier, '/'); - if (str1) { - str = strdup(str1 + 1); - if (str == NULL) { - err = -ENOMEM; - goto __end; - } - } else { - str = NULL; - } - if (check_identifier(identifier, "_devstatus")) { - if (!str) { - err = -EINVAL; - goto __end; - } - err = device_status(uc_mgr, str); - if (err >= 0) { - *value = err; - err = 0; - } - } else if (check_identifier(identifier, "_modstatus")) { - if (!str) { - err = -EINVAL; - goto __end; - } - err = modifier_status(uc_mgr, str); - if (err >= 0) { - *value = err; - err = 0; - } -#if 0 - /* - * enable this block if the else clause below is expanded to query - * user-supplied values - */ - } else if (identifier[0] == '_') - err = -ENOENT; -#endif - } else - err = -ENOENT; - if (str) - free(str); - } - __end: - pthread_mutex_unlock(&uc_mgr->mutex); - return err; -} - -static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr, - struct use_case_verb *new_verb) -{ - struct list_head *pos; - struct transition_sequence *trans; - int err; - - list_for_each(pos, &uc_mgr->active_verb->transition_list) { - trans = list_entry(pos, struct transition_sequence, list); - if (strcmp(trans->name, new_verb->name) == 0) { - err = execute_sequence(uc_mgr, &trans->transition_list, - &uc_mgr->active_verb->value_list, - &uc_mgr->value_list, - NULL); - if (err >= 0) - return 1; - return err; - } - } - return 0; -} - -static int set_verb_user(snd_use_case_mgr_t *uc_mgr, - const char *verb_name) -{ - struct use_case_verb *verb; - int err = 0; - - if (uc_mgr->active_verb && - strcmp(uc_mgr->active_verb->name, verb_name) == 0) - return 0; - if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) { - verb = find_verb(uc_mgr, verb_name); - if (verb == NULL) - return -ENOENT; - } else { - verb = NULL; - } - if (uc_mgr->active_verb) { - err = handle_transition_verb(uc_mgr, verb); - if (err == 0) { - err = dismantle_use_case(uc_mgr); - if (err < 0) - return err; - } else if (err == 1) { - uc_mgr->active_verb = verb; - verb = NULL; - } else { - verb = NULL; /* show error */ - } - } - if (verb) { - err = set_verb(uc_mgr, verb, 1); - if (err < 0) - uc_error("error: failed to initialize new use case: %s", - verb_name); - } - return err; -} - - -static int set_device_user(snd_use_case_mgr_t *uc_mgr, - const char *device_name, - int enable) -{ - struct use_case_device *device; - - if (uc_mgr->active_verb == NULL) - return -ENOENT; - device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1); - if (device == NULL) - return -ENOENT; - return set_device(uc_mgr, device, enable); -} - -static int set_modifier_user(snd_use_case_mgr_t *uc_mgr, - const char *modifier_name, - int enable) -{ - struct use_case_modifier *modifier; - - if (uc_mgr->active_verb == NULL) - return -ENOENT; - - modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1); - if (modifier == NULL) - return -ENOENT; - return set_modifier(uc_mgr, modifier, enable); -} - -static int switch_device(snd_use_case_mgr_t *uc_mgr, - const char *old_device, - const char *new_device) -{ - struct use_case_device *xold, *xnew; - struct transition_sequence *trans; - struct list_head *pos; - int err, seq_found = 0; - - if (uc_mgr->active_verb == NULL) - return -ENOENT; - if (device_status(uc_mgr, old_device) == 0) { - uc_error("error: device %s not enabled", old_device); - return -EINVAL; - } - if (device_status(uc_mgr, new_device) != 0) { - uc_error("error: device %s already enabled", new_device); - return -EINVAL; - } - xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1); - if (xold == NULL) - return -ENOENT; - list_del(&xold->active_list); - xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1); - list_add_tail(&xold->active_list, &uc_mgr->active_devices); - if (xnew == NULL) - return -ENOENT; - err = 0; - list_for_each(pos, &xold->transition_list) { - trans = list_entry(pos, struct transition_sequence, list); - if (strcmp(trans->name, new_device) == 0) { - err = execute_sequence(uc_mgr, &trans->transition_list, - &xold->value_list, - &uc_mgr->active_verb->value_list, - &uc_mgr->value_list); - if (err >= 0) { - list_del(&xold->active_list); - list_add_tail(&xnew->active_list, &uc_mgr->active_devices); - } - seq_found = 1; - break; - } - } - if (!seq_found) { - err = set_device(uc_mgr, xold, 0); - if (err < 0) - return err; - err = set_device(uc_mgr, xnew, 1); - if (err < 0) - return err; - } - return err; -} - -static int switch_modifier(snd_use_case_mgr_t *uc_mgr, - const char *old_modifier, - const char *new_modifier) -{ - struct use_case_modifier *xold, *xnew; - struct transition_sequence *trans; - struct list_head *pos; - int err, seq_found = 0; - - if (uc_mgr->active_verb == NULL) - return -ENOENT; - if (modifier_status(uc_mgr, old_modifier) == 0) { - uc_error("error: modifier %s not enabled", old_modifier); - return -EINVAL; - } - if (modifier_status(uc_mgr, new_modifier) != 0) { - uc_error("error: modifier %s already enabled", new_modifier); - return -EINVAL; - } - xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1); - if (xold == NULL) - return -ENOENT; - xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1); - if (xnew == NULL) - return -ENOENT; - err = 0; - list_for_each(pos, &xold->transition_list) { - trans = list_entry(pos, struct transition_sequence, list); - if (strcmp(trans->name, new_modifier) == 0) { - err = execute_sequence(uc_mgr, &trans->transition_list, - &xold->value_list, - &uc_mgr->active_verb->value_list, - &uc_mgr->value_list); - if (err >= 0) { - list_del(&xold->active_list); - list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers); - } - seq_found = 1; - break; - } - } - if (!seq_found) { - err = set_modifier(uc_mgr, xold, 0); - if (err < 0) - return err; - err = set_modifier(uc_mgr, xnew, 1); - if (err < 0) - return err; - } - return err; -} - -/** - * \brief Set new - * \param uc_mgr Use case manager - * \param identifier - * \param value Value - * \return Zero if success, otherwise a negative error code - */ -int snd_use_case_set(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char *value) -{ - char *str, *str1; - int err = 0; - - pthread_mutex_lock(&uc_mgr->mutex); - if (strcmp(identifier, "_verb") == 0) - err = set_verb_user(uc_mgr, value); - else if (strcmp(identifier, "_enadev") == 0) - err = set_device_user(uc_mgr, value, 1); - else if (strcmp(identifier, "_disdev") == 0) - err = set_device_user(uc_mgr, value, 0); - else if (strcmp(identifier, "_enamod") == 0) - err = set_modifier_user(uc_mgr, value, 1); - else if (strcmp(identifier, "_dismod") == 0) - err = set_modifier_user(uc_mgr, value, 0); - else { - str1 = strchr(identifier, '/'); - if (str1) { - str = strdup(str1 + 1); - if (str == NULL) { - err = -ENOMEM; - goto __end; - } - } else { - err = -EINVAL; - goto __end; - } - if (check_identifier(identifier, "_swdev")) - err = switch_device(uc_mgr, str, value); - else if (check_identifier(identifier, "_swmod")) - err = switch_modifier(uc_mgr, str, value); - else - err = -EINVAL; - if (str) - free(str); - } - __end: - pthread_mutex_unlock(&uc_mgr->mutex); - return err; -} - -/** - * \brief Parse control element identifier - * \param elem_id Element identifier - * \param ucm_id Use case identifier - * \param value String value to be parsed - * \return Zero if success, otherwise a negative error code - */ -int snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst, - const char *ucm_id, - const char *value) -{ - snd_ctl_elem_iface_t iface; - int jack_control; - - jack_control = strcmp(ucm_id, "JackControl") == 0; - if (!jack_control && - strcmp(ucm_id, "PlaybackVolume") && - strcmp(ucm_id, "PlaybackSwitch") && - strcmp(ucm_id, "CaptureVolume") && - strcmp(ucm_id, "CaptureSwitch")) - return -EINVAL; - snd_ctl_elem_id_clear(dst); - if (strcasestr(ucm_id, "name=")) - return __snd_ctl_ascii_elem_id_parse(dst, value, NULL); - iface = SND_CTL_ELEM_IFACE_MIXER; - if (jack_control) - iface = SND_CTL_ELEM_IFACE_CARD; - snd_ctl_elem_id_set_interface(dst, iface); - snd_ctl_elem_id_set_name(dst, value); - return 0; -} - -/** - * \brief Parse mixer element identifier - * \param dst Simple mixer element identifier - * \param ucm_id Use case identifier - * \param value String value to be parsed - * \return Zero if success, otherwise a negative error code - */ -int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst, - const char *ucm_id, - const char *value) -{ - if (strcmp(ucm_id, "PlaybackMixerId") == 0 || - strcmp(ucm_id, "CaptureMixerId") == 0) - return snd_mixer_selem_id_parse(dst, value); - return -EINVAL; -} diff --git a/src/ucm/ucm_subs.c b/src/ucm/ucm_subs.c index 90e395f..00afa9e 100644 --- a/src/ucm/ucm_subs.c +++ b/src/ucm/ucm_subs.c @@ -25,7 +25,6 @@ */ #include "ucm_local.h" -#include #include #include @@ -146,11 +145,10 @@ static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char return strdup(path); } -#define MATCH_VARIABLE(name, id, fcn, empty_ok) \ +#define MATCH_VARIABLE(name, id, fcn) \ if (strncmp((name), (id), sizeof(id) - 1) == 0) { \ rval = fcn(uc_mgr); \ idsize = sizeof(id) - 1; \ - allow_empty = (empty_ok); \ goto __rval; \ } @@ -191,14 +189,12 @@ int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, while (*value) { if (*value == '$' && *(value+1) == '{') { - bool allow_empty = false; - - MATCH_VARIABLE(value, "${ConfName}", rval_conf_name, false); - MATCH_VARIABLE(value, "${CardId}", rval_card_id, false); - MATCH_VARIABLE(value, "${CardDriver}", rval_card_driver, false); - MATCH_VARIABLE(value, "${CardName}", rval_card_name, false); - MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname, false); - MATCH_VARIABLE(value, "${CardComponents}", rval_card_components, true); + MATCH_VARIABLE(value, "${ConfName}", rval_conf_name); + MATCH_VARIABLE(value, "${CardId}", rval_card_id); + MATCH_VARIABLE(value, "${CardDriver}", rval_card_driver); + MATCH_VARIABLE(value, "${CardName}", rval_card_name); + MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname); + MATCH_VARIABLE(value, "${CardComponents}", rval_card_components); MATCH_VARIABLE2(value, "${env:", rval_env); MATCH_VARIABLE2(value, "${sys:", rval_sysfs); err = -EINVAL; @@ -212,7 +208,7 @@ int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, } goto __error; __rval: - if (rval == NULL || (!allow_empty && rval[0] == '\0')) { + if (rval == NULL || rval[0] == '\0') { free(rval); strncpy(r, value, idsize); r[idsize] = '\0'; diff --git a/src/ucm/ucm_subs.c.alsa-git b/src/ucm/ucm_subs.c.alsa-git deleted file mode 100644 index 00afa9e..0000000 --- a/src/ucm/ucm_subs.c.alsa-git +++ /dev/null @@ -1,248 +0,0 @@ -/* - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Support for the verb/device/modifier core logic and API, - * command line tool and file parser was kindly sponsored by - * Texas Instruments Inc. - * Support for multiple active modifiers and devices, - * transition sequences, multiple client access and user defined use - * cases was kindly sponsored by Wolfson Microelectronics PLC. - * - * Copyright (C) 2019 Red Hat Inc. - * Authors: Jaroslav Kysela - */ - -#include "ucm_local.h" -#include -#include - -static char *rval_conf_name(snd_use_case_mgr_t *uc_mgr) -{ - if (uc_mgr->conf_file_name[0]) - return strdup(uc_mgr->conf_file_name); - return NULL; -} - -static char *rval_card_id(snd_use_case_mgr_t *uc_mgr) -{ - struct ctl_list *ctl_list; - - ctl_list = uc_mgr_get_one_ctl(uc_mgr); - if (ctl_list == NULL) - return NULL; - return strdup(snd_ctl_card_info_get_id(ctl_list->ctl_info)); -} - -static char *rval_card_driver(snd_use_case_mgr_t *uc_mgr) -{ - struct ctl_list *ctl_list; - - ctl_list = uc_mgr_get_one_ctl(uc_mgr); - if (ctl_list == NULL) - return NULL; - return strdup(snd_ctl_card_info_get_driver(ctl_list->ctl_info)); -} - -static char *rval_card_name(snd_use_case_mgr_t *uc_mgr) -{ - struct ctl_list *ctl_list; - - ctl_list = uc_mgr_get_one_ctl(uc_mgr); - if (ctl_list == NULL) - return NULL; - return strdup(snd_ctl_card_info_get_name(ctl_list->ctl_info)); -} - -static char *rval_card_longname(snd_use_case_mgr_t *uc_mgr) -{ - struct ctl_list *ctl_list; - - ctl_list = uc_mgr_get_one_ctl(uc_mgr); - if (ctl_list == NULL) - return NULL; - return strdup(snd_ctl_card_info_get_longname(ctl_list->ctl_info)); -} - -static char *rval_card_components(snd_use_case_mgr_t *uc_mgr) -{ - struct ctl_list *ctl_list; - - ctl_list = uc_mgr_get_one_ctl(uc_mgr); - if (ctl_list == NULL) - return NULL; - return strdup(snd_ctl_card_info_get_components(ctl_list->ctl_info)); -} - -static char *rval_env(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id) -{ - char *e; - - e = getenv(id); - if (e) - return strdup(e); - return NULL; -} - -static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id) -{ - char path[PATH_MAX], link[PATH_MAX + 1]; - struct stat sb; - ssize_t len; - char *e; - int fd; - - e = getenv("SYSFS_PATH"); - if (e == NULL) - e = "/sys"; - if (id[0] == '/') - id++; - snprintf(path, sizeof(path), "%s/%s", e, id); - if (lstat(path, &sb) != 0) - return NULL; - if (S_ISLNK(sb.st_mode)) { - len = readlink(path, link, sizeof(link) - 1); - if (len <= 0) { - uc_error("sysfs: cannot read link '%s' (%d)", path, errno); - return NULL; - } - link[len] = '\0'; - e = strrchr(link, '/'); - if (e) - return strdup(e + 1); - return NULL; - } - if (S_ISDIR(sb.st_mode)) - return NULL; - if ((sb.st_mode & S_IRUSR) == 0) - return NULL; - - fd = open(path, O_RDONLY); - if (fd < 0) { - uc_error("sysfs open failed for '%s' (%d)", path, errno); - return NULL; - } - len = read(fd, path, sizeof(path)-1); - close(fd); - if (len < 0) { - uc_error("sysfs unable to read value '%s' (%d)", path, errno); - return NULL; - } - while (len > 0 && path[len-1] == '\n') - len--; - path[len] = '\0'; - return strdup(path); -} - -#define MATCH_VARIABLE(name, id, fcn) \ - if (strncmp((name), (id), sizeof(id) - 1) == 0) { \ - rval = fcn(uc_mgr); \ - idsize = sizeof(id) - 1; \ - goto __rval; \ - } - -#define MATCH_VARIABLE2(name, id, fcn) \ - if (strncmp((name), (id), sizeof(id) - 1) == 0) { \ - idsize = sizeof(id) - 1; \ - tmp = strchr(value + idsize, '}'); \ - if (tmp) { \ - rvalsize = tmp - (value + idsize); \ - if (rvalsize > sizeof(v2)) { \ - err = -ENOMEM; \ - goto __error; \ - } \ - strncpy(v2, value + idsize, rvalsize); \ - v2[rvalsize] = '\0'; \ - idsize += rvalsize + 1; \ - rval = fcn(uc_mgr, v2); \ - goto __rval; \ - } \ - } - -int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, - char **_rvalue, - const char *value) -{ - size_t size, nsize, idsize, rvalsize, dpos = 0; - const char *tmp; - char *r, *nr, *rval, v2[32]; - int err; - - if (value == NULL) - return -ENOENT; - - size = strlen(value) + 1; - r = malloc(size); - if (r == NULL) - return -ENOMEM; - - while (*value) { - if (*value == '$' && *(value+1) == '{') { - MATCH_VARIABLE(value, "${ConfName}", rval_conf_name); - MATCH_VARIABLE(value, "${CardId}", rval_card_id); - MATCH_VARIABLE(value, "${CardDriver}", rval_card_driver); - MATCH_VARIABLE(value, "${CardName}", rval_card_name); - MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname); - MATCH_VARIABLE(value, "${CardComponents}", rval_card_components); - MATCH_VARIABLE2(value, "${env:", rval_env); - MATCH_VARIABLE2(value, "${sys:", rval_sysfs); - err = -EINVAL; - tmp = strchr(value, '}'); - if (tmp) { - strncpy(r, value, tmp + 1 - value); - r[tmp + 1 - value] = '\0'; - uc_error("variable '%s' is not known!", r); - } else { - uc_error("variable reference '%s' is not complete", value); - } - goto __error; -__rval: - if (rval == NULL || rval[0] == '\0') { - free(rval); - strncpy(r, value, idsize); - r[idsize] = '\0'; - uc_error("variable '%s' is not defined in this context!", r); - err = -EINVAL; - goto __error; - } - value += idsize; - rvalsize = strlen(rval); - nsize = size + rvalsize - idsize; - if (nsize > size) { - nr = realloc(r, nsize); - if (nr == NULL) { - free(rval); - err = -ENOMEM; - goto __error; - } - size = nsize; - r = nr; - } - strcpy(r + dpos, rval); - dpos += rvalsize; - free(rval); - } else { - r[dpos++] = *value; - value++; - } - } - r[dpos] = '\0'; - - *_rvalue = r; - return 0; - -__error: - free(r); - return err; -} diff --git a/utils/alsa.m4 b/utils/alsa.m4 index 320e433..4c457f0 100644 --- a/utils/alsa.m4 +++ b/utils/alsa.m4 @@ -22,7 +22,6 @@ alsa_save_CFLAGS="$CFLAGS" alsa_save_LDFLAGS="$LDFLAGS" alsa_save_LIBS="$LIBS" alsa_found=yes -alsa_topology_found=no dnl dnl Get the cflags and libraries for alsa @@ -159,17 +158,11 @@ AC_CHECK_LIB([asound], [snd_ctl_open],, alsa_found=no] ) if test "x$enable_atopology" = "xyes"; then -alsa_topology_found=yes AC_CHECK_LIB([atopology], [snd_tplg_new],, [ifelse([$3], , [AC_MSG_ERROR(No linkable libatopology was found.)]) - alsa_topology_found=no, -] + alsa_found=no] ) fi -else -if test "x$enable_atopology" = "xyes"; then - alsa_topology_found=yes -fi fi if test "x$alsa_found" = "xyes" ; then @@ -190,7 +183,7 @@ fi dnl add the alsa topology library; must be at the end AC_MSG_CHECKING(for ALSA topology LDFLAGS) -if test "x$alsa_topology_found" = "xyes"; then +if test "x$enable_atopology" = "xyes"; then ALSA_TOPOLOGY_LIBS="$ALSA_TOPOLOGY_LIBS -latopology" fi AC_MSG_RESULT($ALSA_TOPOLOGY_LIBS) diff --git a/utils/alsa.m4.alsa-git b/utils/alsa.m4.alsa-git deleted file mode 100644 index 4c457f0..0000000 --- a/utils/alsa.m4.alsa-git +++ /dev/null @@ -1,195 +0,0 @@ -dnl Configure Paths for Alsa -dnl Some modifications by Richard Boulton -dnl Christopher Lansdown -dnl Jaroslav Kysela -dnl Last modification: $Id: alsa.m4,v 1.24 2004/09/15 18:48:07 tiwai Exp $ -dnl -dnl AM_PATH_ALSA([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) -dnl Test for libasound, and define ALSA_CFLAGS, ALSA_LIBS and -dnl ALSA_TOPOLOGY_LIBS as appropriate. -dnl -dnl enables arguments --with-alsa-prefix= -dnl --with-alsa-inc-prefix= -dnl --disable-alsatest -dnl -dnl For backwards compatibility, if ACTION_IF_NOT_FOUND is not specified, -dnl and the alsa libraries are not found, a fatal AC_MSG_ERROR() will result. -dnl - -AC_DEFUN([AM_PATH_ALSA], -[dnl Save the original CFLAGS, LDFLAGS, and LIBS -alsa_save_CFLAGS="$CFLAGS" -alsa_save_LDFLAGS="$LDFLAGS" -alsa_save_LIBS="$LIBS" -alsa_found=yes - -dnl -dnl Get the cflags and libraries for alsa -dnl -AC_ARG_WITH(alsa-prefix, - AS_HELP_STRING([--with-alsa-prefix=PFX], [Prefix where Alsa library is installed(optional)]), - [alsa_prefix="$withval"], [alsa_prefix=""]) - -AC_ARG_WITH(alsa-inc-prefix, - AS_HELP_STRING([--with-alsa-inc-prefix=PFX], [Prefix where include libraries are (optional)]), - [alsa_inc_prefix="$withval"], [alsa_inc_prefix=""]) - -AC_ARG_ENABLE(alsa-topology, - AS_HELP_STRING([--enable-alsatopology], [Force to use the Alsa topology library]), - [enable_atopology="$enableval"], - [enable_atopology=no]) - -AC_ARG_ENABLE(alsatest, - AS_HELP_STRING([--disable-alsatest], [Do not try to compile and run a test Alsa program]), - [enable_alsatest="$enableval"], - [enable_alsatest=yes]) - -dnl Add any special include directories -AC_MSG_CHECKING(for ALSA CFLAGS) -if test "$alsa_inc_prefix" != "" ; then - ALSA_CFLAGS="$ALSA_CFLAGS -I$alsa_inc_prefix" - CFLAGS="$CFLAGS -I$alsa_inc_prefix" -fi -AC_MSG_RESULT($ALSA_CFLAGS) - -AC_CHECK_LIB(c, dlopen, LIBDL="", [AC_CHECK_LIB(dl, dlopen, LIBDL="-ldl")]) - -dnl add any special lib dirs -AC_MSG_CHECKING(for ALSA LDFLAGS) -if test "$alsa_prefix" != "" ; then - ALSA_LIBS="$ALSA_LIBS -L$alsa_prefix" - LDFLAGS="$LDFLAGS $ALSA_LIBS" -fi - -dnl add the alsa library -ALSA_LIBS="$ALSA_LIBS -lasound -lm $LIBDL -lpthread" -LIBS="$ALSA_LIBS $LIBS" -AC_MSG_RESULT($ALSA_LIBS) - -dnl Check for a working version of libasound that is of the right version. -if test "x$enable_alsatest" = "xyes"; then - -AC_MSG_CHECKING([required libasound headers version]) -min_alsa_version=ifelse([$1], , 0.1.1, $1) -no_alsa="" - alsa_min_major_version=`echo $min_alsa_version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` - alsa_min_minor_version=`echo $min_alsa_version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` - alsa_min_micro_version=`echo $min_alsa_version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` -AC_MSG_RESULT($alsa_min_major_version.$alsa_min_minor_version.$alsa_min_micro_version) - -AC_LANG_SAVE -AC_LANG_C -AC_MSG_CHECKING([for libasound headers version >= $alsa_min_major_version.$alsa_min_minor_version.$alsa_min_micro_version ($min_alsa_version)]) -AC_TRY_COMPILE([ -#include -], [ -/* ensure backward compatibility */ -#if !defined(SND_LIB_MAJOR) && defined(SOUNDLIB_VERSION_MAJOR) -#define SND_LIB_MAJOR SOUNDLIB_VERSION_MAJOR -#endif -#if !defined(SND_LIB_MINOR) && defined(SOUNDLIB_VERSION_MINOR) -#define SND_LIB_MINOR SOUNDLIB_VERSION_MINOR -#endif -#if !defined(SND_LIB_SUBMINOR) && defined(SOUNDLIB_VERSION_SUBMINOR) -#define SND_LIB_SUBMINOR SOUNDLIB_VERSION_SUBMINOR -#endif - -# if(SND_LIB_MAJOR > $alsa_min_major_version) - exit(0); -# else -# if(SND_LIB_MAJOR < $alsa_min_major_version) -# error not present -# endif - -# if(SND_LIB_MINOR > $alsa_min_minor_version) - exit(0); -# else -# if(SND_LIB_MINOR < $alsa_min_minor_version) -# error not present -# endif - -# if(SND_LIB_SUBMINOR < $alsa_min_micro_version) -# error not present -# endif -# endif -# endif -exit(0); -], - [AC_MSG_RESULT(found.)], - [AC_MSG_RESULT(not present.) - ifelse([$3], , [AC_MSG_ERROR(Sufficiently new version of libasound not found.)]) - alsa_found=no] -) -AC_LANG_RESTORE - -AC_LANG_SAVE -AC_LANG_C -AC_MSG_CHECKING([for libatopology (sound headers version > 1.1.9)]) -AC_TRY_COMPILE([ -#include -#include -], [ -/* ensure backward compatibility */ -#if !defined(SND_LIB_VERSION) -#define SND_LIB_VERSION 0 -#endif -#if SND_LIB_VERSION > 0x00010109 - exit(0); -#else -# error not present -#endif -exit(0); -], - [AC_MSG_RESULT(yes) - enable_atopology="yes"], - [AC_MSG_RESULT(no)] -) -AC_LANG_RESTORE - -fi - -dnl Now that we know that we have the right version, let's see if we have the library and not just the headers. -if test "x$enable_alsatest" = "xyes"; then -AC_CHECK_LIB([asound], [snd_ctl_open],, - [ifelse([$3], , [AC_MSG_ERROR(No linkable libasound was found.)]) - alsa_found=no] -) -if test "x$enable_atopology" = "xyes"; then -AC_CHECK_LIB([atopology], [snd_tplg_new],, - [ifelse([$3], , [AC_MSG_ERROR(No linkable libatopology was found.)]) - alsa_found=no] -) -fi -fi - -if test "x$alsa_found" = "xyes" ; then - ifelse([$2], , :, [$2]) - LIBS=`echo $LIBS | sed 's/-lasound//g'` - LIBS=`echo $LIBS | sed 's/ //'` - LIBS="-lasound $LIBS" -fi -if test "x$alsa_found" = "xno" ; then - ifelse([$3], , :, [$3]) - CFLAGS="$alsa_save_CFLAGS" - LDFLAGS="$alsa_save_LDFLAGS" - LIBS="$alsa_save_LIBS" - ALSA_CFLAGS="" - ALSA_LIBS="" - ALSA_TOPOLOGY_LIBS="" -fi - -dnl add the alsa topology library; must be at the end -AC_MSG_CHECKING(for ALSA topology LDFLAGS) -if test "x$enable_atopology" = "xyes"; then - ALSA_TOPOLOGY_LIBS="$ALSA_TOPOLOGY_LIBS -latopology" -fi -AC_MSG_RESULT($ALSA_TOPOLOGY_LIBS) - -dnl That should be it. Now just export out symbols: -AC_SUBST(ALSA_CFLAGS) -AC_SUBST(ALSA_LIBS) -AC_SUBST(ALSA_TOPOLOGY_LIBS) -])