ref: e6b3f421310f111974523e15d39d14d5eefbc402
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/5, /* ⅕ second */ }; static char *progs[] = { [FmtAAC] = "/bin/audio/aacdec", [FmtMp3] = "/bin/audio/mp3dec", [FmtOpus] = "/bin/audio/opusdec", [FmtVorbis] = "/bin/audio/oggdec", [FmtFlac] = "/bin/audio/flacdec", }; 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); } 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, };