mirror of https://github.com/ericonr/sndio.git
remove mixer api files
This commit is contained in:
parent
1e958d6853
commit
a162cfd9e6
|
@ -1,198 +0,0 @@
|
|||
/* $OpenBSD$ */
|
||||
/*
|
||||
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "siomix_priv.h"
|
||||
#include "bsd-compat.h"
|
||||
|
||||
struct siomix_hdl *
|
||||
siomix_open(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
static char devany[] = SIOMIX_DEVANY;
|
||||
struct siomix_hdl *hdl;
|
||||
const char *p;
|
||||
|
||||
#ifdef DEBUG
|
||||
_sndio_debug_init();
|
||||
#endif
|
||||
if (str == NULL) /* backward compat */
|
||||
str = devany;
|
||||
if (strcmp(str, devany) == 0 && !issetugid()) {
|
||||
str = getenv("AUDIODEVICE");
|
||||
if (str == NULL)
|
||||
str = devany;
|
||||
}
|
||||
if (strcmp(str, devany) == 0) {
|
||||
hdl = _siomix_aucat_open("/0", mode, nbio);
|
||||
if (hdl != NULL)
|
||||
return hdl;
|
||||
#if defined(USE_SUN_MIXER)
|
||||
return _siomix_sun_open("/0", mode, nbio);
|
||||
#elif defined(USE_ALSA_MIXER)
|
||||
return _siomix_alsa_open("/0", mode, nbio);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
if ((p = _sndio_parsetype(str, "snd")) != NULL)
|
||||
return _siomix_aucat_open(p, mode, nbio);
|
||||
#if defined(USE_ALSA_MIXER) || defined(USE_SUN_MIXER)
|
||||
if ((p = _sndio_parsetype(str, "rsnd")) != NULL) {
|
||||
#if defined(USE_SUN_MIXER)
|
||||
return _siomix_sun_open(p, mode, nbio);
|
||||
#elif defined(USE_ALSA_MIXER)
|
||||
return _siomix_alsa_open(p, mode, nbio);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
DPRINTF("siomix_open: %s: unknown device type\n", str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_siomix_create(struct siomix_hdl *hdl, struct siomix_ops *ops,
|
||||
unsigned int mode, int nbio)
|
||||
{
|
||||
hdl->ops = ops;
|
||||
hdl->mode = mode;
|
||||
hdl->nbio = nbio;
|
||||
hdl->eof = 0;
|
||||
hdl->ctl_cb = NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_siomix_psleep(struct siomix_hdl *hdl, int event)
|
||||
{
|
||||
struct pollfd pfds[SIOMIX_MAXNFDS];
|
||||
int revents, nfds;
|
||||
|
||||
for (;;) {
|
||||
nfds = siomix_pollfd(hdl, pfds, event);
|
||||
if (nfds == 0)
|
||||
return 0;
|
||||
while (poll(pfds, nfds, -1) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
DPERROR("siomix_psleep: poll");
|
||||
hdl->eof = 1;
|
||||
return 0;
|
||||
}
|
||||
revents = siomix_revents(hdl, pfds);
|
||||
if (revents & POLLHUP) {
|
||||
DPRINTF("siomix_psleep: hang-up\n");
|
||||
return 0;
|
||||
}
|
||||
if (event == 0 || (revents & event))
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
siomix_close(struct siomix_hdl *hdl)
|
||||
{
|
||||
hdl->ops->close(hdl);
|
||||
}
|
||||
|
||||
int
|
||||
siomix_nfds(struct siomix_hdl *hdl)
|
||||
{
|
||||
return hdl->ops->nfds(hdl);
|
||||
}
|
||||
|
||||
int
|
||||
siomix_pollfd(struct siomix_hdl *hdl, struct pollfd *pfd, int events)
|
||||
{
|
||||
if (hdl->eof)
|
||||
return 0;
|
||||
return hdl->ops->pollfd(hdl, pfd, events);
|
||||
}
|
||||
|
||||
int
|
||||
siomix_revents(struct siomix_hdl *hdl, struct pollfd *pfd)
|
||||
{
|
||||
if (hdl->eof)
|
||||
return POLLHUP;
|
||||
return hdl->ops->revents(hdl, pfd);
|
||||
}
|
||||
|
||||
int
|
||||
siomix_eof(struct siomix_hdl *hdl)
|
||||
{
|
||||
return hdl->eof;
|
||||
}
|
||||
|
||||
int
|
||||
siomix_ondesc(struct siomix_hdl *hdl,
|
||||
void (*cb)(void *, struct siomix_desc *, int), void *arg)
|
||||
{
|
||||
hdl->desc_cb = cb;
|
||||
hdl->desc_arg = arg;
|
||||
return hdl->ops->ondesc(hdl);
|
||||
}
|
||||
|
||||
int
|
||||
siomix_onctl(struct siomix_hdl *hdl,
|
||||
void (*cb)(void *, unsigned int, unsigned int), void *arg)
|
||||
{
|
||||
hdl->ctl_cb = cb;
|
||||
hdl->ctl_arg = arg;
|
||||
return hdl->ops->onctl(hdl);
|
||||
}
|
||||
|
||||
void
|
||||
_siomix_ondesc_cb(struct siomix_hdl *hdl,
|
||||
struct siomix_desc *desc, unsigned int val)
|
||||
{
|
||||
if (desc) {
|
||||
DPRINTF("%u -> %s[%s].%s=%s[%s]\n",
|
||||
desc->addr,
|
||||
desc->chan0.str, desc->chan0.opt,
|
||||
desc->func,
|
||||
desc->chan1.str, desc->chan1.opt);
|
||||
}
|
||||
if (hdl->desc_cb)
|
||||
hdl->desc_cb(hdl->desc_arg, desc, val);
|
||||
}
|
||||
|
||||
void
|
||||
_siomix_onctl_cb(struct siomix_hdl *hdl, unsigned int addr, unsigned int val)
|
||||
{
|
||||
if (hdl->ctl_cb)
|
||||
hdl->ctl_cb(hdl->ctl_arg, addr, val);
|
||||
}
|
||||
|
||||
int
|
||||
siomix_setctl(struct siomix_hdl *hdl, unsigned int addr, unsigned int val)
|
||||
{
|
||||
if (!(hdl->mode & SIOMIX_WRITE))
|
||||
return 0;
|
||||
return hdl->ops->setctl(hdl, addr, val);
|
||||
}
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2011 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sndio.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "debug.h"
|
||||
#include "aucat.h"
|
||||
#include "siomix_priv.h"
|
||||
#include "bsd-compat.h"
|
||||
|
||||
struct siomix_aucat_hdl {
|
||||
struct siomix_hdl siomix;
|
||||
struct aucat aucat;
|
||||
struct siomix_desc desc;
|
||||
struct amsg_mix_desc *tmp;
|
||||
int dump_wait;
|
||||
};
|
||||
|
||||
static void siomix_aucat_close(struct siomix_hdl *);
|
||||
static int siomix_aucat_nfds(struct siomix_hdl *);
|
||||
static int siomix_aucat_pollfd(struct siomix_hdl *, struct pollfd *, int);
|
||||
static int siomix_aucat_revents(struct siomix_hdl *, struct pollfd *);
|
||||
static int siomix_aucat_setctl(struct siomix_hdl *, unsigned int, unsigned int);
|
||||
static int siomix_aucat_onctl(struct siomix_hdl *);
|
||||
static int siomix_aucat_ondesc(struct siomix_hdl *);
|
||||
|
||||
/*
|
||||
* operations every device should support
|
||||
*/
|
||||
struct siomix_ops siomix_aucat_ops = {
|
||||
siomix_aucat_close,
|
||||
siomix_aucat_nfds,
|
||||
siomix_aucat_pollfd,
|
||||
siomix_aucat_revents,
|
||||
siomix_aucat_setctl,
|
||||
siomix_aucat_onctl,
|
||||
siomix_aucat_ondesc
|
||||
};
|
||||
|
||||
static int
|
||||
siomix_aucat_rdata(struct siomix_aucat_hdl *hdl)
|
||||
{
|
||||
struct siomix_desc desc;
|
||||
struct amsg_mix_desc *c;
|
||||
int n, size;
|
||||
|
||||
size = ntohl(hdl->aucat.rmsg.u.data.size);
|
||||
for (;;) {
|
||||
n = _aucat_rdata(&hdl->aucat,
|
||||
(unsigned char *)hdl->tmp + size - hdl->aucat.rtodo,
|
||||
hdl->aucat.rtodo, &hdl->siomix.eof);
|
||||
if (n == 0 || hdl->siomix.eof)
|
||||
return 0;
|
||||
if (hdl->aucat.rstate != RSTATE_DATA)
|
||||
break;
|
||||
}
|
||||
c = hdl->tmp;
|
||||
while (size >= sizeof(struct amsg_mix_desc)) {
|
||||
strlcpy(desc.chan0.str, c->chan0.str, SIOMIX_NAMEMAX);
|
||||
strlcpy(desc.chan0.opt, c->chan0.opt, SIOMIX_NAMEMAX);
|
||||
strlcpy(desc.chan1.str, c->chan1.str, SIOMIX_NAMEMAX);
|
||||
strlcpy(desc.chan1.opt, c->chan1.opt, SIOMIX_NAMEMAX);
|
||||
strlcpy(desc.func, c->func, SIOMIX_NAMEMAX);
|
||||
desc.type = c->type;
|
||||
desc.addr = ntohs(c->addr);
|
||||
_siomix_ondesc_cb(&hdl->siomix, &desc, ntohs(c->curval));
|
||||
size -= sizeof(struct amsg_mix_desc);
|
||||
c++;
|
||||
}
|
||||
free(hdl->tmp);
|
||||
hdl->dump_wait = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* execute the next message, return 0 if blocked
|
||||
*/
|
||||
static int
|
||||
siomix_aucat_runmsg(struct siomix_aucat_hdl *hdl)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (!_aucat_rmsg(&hdl->aucat, &hdl->siomix.eof))
|
||||
return 0;
|
||||
switch (ntohl(hdl->aucat.rmsg.cmd)) {
|
||||
case AMSG_DATA:
|
||||
size = ntohl(hdl->aucat.rmsg.u.data.size);
|
||||
hdl->tmp = malloc(size);
|
||||
if (hdl->tmp == NULL) {
|
||||
DPRINTF("siomix_aucat_runmsg: malloc failed\n");
|
||||
hdl->siomix.eof = 1;
|
||||
return 0;
|
||||
}
|
||||
if (!siomix_aucat_rdata(hdl))
|
||||
return 0;
|
||||
break;
|
||||
case AMSG_MIXSET:
|
||||
DPRINTF("siomix_aucat_runmsg: got MIXSET\n");
|
||||
_siomix_onctl_cb(&hdl->siomix,
|
||||
ntohs(hdl->aucat.rmsg.u.mixset.addr),
|
||||
ntohs(hdl->aucat.rmsg.u.mixset.val));
|
||||
break;
|
||||
default:
|
||||
DPRINTF("sio_aucat_runmsg: unhandled message %u\n",
|
||||
hdl->aucat.rmsg.cmd);
|
||||
hdl->siomix.eof = 1;
|
||||
return 0;
|
||||
}
|
||||
hdl->aucat.rstate = RSTATE_MSG;
|
||||
hdl->aucat.rtodo = sizeof(struct amsg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct siomix_hdl *
|
||||
_siomix_aucat_open(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
struct siomix_aucat_hdl *hdl;
|
||||
|
||||
hdl = malloc(sizeof(struct siomix_aucat_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
if (!_aucat_open(&hdl->aucat, str, mode, 0)) {
|
||||
free(hdl);
|
||||
return NULL;
|
||||
}
|
||||
_siomix_create(&hdl->siomix, &siomix_aucat_ops, mode, nbio);
|
||||
hdl->tmp = NULL;
|
||||
hdl->dump_wait = 0;
|
||||
return (struct siomix_hdl *)hdl;
|
||||
}
|
||||
|
||||
static void
|
||||
siomix_aucat_close(struct siomix_hdl *addr)
|
||||
{
|
||||
struct siomix_aucat_hdl *hdl = (struct siomix_aucat_hdl *)addr;
|
||||
|
||||
_aucat_close(&hdl->aucat, hdl->siomix.eof);
|
||||
free(hdl);
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_aucat_ondesc(struct siomix_hdl *addr)
|
||||
{
|
||||
struct siomix_aucat_hdl *hdl = (struct siomix_aucat_hdl *)addr;
|
||||
|
||||
while (hdl->aucat.wstate != WSTATE_IDLE) {
|
||||
if (!_siomix_psleep(&hdl->siomix, POLLOUT))
|
||||
return 0;
|
||||
}
|
||||
AMSG_INIT(&hdl->aucat.wmsg);
|
||||
hdl->aucat.wmsg.cmd = htonl(AMSG_MIXSUB);
|
||||
hdl->aucat.wmsg.u.mixsub.desc = 1;
|
||||
hdl->aucat.wmsg.u.mixsub.val = 0;
|
||||
hdl->aucat.wtodo = sizeof(struct amsg);
|
||||
if (!_aucat_wmsg(&hdl->aucat, &hdl->siomix.eof))
|
||||
return 0;
|
||||
hdl->dump_wait = 1;
|
||||
while (hdl->dump_wait) {
|
||||
DPRINTF("psleeping...\n");
|
||||
if (!_siomix_psleep(&hdl->siomix, 0))
|
||||
return 0;
|
||||
DPRINTF("psleeping done\n");
|
||||
}
|
||||
DPRINTF("done\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_aucat_onctl(struct siomix_hdl *addr)
|
||||
{
|
||||
struct siomix_aucat_hdl *hdl = (struct siomix_aucat_hdl *)addr;
|
||||
|
||||
while (hdl->aucat.wstate != WSTATE_IDLE) {
|
||||
if (!_siomix_psleep(&hdl->siomix, POLLOUT))
|
||||
return 0;
|
||||
}
|
||||
AMSG_INIT(&hdl->aucat.wmsg);
|
||||
hdl->aucat.wmsg.cmd = htonl(AMSG_MIXSUB);
|
||||
hdl->aucat.wmsg.u.mixsub.desc = 1;
|
||||
hdl->aucat.wmsg.u.mixsub.val = 1;
|
||||
hdl->aucat.wtodo = sizeof(struct amsg);
|
||||
if (!_aucat_wmsg(&hdl->aucat, &hdl->siomix.eof))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_aucat_setctl(struct siomix_hdl *addr, unsigned int a, unsigned int v)
|
||||
{
|
||||
struct siomix_aucat_hdl *hdl = (struct siomix_aucat_hdl *)addr;
|
||||
|
||||
hdl->aucat.wstate = WSTATE_MSG;
|
||||
hdl->aucat.wtodo = sizeof(struct amsg);
|
||||
hdl->aucat.wmsg.cmd = htonl(AMSG_MIXSET);
|
||||
hdl->aucat.wmsg.u.mixset.addr = htons(a);
|
||||
hdl->aucat.wmsg.u.mixset.val = htons(v);
|
||||
return _aucat_wmsg(&hdl->aucat, &hdl->siomix.eof);
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_aucat_nfds(struct siomix_hdl *addr)
|
||||
{
|
||||
//struct siomix_aucat_hdl *hdl = (struct siomix_aucat_hdl *)addr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_aucat_pollfd(struct siomix_hdl *addr, struct pollfd *pfd, int events)
|
||||
{
|
||||
struct siomix_aucat_hdl *hdl = (struct siomix_aucat_hdl *)addr;
|
||||
|
||||
return _aucat_pollfd(&hdl->aucat, pfd, events | POLLIN);
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_aucat_revents(struct siomix_hdl *addr, struct pollfd *pfd)
|
||||
{
|
||||
struct siomix_aucat_hdl *hdl = (struct siomix_aucat_hdl *)addr;
|
||||
int revents;
|
||||
|
||||
revents = _aucat_revents(&hdl->aucat, pfd);
|
||||
if (revents & POLLIN) {
|
||||
do {
|
||||
if (hdl->aucat.rstate == RSTATE_MSG) {
|
||||
if (!siomix_aucat_runmsg(hdl))
|
||||
break;
|
||||
}
|
||||
if (hdl->aucat.rstate == RSTATE_DATA) {
|
||||
if (!siomix_aucat_rdata(hdl))
|
||||
break;
|
||||
}
|
||||
} while (0);
|
||||
revents &= ~POLLIN;
|
||||
}
|
||||
if (hdl->siomix.eof)
|
||||
return POLLHUP;
|
||||
DPRINTFN(3, "siomix_aucat_revents: revents = 0x%x\n", revents);
|
||||
return revents;
|
||||
}
|
|
@ -1,261 +0,0 @@
|
|||
.\" $OpenBSD$
|
||||
.\"
|
||||
.\" Copyright (c) 2011 Alexandre Ratchov <alex@caoua.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: September 29 2012 $
|
||||
.Dt SIO_OPEN 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm siomix_open ,
|
||||
.Nm siomix_close ,
|
||||
.Nm siomix_ondesc ,
|
||||
.Nm siomix_onctl ,
|
||||
.Nm siomix_setctl ,
|
||||
.Nm siomix_nfds ,
|
||||
.Nm siomix_pollfd ,
|
||||
.Nm siomix_eof
|
||||
.Nd interface to audio mixer
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <sndio.h>
|
||||
.Ft "struct siomix_hdl *"
|
||||
.Fn "siomix_open" "const char *name" "unsigned int mode" "int nbio_flag"
|
||||
.Ft "void"
|
||||
.Fn "siomix_close" "struct siomix_hdl *hdl"
|
||||
.Ft "int"
|
||||
.Fn "siomix_ondesc" "struct siomix_hdl *hdl" "void (*cb)(void *arg, struct siomix_desc *desc, int val)" "void *arg"
|
||||
.Ft "void"
|
||||
.Fn "siomix_onctl" "struct siomix_hdl *hdl" "void (*cb)(void *arg, unsigned int addr, unsigned int val)" "void *arg"
|
||||
.Ft "int"
|
||||
.Fn "siomix_setctl" "struct siomix_hdl *hdl" "unsigned int addr" "unsigned int val"
|
||||
.Ft "int"
|
||||
.Fn "siomix_nfds" "struct siomix_hdl *hdl"
|
||||
.Ft "int"
|
||||
.Fn "siomix_pollfd" "struct siomix_hdl *hdl" "struct pollfd *pfd" "int events"
|
||||
.Ft "int"
|
||||
.Fn "siomix_revents" "struct siomix_hdl *hdl" "struct pollfd *pfd"
|
||||
.Ft "int"
|
||||
.Fn "siomix_eof" "struct siomix_hdl *hdl"
|
||||
.Sh DESCRIPTION
|
||||
The audio mixer of a sound device is the set of available controls,
|
||||
e.g. the volume control.
|
||||
Each control has an integer
|
||||
.Em address
|
||||
and an integer
|
||||
.Em value .
|
||||
Depending on the control type, its integer value represents either a
|
||||
continuous quantity or a boolean.
|
||||
Any control may be changed by submitting
|
||||
a new value to its address.
|
||||
When values change, asynchronous notifications are sent.
|
||||
.Pp
|
||||
Controls descriptions are available, allowing them to be grouped and
|
||||
represented in a human usable form.
|
||||
.Sh Opening and closing the mixer
|
||||
First the application must call the
|
||||
.Fn siomix_open
|
||||
function to obtain a handle
|
||||
that will be passed as the
|
||||
.Ar hdl
|
||||
argument to other functions.
|
||||
.Pp
|
||||
The
|
||||
.Ar name
|
||||
parameter gives the device string discussed in
|
||||
.Xr sndio 7 .
|
||||
In most cases it should be set to SIOMIX_DEVANY to allow
|
||||
the user to select it using the
|
||||
.Ev AUDIODEVICE
|
||||
environment variable.
|
||||
The
|
||||
.Ar mode
|
||||
parameter is a bitmap of the SIOMIX_READ and SIOMIX_WRITE constants
|
||||
indicating whether control values can be read and
|
||||
modified respectively.
|
||||
.Pp
|
||||
If the
|
||||
.Ar nbio_flag
|
||||
argument is 1, then the
|
||||
.Fn siomix_setctl
|
||||
function (see below) may fail instead of blocking and
|
||||
the
|
||||
.Fn siomix_ondesc
|
||||
function doesn't block.
|
||||
.Pp
|
||||
The
|
||||
.Fn siomix_close
|
||||
function closes the mixer and frees any allocated resources
|
||||
associated with the handle.
|
||||
.Sh Mixer description
|
||||
The
|
||||
.Fn siomix_ondesc
|
||||
function can be used to obtain the description of all available mixer controls
|
||||
and their initial values.
|
||||
It registers a call-back that is immediately invoked for all
|
||||
controls.
|
||||
It's called once with a NULL argument to indicate that the full
|
||||
description was sent and that the caller has a consistent
|
||||
representation of the mixer.
|
||||
.Pp
|
||||
Then, whenever a mixer control description changes (currently only
|
||||
label strings may change, see below), the call-back is invoked with the
|
||||
updated information followed by a call with a NULL argument.
|
||||
.Pp
|
||||
Controls are described by the
|
||||
.Va siomix_ondesc
|
||||
stucture as follows:
|
||||
.Bd -literal
|
||||
struct siomix_chan {
|
||||
char str[SIOMIX_NAMEMAX]; /* stream name */
|
||||
char opt[SIOMIX_NAMEMAX]; /* optional channel */
|
||||
};
|
||||
|
||||
struct siomix_desc {
|
||||
unsigned int addr; /* control's address */
|
||||
#define SIOMIX_NUM 2 /* number in the 0..127 range */
|
||||
#define SIOMIX_SW 3 /* on/off switch */
|
||||
#define SIOMIX_VEC 4 /* element of array of numbers */
|
||||
#define SIOMIX_LIST 5 /* element of array of switches */
|
||||
#define SIOMIX_LABEL 6 /* string attached to chan0 */
|
||||
unsigned int type; /* one of above */
|
||||
char func[SIOMIX_NAMEMAX]; /* parameter group name */
|
||||
struct siomix_chan chan0; /* affected channels */
|
||||
struct siomix_chan chan1; /* dito for vec, and list */
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Va addr
|
||||
attribute is the mixer control address, usable with
|
||||
.Fn siomix_setval
|
||||
to set its value.
|
||||
.Pp
|
||||
The
|
||||
.Va type
|
||||
attribute indicates what the structure describes.
|
||||
Possible types are:
|
||||
.Bl -tag -width "SIOMIX_LABEL"
|
||||
.It SIOMIX_NUM
|
||||
A continuous control in the 0..SIOMIX_INTMAX range.
|
||||
For instance the volume of the speaker.
|
||||
.It SIOMIX_SW
|
||||
A on/off switch control.
|
||||
For instance the switch to mute the speaker.
|
||||
.It SIOMIX_VEC
|
||||
Element of an array of continuous controls.
|
||||
For instance the knob to control the amount of signal flowing
|
||||
from the line input to the speaker.
|
||||
.It SIOMIX_LIST
|
||||
An element of an array of on/off switches.
|
||||
For instance the line-in position of the
|
||||
speaker source selector.
|
||||
.It SIOMIX_LABEL
|
||||
A label attached to the channel.
|
||||
In mixers exposed by
|
||||
.Xr sndiod 1 ,
|
||||
they correspond to program names.
|
||||
The label string is stored in the
|
||||
.Va chan1
|
||||
attribute and is not unique.
|
||||
Labels may dynamically change, but their
|
||||
.Va addr
|
||||
attribute remains the same and can be used to figure out which
|
||||
label is changing.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Va func
|
||||
attribute is the name of the parameter being controlled.
|
||||
There may be no parameters of different types with the same name.
|
||||
.Pp
|
||||
The
|
||||
.Va chan0
|
||||
and
|
||||
.Va chan1
|
||||
attributes indicate the names of the affected streams, and
|
||||
an optional channel sub-set.
|
||||
.Va chan1
|
||||
is meaningful for
|
||||
.Va SIOMIX_VEC
|
||||
and
|
||||
.Va SIOMIX_LIST
|
||||
only.
|
||||
.Pp
|
||||
Stream names in the
|
||||
.Va chan0
|
||||
and
|
||||
.Va chan1
|
||||
attributes and
|
||||
.Va func
|
||||
are static strings usable as unique identifiers.
|
||||
.Sh Changing and reading control values
|
||||
Controls are changed with the
|
||||
.Fn siomix_setctl
|
||||
function, by giving the index of the control and the new value.
|
||||
The
|
||||
.Fn siomix_onctl
|
||||
function can be used to register a call-back which will be invoked whenever
|
||||
a control changes.
|
||||
Continuous values are in the 0..127 range.
|
||||
.Sh "Interface to" Xr poll 2
|
||||
The
|
||||
.Fn siomix_pollfd
|
||||
function fills the array
|
||||
.Ar pfd
|
||||
of
|
||||
.Va pollfd
|
||||
structures, used by
|
||||
.Xr poll 2 ,
|
||||
with
|
||||
.Ar events ;
|
||||
the latter is a bit-mask of
|
||||
.Va POLLIN
|
||||
and
|
||||
.Va POLLOUT
|
||||
constants.
|
||||
.Fn siomix_pollfd
|
||||
returns the number of
|
||||
.Va pollfd
|
||||
structures filled.
|
||||
The
|
||||
.Fn siomix_revents
|
||||
function returns the bit-mask set by
|
||||
.Xr poll 2
|
||||
in the
|
||||
.Va pfd
|
||||
array of
|
||||
.Va pollfd
|
||||
structures.
|
||||
If
|
||||
.Va POLLOUT
|
||||
is set,
|
||||
.Fn siomix_setctl
|
||||
can be called without blocking.
|
||||
POLLHUP may be set if an error occurs, even if
|
||||
it is not selected with
|
||||
.Fn siomix_pollfd .
|
||||
POLLIN is not used yet.
|
||||
.Pp
|
||||
The
|
||||
.Fn siomix_nfds
|
||||
function returns the number of
|
||||
.Va pollfd
|
||||
structures the caller must preallocate in order to be sure
|
||||
that
|
||||
.Fn siomix_pollfd
|
||||
will never overrun.
|
||||
.Sh SEE ALSO
|
||||
.Xr sndioctl 1 ,
|
||||
.Xr poll 2 ,
|
||||
.Xr sndio 7
|
|
@ -1,67 +0,0 @@
|
|||
/* $OpenBSD$ */
|
||||
/*
|
||||
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef SIOMIX_PRIV_H
|
||||
#define SIOMIX_PRIV_H
|
||||
|
||||
#include <sndio.h>
|
||||
|
||||
#define SIOMIX_MAXNFDS 4
|
||||
|
||||
/*
|
||||
* private ``handle'' structure
|
||||
*/
|
||||
struct siomix_hdl {
|
||||
struct siomix_ops *ops;
|
||||
void (*desc_cb)(void *, struct siomix_desc *, int);
|
||||
void *desc_arg;
|
||||
void (*ctl_cb)(void *, unsigned int, unsigned int);
|
||||
void *ctl_arg;
|
||||
unsigned int mode; /* SIOMIX_READ | SIOMIX_WRITE */
|
||||
int nbio; /* true if non-blocking io */
|
||||
int eof; /* true if error occured */
|
||||
};
|
||||
|
||||
/*
|
||||
* operations every device should support
|
||||
*/
|
||||
struct siomix_ops {
|
||||
void (*close)(struct siomix_hdl *);
|
||||
int (*nfds)(struct siomix_hdl *);
|
||||
int (*pollfd)(struct siomix_hdl *, struct pollfd *, int);
|
||||
int (*revents)(struct siomix_hdl *, struct pollfd *);
|
||||
int (*setctl)(struct siomix_hdl *, unsigned int, unsigned int);
|
||||
int (*onctl)(struct siomix_hdl *);
|
||||
int (*ondesc)(struct siomix_hdl *);
|
||||
};
|
||||
|
||||
struct siomix_hdl *_siomix_aucat_open(const char *, unsigned int, int);
|
||||
struct siomix_hdl *_siomix_obsd_open(const char *, unsigned int, int);
|
||||
struct siomix_hdl *_siomix_fake_open(const char *, unsigned int, int);
|
||||
#ifdef USE_SUN_MIXER
|
||||
struct siomix_hdl *_siomix_sun_open(const char *, unsigned int, int);
|
||||
#endif
|
||||
#ifdef USE_ALSA_MIXER
|
||||
struct siomix_hdl *_siomix_alsa_open(const char *, unsigned int, int);
|
||||
#endif
|
||||
void _siomix_create(struct siomix_hdl *,
|
||||
struct siomix_ops *, unsigned int, int);
|
||||
void _siomix_ondesc_cb(struct siomix_hdl *,
|
||||
struct siomix_desc *, unsigned int);
|
||||
void _siomix_onctl_cb(struct siomix_hdl *, unsigned int, unsigned int);
|
||||
int _siomix_psleep(struct siomix_hdl *, int);
|
||||
|
||||
#endif /* !defined(SIOMIX_PRIV_H) */
|
|
@ -1,573 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2011 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* TODO
|
||||
* - fix ac97 based mixers
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef USE_SUN_MIXER
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/audioio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <sndio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "debug.h"
|
||||
#include "siomix_priv.h"
|
||||
|
||||
struct siomix_sun_hdl {
|
||||
struct siomix_hdl siomix;
|
||||
struct mixer_devinfo *info;
|
||||
struct mixer_ctrl *curval;
|
||||
int fd, ninfo, events;
|
||||
int iclass, oclass, rclass;
|
||||
};
|
||||
|
||||
static void siomix_sun_close(struct siomix_hdl *);
|
||||
static int siomix_sun_nfds(struct siomix_hdl *);
|
||||
static int siomix_sun_pollfd(struct siomix_hdl *, struct pollfd *, int);
|
||||
static int siomix_sun_revents(struct siomix_hdl *, struct pollfd *);
|
||||
static int siomix_sun_setctl(struct siomix_hdl *, unsigned int, unsigned int);
|
||||
static int siomix_sun_onctl(struct siomix_hdl *);
|
||||
static int siomix_sun_ondesc(struct siomix_hdl *);
|
||||
|
||||
/*
|
||||
* operations every device should support
|
||||
*/
|
||||
struct siomix_ops siomix_sun_ops = {
|
||||
siomix_sun_close,
|
||||
siomix_sun_nfds,
|
||||
siomix_sun_pollfd,
|
||||
siomix_sun_revents,
|
||||
siomix_sun_setctl,
|
||||
siomix_sun_onctl,
|
||||
siomix_sun_ondesc
|
||||
};
|
||||
|
||||
struct siomix_hdl *
|
||||
_siomix_sun_open(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
struct siomix_sun_hdl *hdl;
|
||||
int i, fd, flags;
|
||||
char path[PATH_MAX];
|
||||
struct mixer_devinfo mi;
|
||||
|
||||
if (*str != '/') {
|
||||
DPRINTF("siomix_sun_open: %s: '/<devnum>' expected\n", str);
|
||||
return NULL;
|
||||
}
|
||||
str++;
|
||||
hdl = malloc(sizeof(struct siomix_sun_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
_siomix_create(&hdl->siomix, &siomix_sun_ops, mode, nbio);
|
||||
snprintf(path, sizeof(path), "/dev/mixer%s", str);
|
||||
if (mode == (SIOMIX_READ | SIOMIX_WRITE))
|
||||
flags = O_RDWR;
|
||||
else
|
||||
flags = (mode & SIOMIX_WRITE) ? O_WRONLY : O_RDONLY;
|
||||
|
||||
while ((fd = open(path, flags)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
DPERROR(path);
|
||||
goto bad_free;
|
||||
}
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
DPERROR("FD_CLOEXEC");
|
||||
goto bad_close;
|
||||
}
|
||||
hdl->iclass = hdl->oclass = hdl->rclass = -1;
|
||||
hdl->fd = fd;
|
||||
|
||||
/*
|
||||
* count the number of mixer knobs, and fetch the full mixer
|
||||
* description
|
||||
*/
|
||||
for (mi.index = 0; ; mi.index++) {
|
||||
if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
|
||||
break;
|
||||
}
|
||||
hdl->ninfo = mi.index;
|
||||
hdl->info = malloc(hdl->ninfo * sizeof(struct mixer_devinfo));
|
||||
if (hdl->info == NULL) {
|
||||
DPERROR("malloc");
|
||||
goto bad_close;
|
||||
}
|
||||
hdl->curval = malloc(hdl->ninfo * sizeof(struct mixer_ctrl));
|
||||
if (hdl->curval == NULL) {
|
||||
DPERROR("malloc");
|
||||
goto bad_freeinfo;
|
||||
}
|
||||
for (i = 0; i < hdl->ninfo; i++) {
|
||||
hdl->info[i].index = i;
|
||||
if (ioctl(fd, AUDIO_MIXER_DEVINFO, &hdl->info[i]) < 0) {
|
||||
DPERROR("AUDIO_MIXER_DEVINFO");
|
||||
goto bad_freeval;
|
||||
}
|
||||
}
|
||||
return (struct siomix_hdl *)hdl;
|
||||
bad_freeval:
|
||||
free(hdl->curval);
|
||||
bad_freeinfo:
|
||||
free(hdl->info);
|
||||
bad_close:
|
||||
close(fd);
|
||||
bad_free:
|
||||
free(hdl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
siomix_sun_close(struct siomix_hdl *addr)
|
||||
{
|
||||
struct siomix_sun_hdl *hdl = (struct siomix_sun_hdl *)addr;
|
||||
|
||||
close(hdl->fd);
|
||||
free(hdl);
|
||||
}
|
||||
|
||||
/*
|
||||
* parse foo-4:5 and convert it to "foo", 4, 2
|
||||
*/
|
||||
static int
|
||||
copy_ch(struct siomix_sun_hdl *hdl,
|
||||
int icls, char *istr, char *ostr, int *rmin, int *rnum)
|
||||
{
|
||||
size_t len;
|
||||
char *sep, *endp;
|
||||
long cmin, cmax;
|
||||
|
||||
ostr[0] = 0;
|
||||
|
||||
sep = strchr(istr, '-');
|
||||
if (sep) {
|
||||
len = sep - istr;
|
||||
if (len >= SIOMIX_NAMEMAX - 1)
|
||||
return 0;
|
||||
memcpy(ostr, istr, len);
|
||||
ostr[len] = 0;
|
||||
istr = sep + 1;
|
||||
|
||||
cmin = strtol(istr, &endp, 10);
|
||||
if (endp != istr) {
|
||||
/*
|
||||
* this a "foo-0:3" style range
|
||||
*/
|
||||
istr = endp;
|
||||
if (*endp == ':') {
|
||||
istr++;
|
||||
cmax = strtol(istr, &endp, 10);
|
||||
if (endp == istr) {
|
||||
DPRINTF("bad range\n");
|
||||
return 0;
|
||||
}
|
||||
istr = endp;
|
||||
} else if (*endp == 0) {
|
||||
cmax = cmin;
|
||||
} else {
|
||||
DPRINTF("unknown range\n");
|
||||
return 0;
|
||||
}
|
||||
*rmin = cmin;
|
||||
*rnum = cmax - cmin + 1;
|
||||
} else {
|
||||
if (strcmp(ostr, "line") == 0) {
|
||||
/* rename make "line-foo" to "foo" */
|
||||
ostr[0] = 0;
|
||||
} else {
|
||||
/* append unknown suffix with '_' */
|
||||
strlcat(ostr, "_", SIOMIX_NAMEMAX);
|
||||
}
|
||||
strlcat(ostr, istr, SIOMIX_NAMEMAX);
|
||||
*rmin = 0;
|
||||
*rnum = 0;
|
||||
}
|
||||
} else {
|
||||
*rmin = 0;
|
||||
*rnum = 0;
|
||||
strlcpy(ostr, istr, SIOMIX_NAMEMAX);
|
||||
}
|
||||
if (icls == -1)
|
||||
return 1;
|
||||
/*
|
||||
* append "_in" and "_out" suffixes, as nowadays
|
||||
* most jacks are bidirectional
|
||||
*/
|
||||
if (strcmp(ostr, "mic") == 0 ||
|
||||
strcmp(ostr, "spkr") == 0 ||
|
||||
strcmp(ostr, "hp") == 0 ||
|
||||
strcmp(ostr, "line") == 0) {
|
||||
if (icls == hdl->iclass)
|
||||
strlcat(ostr, "_in", SIOMIX_NAMEMAX);
|
||||
if (icls == hdl->oclass)
|
||||
strlcat(ostr, "_out", SIOMIX_NAMEMAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* record class may conflict with input/output
|
||||
*/
|
||||
if (icls == hdl->rclass) {
|
||||
if (strcmp(ostr, "volume") == 0)
|
||||
strlcpy(ostr, "rec", SIOMIX_NAMEMAX);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
make_opt(char *opt, int min, int num)
|
||||
{
|
||||
switch (num) {
|
||||
case 0:
|
||||
opt[0] = 0;
|
||||
break;
|
||||
case 1:
|
||||
snprintf(opt, SIOMIX_NAMEMAX, "%u", min);
|
||||
break;
|
||||
default:
|
||||
snprintf(opt, SIOMIX_NAMEMAX, "%u-%u", min, min + num - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
copyname_num(struct siomix_sun_hdl *hdl,
|
||||
struct mixer_devinfo *info, struct siomix_desc *desc, int *rmin, int *rnum)
|
||||
{
|
||||
size_t len;
|
||||
char *sep, *istr;
|
||||
|
||||
sep = strchr(info->label.name, '_');
|
||||
if (sep) {
|
||||
strlcpy(desc->func, "mix", SIOMIX_NAMEMAX);
|
||||
desc->type = SIOMIX_VEC;
|
||||
len = sep - info->label.name;
|
||||
if (len >= SIOMIX_NAMEMAX - 1)
|
||||
return 0;
|
||||
memcpy(desc->chan0.str, info->label.name, len);
|
||||
desc->chan0.str[len] = 0;
|
||||
istr = sep + 1;
|
||||
if (!copy_ch(hdl, info->mixer_class, istr,
|
||||
desc->chan1.str, rmin, rnum))
|
||||
return 0;
|
||||
} else {
|
||||
strlcpy(desc->func, "level", SIOMIX_NAMEMAX);
|
||||
desc->type = SIOMIX_NUM;
|
||||
istr = info->label.name;
|
||||
if (!copy_ch(hdl, info->mixer_class, istr,
|
||||
desc->chan0.str, rmin, rnum))
|
||||
return 0;
|
||||
desc->chan1.str[0] = '\0';
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
copyname_enum(struct siomix_sun_hdl *hdl,
|
||||
struct mixer_devinfo *info, struct siomix_desc *desc, int *rmin, int *rnum)
|
||||
{
|
||||
char istr[SIOMIX_NAMEMAX], *sep;
|
||||
size_t len;
|
||||
|
||||
sep = strrchr(info->label.name, '.');
|
||||
if (sep == NULL)
|
||||
sep = strrchr(info->label.name, '_');
|
||||
if (sep == NULL) {
|
||||
if (info->prev < 0) {
|
||||
fprintf(stderr, "no separator\n");
|
||||
return 0;
|
||||
}
|
||||
strlcpy(desc->func, info->label.name, SIOMIX_NAMEMAX);
|
||||
while (info->prev >= 0)
|
||||
info = hdl->info + info->prev;
|
||||
if (!copy_ch(hdl, info->mixer_class, info->label.name,
|
||||
desc->chan0.str, rmin, rnum))
|
||||
return 0;
|
||||
desc->chan1.str[0] = 0;
|
||||
} else {
|
||||
strlcpy(desc->func, sep + 1, SIOMIX_NAMEMAX);
|
||||
len = sep - info->label.name;
|
||||
if (len >= SIOMIX_NAMEMAX - 1)
|
||||
return 0;
|
||||
memcpy(istr, info->label.name, len);
|
||||
istr[len] = '\0';
|
||||
if (!copy_ch(hdl, info->mixer_class, istr,
|
||||
desc->chan0.str, rmin, rnum))
|
||||
return 0;
|
||||
desc->chan1.str[0] = 0;
|
||||
}
|
||||
/*
|
||||
* certain cards expose adc[0-1].source and adc[2-3].source
|
||||
* as different types, which we forbid.
|
||||
*/
|
||||
if (strcmp(desc->func, "source") == 0) {
|
||||
if (info->type == AUDIO_MIXER_SET)
|
||||
strlcpy(desc->func, "sources", SIOMIX_NAMEMAX);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ord_to_num(struct mixer_devinfo *info, int ord)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < info->un.e.num_mem; i++) {
|
||||
if (ord == info->un.e.member[i].ord)
|
||||
return i;
|
||||
}
|
||||
DPRINTF("mixer bug: order not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mask_to_bit(struct mixer_devinfo *info, int index, int val)
|
||||
{
|
||||
int mask;
|
||||
|
||||
mask = info->un.s.member[index].mask;
|
||||
if ((mask & val) == mask)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
enum_to_sw(struct mixer_devinfo *info, struct siomix_desc *desc)
|
||||
{
|
||||
char *v0, *v1;
|
||||
|
||||
if (info->un.e.num_mem != 2)
|
||||
return 0;
|
||||
v0 = info->un.e.member[ord_to_num(info, 0)].label.name;
|
||||
v1 = info->un.e.member[ord_to_num(info, 1)].label.name;
|
||||
if (strcmp(v0, "off") == 0 && strcmp(v1, "on") == 0)
|
||||
goto make_sw;
|
||||
if (strcmp(v0, "unplugged") == 0 && strcmp(v1, "plugged") == 0) {
|
||||
strlcpy(desc->func,
|
||||
info->un.e.member[1].label.name,
|
||||
SIOMIX_NAMEMAX);
|
||||
goto make_sw;
|
||||
}
|
||||
return 0;
|
||||
make_sw:
|
||||
desc->chan1.str[0] = 0;
|
||||
desc->chan1.opt[0] = 0;
|
||||
desc->type = SIOMIX_SW;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_sun_ondesc(struct siomix_hdl *addr)
|
||||
{
|
||||
struct siomix_sun_hdl *hdl = (struct siomix_sun_hdl *)addr;
|
||||
struct mixer_devinfo *info;
|
||||
struct mixer_ctrl *ctrl;
|
||||
struct siomix_desc desc;
|
||||
char *ostr;
|
||||
int i, j, v, cmin, cnum;
|
||||
|
||||
for (i = 0; i < hdl->ninfo; i++) {
|
||||
info = hdl->info + i;
|
||||
ctrl = hdl->curval + i;
|
||||
ctrl->dev = i;
|
||||
ctrl->type = info->type;
|
||||
if (ctrl->type == AUDIO_MIXER_CLASS) {
|
||||
if (strcmp(info->label.name, "inputs") == 0)
|
||||
hdl->iclass = i;
|
||||
if (strcmp(info->label.name, "outputs") == 0)
|
||||
hdl->oclass = i;
|
||||
if (strcmp(info->label.name, "record") == 0)
|
||||
hdl->rclass = i;
|
||||
continue;
|
||||
}
|
||||
if (ctrl->type == AUDIO_MIXER_VALUE)
|
||||
ctrl->un.value.num_channels = info->un.v.num_channels;
|
||||
if (ioctl(hdl->fd, AUDIO_MIXER_READ, ctrl) < 0) {
|
||||
DPERROR("AUDIO_MIXER_READ");
|
||||
hdl->siomix.eof = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
info = hdl->info;
|
||||
for (i = 0; i < hdl->ninfo; i++) {
|
||||
DPRINTF("psarsing \"%s\"\n", info->label.name);
|
||||
switch (info->type) {
|
||||
case AUDIO_MIXER_VALUE:
|
||||
desc.addr = i * 32;
|
||||
if (!copyname_num(hdl, info, &desc, &cmin, &cnum))
|
||||
return 0;
|
||||
make_opt(desc.chan0.opt, cmin, cnum);
|
||||
desc.chan1.opt[0] = 0;
|
||||
for (j = 0; j < info->un.v.num_channels; j++) {
|
||||
v = hdl->curval[i].un.value.level[j] *
|
||||
127 / 255;
|
||||
ostr = desc.type == SIOMIX_NUM ?
|
||||
desc.chan0.opt : desc.chan1.opt;
|
||||
if (info->un.v.num_channels > 1) {
|
||||
make_opt(ostr, cmin + j, 1);
|
||||
} else {
|
||||
make_opt(ostr, cmin, cnum);
|
||||
}
|
||||
_siomix_ondesc_cb(&hdl->siomix, &desc, v);
|
||||
desc.addr++;
|
||||
}
|
||||
break;
|
||||
case AUDIO_MIXER_ENUM:
|
||||
desc.addr = i * 32;
|
||||
if (info->un.e.num_mem <= 1)
|
||||
break;
|
||||
if (!copyname_enum(hdl, info, &desc, &cmin, &cnum))
|
||||
return 0;
|
||||
if (enum_to_sw(info, &desc)) {
|
||||
make_opt(desc.chan0.opt, cmin, cnum);
|
||||
_siomix_ondesc_cb(&hdl->siomix, &desc,
|
||||
ord_to_num(info, hdl->curval[i].un.ord));
|
||||
break;
|
||||
}
|
||||
for (j = 0; j < info->un.e.num_mem; j++) {
|
||||
if (!copyname_enum(hdl, info,
|
||||
&desc, &cmin, &cnum))
|
||||
return 0;
|
||||
make_opt(desc.chan0.opt, cmin, cnum);
|
||||
if (!copy_ch(hdl, info->mixer_class,
|
||||
info->un.e.member[j].label.name,
|
||||
desc.chan1.str, &cmin, &cnum))
|
||||
return 0;
|
||||
make_opt(desc.chan1.opt, cmin, cnum);
|
||||
desc.type = SIOMIX_LIST;
|
||||
v = (j == ord_to_num(info,
|
||||
hdl->curval[i].un.ord)) ? 1 : 0;
|
||||
_siomix_ondesc_cb(&hdl->siomix, &desc, v);
|
||||
desc.addr++;
|
||||
}
|
||||
break;
|
||||
case AUDIO_MIXER_SET:
|
||||
desc.addr = i * 32;
|
||||
if (info->un.s.num_mem == 0)
|
||||
break;
|
||||
if (!copyname_enum(hdl, info, &desc, &cmin, &cnum))
|
||||
return 0;
|
||||
make_opt(desc.chan0.opt, cmin, cnum);
|
||||
desc.type = SIOMIX_LIST;
|
||||
for (j = 0; j < info->un.s.num_mem; j++) {
|
||||
if (!copy_ch(hdl, info->mixer_class,
|
||||
info->un.s.member[j].label.name,
|
||||
desc.chan1.str, &cmin, &cnum))
|
||||
return 0;
|
||||
make_opt(desc.chan1.opt, cmin, cnum);
|
||||
_siomix_ondesc_cb(&hdl->siomix, &desc,
|
||||
mask_to_bit(info, j,
|
||||
hdl->curval[i].un.mask));
|
||||
desc.addr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
info++;
|
||||
}
|
||||
_siomix_ondesc_cb(&hdl->siomix, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_sun_onctl(struct siomix_hdl *addr)
|
||||
{
|
||||
//struct siomix_sun_hdl *hdl = (struct siomix_sun_hdl *)addr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_sun_setctl(struct siomix_hdl *arg, unsigned int addr, unsigned int val)
|
||||
{
|
||||
struct siomix_sun_hdl *hdl = (struct siomix_sun_hdl *)arg;
|
||||
struct mixer_ctrl *ctrl;
|
||||
struct mixer_devinfo *info;
|
||||
int base, offs, oldv;
|
||||
|
||||
DPRINTF("siomix_sun_setctl: %d set to %d\n", addr, val);
|
||||
base = addr / 32;
|
||||
offs = addr % 32;
|
||||
ctrl = hdl->curval + base;
|
||||
info = hdl->info + base;
|
||||
|
||||
switch (ctrl->type) {
|
||||
case AUDIO_MIXER_VALUE:
|
||||
oldv = ctrl->un.value.level[offs];
|
||||
ctrl->un.value.level[offs] = (val * 255 + 63) / 127;
|
||||
break;
|
||||
case AUDIO_MIXER_ENUM:
|
||||
if (val == 0)
|
||||
return 1;
|
||||
oldv = ord_to_num(info, ctrl->un.ord);
|
||||
if (oldv == offs)
|
||||
return 1;
|
||||
_siomix_onctl_cb(&hdl->siomix, 32 * base + oldv, 0);
|
||||
ctrl->un.ord = info->un.e.member[offs].ord;
|
||||
break;
|
||||
case AUDIO_MIXER_SET:
|
||||
if (val)
|
||||
ctrl->un.mask |= info->un.s.member[offs].mask;
|
||||
else
|
||||
ctrl->un.mask &= ~info->un.s.member[offs].mask;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("siomix_sun_setctl: wrong addr %d\n", addr);
|
||||
hdl->siomix.eof = 1;
|
||||
return 0;
|
||||
}
|
||||
if (ioctl(hdl->fd, AUDIO_MIXER_WRITE, ctrl) < 0) {
|
||||
DPERROR("siomix_sun_setctl");
|
||||
hdl->siomix.eof = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_sun_nfds(struct siomix_hdl *addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_sun_pollfd(struct siomix_hdl *addr, struct pollfd *pfd, int events)
|
||||
{
|
||||
struct siomix_sun_hdl *hdl = (struct siomix_sun_hdl *)addr;
|
||||
|
||||
hdl->events = events;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
siomix_sun_revents(struct siomix_hdl *addr, struct pollfd *pfd)
|
||||
{
|
||||
struct siomix_sun_hdl *hdl = (struct siomix_sun_hdl *)addr;
|
||||
|
||||
return hdl->events & POLLOUT;
|
||||
}
|
||||
#endif
|
|
@ -1,193 +0,0 @@
|
|||
/* $OpenBSD$ */
|
||||
/*
|
||||
* Copyright (c) 2014 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <sndio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "abuf.h"
|
||||
#include "defs.h"
|
||||
#include "dev.h"
|
||||
#include "dsp.h"
|
||||
#include "file.h"
|
||||
#include "dev_siomix.h"
|
||||
#include "utils.h"
|
||||
#include "bsd-compat.h"
|
||||
|
||||
void dev_siomix_ondesc(void *, struct siomix_desc *, int);
|
||||
void dev_siomix_onctl(void *, unsigned int, unsigned int);
|
||||
int dev_siomix_pollfd(void *, struct pollfd *);
|
||||
int dev_siomix_revents(void *, struct pollfd *);
|
||||
void dev_siomix_in(void *);
|
||||
void dev_siomix_out(void *);
|
||||
void dev_siomix_hup(void *);
|
||||
|
||||
struct fileops dev_siomix_ops = {
|
||||
"siomix",
|
||||
dev_siomix_pollfd,
|
||||
dev_siomix_revents,
|
||||
dev_siomix_in,
|
||||
dev_siomix_out,
|
||||
dev_siomix_hup
|
||||
};
|
||||
|
||||
void
|
||||
dev_siomix_ondesc(void *arg, struct siomix_desc *desc, int val)
|
||||
{
|
||||
struct dev *d = arg;
|
||||
struct ctl *c;
|
||||
|
||||
if (desc == NULL)
|
||||
return;
|
||||
|
||||
for (c = d->ctl_list; c != NULL; c = c->next) {
|
||||
if (c->addr != desc->addr)
|
||||
continue;
|
||||
if (c->type != SIOMIX_LABEL)
|
||||
continue;
|
||||
ctl_log(c);
|
||||
log_puts(": label -> ");
|
||||
log_puts(desc->chan0.str);
|
||||
log_puts("\n");
|
||||
strlcpy(c->chan0.str, desc->chan0.str, CTL_NAMEMAX);
|
||||
c->desc_mask = ~0;
|
||||
return;
|
||||
}
|
||||
c = dev_addctl(d, desc->type, desc->addr,
|
||||
desc->chan0.str, desc->chan0.opt, desc->func,
|
||||
desc->chan1.str, desc->chan1.opt);
|
||||
c->curval = val;
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 3) {
|
||||
dev_log(d);
|
||||
log_puts(": added: ");
|
||||
ctl_log(c);
|
||||
log_puts("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
dev_siomix_onctl(void *arg, unsigned int addr, unsigned int val)
|
||||
{
|
||||
struct dev *d = arg;
|
||||
struct ctl *c;
|
||||
|
||||
dev_log(d);
|
||||
log_puts(": onctl ");
|
||||
log_putu(addr);
|
||||
log_puts(", ");
|
||||
log_putu(val);
|
||||
log_puts("\n");
|
||||
|
||||
for (c = d->ctl_list; c != NULL; c = c->next) {
|
||||
if (c->addr != addr)
|
||||
continue;
|
||||
ctl_log(c);
|
||||
log_puts(": new value -> ");
|
||||
log_putu(val);
|
||||
log_puts("\n");
|
||||
c->val_mask = ~0U;
|
||||
c->curval = val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* open the mixer device.
|
||||
*/
|
||||
void
|
||||
dev_siomix_open(struct dev *d)
|
||||
{
|
||||
d->siomix.hdl = siomix_open(d->path, SIOMIX_READ | SIOMIX_WRITE, 0);
|
||||
if (d->siomix.hdl == NULL)
|
||||
return;
|
||||
siomix_ondesc(d->siomix.hdl, dev_siomix_ondesc, d);
|
||||
siomix_onctl(d->siomix.hdl, dev_siomix_onctl, d);
|
||||
d->siomix.file = file_new(&dev_siomix_ops, d, d->path,
|
||||
siomix_nfds(d->siomix.hdl));
|
||||
}
|
||||
|
||||
/*
|
||||
* close the mixer device.
|
||||
*/
|
||||
void
|
||||
dev_siomix_close(struct dev *d)
|
||||
{
|
||||
if (d->siomix.hdl == NULL)
|
||||
return;
|
||||
file_del(d->siomix.file);
|
||||
siomix_close(d->siomix.hdl);
|
||||
d->siomix.hdl = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
dev_siomix_pollfd(void *arg, struct pollfd *pfd)
|
||||
{
|
||||
struct dev *d = arg;
|
||||
struct ctl *c;
|
||||
int events = 0;
|
||||
|
||||
for (c = d->ctl_list; c != NULL; c = c->next) {
|
||||
if (c->dirty)
|
||||
events |= POLLOUT;
|
||||
}
|
||||
return siomix_pollfd(d->siomix.hdl, pfd, events);
|
||||
}
|
||||
|
||||
int
|
||||
dev_siomix_revents(void *arg, struct pollfd *pfd)
|
||||
{
|
||||
struct dev *d = arg;
|
||||
|
||||
return siomix_revents(d->siomix.hdl, pfd);
|
||||
}
|
||||
|
||||
void
|
||||
dev_siomix_in(void *arg)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
dev_siomix_out(void *arg)
|
||||
{
|
||||
struct dev *d = arg;
|
||||
struct ctl *c;
|
||||
|
||||
for (c = d->ctl_list; c != NULL; c = c->next) {
|
||||
if (!c->dirty)
|
||||
continue;
|
||||
if (!siomix_setctl(d->siomix.hdl, c->addr, c->curval))
|
||||
break;
|
||||
if (log_level >= 2) {
|
||||
ctl_log(c);
|
||||
log_puts(": changed\n");
|
||||
}
|
||||
c->dirty = 0;
|
||||
dev_unref(d);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dev_siomix_hup(void *arg)
|
||||
{
|
||||
struct dev *d = arg;
|
||||
|
||||
dev_siomix_close(d);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/* $OpenBSD$ */
|
||||
/*
|
||||
* Copyright (c) 2014 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef DEV_SIOMIX_H
|
||||
#define DEV_SIOMIX_H
|
||||
|
||||
#include "file.h"
|
||||
|
||||
struct dev;
|
||||
|
||||
struct dev_siomix {
|
||||
struct siomix_hdl *hdl;
|
||||
struct file *file;
|
||||
};
|
||||
|
||||
void dev_siomix_open(struct dev *);
|
||||
void dev_siomix_close(struct dev *);
|
||||
|
||||
#endif /* !defined(DEV_SIOMIX_H) */
|
Loading…
Reference in New Issue