ref: 709cb723bba3aa43ba40a5c70dba0b337bae54e2
dir: /stream_audio.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "misc.h"
#include "stream.h"
enum {
Onesec = 2*2*44100, /* 16-bit, stereo */
Framesz = Onesec/10, /* 1/10th second */
};
static char *progs[] = {
[FmtAAC] = "/bin/audio/aacdec",
[FmtOpus] = "/bin/audio/opusdec",
[FmtVorbis] = "/bin/audio/oggdec",
};
extern Streamops audops;
int
audopenfd(int fd, Stream *s, int *failed)
{
int p[2], pid;
char *prog;
Dir *d;
if(fd < 0)
return -1;
if(s->fmt >= nelem(progs) || (prog = progs[s->fmt]) == nil){
werrstr("unsupported audio format %d", s->fmt);
goto err;
}
*failed = 1;
if((d = dirstat(prog)) == nil){
werrstr("can't decode, %s isn't available", prog);
goto err;
}
free(d);
pipe(p);
if((pid = rfork(RFFDG|RFPROC)) == 0){
dup(fd, 0); close(fd);
close(p[0]);
dup(p[1], 1); close(p[1]);
if(!debug){
dup(fd = open("/dev/null", OWRITE), 2);
close(fd);
}
/* FIXME why oh why */
if(s->fmt == FmtOpus)
execl(prog, prog, "--rate", "44100", "--force-stereo", "-", "-", nil);
else
execl(prog, prog, nil);
sysfatal("exec: %r");
}
close(p[1]);
if(pid < 0){
close(p[0]);
goto err;
}
close(fd);
s->type = Saudio;
s->timebase.denum = 1;
s->timebase.num = 1;
s->b = Bfdopen(p[0], OREAD);
memmove(&s->ops, &audops, sizeof(audops));
*failed = 0;
return 0;
err:
close(fd);
return -1;
}
static Stream *
audopen(char *path, int *num, int *failed)
{
Stream *s;
if((s = calloc(1, sizeof(*s))) == nil){
*failed = 1;
return nil;
}
*num = 1;
if(audopenfd(open(path, OREAD), s, failed) != 0){
free(s);
s = nil;
}
return s;
}
static int
audread(Stream *s, Streamframe *f)
{
if(s->buf == nil)
s->buf = malloc(Framesz);
f->buf = s->buf;
f->timestamp = s->timestamp;
if((f->sz = Bread(s->b, f->buf, Framesz)) < 0){ /* eof */
f->sz = 0;
return -1;
}
f->dt = f->sz * 1000000000ULL / Onesec;
s->timestamp += f->dt;
return 0;
}
static void
audclose(Stream *s)
{
Bterm(s->b);
free(s->buf);
}
Streamops audops = {
.open = audopen,
.read = audread,
.close = audclose,
};