playlistfs: use play(1) for format detection and decoding

This commit is contained in:
cinap_lenrek 2012-05-24 08:13:31 +02:00
parent a170c952ff
commit 8bfd915415
2 changed files with 43 additions and 107 deletions

View file

@ -119,22 +119,12 @@ The
flag can be used to specify a mount point other than flag can be used to specify a mount point other than
.BR /mnt . .BR /mnt .
.PP .PP
The files to be played are recognized by one of four extensions, and an appropriate .B Playlistfs
player is then selected to play them. Files without a recognized extension are played by the uses the
.I pac .IR audio (1)
player: decoders by running
.TP .IR play (1)
\&.mp3 for format detection and conversion to pcm.
/bin/games/mp3dec
.TP
\&.pac
/bin/games/pac4dec
.TP
\&.pcm
/bin/cp
.TP
\&.ogg
/bin/games/vorbisdec
.SH FILES .SH FILES
.BR /srv/playlistfs.\f2user\fP : .BR /srv/playlistfs.\f2user\fP :
default default
@ -152,4 +142,6 @@ Volume control file
.SH SOURCE .SH SOURCE
.B /sys/src/games/music/playlistfs .B /sys/src/games/music/playlistfs
.SH SEE ALSO .SH SEE ALSO
.IR play (1),
.IR audio (1),
.IR juke (7). .IR juke (7).

View file

