mirror of
git://git.9front.org/plan9front/plan9front
synced 2025-01-12 11:10:06 +00:00
mixfs: allow switching between audio devices (/dev/audio*)
At startup, look for audio devices like /dev/audio* and open the first one that shows up. We allow to later changing the audio device using the new "new" control message to /dev/audio. Only devices named /dev/audio*, #u/audio* and #A/audio* are allowd so far to prevent accidents.
This commit is contained in:
parent
3d706f9621
commit
5e370061e0
2 changed files with 127 additions and 35 deletions
|
@ -92,6 +92,8 @@ q ] [
|
|||
] [
|
||||
.B -m
|
||||
.I mtpt
|
||||
] [
|
||||
/dev/audio
|
||||
]
|
||||
.PP
|
||||
.SH DESCRIPTION
|
||||
|
@ -352,6 +354,8 @@ over
|
|||
.B /dev/volume
|
||||
from the parent namespace is proxied with an additional control "mix"
|
||||
which is used to set the output volume of the mixer.
|
||||
Another additional control "dev" can be used to switch between
|
||||
audio devices.
|
||||
A alternative mountpoint
|
||||
.I mtpt
|
||||
can be specified with the
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
enum {
|
||||
NBUF = 8*1024,
|
||||
NDELAY = 2048,
|
||||
NDELAY = 512, /* ~11.6ms */
|
||||
NQUANTA = 64, /* ~1.45ms */
|
||||
NCHAN = 2,
|
||||
FREQ = 44100,
|
||||
};
|
||||
|
@ -34,9 +35,13 @@ int lbbuf[NBUF][NCHAN];
|
|||
int mixbuf[NBUF][NCHAN];
|
||||
Lock mixlock;
|
||||
|
||||
Stream streams[16];
|
||||
Stream streams[64];
|
||||
|
||||
char *devaudio;
|
||||
QLock devlock;
|
||||
int audiofd = -1;
|
||||
int volfd = -1;
|
||||
|
||||
int volfd;
|
||||
int volume[2] = {100, 100};
|
||||
int vol64k[2] = {65536, 65536};
|
||||
|
||||
|
@ -60,6 +65,86 @@ clip16(int v)
|
|||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
closeaudiodev(void)
|
||||
{
|
||||
qlock(&devlock);
|
||||
if(audiofd >= 0){
|
||||
close(audiofd);
|
||||
audiofd = -1;
|
||||
}
|
||||
qunlock(&devlock);
|
||||
}
|
||||
|
||||
int
|
||||
reopendevs(char *name)
|
||||
{
|
||||
static char dir[] = "/dev/";
|
||||
int i, n, dfd, afd;
|
||||
char *p;
|
||||
Dir *d;
|
||||
|
||||
if(name != nil){
|
||||
if(name != devaudio){
|
||||
/* hack: restrict to known audio device names */
|
||||
if((strncmp(name, "/dev/audio", 10) != 0 || strchr(name+10, '/') != nil)
|
||||
&& (strncmp(name, "#u/audio", 8) != 0 || strchr(name+8, '/') != nil)
|
||||
&& (strncmp(name, "#A/audio", 8) != 0 || strchr(name+8, '/') != nil)){
|
||||
werrstr("name doesnt look like an audio device");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if((afd = open(name, OWRITE)) >= 0){
|
||||
name = strdup(name);
|
||||
goto found;
|
||||
}
|
||||
if(name != devaudio)
|
||||
return -1;
|
||||
}
|
||||
if((dfd = open(dir, OREAD)) >= 0){
|
||||
while((n = dirread(dfd, &d)) > 0){
|
||||
for(i = 0; i < n; i++){
|
||||
if((d[i].mode & DMDIR) != 0
|
||||
|| strncmp(d[i].name, "audio", 5) != 0)
|
||||
continue;
|
||||
name = smprint("%s%s", dir, d[i].name);
|
||||
if((afd = open(name, OWRITE)) >= 0){
|
||||
close(dfd);
|
||||
free(d);
|
||||
goto found;
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
free(d);
|
||||
}
|
||||
close(dfd);
|
||||
werrstr("no devices found");
|
||||
}
|
||||
return -1;
|
||||
found:
|
||||
qlock(&devlock);
|
||||
free(devaudio);
|
||||
devaudio = name;
|
||||
audiofd = dup(afd, audiofd);
|
||||
qunlock(&devlock);
|
||||
|
||||
close(afd);
|
||||
if(volfd >= 0){
|
||||
close(volfd);
|
||||
volfd = -1;
|
||||
}
|
||||
if((p = utfrrune(name, '/')) != nil)
|
||||
p++;
|
||||
else
|
||||
p = name;
|
||||
if(strncmp(p, "audio", 5) == 0){
|
||||
name = smprint("%.*svolume%s", (int)(p - name), name, p+5);
|
||||
volfd = open(name, ORDWR);
|
||||
free(name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
fsopen(Req *r)
|
||||
{
|
||||
|
@ -117,14 +202,13 @@ void
|
|||
audioproc(void *)
|
||||
{
|
||||
static uchar buf[NBUF*NCHAN*2];
|
||||
int sweep, fd, i, j, n, m, v;
|
||||
int sweep, i, j, n, m, v;
|
||||
ulong rp;
|
||||
Stream *s;
|
||||
uchar *p;
|
||||
|
||||
threadsetname("audioproc");
|
||||
|
||||
fd = -1;
|
||||
sweep = 0;
|
||||
for(;;){
|
||||
m = NBUF;
|
||||
|
@ -155,18 +239,14 @@ audioproc(void *)
|
|||
int ms;
|
||||
|
||||
ms = 100;
|
||||
if(fd >= 0){
|
||||
if(sweep){
|
||||
close(fd);
|
||||
fd = -1;
|
||||
} else {
|
||||
if(audiofd >= 0){
|
||||
if(sweep)
|
||||
closeaudiodev();
|
||||
else {
|
||||
/* attempt to sleep just shortly before buffer underrun */
|
||||
ms = seek(fd, 0, 2);
|
||||
if(ms > 0){
|
||||
ms = seek(audiofd, 0, 2);
|
||||
ms *= 800;
|
||||
ms /= FREQ*NCHAN*2;
|
||||
} else
|
||||
ms = 4;
|
||||
}
|
||||
sweep = 1;
|
||||
}
|
||||
|
@ -174,13 +254,15 @@ audioproc(void *)
|
|||
continue;
|
||||
}
|
||||
sweep = 0;
|
||||
if(fd < 0)
|
||||
if((fd = open("/dev/audio", OWRITE)) < 0){
|
||||
fprint(2, "%s: open /dev/audio: %r\n", argv0);
|
||||
if(audiofd < 0 && reopendevs(devaudio) < 0){
|
||||
fprint(2, "%s: reopendevs: %r\n", argv0);
|
||||
sleep(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(m > NQUANTA)
|
||||
m = NQUANTA;
|
||||
|
||||
p = buf;
|
||||
rp = mixrp;
|
||||
for(i=0; i<m; i++){
|
||||
|
@ -199,7 +281,9 @@ audioproc(void *)
|
|||
mixrp = rp;
|
||||
unlock(&rplock);
|
||||
|
||||
write(fd, buf, p - buf);
|
||||
n = p - buf;
|
||||
if(write(audiofd, buf, n) != n)
|
||||
closeaudiodev();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,8 +298,11 @@ fsread(Req *r)
|
|||
if(r->fid->file->aux == &volfd){
|
||||
static char svol[4096];
|
||||
if(r->ifcall.offset == 0){
|
||||
m = snprint(svol, sizeof(svol), "mix %d %d\n", volume[0], volume[1]);
|
||||
if((n = pread(volfd, svol+m, sizeof(svol)-m-1, 0)) > 0)
|
||||
n = 0;
|
||||
m = snprint(svol, sizeof(svol), "dev %s\nmix %d %d\n",
|
||||
devaudio?devaudio:"",
|
||||
volume[0], volume[1]);
|
||||
if(volfd < 0 || (n = pread(volfd, svol+m, sizeof(svol)-m-1, 0)) > 0)
|
||||
svol[m+n] = 0;
|
||||
}
|
||||
readstr(r, svol);
|
||||
|
@ -286,7 +373,12 @@ fswrite(Req *r)
|
|||
snprint(msg, sizeof(msg), "%.*s",
|
||||
utfnlen((char*)r->ifcall.data, r->ifcall.count), (char*)r->ifcall.data);
|
||||
nf = tokenize(msg, f, nelem(f));
|
||||
if(nf > 1 && strcmp(f[0], "mix") == 0){
|
||||
if(nf > 1 && strcmp(f[0], "dev") == 0){
|
||||
if(reopendevs(f[1]) < 0){
|
||||
responderror(r);
|
||||
return;
|
||||
}
|
||||
}else if(nf > 1 && strcmp(f[0], "mix") == 0){
|
||||
x[0] = atoi(f[1]);
|
||||
x[1] = nf < 3 ? x[0] : atoi(f[2]);
|
||||
if(f[1][0] == '+' || f[1][0] == '-'){
|
||||
|
@ -432,26 +524,22 @@ threadmain(int argc, char **argv)
|
|||
usage();
|
||||
}ARGEND;
|
||||
|
||||
if(argc)
|
||||
if(argc > 1)
|
||||
usage();
|
||||
|
||||
volfd = open("/dev/volume", ORDWR);
|
||||
reopendevs(argv[0]);
|
||||
closeaudiodev();
|
||||
|
||||
fs.tree = alloctree(nil, nil, DMDIR|0777, nil);
|
||||
createfile(fs.tree->root, "audio", nil, 0666, nil);
|
||||
createfile(fs.tree->root, "volume", nil, 0666, &volfd);
|
||||
threadpostmountsrv(&fs, srv, mtpt, MREPL);
|
||||
|
||||
bind(mtpt, "/dev", MAFTER);
|
||||
m = smprint("%s/audio", mtpt);
|
||||
if(bind(m, "/dev/audio", MREPL) < 0)
|
||||
sysfatal("bind: %r");
|
||||
free(m);
|
||||
|
||||
if(volfd >= 0){
|
||||
bind(m, "/dev/audio", MREPL);
|
||||
m = smprint("%s/volume", mtpt);
|
||||
if(bind(m, "/dev/volume", MREPL) < 0)
|
||||
sysfatal("bind: %r");
|
||||
free(m);
|
||||
}
|
||||
bind(m, "/dev/volume", MREPL);
|
||||
|
||||
threadexits(0);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue