#include <netinet/in.h>
#include <netdb.h>
#include <limits.h>
+#include <signal.h>
#include "aserver.h"
-#include "list.h"
char *command;
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;
struct {
snd_ctl_t *handle;
int fd;
- } control;
+ } ctl;
#if 0
struct {
snd_rawmidi_t *handle;
return 0;
}
+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;
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);
err = snd_ctl_open(&ctl, client->name, SND_CTL_NONBLOCK);
if (err < 0)
return err;
- client->device.control.handle = ctl;
- client->device.control.fd = _snd_ctl_poll_descriptor(ctl);
+ 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) {
goto _err;
}
*cookie = shmid;
- add_waiter(client->device.control.fd, POLLIN, ctl_handler, client);
+ add_waiter(client->device.ctl.fd, POLLIN, ctl_handler, client);
client->polling = 1;
return 0;
int err;
snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
if (client->polling) {
- del_waiter(client->device.control.fd);
+ del_waiter(client->device.ctl.fd);
client->polling = 0;
}
- err = snd_ctl_close(client->device.control.handle);
+ err = snd_ctl_close(client->device.ctl.handle);
ctrl->result = err;
if (err < 0)
ERROR("snd_ctl_close");
return -EBADFD;
cmd = ctrl->cmd;
ctrl->cmd = 0;
- ctl = client->device.control.handle;
+ 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);
int snd_ctl_open(snd_ctl_t **ctl, const char *name, int mode);
int snd_ctl_close(snd_ctl_t *ctl);
int snd_ctl_nonblock(snd_ctl_t *ctl, int nonblock);
-int snd_ctl_async(snd_ctl_t *ctl, int sig, pid_t pid);
+int snd_async_add_ctl_handler(snd_async_handler_t **handler, snd_ctl_t *ctl,
+ snd_async_callback_t callback, void *private_data);
+snd_ctl_t *snd_async_handler_get_ctl(snd_async_handler_t *handler);
int snd_ctl_poll_descriptors_count(snd_ctl_t *ctl);
int snd_ctl_poll_descriptors(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int space);
int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe);
int snd_hctl_open(snd_hctl_t **hctl, const char *name, int mode);
int snd_hctl_close(snd_hctl_t *hctl);
int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock);
-int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid);
int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl);
int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space);
unsigned int snd_hctl_get_count(snd_hctl_t *hctl);
/** \} */
+/** Async notification client handler */
+typedef struct _snd_async_handler snd_async_handler_t;
+
+/** Async notification callback */
+typedef void (*snd_async_callback_t)(snd_async_handler_t *handler);
+
+int snd_async_add_handler(snd_async_handler_t **handler, int fd,
+ snd_async_callback_t callback, void *private_data);
+int snd_async_del_handler(snd_async_handler_t *handler);
+int snd_async_handler_get_fd(snd_async_handler_t *handler);
+void *snd_async_handler_get_callback_private(snd_async_handler_t *handler);
#define _snd_hwdep_info sndrv_hwdep_info
#include "asoundlib.h"
+#include "list.h"
+
+struct _snd_async_handler {
+ enum {
+ SND_ASYNC_HANDLER_GENERIC,
+ SND_ASYNC_HANDLER_PCM,
+ SND_ASYNC_HANDLER_CTL,
+ } type;
+ int fd;
+ union {
+ snd_pcm_t *pcm;
+ snd_ctl_t *ctl;
+ } u;
+ snd_async_callback_t callback;
+ void *private_data;
+ struct list_head glist;
+ struct list_head hlist;
+};
typedef enum _snd_set_mode {
SND_CHANGE,
int snd_pcm_poll_descriptors_count(snd_pcm_t *pcm);
int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock);
-int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid);
+int snd_async_add_pcm_handler(snd_async_handler_t **handler, snd_pcm_t *pcm,
+ snd_async_callback_t callback, void *private_data);
+snd_pcm_t *snd_async_handler_get_pcm(snd_async_handler_t *handler);
int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info);
int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int snd_pcm_hw_free(snd_pcm_t *pcm);
COMPATNUM=@LIBTOOL_VERSION_INFO@
lib_LTLIBRARIES = libasound.la
-libasound_la_SOURCES = conf.c confmisc.c input.c output.c error.c
+libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c
libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
rawmidi/librawmidi.la timer/libtimer.la \
hwdep/libhwdep.la seq/libseq.la instr/libinstr.la \
--- /dev/null
+/*
+ * Async notification helpers
+ * Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "pcm/pcm_local.h"
+#include "control/control_local.h"
+#include <signal.h>
+
+static struct list_head snd_async_handlers;
+
+static void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED)
+{
+ int fd;
+ struct list_head *i;
+ assert(siginfo->si_code = SI_SIGIO);
+ fd = siginfo->si_fd;
+ list_for_each(i, &snd_async_handlers) {
+ snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist);
+ if (h->fd == fd) {
+ h->callback(h);
+ // break;
+ }
+ }
+}
+
+int snd_async_add_handler(snd_async_handler_t **handler, int fd,
+ snd_async_callback_t callback, void *private_data)
+{
+ snd_async_handler_t *h;
+ int was_empty;
+ h = malloc(sizeof(*h));
+ if (!h)
+ return -ENOMEM;
+ h->fd = fd;
+ h->callback = callback;
+ h->private_data = private_data;
+ was_empty = list_empty(&snd_async_handlers);
+ list_add_tail(&h->glist, &snd_async_handlers);
+ *handler = h;
+ if (was_empty) {
+ int err;
+ struct sigaction act;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ act.sa_sigaction = snd_async_handler;
+ sigemptyset(&act.sa_mask);
+ err = sigaction(SIGIO, &act, NULL);
+ if (err < 0) {
+ SYSERR("sigaction");
+ return -errno;
+ }
+ }
+ return 0;
+}
+
+int snd_async_del_handler(snd_async_handler_t *handler)
+{
+ int err = 0;
+ list_del(&handler->glist);
+ if (list_empty(&snd_async_handlers)) {
+ struct sigaction act;
+ act.sa_flags = 0;
+ act.sa_handler = SIG_DFL;
+ err = sigaction(SIGIO, &act, NULL);
+ if (err < 0) {
+ SYSERR("sigaction");
+ return -errno;
+ }
+ }
+ if (handler->type == SND_ASYNC_HANDLER_GENERIC)
+ goto _end;
+ list_del(&handler->hlist);
+ if (!list_empty(&handler->hlist))
+ goto _end;
+ switch (handler->type) {
+ case SND_ASYNC_HANDLER_PCM:
+ err = snd_pcm_async(handler->u.pcm, -1, 1);
+ break;
+ case SND_ASYNC_HANDLER_CTL:
+ err = snd_ctl_async(handler->u.ctl, -1, 1);
+ break;
+ default:
+ assert(0);
+ }
+ _end:
+ free(handler);
+ return err;
+}
+
+int snd_async_handler_get_fd(snd_async_handler_t *handler)
+{
+ return handler->fd;
+}
+
+void *snd_async_handler_get_callback_private(snd_async_handler_t *handler)
+{
+ return handler->private_data;
+}
+
#include <sys/stat.h>
#include <dlfcn.h>
#include "local.h"
-#include "list.h"
#ifndef DOC_HIDDEN
*/
int snd_ctl_close(snd_ctl_t *ctl)
{
- int res;
- res = ctl->ops->close(ctl);
+ int err;
+ while (!list_empty(&ctl->async_handlers)) {
+ snd_async_handler_t *h = list_entry(&ctl->async_handlers.next, snd_async_handler_t, hlist);
+ snd_async_del_handler(h);
+ }
+ err = ctl->ops->close(ctl);
if (ctl->name)
free(ctl->name);
free(ctl);
- return res;
+ return err;
}
/**
return 0;
}
+#ifndef DOC_HIDDEN
+int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name)
+{
+ snd_ctl_t *ctl;
+ ctl = calloc(1, sizeof(*ctl));
+ if (!ctl)
+ return -ENOMEM;
+ ctl->type = type;
+ if (name)
+ ctl->name = strdup(name);
+ INIT_LIST_HEAD(&ctl->async_handlers);
+ *ctlp = ctl;
+ return 0;
+}
+
+
/**
* \brief set async mode
* \param ctl CTL handle
*/
int snd_ctl_async(snd_ctl_t *ctl, int sig, pid_t pid)
{
- int err;
assert(ctl);
- err = ctl->ops->async(ctl, sig, pid);
- if (err < 0)
- return err;
- if (sig)
- ctl->async_sig = sig;
- else
- ctl->async_sig = SIGIO;
- if (pid)
- ctl->async_pid = pid;
- else
- ctl->async_pid = getpid();
- return 0;
+ return ctl->ops->async(ctl, sig, pid);
}
+#endif
/**
* \brief get count of poll descriptors for CTL handle
{
assert(ctl);
if (space > 0) {
- pfds->fd = ctl->ops->poll_descriptor(ctl);
+ pfds->fd = ctl->poll_fd;
pfds->events = POLLIN;
return 1;
}
return 0;
}
+/**
+ * \brief Add an async handler for a CTL
+ * \param handler Returned handler handle
+ * \param ctl CTL handle
+ * \param callback Callback function
+ * \param private_data Callback private data
+ * \return 0 otherwise a negative error code on failure
+ */
+int snd_async_add_ctl_handler(snd_async_handler_t **handler, snd_ctl_t *ctl,
+ snd_async_callback_t callback, void *private_data)
+{
+ int err;
+ int was_empty;
+ snd_async_handler_t *h;
+ err = snd_async_add_handler(&h, _snd_ctl_async_descriptor(ctl),
+ callback, private_data);
+ if (err < 0)
+ return err;
+ h->type = SND_ASYNC_HANDLER_CTL;
+ h->u.ctl = ctl;
+ was_empty = list_empty(&ctl->async_handlers);
+ list_add_tail(&h->hlist, &ctl->async_handlers);
+ if (was_empty) {
+ err = snd_ctl_async(ctl, getpid(), SIGIO);
+ if (err < 0) {
+ snd_async_del_handler(h);
+ return err;
+ }
+ }
+ *handler = h;
+ return 0;
+}
+
+/**
+ * \brief Return CTL handle related to an async handler
+ * \param handler Async handler handle
+ * \return CTL handle
+ */
+snd_ctl_t *snd_async_handler_get_ctl(snd_async_handler_t *handler)
+{
+ assert(handler->type = SND_ASYNC_HANDLER_CTL);
+ return handler->u.ctl;
+}
+
int snd_ctl_open_conf(snd_ctl_t **ctlp, const char *name,
snd_config_t *ctl_root, snd_config_t *ctl_conf, int mode)
{
int _snd_ctl_poll_descriptor(snd_ctl_t *ctl)
{
assert(ctl);
- return ctl->ops->poll_descriptor(ctl);
+ return ctl->poll_fd;
}
#endif
return 0;
}
-static int snd_ctl_hw_poll_descriptor(snd_ctl_t *handle)
-{
- snd_ctl_hw_t *hw = handle->private_data;
- return hw->fd;
-}
-
static int snd_ctl_hw_subscribe_events(snd_ctl_t *handle, int subscribe)
{
snd_ctl_hw_t *hw = handle->private_data;
close: snd_ctl_hw_close,
nonblock: snd_ctl_hw_nonblock,
async: snd_ctl_hw_async,
- poll_descriptor: snd_ctl_hw_poll_descriptor,
subscribe_events: snd_ctl_hw_subscribe_events,
card_info: snd_ctl_hw_card_info,
element_list: snd_ctl_hw_elem_list,
int fmode;
snd_ctl_t *ctl;
snd_ctl_hw_t *hw;
+ int err;
*handle = NULL;
close(fd);
return -SND_ERROR_INCOMPATIBLE_VERSION;
}
- ctl = calloc(1, sizeof(snd_ctl_t));
- if (ctl == NULL) {
- close(fd);
- return -ENOMEM;
- }
hw = calloc(1, sizeof(snd_ctl_hw_t));
if (hw == NULL) {
close(fd);
- free(ctl);
return -ENOMEM;
}
hw->card = card;
hw->fd = fd;
- if (name)
- ctl->name = strdup(name);
- ctl->type = SND_CTL_TYPE_HW;
+
+ err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name);
+ if (err < 0) {
+ close(fd);
+ free(hw);
+ }
ctl->ops = &snd_ctl_hw_ops;
ctl->private_data = hw;
+ ctl->poll_fd = fd;
*handle = ctl;
return 0;
}
*/
#include "local.h"
-#include "list.h"
typedef struct _snd_ctl_ops {
int (*close)(snd_ctl_t *handle);
int (*nonblock)(snd_ctl_t *handle, int nonblock);
int (*async)(snd_ctl_t *handle, int sig, pid_t pid);
- int (*poll_descriptor)(snd_ctl_t *handle);
int (*subscribe_events)(snd_ctl_t *handle, int subscribe);
int (*card_info)(snd_ctl_t *handle, snd_ctl_card_info_t *info);
int (*element_list)(snd_ctl_t *handle, snd_ctl_elem_list_t *list);
snd_ctl_ops_t *ops;
void *private_data;
int nonblock;
- int async_sig;
- pid_t async_pid;
+ int poll_fd;
+ struct list_head async_handlers;
};
struct _snd_hctl_elem {
};
+int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name);
int _snd_ctl_poll_descriptor(snd_ctl_t *ctl);
+#define _snd_ctl_async_descriptor _snd_ctl_poll_descriptor
int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode);
int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname, const char *sname, int mode);
+int snd_ctl_async(snd_ctl_t *ctl, int sig, pid_t pid);
{
snd_ctl_shm_t *shm = ctl->private_data;
volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
- ctrl->cmd = SND_CTL_IOCTL_POLL_DESCRIPTOR;
+ ctrl->cmd = SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS;
ctrl->u.subscribe_events = subscribe;
return snd_ctl_shm_action(ctl);
}
close: snd_ctl_shm_close,
nonblock: snd_ctl_shm_nonblock,
async: snd_ctl_shm_async,
- poll_descriptor: snd_ctl_shm_poll_descriptor,
subscribe_events: snd_ctl_shm_subscribe_events,
card_info: snd_ctl_shm_card_info,
element_list: snd_ctl_shm_elem_list,
goto _err;
}
- ctl = calloc(1, sizeof(snd_ctl_t));
- if (!ctl) {
- result = -ENOMEM;
- goto _err;
- }
shm = calloc(1, sizeof(snd_ctl_shm_t));
if (!shm) {
- free(ctl);
result = -ENOMEM;
goto _err;
}
shm->socket = sock;
shm->ctrl = ctrl;
- if (name)
- ctl->name = strdup(name);
- ctl->type = SND_CTL_TYPE_SHM;
+ err = snd_ctl_new(&ctl, SND_CTL_TYPE_SHM, name);
+ if (err < 0) {
+ result = err;
+ goto _err;
+ }
ctl->ops = &snd_ctl_shm_ops;
ctl->private_data = shm;
+ err = snd_ctl_shm_poll_descriptor(ctl);
+ if (err < 0) {
+ snd_ctl_close(ctl);
+ return err;
+ }
+ ctl->poll_fd = err;
*handlep = ctl;
return 0;
#include <unistd.h>
#include <string.h>
#include <ctype.h>
-#include "list.h"
#include "local.h"
typedef struct {
*
*/
-#include "list.h"
#include "local.h"
typedef struct _bag1 {
noinst_HEADERS = atomic.h pcm_local.h pcm_plugin.h mask.h mask_inline.h \
interval.h interval_inline.h plugin_ops.h
-EXTRA_DIST = surround.conf
-
alsadir = $(datadir)/alsa
alsa_DATA = surround.conf
#include <limits.h>
#include <dlfcn.h>
#include "pcm_local.h"
-#include "list.h"
/**
* \brief get identifier of PCM handle
if (err < 0)
return err;
}
+ while (!list_empty(&pcm->async_handlers)) {
+ snd_async_handler_t *h = list_entry(&pcm->async_handlers.next, snd_async_handler_t, hlist);
+ snd_async_del_handler(h);
+ }
err = pcm->ops->close(pcm->op_arg);
if (err < 0)
return err;
return 0;
}
+#ifndef DOC_HIDDEN
/**
* \brief set async mode
* \param pcm PCM handle
*/
int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid)
{
- int err;
assert(pcm);
- err = pcm->ops->async(pcm->op_arg, sig, pid);
- if (err < 0)
- return err;
- if (sig)
- pcm->async_sig = sig;
- else
- pcm->async_sig = SIGIO;
- if (pid)
- pcm->async_pid = pid;
- else
- pcm->async_pid = getpid();
- return 0;
+ if (sig == 0)
+ sig = SIGIO;
+ if (pid == 0)
+ pid = getpid();
+ return pcm->ops->async(pcm->op_arg, sig, pid);
}
+#endif
/**
* \brief Obtain general (static) information for PCM handle
return samples * pcm->sample_bits / 8;
}
+/**
+ * \brief Add an async handler for a PCM
+ * \param handler Returned handler handle
+ * \param pcm PCM handle
+ * \param callback Callback function
+ * \param private_data Callback private data
+ * \return 0 otherwise a negative error code on failure
+ */
+int snd_async_add_pcm_handler(snd_async_handler_t **handler, snd_pcm_t *pcm,
+ snd_async_callback_t callback, void *private_data)
+{
+ int err;
+ int was_empty;
+ snd_async_handler_t *h;
+ err = snd_async_add_handler(&h, _snd_pcm_async_descriptor(pcm),
+ callback, private_data);
+ if (err < 0)
+ return err;
+ h->type = SND_ASYNC_HANDLER_PCM;
+ h->u.pcm = pcm;
+ was_empty = list_empty(&pcm->async_handlers);
+ list_add_tail(&h->hlist, &pcm->async_handlers);
+ if (was_empty) {
+ err = snd_pcm_async(pcm, getpid(), SIGIO);
+ if (err < 0) {
+ snd_async_del_handler(h);
+ return err;
+ }
+ }
+ *handler = h;
+ return 0;
+}
+
+/**
+ * \brief Return PCM handle related to an async handler
+ * \param handler Async handler handle
+ * \return PCM handle
+ */
+snd_pcm_t *snd_async_handler_get_pcm(snd_async_handler_t *handler)
+{
+ assert(handler->type = SND_ASYNC_HANDLER_PCM);
+ return handler->u.pcm;
+}
+
static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
snd_config_t *pcm_root, snd_config_t *pcm_conf,
snd_pcm_stream_t stream, int mode)
}
#ifndef DOC_HIDDEN
+
+int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name,
+ snd_pcm_stream_t stream, int mode)
+{
+ snd_pcm_t *pcm;
+ pcm = calloc(1, sizeof(*pcm));
+ if (!pcm)
+ return -ENOMEM;
+ pcm->type = type;
+ if (name)
+ pcm->name = strdup(name);
+ pcm->stream = stream;
+ pcm->mode = mode;
+ pcm->op_arg = pcm;
+ pcm->fast_op_arg = pcm;
+ INIT_LIST_HEAD(&pcm->async_handlers);
+ *pcmp = pcm;
+ return 0;
+}
+
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
snd_config_t *conf, snd_pcm_stream_t stream,
int mode)
{
snd_pcm_t *pcm;
snd_pcm_adpcm_t *adpcm;
+ int err;
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1 &&
sformat != SND_PCM_FORMAT_IMA_ADPCM)
adpcm->plug.slave = slave;
adpcm->plug.close_slave = close_slave;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_ADPCM, name, slave->stream, slave->mode);
+ if (err < 0) {
free(adpcm);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_ADPCM;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_adpcm_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = adpcm;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &adpcm->plug.hw_ptr;
{
snd_pcm_t *pcm;
snd_pcm_alaw_t *alaw;
+ int err;
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1 &&
sformat != SND_PCM_FORMAT_A_LAW)
alaw->plug.slave = slave;
alaw->plug.close_slave = close_slave;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_ALAW, name, slave->stream, slave->mode);
+ if (err < 0) {
free(alaw);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_ALAW;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_alaw_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = alaw;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &alaw->plug.hw_ptr;
{
snd_pcm_t *pcm;
snd_pcm_copy_t *copy;
+ int err;
assert(pcmp && slave);
copy = calloc(1, sizeof(snd_pcm_copy_t));
if (!copy) {
copy->plug.slave = slave;
copy->plug.close_slave = close_slave;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_COPY, name, slave->stream, slave->mode);
+ if (err < 0) {
free(copy);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_COPY;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_copy_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = copy;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = ©->plug.hw_ptr;
snd_pcm_t *pcm;
snd_pcm_file_t *file;
snd_pcm_file_format_t format;
+ int err;
assert(pcmp);
if (fmt == NULL ||
strcmp(fmt, "raw") == 0)
file->slave = slave;
file->close_slave = close_slave;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_FILE, name, slave->stream, slave->mode);
+ if (err < 0) {
if (fname)
free(file->fname);
free(file);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_FILE;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_file_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_file_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = file;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
snd_pcm_t *pcm;
snd_pcm_hooks_t *h;
unsigned int k;
+ int err;
assert(pcmp && slave);
h = calloc(1, sizeof(snd_pcm_hooks_t));
if (!h)
for (k = 0; k <= SND_PCM_HOOK_TYPE_LAST; ++k) {
INIT_LIST_HEAD(&h->hooks[k]);
}
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_HOOKS, name, slave->stream, slave->mode);
+ if (err < 0) {
free(h);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_HOOKS;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_hooks_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_hooks_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = h;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
}
if (sig < 0)
return 0;
- if (sig == 0)
- sig = SIGIO;
if (fcntl(fd, F_SETSIG, sig) < 0) {
SYSERR("F_SETSIG failed");
return -errno;
}
- if (pid == 0)
- pid = getpid();
if (fcntl(fd, F_SETOWN, pid) < 0) {
SYSERR("F_SETOWN failed");
return -errno;
mmap_commit: snd_pcm_hw_mmap_commit,
};
-static int snd_pcm_hw_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, snd_pcm_stream_t stream, int mode)
+int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, int card, int device, int subdevice, snd_pcm_stream_t stream, int mode)
{
char filename[32];
const char *filefmt;
int ver;
- int ret = 0, fd = -1;
+ int err, ret = 0, fd = -1;
int attempt = 0;
snd_pcm_info_t info;
int fmode;
hw->subdevice = subdevice;
hw->fd = fd;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
- ret = -ENOMEM;
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, stream, mode);
+ if (err < 0) {
+ ret = err;
goto _err;
}
snd_ctl_close(ctl);
- pcm->type = SND_PCM_TYPE_HW;
- pcm->stream = stream;
- pcm->mode = mode;
pcm->ops = &snd_pcm_hw_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_hw_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = hw;
pcm->poll_fd = fd;
*pcmp = pcm;
return ret;
}
-int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, int card, int device, int subdevice, snd_pcm_stream_t stream, int mode)
-{
- int err = snd_pcm_hw_open_subdevice(pcmp, card, device, subdevice, stream, mode);
- if (err < 0)
- return err;
- if (name)
- (*pcmp)->name = strdup(name);
- return 0;
-}
-
int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
snd_pcm_stream_t stream, int mode)
{
snd_pcm_t *pcm;
snd_pcm_linear_t *linear;
+ int err;
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1)
return -EINVAL;
linear->plug.slave = slave;
linear->plug.close_slave = close_slave;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_LINEAR, name, slave->stream, slave->mode);
+ if (err < 0) {
free(linear);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_LINEAR;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_linear_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = linear;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &linear->plug.hw_ptr;
#define _snd_pcm_subformat_mask _snd_mask
#include "local.h"
-#include "list.h"
#define SND_INTERVAL_INLINE
#include "interval.h"
#define SND_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_LAST_INTERVAL
#define SND_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_FIRST_INTERVAL
-/** Surround type */
-typedef enum _snd_pcm_surround_type {
- /** 4.0 speakers */
- SND_PCM_SURROUND_40 = 0,
- /** 5.1 speakers */
- SND_PCM_SURROUND_51 = 1,
- SND_PCM_SURROUND_LAST = SND_PCM_SURROUND_51
-} snd_pcm_surround_type_t;
-
typedef struct _snd_pcm_channel_info {
unsigned int channel;
void *addr; /* base address of channel samples */
snd_pcm_uframes_t silence_size; /* Silence filling size */
snd_pcm_uframes_t xfer_align; /* xfer size need to be a multiple */
snd_pcm_uframes_t boundary; /* pointers wrap point */
- int async_sig;
- pid_t async_pid;
unsigned int info; /* Info for returned setup */
unsigned int msbits; /* used most significant bits */
unsigned int rate_num; /* rate numerator */
snd_pcm_t *op_arg;
snd_pcm_t *fast_op_arg;
void *private_data;
+ struct list_head async_handlers;
};
#define ROUTE_PLUGIN_FLOAT 1
/* FIXME */
#define _snd_pcm_link_descriptor _snd_pcm_poll_descriptor
+#define _snd_pcm_async_descriptor _snd_pcm_poll_descriptor
+int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name,
+ snd_pcm_stream_t stream, int mode);
int snd_pcm_hw_open(snd_pcm_t **pcm, const char *name, int card, int device, int subdevice, snd_pcm_stream_t stream, int mode);
int snd_pcm_plug_open(snd_pcm_t **pcmp,
const char *name,
int snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name, const char *sockname, const char *sname, snd_pcm_stream_t stream, int mode);
int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, const char *fname, int fd, const char *fmt, snd_pcm_t *slave, int close_slave);
int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode);
-int snd_pcm_surround_open(snd_pcm_t **pcmp, const char *name, int card, int device, snd_pcm_surround_type_t type, snd_pcm_stream_t stream, int mode);
-
void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf);
void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs);
+int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid);
int snd_pcm_mmap(snd_pcm_t *pcm);
int snd_pcm_munmap(snd_pcm_t *pcm);
int snd_pcm_mmap_ready(snd_pcm_t *pcm);
#include <time.h>
#include <pthread.h>
#include <dlfcn.h>
-#include "list.h"
#include "pcm_local.h"
#include "pcm_plugin.h"
{
snd_pcm_t *pcm;
snd_pcm_meter_t *meter;
+ int err;
assert(pcmp);
meter = calloc(1, sizeof(snd_pcm_meter_t));
if (!meter)
meter->delay.tv_nsec = 1000000000 / frequency;
INIT_LIST_HEAD(&meter->scopes);
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_METER, name, slave->stream, slave->mode);
+ if (err < 0) {
free(meter);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_METER;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->mmap_rw = 1;
pcm->ops = &snd_pcm_meter_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_meter_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = meter;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
{
snd_pcm_t *pcm;
snd_pcm_mulaw_t *mulaw;
+ int err;
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1 &&
sformat != SND_PCM_FORMAT_MU_LAW)
mulaw->plug.slave = slave;
mulaw->plug.close_slave = close_slave;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_MULAW, name, slave->stream, slave->mode);
+ if (err < 0) {
free(mulaw);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_MULAW;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_mulaw_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = mulaw;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &mulaw->plug.hw_ptr;
unsigned int i;
snd_pcm_stream_t stream;
char slave_map[32][32] = { { 0 } };
+ int err;
assert(pcmp);
assert(slaves_count > 0 && slaves_pcm && schannels_count);
}
multi->channels_count = channels_count;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_MULTI, name, stream,
+ multi->slaves[0].pcm->mode);
+ if (err < 0) {
free(multi);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_MULTI;
- pcm->stream = stream;
- pcm->mode = multi->slaves[0].pcm->mode;
pcm->mmap_rw = 1;
pcm->ops = &snd_pcm_multi_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_multi_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = multi;
pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd;
pcm->hw_ptr = multi->slaves[master_slave].pcm->hw_ptr;
snd_pcm_t *pcm;
snd_pcm_null_t *null;
int fd;
+ int err;
assert(pcmp);
if (stream == SND_PCM_STREAM_PLAYBACK) {
fd = open("/dev/null", O_WRONLY);
null->poll_fd = fd;
null->state = SND_PCM_STATE_OPEN;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_NULL, name, stream, mode);
+ if (err < 0) {
close(fd);
free(null);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_NULL;
- pcm->stream = stream;
- pcm->mode = mode;
pcm->ops = &snd_pcm_null_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_null_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = null;
pcm->poll_fd = fd;
pcm->hw_ptr = &null->hw_ptr;
{
snd_pcm_t *pcm;
snd_pcm_plug_t *plug;
+ int err;
assert(pcmp && slave);
plug = calloc(1, sizeof(snd_pcm_plug_t));
if (!plug)
plug->tt_cused = tt_cused;
plug->tt_sused = tt_sused;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_PLUG, name, slave->stream, slave->mode);
+ if (err < 0) {
free(plug);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_PLUG;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_plug_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = slave->fast_ops;
pcm->fast_op_arg = slave->fast_op_arg;
pcm->private_data = plug;
{
snd_pcm_t *pcm;
snd_pcm_rate_t *rate;
+ int err;
assert(pcmp && slave);
if (sformat != SND_PCM_FORMAT_UNKNOWN &&
snd_pcm_format_linear(sformat) != 1)
rate->plug.slave = slave;
rate->plug.close_slave = close_slave;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_RATE, name, slave->stream, slave->mode);
+ if (err < 0) {
free(rate);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_RATE;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_rate_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = rate;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &rate->plug.hw_ptr;
route->plug.slave = slave;
route->plug.close_slave = close_slave;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_ROUTE, name, slave->stream, slave->mode);
+ if (err < 0) {
free(route);
- return -ENOMEM;
+ return err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_ROUTE;
- pcm->stream = slave->stream;
- pcm->mode = slave->mode;
pcm->ops = &snd_pcm_route_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = route;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = &route->plug.hw_ptr;
#include <sys/shm.h>
#include <pthread.h>
#include "pcm_local.h"
-#include "list.h"
static LIST_HEAD(snd_pcm_share_slaves);
}
memcpy(share->slave_channels, channels_map, channels * sizeof(*share->slave_channels));
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_SHARE, name, stream, mode);
+ if (err < 0) {
free(share->slave_channels);
free(share);
- return -ENOMEM;
+ return err;
}
err = socketpair(AF_LOCAL, SOCK_STREAM, 0, sd);
if (err < 0) {
share->client_socket = sd[0];
share->slave_socket = sd[1];
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_SHARE;
- pcm->stream = stream;
- pcm->mode = mode;
pcm->mmap_rw = 1;
pcm->ops = &snd_pcm_share_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_share_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = share;
pcm->poll_fd = share->client_socket;
pcm->hw_ptr = &share->hw_ptr;
return -EINVAL;
}
err = snd_pcm_slave_conf(root, slave, &sconf, 5,
- SND_PCM_HW_PARAM_CHANNELS, 0, &schannels,
SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
+ SND_PCM_HW_PARAM_CHANNELS, 0, &schannels,
SND_PCM_HW_PARAM_RATE, 0, &srate,
SND_PCM_HW_PARAM_PERIOD_TIME, 0, &speriod_time,
SND_PCM_HW_PARAM_BUFFER_TIME, 0, &sbuffer_time);
/* FIXME: nothing strictly forces to have named definition */
err = snd_config_get_string(sconf, &sname);
+ snd_config_delete(sconf);
if (err < 0) {
- snd_config_delete(sconf);
SNDERR("slave.pcm is not a string");
return err;
}
const char *id = snd_config_get_id(n);
err = safe_strtol(id, &cchannel);
if (err < 0 || cchannel < 0) {
- snd_config_delete(sconf);
SNDERR("Invalid client channel in binding: %s", id);
return -EINVAL;
}
channels = cchannel + 1;
}
if (channels == 0) {
- snd_config_delete(sconf);
SNDERR("No bindings defined");
return -EINVAL;
}
cchannel = atoi(id);
err = snd_config_get_integer(n, &schannel);
if (err < 0) {
- snd_config_delete(sconf);
goto _free;
}
assert(schannel >= 0);
(unsigned int) schannels,
speriod_time, sbuffer_time,
channels, channels_map, stream, mode);
- snd_config_delete(sconf);
_free:
free(channels_map);
return err;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
ctrl->cmd = SND_PCM_IOCTL_ASYNC;
ctrl->u.async.sig = sig;
- if (pid == 0)
- pid = getpid();
ctrl->u.async.pid = pid;
return snd_pcm_shm_action(pcm);
}
shm->socket = sock;
shm->ctrl = ctrl;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
- result = -ENOMEM;
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_SHM, name, stream, mode);
+ if (err < 0) {
+ result = err;
goto _err;
}
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_SHM;
- pcm->stream = stream;
- pcm->mode = mode;
pcm->mmap_rw = 1;
pcm->ops = &snd_pcm_shm_ops;
- pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_shm_fast_ops;
- pcm->fast_op_arg = pcm;
pcm->private_data = shm;
err = snd_pcm_shm_poll_descriptor(pcm);
if (err < 0) {
+++ /dev/null
-/*
- * PCM - Surround plugin
- * Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
- *
- * This plugin offers 4.0 and 5.1 surround devices with these routing:
- *
- * 1st channel - front left speaker
- * 2nd channel - front rear speaker
- * 3rd channel - rear left speaker
- * 4th channel - rear right speaker
- * 5th channel - center speaker
- * 6th channel - LFE channel (woofer)
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library 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 Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <byteswap.h>
-#include <limits.h>
-#include <ctype.h>
-#include <sys/shm.h>
-#include "../control/control_local.h"
-#include "pcm_local.h"
-#include "pcm_plugin.h"
-
-#define ALSA_SURROUND_FILE DATADIR "/alsa/surround.conf"
-
-#define SURR_CAP_CAPTURE (1<<0)
-#define SURR_CAP_4CH (1<<1)
-#define SURR_CAP_6CH (1<<2)
-
-typedef struct _snd_pcm_surround snd_pcm_surround_t;
-
-struct _snd_pcm_surround {
- int card; /* card number */
- int device; /* device number */
- unsigned int channels; /* count of channels (4 or 6) */
- int pcms; /* count of PCM channels */
- int use_fd; /* use this FD for the direct access */
- int use_fd_four;
- int use_fd_six;
- snd_pcm_t *pcm[3]; /* up to three PCM stereo streams */
- int use_route: 1; /* route is used */
- int route[6]; /* channel route */
- int linked[3]; /* streams are linked */
- snd_ctl_t *ctl; /* CTL handle */
- unsigned int caps; /* capabilities */
- snd_sctl_t *store; /* control store container */
-};
-
-static int snd_pcm_surround_free(snd_pcm_surround_t *surr);
-
-static int snd_pcm_surround_close(snd_pcm_t *pcm)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_surround_free(surr);
-}
-
-static int snd_pcm_surround_nonblock(snd_pcm_t *pcm, int nonblock)
-{
- int i, err = 0, err1;
- snd_pcm_surround_t *surr = pcm->private_data;
- for (i = 0; i < surr->pcms; i++) {
- err1 = snd_pcm_nonblock(surr->pcm[i], nonblock);
- if (err1 && !err)
- err = err1;
- }
- return err;
-}
-
-static int snd_pcm_surround_async(snd_pcm_t *pcm, int sig, pid_t pid)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_async(surr->pcm[0], sig, pid);
-}
-
-static int snd_pcm_surround_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- memset(info, 0, sizeof(*info));
- info->stream = snd_enum_to_int(pcm->stream);
- info->card = surr->card;
- strncpy(info->id, "Surround", sizeof(info->id));
- strncpy(info->name, "Surround", sizeof(info->name));
- strncpy(info->subname, "Surround", sizeof(info->subname));
- info->subdevices_count = 1;
- return 0;
-}
-
-static int snd_pcm_surround_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- int err, old_channel, use_pcm;
-
- old_channel = info->channel;
- if (old_channel < 0 || old_channel > 5)
- return -EINVAL;
- info->channel = surr->route[old_channel];
- use_pcm = 0;
- if (surr->pcms > 1) {
- use_pcm = info->channel / 2;
- info->channel %= 2;
- }
- if (surr->pcm[use_pcm] == NULL) {
- info->channel = old_channel;
- return -EINVAL;
- }
- err = snd_pcm_channel_info(surr->pcm[use_pcm], info);
- info->channel = old_channel;
- return err;
-}
-
-static int snd_pcm_surround_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_status(surr->pcm[0], status);
-}
-
-static snd_pcm_state_t snd_pcm_surround_state(snd_pcm_t *pcm)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_state(surr->pcm[0]);
-}
-
-static int snd_pcm_surround_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_delay(surr->pcm[0], delayp);
-}
-
-static int snd_pcm_surround_prepare(snd_pcm_t *pcm)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_prepare(surr->pcm[0]);
-}
-
-static int snd_pcm_surround_reset(snd_pcm_t *pcm)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_reset(surr->pcm[0]);
-}
-
-static int snd_pcm_surround_start(snd_pcm_t *pcm)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_start(surr->pcm[0]);
-}
-
-static int snd_pcm_surround_drop(snd_pcm_t *pcm)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_drop(surr->pcm[0]);
-}
-
-static int snd_pcm_surround_drain(snd_pcm_t *pcm)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_drain(surr->pcm[0]);
-}
-
-static int snd_pcm_surround_pause(snd_pcm_t *pcm, int enable)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_pause(surr->pcm[0], enable);
-}
-
-static snd_pcm_sframes_t snd_pcm_surround_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_rewind(surr->pcm[0], frames);
-}
-
-static snd_pcm_sframes_t snd_pcm_surround_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- if (surr->pcms == 1 && !surr->use_route)
- return snd_pcm_writei(surr->pcm[0], buffer, size);
- if (pcm->running_areas == NULL) {
- int err;
- if ((err = snd_pcm_mmap(pcm)) < 0)
- return err;
- }
- return snd_pcm_mmap_writei(pcm, buffer, size);
-}
-
-static snd_pcm_sframes_t snd_pcm_surround_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
-{
- int i;
- snd_pcm_sframes_t res = -1, res1;
- snd_pcm_surround_t *surr = pcm->private_data;
- if (surr->use_route) {
- if (pcm->running_areas == NULL) {
- int err;
- if ((err = snd_pcm_mmap(pcm)) < 0)
- return err;
- }
- return snd_pcm_mmap_writen(pcm, bufs, size);
- }
- for (i = 0; i < surr->pcms; i++, bufs += 2) {
- res1 = snd_pcm_writen(pcm, bufs, size);
- if (res1 < 0)
- return res1;
- if (res < 0)
- res = res1;
- else if (res != res1)
- return -EPIPE;
- }
- return res;
-}
-
-static snd_pcm_sframes_t snd_pcm_surround_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- if (surr->pcms == 1 && !surr->use_route)
- return snd_pcm_readi(surr->pcm[0], buffer, size);
- if (pcm->running_areas == NULL) {
- int err;
- if ((err = snd_pcm_mmap(pcm)) < 0)
- return err;
- }
- return snd_pcm_mmap_readi(pcm, buffer, size);
-}
-
-static snd_pcm_sframes_t snd_pcm_surround_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
-{
- int i;
- snd_pcm_sframes_t res = -1, res1;
- snd_pcm_surround_t *surr = pcm->private_data;
- if (surr->use_route) {
- if (pcm->running_areas == NULL) {
- int err;
- if ((err = snd_pcm_mmap(pcm)) < 0)
- return err;
- }
- return snd_pcm_mmap_readn(pcm, bufs, size);
- }
- for (i = 0; i < surr->pcms; i++) {
- res1 = snd_pcm_writen(pcm, bufs, size);
- if (res1 < 0)
- return res1;
- if (res < 0) {
- res = size = res1;
- } else if (res != res1)
- return -EPIPE;
- }
- return res;
-}
-
-static snd_pcm_sframes_t snd_pcm_surround_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
-{
- int i;
- snd_pcm_sframes_t res = -1, res1;
- snd_pcm_surround_t *surr = pcm->private_data;
- for (i = 0; i < surr->pcms; i++) {
- res1 = snd_pcm_mmap_commit(surr->pcm[i], offset, size);
- if (res1 < 0)
- return res1;
- if (res < 0) {
- res = size = res1;
- } else if (res != res1)
- return -EPIPE;
- }
- return res;
-}
-
-static snd_pcm_sframes_t snd_pcm_surround_avail_update(snd_pcm_t *pcm)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- return snd_pcm_avail_update(surr->pcm[0]);
-}
-
-static int snd_pcm_surround_interval_channels(snd_pcm_surround_t *surr,
- snd_pcm_hw_params_t *params,
- int refine)
-{
- snd_interval_t *interval;
- interval = ¶ms->intervals[SND_PCM_HW_PARAM_CHANNELS-SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
- if (interval->empty)
- return -EINVAL;
- if (interval->openmin) {
- if (!refine) {
- interval->empty = 1;
- return -EINVAL;
- }
- interval->min = surr->channels;
- interval->openmin = 0;
- }
- if (interval->openmax) {
- if (!refine) {
- interval->empty = 1;
- return -EINVAL;
- }
- interval->max = surr->channels;
- interval->openmax = 0;
- }
- if (refine && interval->min <= surr->channels && interval->max >= surr->channels)
- interval->min = interval->max = surr->channels;
- if (interval->min != interval->max || interval->min != surr->channels) {
- interval->empty = 1;
- return -EINVAL;
- }
- if (surr->pcms != 1)
- interval->min = interval->max = 2;
- return 0;
-}
-
-static void snd_pcm_surround_interval_channels_fixup(snd_pcm_surround_t *surr,
- snd_pcm_hw_params_t *params)
-{
- snd_interval_t *interval;
- interval = ¶ms->intervals[SND_PCM_HW_PARAM_CHANNELS-SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
- interval->min = interval->max = surr->channels;
-}
-
-static int snd_pcm_surround_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- snd_pcm_access_mask_t *access_mask;
- snd_pcm_access_mask_t *access_mask1;
- int i, err;
-
- err = snd_pcm_surround_interval_channels(surr, params, 1);
- if (err < 0)
- return err;
- if (surr->pcms == 1 && !surr->use_route)
- return snd_pcm_hw_refine(surr->pcm[0], params);
- access_mask = (snd_pcm_access_mask_t *)snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
- snd_pcm_access_mask_alloca(&access_mask1);
- snd_pcm_access_mask_copy(access_mask1, access_mask);
- snd_pcm_access_mask_reset(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
- if (snd_pcm_access_mask_test(access_mask1, SND_PCM_ACCESS_RW_INTERLEAVED))
- snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
- for (i = 0; i < surr->pcms; i++) {
- err = snd_pcm_hw_refine(surr->pcm[i], params);
- if (err < 0)
- goto __error;
- }
- err = 0;
- __error:
- snd_pcm_access_mask_none(access_mask);
- if (snd_pcm_access_mask_test(access_mask1, SND_PCM_ACCESS_RW_INTERLEAVED))
- snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
- if (snd_pcm_access_mask_test(access_mask1, SND_PCM_ACCESS_RW_NONINTERLEAVED))
- snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
- if (snd_pcm_access_mask_test(access_mask1, SND_PCM_ACCESS_MMAP_COMPLEX))
- snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
- snd_pcm_surround_interval_channels_fixup(surr, params);
- return err;
-}
-
-static int snd_pcm_surround_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
-{
- snd_pcm_surround_t *surr = pcm->private_data;
- snd_pcm_access_mask_t *access_mask;
- snd_pcm_access_mask_t *access_mask1;
- int i, err;
-
- err = snd_pcm_surround_interval_channels(surr, params, 0);
- if (err < 0)
- return err;
- if (surr->pcms == 1 && !surr->use_route)
- return snd_pcm_hw_params(surr->pcm[0], params);
- access_mask = (snd_pcm_access_mask_t *)snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
- snd_pcm_access_mask_alloca(&access_mask1);
- snd_pcm_access_mask_copy(access_mask1, access_mask);
- snd_pcm_access_mask_reset(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
- if (snd_pcm_access_mask_test(access_mask1, SND_PCM_ACCESS_RW_INTERLEAVED))
- snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
- for (i = 0; i < surr->pcms; i++) {
- err = snd_pcm_hw_params(surr->pcm[i], params);
- if (err < 0) {
- snd_pcm_access_mask_copy(access_mask, access_mask1);
- snd_pcm_surround_interval_channels_fixup(surr, params);
- return err;
- }
- }
- snd_pcm_access_mask_copy(access_mask, access_mask1);
- snd_pcm_surround_interval_channels_fixup(surr, params);
- surr->linked[0] = 0;
- for (i = 1; i < surr->pcms; i++) {
- err = snd_pcm_link(surr->pcm[0], surr->pcm[i]);
- if ((surr->linked[i] = (err >= 0)) == 0)
- return err;
- }
- return 0;
-}
-
-static int snd_pcm_surround_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
-{
- int i, err, res = 0;
- snd_pcm_surround_t *surr = pcm->private_data;
- for (i = 0; i < surr->pcms; i++) {
- err = snd_pcm_hw_free(surr->pcm[i]);
- if (err < 0)
- res = err;
- if (!surr->linked[i])
- continue;
- surr->linked[i] = 0;
- err = snd_pcm_unlink(surr->pcm[i]);
- if (err < 0)
- res = err;
- }
- return res;
-}
-
-static int snd_pcm_surround_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
-{
- int i, err;
- snd_pcm_surround_t *surr = pcm->private_data;
- for (i = 0; i < surr->pcms; i++) {
- err = snd_pcm_sw_params(surr->pcm[i], params);
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static int snd_pcm_surround_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
-{
- // snd_pcm_surround_t *surr = pcm->private_data;
- return 0;
-}
-
-static int snd_pcm_surround_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
-{
- // snd_pcm_surround_t *surr = pcm->private_data;
- return 0;
-}
-
-static void snd_pcm_surround_dump(snd_pcm_t *pcm, snd_output_t *out)
-{
- snd_output_printf(out, "Surround PCM\n");
- if (pcm->setup) {
- snd_output_printf(out, "Its setup is:\n");
- snd_pcm_dump_setup(pcm, out);
- }
-}
-
-snd_pcm_ops_t snd_pcm_surround_ops = {
- close: snd_pcm_surround_close,
- info: snd_pcm_surround_info,
- hw_refine: snd_pcm_surround_hw_refine,
- hw_params: snd_pcm_surround_hw_params,
- hw_free: snd_pcm_surround_hw_free,
- sw_params: snd_pcm_surround_sw_params,
- channel_info: snd_pcm_surround_channel_info,
- dump: snd_pcm_surround_dump,
- nonblock: snd_pcm_surround_nonblock,
- async: snd_pcm_surround_async,
- mmap: snd_pcm_surround_mmap,
- munmap: snd_pcm_surround_munmap,
-};
-
-snd_pcm_fast_ops_t snd_pcm_surround_fast_ops = {
- status: snd_pcm_surround_status,
- state: snd_pcm_surround_state,
- delay: snd_pcm_surround_delay,
- prepare: snd_pcm_surround_prepare,
- reset: snd_pcm_surround_reset,
- start: snd_pcm_surround_start,
- drop: snd_pcm_surround_drop,
- drain: snd_pcm_surround_drain,
- pause: snd_pcm_surround_pause,
- rewind: snd_pcm_surround_rewind,
- writei: snd_pcm_surround_writei,
- writen: snd_pcm_surround_writen,
- readi: snd_pcm_surround_readi,
- readn: snd_pcm_surround_readn,
- avail_update: snd_pcm_surround_avail_update,
- mmap_commit: snd_pcm_surround_mmap_commit,
-};
-
-static int snd_pcm_surround_free(snd_pcm_surround_t *surr)
-{
- int i;
-
- assert(surr);
- for (i = 2; i >= 0; i--) {
- if (surr->pcm[i] == NULL)
- continue;
- snd_pcm_close(surr->pcm[i]);
- surr->pcm[i] = NULL;
- }
- if (surr->store)
- snd_sctl_free(surr->ctl, surr->store);
- if (surr->ctl)
- snd_ctl_close(surr->ctl);
- free(surr);
- return 0;
-}
-
-static int snd_pcm_surround_one_stream(snd_pcm_surround_t *surr,
- snd_pcm_surround_type_t type ATTRIBUTE_UNUSED,
- int card,
- int dev, int subdev,
- snd_pcm_stream_t stream, int mode)
-{
- int err;
-
- if ((err = snd_pcm_hw_open(&surr->pcm[0], "Surround", card, dev,
- subdev, stream, mode)) < 0)
- return err;
- surr->pcms++;
- return 0;
-}
-
-static int snd_pcm_surround_three_streams(snd_pcm_surround_t *surr,
- snd_pcm_surround_type_t type,
- int card,
- int dev0, int subdev0,
- int dev1, int subdev1,
- int dev2, int subdev2,
- snd_pcm_stream_t stream, int mode)
-{
- int err;
-
- if ((err = snd_pcm_hw_open(&surr->pcm[0], "Surround L/R", card, dev0,
- subdev0, stream, mode)) < 0)
- return err;
- surr->pcms++;
- if ((err = snd_pcm_hw_open(&surr->pcm[1], "Surround Rear L/R", card, dev1,
- subdev1, stream, mode)) < 0)
- return err;
- surr->pcms++;
- if (type == SND_PCM_SURROUND_51) {
- if ((err = snd_pcm_hw_open(&surr->pcm[2], "Surround Center/LFE", card, dev2,
- subdev2, stream, mode)) < 0)
- return err;
- surr->pcms++;
- }
- return 0;
-}
-
-static int build_config(snd_config_t **r_conf)
-{
- int err;
- snd_input_t *in;
- snd_config_t *conf, *file;
- const char *filename = ALSA_SURROUND_FILE;
-
- assert(r_conf);
- *r_conf = NULL;
- if ((err = snd_config_update()) < 0)
- return err;
- if ((err = snd_config_search(snd_config, "surround_file", &file)) >= 0) {
- if ((err = snd_config_get_string(file, &filename)) < 0) {
- SNDERR("cards_file definition must be string");
- filename = ALSA_SURROUND_FILE;
- }
- }
- if ((err = snd_input_stdio_open(&in, filename, "r")) < 0) {
- SNDERR("unable to open configuration file '%s'", filename);
- return err;
- }
- if ((err = snd_config_top(&conf)) < 0) {
- SNDERR("config_top");
- snd_input_close(in);
- return err;
- }
- if ((err = snd_config_load(conf, in)) < 0) {
- SNDERR("config load error");
- snd_config_delete(conf);
- snd_input_close(in);
- return err;
- }
- snd_input_close(in);
- *r_conf = conf;
- return 0;
-}
-
-int load_surround_config(snd_ctl_t *ctl, snd_pcm_surround_t *surr,
- snd_pcm_surround_type_t stype,
- snd_card_type_t ctype,
- snd_pcm_stream_t stream,
- int mode)
-{
- int err, res = -EINVAL;
- snd_config_t *conf = NULL, *surrconf;
- snd_config_iterator_t i, next;
-
- if ((err = build_config(&conf)) < 0)
- return err;
- if ((err = snd_config_search(conf, "surround_plugin", &surrconf)) < 0) {
- SNDERR("unable to find card definitions");
- snd_config_delete(conf);
- return err;
- }
- if (snd_config_get_type(surrconf) != SND_CONFIG_TYPE_COMPOUND) {
- SNDERR("compound type expected");
- snd_config_delete(conf);
- return err;
- }
- snd_config_for_each(i, next, surrconf) {
- snd_config_t *n = snd_config_iterator_entry(i), *n1;
- const char *id = snd_config_get_id(n);
- snd_card_type_t mytype = (snd_card_type_t)-1;
- int opened = 0;
- if (isdigit(*id)) {
- mytype = (snd_card_type_t)atoi(id);
- } else {
- if (snd_card_type_string_to_enum(id, &mytype) < 0) {
- SNDERR("snd_card_type_string_to_enum %s", id);
- continue;
- }
- }
- if (mytype != ctype)
- continue;
- if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
- SNDERR("compound type expected");
- goto __error;
- }
- if (snd_config_search(n, "device", &n1) >= 0) {
- unsigned long i;
- if ((err = snd_config_get_integer(n1, &i)) < 0) {
- SNDERR("Invalid type for field device");
- goto __error;
- }
- if (surr->device != (int)i)
- continue;
- }
- if (snd_config_search(n, "channels_four", &n1) >= 0) {
- const char *str;
- if ((err = snd_config_get_string(n1, &str)) < 0) {
- SNDERR("Invalid value for %s", id);
- goto __error;
- } else if (!strcasecmp(str, "true")) {
- surr->caps |= SURR_CAP_4CH;
- } else if (isdigit(*str) && atoi(str) != 0)
- surr->caps |= SURR_CAP_4CH;
- }
- if (snd_config_search(n, "channels_six", &n1) >= 0) {
- const char *str;
- if ((err = snd_config_get_string(n1, &str)) < 0) {
- SNDERR("Invalid value for %s", id);
- goto __error;
- } else if (!strcasecmp(str, "true")) {
- surr->caps |= SURR_CAP_6CH;
- } else if (isdigit(*str) && atoi(str) != 0)
- surr->caps |= SURR_CAP_6CH;
- }
- if (snd_config_search(n, "use_fd_four", &n1) >= 0) {
- unsigned long i;
- if ((err = snd_config_get_integer(n1, &i)) < 0) {
- SNDERR("Invalid type for %s", id);
- goto __error;
- } else if (i <= 1)
- surr->use_fd_four = i;
- else {
- SNDERR("Invalid range for use_fd (0-2): %li", i);
- goto __error;
- }
- }
- if (snd_config_search(n, "use_fd_six", &n1) >= 0) {
- unsigned long i;
- if ((err = snd_config_get_integer(n1, &i)) < 0) {
- SNDERR("Invalid type for %s", id);
- goto __error;
- } else if (i <= 2)
- surr->use_fd_six = i;
- else {
- SNDERR("Invalid range for use_fd (0-2): %li", i);
- goto __error;
- }
- }
- if (snd_config_search(n, "route_four", &n1) >= 0) {
- snd_config_iterator_t i, next;
- snd_config_t *n2;
- if (stype == SND_PCM_SURROUND_40) {
- if (snd_config_get_type(n1) != SND_CONFIG_TYPE_COMPOUND) {
- SNDERR("compound type expected");
- goto __error;
- }
- if (snd_config_search(n1, "channel", &n2) >= 0) {
- snd_config_for_each(i, next, n2) {
- snd_config_t *n = snd_config_iterator_entry(i);
- int idx = atoi(snd_config_get_id(n));
- unsigned long i;
- int err = snd_config_get_integer(n, &i);
- if (err < 0) {
- SNDERR("Invalid field channel.%s", snd_config_get_id(n));
- goto __error;
- }
- if (idx < 0 || idx >= 4) {
- SNDERR("Index is out of range (0-3): %i", idx);
- goto __error;
- }
- if (idx != (int)i)
- surr->use_route = 1;
- surr->route[idx] = i;
- }
- }
- }
- }
- if (snd_config_search(n, "route_six", &n1) >= 0) {
- snd_config_iterator_t i, next;
- snd_config_t *n2;
- if (stype == SND_PCM_SURROUND_51) {
- if (snd_config_get_type(n1) != SND_CONFIG_TYPE_COMPOUND) {
- SNDERR("compound type expected");
- goto __error;
- }
- if (snd_config_search(n1, "channel", &n2) >= 0) {
- snd_config_for_each(i, next, n2) {
- snd_config_t *n = snd_config_iterator_entry(i);
- int idx = atoi(snd_config_get_id(n));
- unsigned long i;
- int err = snd_config_get_integer(n, &i);
- if (err < 0) {
- SNDERR("Invalid field channel.%s", snd_config_get_id(n));
- goto __error;
- }
- if (idx < 0 || idx >= 6) {
- SNDERR("Index is out of range (0-5): %i", idx);
- goto __error;
- }
- if (idx != (int)i)
- surr->use_route = 1;
- surr->route[idx] = i;
- }
- }
- }
- }
- if (snd_config_search(n, "open_single", &n1) >= 0) {
- snd_config_iterator_t i, next;
- int device = 0, subdevice = -1;
- surr->use_fd = 0;
- if (snd_config_get_type(n1) != SND_CONFIG_TYPE_COMPOUND) {
- SNDERR("compound type expected");
- goto __error;
- }
- snd_config_for_each(i, next, n1) {
- snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
- unsigned long i;
- if (!strcmp(id, "device")) {
- if ((err = snd_config_get_integer(n, &i)) < 0) {
- SNDERR("Invalid type for %s", id);
- goto __error;
- }
- device = i;
- } else if (!strcmp(id, "subdevice")) {
- if ((err = snd_config_get_integer(n, &i)) < 0) {
- SNDERR("Invalid type for %s", id);
- goto __error;
- }
- subdevice = i;
- } else {
- SNDERR("Invalid field %s", id);
- goto __error;
- }
- }
- if (stream == SND_PCM_STREAM_CAPTURE && !(surr->caps & SURR_CAP_CAPTURE)) {
- err = -ENODEV;
- goto __error;
- }
- switch (stype) {
- case SND_PCM_SURROUND_40:
- if (!(surr->caps & SURR_CAP_4CH)) {
- err = -ENODEV;
- goto __error;
- }
- break;
- case SND_PCM_SURROUND_51:
- if (!(surr->caps & SURR_CAP_6CH)) {
- err = -ENODEV;
- goto __error;
- }
- break;
- }
- if ((err = snd_pcm_surround_one_stream(surr, stype, surr->card, device, subdevice, stream, mode)) < 0) {
- SNDERR("surround single stream open error %i,%i,%i: %s", surr->card, device, subdevice, snd_strerror(err));
- goto __error;
- }
- opened = 1;
- } else if (snd_config_search(n, "open_multi", &n1) >= 0) {
- snd_config_iterator_t i, next;
- int device[3] = { 0, 0, 0 }, subdevice[3] = { -1, -1, -1 };
- if (snd_config_get_type(n1) != SND_CONFIG_TYPE_COMPOUND) {
- SNDERR("compound type expected");
- goto __error;
- }
- snd_config_for_each(i, next, n1) {
- snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
- snd_config_iterator_t i, next;
- if (!strcmp(id, "device") || !strcmp(id, "subdevice")) {
- if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
- SNDERR("compound type expected");
- goto __error;
- }
- snd_config_for_each(i, next, n) {
- snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
- int idx = atoi(snd_config_get_id(n));
- unsigned long i;
- if (idx < 0 || idx > 2) {
- SNDERR("Invalid index %s", snd_config_get_id(n));
- goto __error;
- }
- if ((err = snd_config_get_integer(n, &i)) < 0) {
- SNDERR("Invalid type for %s", id);
- goto __error;
- }
- if (!strcmp(id, "device"))
- device[idx] = i;
- else
- subdevice[idx] = i;
- }
- } else {
- SNDERR("Invalid field %s", id);
- goto __error;
- }
- }
- if (stream == SND_PCM_STREAM_CAPTURE && !(surr->caps & SURR_CAP_CAPTURE)) {
- err = -ENODEV;
- goto __error;
- }
- switch (stype) {
- case SND_PCM_SURROUND_40:
- surr->use_fd = surr->use_fd_four;
- if (!(surr->caps & SURR_CAP_4CH)) {
- err = -ENODEV;
- goto __error;
- }
- break;
- case SND_PCM_SURROUND_51:
- surr->use_fd = surr->use_fd_six;
- if (!(surr->caps & SURR_CAP_6CH)) {
- err = -ENODEV;
- goto __error;
- }
- break;
- }
- if ((err = snd_pcm_surround_three_streams(surr, stype, surr->card, device[0], subdevice[0], device[1], subdevice[1], device[2], subdevice[2], stream, mode)) < 0) {
- SNDERR("surround single stream open error %i,%i,%i,%i,%i,%i,%i: %s", surr->card, device[0], subdevice[0], device[1], subdevice[1], device[2], subdevice[2], snd_strerror(err));
- goto __error;
- }
- if (surr->pcm[surr->use_fd] == NULL)
- surr->use_fd = 0;
- opened = 1;
- }
- if (opened == 0) {
- err = -ENODEV;
- goto __error;
- }
- if (stype == SND_PCM_SURROUND_40 && snd_config_search(n, "open_control_four", &n1) >= 0) {
- snd_sctl_replace_t replace[3];
- char values[2][10] = { "123", "123" };
- snd_pcm_info_t *info;
- int ridx = 0;
-
- snd_pcm_info_alloca(&info);
- if ((err = snd_pcm_info(surr->pcm[0], info)) < 0) {
- SNDERR("snd_pcm_info failed", snd_strerror(err));
- goto __error;
- }
- sprintf(values[0], "%i", snd_pcm_info_get_subdevice(info));
- replace[ridx].key = "index";
- replace[ridx].old_value = "subdevice0";
- replace[ridx].new_value = values[0];
- ridx++;
-
- if (surr->pcm[1]) {
- if ((err = snd_pcm_info(surr->pcm[1], info)) < 0) {
- SNDERR("snd_pcm_info failed", snd_strerror(err));
- goto __error;
- }
- sprintf(values[1], "%i", snd_pcm_info_get_subdevice(info));
- replace[ridx].key = "index";
- replace[ridx].old_value = "subdevice1";
- replace[ridx].new_value = values[1];
- ridx++;
- }
- replace[ridx].key = NULL;
- replace[ridx].old_value = NULL;
- replace[ridx].new_value = NULL;
- if ((err = snd_sctl_build(ctl, &surr->store, n1, replace)) < 0) {
- SNDERR("snd_sctl_build : %s\n", snd_strerror(err));
- goto __error;
- }
- }
- if ((stype == SND_PCM_SURROUND_51 && snd_config_search(n, "open_control_six", &n1) >= 0) ||
- snd_config_search(n, "open_control", &n1) >= 0) {
- snd_sctl_replace_t replace[4];
- char values[3][10] = { "123", "123", "123" };
- snd_pcm_info_t *info;
- int ridx = 0;
-
- snd_pcm_info_alloca(&info);
- if ((err = snd_pcm_info(surr->pcm[0], info)) < 0) {
- SNDERR("snd_pcm_info failed", snd_strerror(err));
- goto __error;
- }
- sprintf(values[0], "%i", snd_pcm_info_get_subdevice(info));
- replace[ridx].key = "index";
- replace[ridx].old_value = "subdevice0";
- replace[ridx].new_value = values[0];
- ridx++;
-
- if (surr->pcm[1]) {
- if ((err = snd_pcm_info(surr->pcm[1], info)) < 0) {
- SNDERR("snd_pcm_info failed", snd_strerror(err));
- goto __error;
- }
- sprintf(values[1], "%i", snd_pcm_info_get_subdevice(info));
- replace[ridx].key = "index";
- replace[ridx].old_value = "subdevice1";
- replace[ridx].new_value = values[1];
- ridx++;
- }
- if (surr->pcm[2]) {
- if ((err = snd_pcm_info(surr->pcm[2], info)) < 0) {
- SNDERR("snd_pcm_info failed", snd_strerror(err));
- goto __error;
- }
- sprintf(values[2], "%i", snd_pcm_info_get_subdevice(info));
- replace[ridx].key = "index";
- replace[ridx].old_value = "subdevice2";
- replace[ridx].new_value = values[2];
- ridx++;
- }
- replace[ridx].key = NULL;
- replace[ridx].old_value = NULL;
- replace[ridx].new_value = NULL;
- if ((err = snd_sctl_build(ctl, &surr->store, n1, replace)) < 0) {
- SNDERR("snd_sctl_build : %s\n", snd_strerror(err));
- goto __error;
- }
- }
- return 0;
- }
- res = -ENOENT;
- SNDERR("configuration for card %i not found", (int)ctype);
- __error:
- snd_config_delete(conf);
- return res;
-}
-
-int snd_pcm_surround_open(snd_pcm_t **pcmp, const char *name, int card, int dev,
- snd_pcm_surround_type_t type,
- snd_pcm_stream_t stream, int mode)
-{
- snd_pcm_t *pcm = NULL;
- snd_pcm_surround_t *surr;
- snd_ctl_t *ctl = NULL;
- snd_ctl_card_info_t *info;
- snd_card_type_t ctype;
- int err, idx;
-
- assert(pcmp);
- surr = calloc(1, sizeof(snd_pcm_surround_t));
- if (!surr)
- return -ENOMEM;
- switch (type) {
- case SND_PCM_SURROUND_40:
- surr->channels = 4;
- break;
- case SND_PCM_SURROUND_51:
- surr->channels = 6;
- break;
- default:
- snd_pcm_surround_free(surr);
- return -EINVAL;
- }
- if ((err = snd_ctl_hw_open(&ctl, "Surround", card, 0)) < 0) {
- snd_pcm_surround_free(surr);
- return err;
- }
- surr->ctl = ctl;
- surr->card = card;
- surr->device = dev;
- surr->caps = SURR_CAP_4CH;
- for (idx = 0; idx < 6; idx++)
- surr->route[idx] = idx;
- snd_ctl_card_info_alloca(&info);
- if ((err = snd_ctl_card_info(ctl, info)) < 0)
- goto __error;
- ctype = snd_ctl_card_info_get_type(info);
- if ((err = load_surround_config(ctl, surr, type, ctype, stream, mode)) < 0)
- goto __error;
- if (surr->store == NULL) {
- snd_ctl_close(ctl);
- surr->ctl = NULL;
- }
- ctl = NULL;
- pcm = calloc(1, sizeof(snd_pcm_t));
- if (!pcm) {
- err = -ENOMEM;
- goto __error;
- }
- if (name)
- pcm->name = strdup(name);
- pcm->type = SND_PCM_TYPE_SURROUND;
- pcm->stream = stream;
- pcm->mode = mode;
- pcm->ops = &snd_pcm_surround_ops;
- pcm->op_arg = pcm;
- pcm->fast_ops = &snd_pcm_surround_fast_ops;
- pcm->fast_op_arg = pcm;
- pcm->private_data = surr;
- pcm->poll_fd = surr->pcm[surr->use_fd]->poll_fd;
- pcm->hw_ptr = surr->pcm[surr->use_fd]->hw_ptr;
- pcm->appl_ptr = surr->pcm[surr->use_fd]->appl_ptr;
-
- *pcmp = pcm;
-
- return 0;
-
- __error:
- snd_pcm_surround_free(surr);
- return err;
-}
-
-int _snd_pcm_surround_open(snd_pcm_t **pcmp, const char *name, snd_config_t *conf,
- snd_pcm_stream_t stream, int mode)
-{
- snd_config_iterator_t i, next;
- long card = -1, device = 0;
- const char *str;
- int err;
- snd_pcm_surround_type_t type = SND_PCM_SURROUND_40;
- snd_config_for_each(i, next, conf) {
- snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
- if (snd_pcm_conf_generic_id(id))
- continue;
- if (strcmp(id, "card") == 0) {
- err = snd_config_get_integer(n, &card);
- if (err < 0) {
- err = snd_config_get_string(n, &str);
- if (err < 0) {
- SNDERR("Invalid type for %s", id);
- return -EINVAL;
- }
- card = snd_card_get_index(str);
- if (card < 0) {
- SNDERR("Invalid value for %s", id);
- return card;
- }
- }
- continue;
- }
- if (strcmp(id, "device") == 0) {
- err = snd_config_get_integer(n, &device);
- if (err < 0) {
- SNDERR("Invalid type for %s", id);
- return err;
- }
- continue;
- }
-#if 0
- if (strcmp(id, "subdevice") == 0) {
- err = snd_config_get_integer(n, &subdevice);
- if (err < 0) {
- SNDERR("Invalid type for %s", id);
- return err;
- }
- continue;
- }
-#endif
- if (strcmp(id, "stype") == 0) {
- err = snd_config_get_string(n, &str);
- if (strcmp(str, "40") == 0 || strcmp(str, "4.0") == 0)
- type = SND_PCM_SURROUND_40;
- else if (strcmp(str, "51") == 0 || strcmp(str, "5.1") == 0)
- type = SND_PCM_SURROUND_51;
- continue;
- }
- SNDERR("Unknown field %s", id);
- return -EINVAL;
- }
- if (card < 0) {
- SNDERR("card is not defined");
- return -EINVAL;
- }
- return snd_pcm_surround_open(pcmp, name, card, device, type, stream, mode);
-}
+++ /dev/null
-#
-# Configuration for the surround plugin
-#
-
-surround_plugin.SI_7018 { # test only
- channels_six = true;
- open_multi {
- device.0 = 0;
- subdevice.0 = -1;
- device.1 = 0;
- subdevice.1 = -1;
- device.2 = 0;
- subdevice.2 = -1;
- }
- open_control.0 {
- iface = MIXER;
- name = 'CD Playback Switch';
- index = 0;
- lock = true;
- preserve = true;
- value.0 = 1;
- value.1 = 1;
- }
- open_control.1 {
- iface = MIXER;
- name = 'CD Playback Volume';
- index = 0;
- lock = true;
- preserve = true;
- value.0 = 16;
- value.1 = 19;
- }
-}
-
-surround_plugin.FM801 {
- channels_six = true;
- open_single {
- device = 0;
- subdevice = 0;
- }
-}
-
-surround_plugin.ENS1370 {
- use_fd_four = 1;
- open_multi {
- device.0 = 1;
- subdevice.0 = 0;
- device.1 = 0;
- subdevice.1 = 0;
- }
- # Reroute PCM0 (rear) to Line-In Jack.
- open_control.0 {
- iface = CARD;
- name = 'PCM 0 Output also on Line-In Jack';
- index = 0;
- lock = true;
- preserve = true;
- value.0 = true;
- }
- # Turn off the PCM volume, the second PCM (front speakers) uses
- # the second PCM control.
- open_control.1 {
- iface = MIXER;
- name = 'PCM Switch';
- index = 0;
- lock = true;
- preserve = true;
- value.0 = false;
- value.1 = false;
- }
-}
-
-surround_plugin.YMFPCI {
- open_multi {
- device.0 = 0;
- subdevice.0 = 0;
- device.1 = 2;
- subdevice.1 = 0;
- }
-}
-
-surround_plugin.TRID4DWAVENX {
- open_multi {
- device.0 = 0;
- subdevice.0 = -1;
- device.1 = 0;
- subdevice.1 = -1;
- }
- # Enable rear path
- open_control.0 {
- iface = MIXER;
- name = 'Rear Path';
- index = subdevice1;
- lock = true;
- value.0 = true;
- }
- # Mute front volume
- open_control.1 {
- iface = MIXER;
- name = 'PCM Front Playback Volume';
- index = subdevice1;
- lock = true;
- value.0 = 0;
- value.1 = 0;
- }
- # Set reverb (rear) volume
- open_control.2 {
- iface = MIXER;
- name = 'PCM Reverb Playback Volume';
- index = subdevice1;
- lock = true;
- value.0 = 127;
- value.1 = 127;
- }
-}
-
-surround_plugin.INTEL8X0 {
- channels_six = true;
- route_four {
- channel.0 = 0; # FR = FR
- channel.1 = 1; # FL = FL
- channel.2 = 2; # SR = SR
- channel.3 = 3; # SL = SL
- }
- route_six {
- channel.0 = 0; # FR = FR
- channel.1 = 1; # FL = FL
- channel.2 = 4; # SR = Center
- channel.3 = 5; # SL = LFE
- channel.4 = 2; # Center = SR
- channel.5 = 3; # LFE = SL
- }
- open_single {
- device = 0;
- subdevice = 0;
- }
-}
-
-surround_plugin.EMU10K1 {
- channels_six = true;
- use_fd_four = 1;
- use_fd_six = 2;
- open_multi {
- device.0 = 0;
- subdevice.0 = -1;
- device.1 = 0;
- subdevice.1 = -1;
- device.2 = 0;
- subdevice.2 = -1;
- }
- open_control_four.0 {
- iface = MIXER;
- name = 'Wave Surround Playback Volume';
- index = 0;
- lock = true;
- preserve = true;
- value.0 = 0;
- value.1 = 0;
- }
- # change send volume from front to rear
- open_control_four.1 {
- iface = MIXER;
- name = 'EMU10K1 PCM Send Volume';
- index = subdevice1;
- lock = true;
- value.4 = 0;
- value.5 = 0;
- value.6 = 255;
- value.7 = 0;
- value.8 = 0;
- value.9 = 0;
- value.10 = 0;
- value.11 = 255;
- }
- open_control_six.0 {
- iface = MIXER;
- name = 'Wave Surround Playback Volume';
- index = 0;
- lock = true;
- preserve = true;
- value.0 = 0;
- value.1 = 0;
- }
- # change send volume from front to rear
- open_control_six.1 {
- iface = MIXER;
- name = 'EMU10K1 PCM Send Volume';
- index = subdevice1;
- lock = true;
- value.4 = 0;
- value.5 = 0;
- value.6 = 255;
- value.7 = 0;
- value.8 = 0;
- value.9 = 0;
- value.10 = 0;
- value.11 = 255;
- }
- # send routing must be changed to 6 (center) and 7 (LFE)
- open_control_six.2 {
- iface = MIXER;
- name = 'EMU10K1 PCM Send Routing';
- index = subdevice2;
- lock = true;
- value.4 = 6;
- value.5 = 7;
- value.6 = 0;
- value.7 = 1;
- value.8 = 6;
- value.9 = 7;
- value.10 = 0;
- value.11 = 1;
- }
-}