@ -5,13 +5,6 @@
#include "pool.h" #include "pool.h"
#include "playlist.h" #include "playlist.h"
enum {
Pac,
Mp3,
Pcm,
Ogg,
};
typedef struct Playfd Playfd; typedef struct Playfd Playfd;
struct Playfd { struct Playfd {
@ -24,102 +17,38 @@ struct Playfd {
Channel *full, *empty, *playout, *spare; Channel *full, *empty, *playout, *spare;
Channel *playc, *pacc; Channel *playc, *pacc;
char *playprog[] = {
[Pac] = "/bin/games/pac4dec",
[Mp3] = "/bin/games/mp3dec",
[Pcm] = "/bin/cp",
[Ogg] = "/bin/games/vorbisdec",
};
ulong totbytes, totbuffers; ulong totbytes, totbuffers;
static char curfile[8192]; static char curfile[8192];
void void
pac4dec(void *a) decexec(void *a)
{ {
char buf[256];
Playfd *pfd; Playfd *pfd;
Pacbuf *pb; Pacbuf *pb;
int fd, type;
char *ext, buf[256];
static char args[6][32];
char *argv[6] = {args[0], args[1], args[2], args[3], args[4], args[5]};
threadsetname("pac4dec"); threadsetname("decexec");
pfd = a; pfd = a;
close(pfd->cfd); /* read fd */ close(pfd->cfd); /* read fd */
ext = strrchr(pfd->filename, '.'); if(pfd->fd != 1){
fd = open(pfd->filename, OREAD); dup(pfd->fd, 1);
if (fd < 0 && ext == nil){ close(pfd->fd);
// Try the alternatives
ext = buf + strlen(pfd->filename);
snprint(buf, sizeof buf, "%s.pac", pfd->filename);
fd = open(buf, OREAD);
if (fd < 0){
snprint(buf, sizeof buf, "%s.mp3", pfd->filename);
fd = open(buf, OREAD);
}
if (fd < 0){
snprint(buf, sizeof buf, "%s.ogg", pfd->filename);
fd = open(buf, OREAD);
}
if (fd < 0){
snprint(buf, sizeof buf, "%s.pcm", pfd->filename);
fd = open(buf, OREAD);
}
}
if (fd < 0){
if (debug & DbgPlayer)
fprint(2, "pac4dec: %s: %r", pfd->filename);
pb = nbrecvp(spare);
pb->cmd = Error;
pb->off = 0;
pb->len = snprint(pb->data, sizeof(pb->data), "startplay: %s: %r", pfd->filename);
sendp(full, pb);
threadexits("open");
}
dup(pfd->fd, 1);
close(pfd->fd);
if(ext == nil || strcmp(ext, ".pac") == 0){
type = Pac;
snprint(args[0], sizeof args[0], "pac4dec");
snprint(args[1], sizeof args[1], "/fd/%d", fd);
snprint(args[2], sizeof args[2], "/fd/1");
argv[3] = nil;
}else if(strcmp(ext, ".mp3") == 0){
type = Mp3;
snprint(args[0], sizeof args[0], "mp3dec");
snprint(args[1], sizeof args[1], "-q");
snprint(args[2], sizeof args[1], "-s");
snprint(args[3], sizeof args[1], "/fd/%d", fd);
argv[4] = nil;
}else if(strcmp(ext, ".ogg") == 0){
type = Ogg;
snprint(args[0], sizeof args[0], "vorbisdec");
argv[1] = nil;
argv[2] = nil;
argv[3] = nil;
dup(fd, 0);
}else{
type = Pcm;
snprint(args[0], sizeof args[0], "cat");
snprint(args[1], sizeof args[1], "/fd/%d", fd);
argv[2] = nil;
argv[3] = nil;
} }
close(0); open("/dev/null", OREAD);
close(2); open("/dev/null", OWRITE);
strncpy(buf, pfd->filename, sizeof(buf)-1);
buf[sizeof(buf)-1] = 0;
free(pfd->filename); free(pfd->filename);
free(pfd); free(pfd);
if (debug & DbgPlayer) procexecl(nil, "/bin/play", "play", "-o", "/fd/1", buf, nil);
fprint(2, "procexecl %s %s %s %s\n",
playprog[type], argv[0], argv[1], argv[2]);
procexec(nil, playprog[type], argv);
if((pb = nbrecvp(spare)) == nil) if((pb = nbrecvp(spare)) == nil)
pb = malloc(sizeof(Pacbuf)); pb = malloc(sizeof(Pacbuf));
pb->cmd = Error; pb->cmd = Error;
pb->off = 0; pb->off = 0;
pb->len = snprint(pb->data, sizeof(pb->data), "startplay: %s: exec", playprog[type]); pb->len = snprint(pb->data, sizeof(pb->data), "startplay: exec play failed");
sendp(full, pb); sendp(full, pb);
threadexits(playprog[type]); threadexits("exec");
} }
static int static int
@ -140,7 +69,7 @@ startplay(ushort n)
pfd->filename = file; /* mallocated already */ pfd->filename = file; /* mallocated already */
pfd->fd = fd[1]; pfd->fd = fd[1];
pfd->cfd = fd[0]; pfd->cfd = fd[0];
procrfork(pac4dec, pfd, 4096, RFFDG); procrfork(decexec, pfd, 4096, RFFDG);
close(fd[1]); /* write fd, for pac4dec */ close(fd[1]); /* write fd, for pac4dec */
return fd[0]; /* read fd */ return fd[0]; /* read fd */
} }
@ -166,8 +95,22 @@ rtsched(void)
free(ctl); free(ctl);
} }
static void
boost(void)
{
int fd;
char *ctl;
ctl = smprint("/proc/%ud/ctl", getpid());
if((fd = open(ctl, ORDWR)) >= 0) {
fprint(fd, "pri 13");
close(fd);
}
free(ctl);
}
void void
pacproc(void*) decproc(void*)
{ {
Pmsg playstate, newstate; Pmsg playstate, newstate;
int fd; int fd;
@ -178,7 +121,7 @@ pacproc(void*)
{nil, nil, CHANEND}, {nil, nil, CHANEND},
}; };
threadsetname("pacproc"); threadsetname("decproc");
close(srvfd[1]); close(srvfd[1]);
newstate.cmd = playstate.cmd = Stop; newstate.cmd = playstate.cmd = Stop;
newstate.off = playstate.off = 0; newstate.off = playstate.off = 0;
@ -235,7 +178,7 @@ pacproc(void*)
a[0].op = CHANNOP; a[0].op = CHANNOP;
switch(newstate.cmd){ switch(newstate.cmd){
default: default:
sysfatal("pacproc: unexpected newstate %d", newstate.cmd); sysfatal("decproc: unexpected newstate %d", newstate.cmd);
case Stop: case Stop:
/* Wait for state to change */ /* Wait for state to change */
break; break;
@ -271,7 +214,7 @@ pcmproc(void*)
/* /*
* This is the real-time proc. * This is the real-time proc.
* It gets its input from two sources, full data/control buffers from the pacproc * It gets its input from two sources, full data/control buffers from the decproc
* which mixes decoded data with control messages, and data buffers from the pcmproc's * which mixes decoded data with control messages, and data buffers from the pcmproc's
* (*this* proc's) own internal playout buffer. * (*this* proc's) own internal playout buffer.
* When a command is received on the `full' channel containing a command that warrants * When a command is received on the `full' channel containing a command that warrants
@ -286,6 +229,7 @@ pcmproc(void*)
newstate.cmd = Stop; newstate.cmd = Stop;
newstate.off = 0; newstate.off = 0;
// rtsched(); // rtsched();
boost();
for(;;){ for(;;){
if(newstate.m != localstate.m){ if(newstate.m != localstate.m){
playupdate(newstate, nil); playupdate(newstate, nil);
@ -293,7 +237,7 @@ pcmproc(void*)
} }
switch(alt(a)){ switch(alt(a)){
case 0: case 0:
/* buffer received from pacproc */ /* buffer received from decproc */
if((debug & DbgPcm) && localstate.m != prevstate.m){ if((debug & DbgPcm) && localstate.m != prevstate.m){
fprint(2, "pcm, full: %s-%d, local state is %s-%d\n", fprint(2, "pcm, full: %s-%d, local state is %s-%d\n",
statetxt[pb->cmd], pb->off, statetxt[pb->cmd], pb->off,
@ -413,7 +357,7 @@ playinit(void)
sendp(spare, malloc(sizeof(Pacbuf))); sendp(spare, malloc(sizeof(Pacbuf)));
playc = chancreate(sizeof(Pmsg), 1); playc = chancreate(sizeof(Pmsg), 1);
procrfork(pacproc, nil, 32*1024, RFFDG); procrfork(decproc, nil, 32*1024, RFFDG);
procrfork(pcmproc, nil, 32*1024, RFFDG); procrfork(pcmproc, nil, 32*1024, RFFDG);
} }