sad

simple audio daemon
git clone git://git.2f30.org/sad
Log | Files | Refs | LICENSE

commit 2a2c264897eb9efdfe1884a57e3b1c2756666446
parent e23111d682e7577e34ac5a8b702b685bee97ede0
Author: sin <sin@2f30.org>
Date:   Fri, 26 Dec 2014 13:52:59 +0000

Add mp3 decoder

Diffstat:
MMakefile | 6++++--
Mcmd.c | 11+++++------
Adecoder.c | 43+++++++++++++++++++++++++++++++++++++++++++
Amp3.c | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msad.c | 18++++++++++--------
Msad.h | 8+++++++-
6 files changed, 172 insertions(+), 17 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,9 +5,9 @@ MANPREFIX = $(PREFIX)/man CFLAGS = -I/usr/local/include -g LDFLAGS = -L /usr/local/lib -LDLIBS = -lsndfile -lsndio +LDLIBS = -lsndfile -lmpg123 -lsndio -OBJ = sndio.o cmd.o wav.o playlist.o sad.o tokenizer.o +OBJ = sndio.o cmd.o mp3.o wav.o playlist.o sad.o tokenizer.o decoder.o BIN = sad all: $(BIN) @@ -18,9 +18,11 @@ $(BIN): $(OBJ) sndio.o: sad.h cmd.o: sad.h wav.o: sad.h +mp3.o: sad.h playlist.o: sad.h sad.o: sad.h tokenizer.o: sad.h +decoder.o: sad.h install: all mkdir -p $(DESTDIR)$(PREFIX)/bin diff --git a/cmd.c b/cmd.c @@ -51,7 +51,7 @@ cmdnext(int fd, int argc, char **argv) } next = getnextsong(); - decoder->close(); + matchdecoder(s->path)->close(); s->state = NONE; next->state = PREPARE; putcursong(next); @@ -116,13 +116,12 @@ cmdplay(int fd, int argc, char **argv) cur = getcursong(); if (cur) { - decoder->close(); + matchdecoder(cur->path)->close(); cur->state = NONE; } s->state = PREPARE; putcursong(s); - printf("Song %s with %d playing\n", s->path, s->id); } @@ -144,7 +143,7 @@ cmdprev(int fd, int argc, char **argv) } prev = getprevsong(); - decoder->close(); + matchdecoder(s->path)->close(); s->state = NONE; prev->state = PREPARE; putcursong(prev); @@ -166,7 +165,7 @@ cmdstop(int fd, int argc, char **argv) dprintf(fd, "ERR \"no song is active\"\n"); return; } - decoder->close(); + matchdecoder(s->path)->close(); s->state = NONE; dprintf(fd, "OK\n"); } @@ -202,7 +201,7 @@ cmdclear(int fd, int argc, char **argv) s = getcursong(); if (s) { - decoder->close(); + matchdecoder(s->path)->close(); s->state = NONE; } clearplaylist(); diff --git a/decoder.c b/decoder.c @@ -0,0 +1,43 @@ +#include <sys/select.h> + +#include <err.h> +#include <limits.h> +#include <stdio.h> +#include <strings.h> +#include <sndfile.h> + +#include "sad.h" + +static struct { + char *ext; + Decoder *decoder; +} Decodermap[] = { + { ".wav", &wavdecoder }, + { ".mp3", &mp3decoder }, +}; + +int +initdecoders(void) +{ + int i; + + for (i = 0; i < LEN(Decodermap); i++) + if (Decodermap[i].decoder->init() < 0) + return -1; + return 0; +} + +Decoder * +matchdecoder(const char *name) +{ + char *ext; + int i; + + ext = strrchr(name, '.'); + if (!ext) + return NULL; + for (i = 0; i < LEN(Decodermap); i++) + if (!strcasecmp(Decodermap[i].ext, ext)) + return Decodermap[i].decoder; + return NULL; +} diff --git a/mp3.c b/mp3.c @@ -0,0 +1,103 @@ +#include <sys/select.h> + +#include <err.h> +#include <limits.h> +#include <stdio.h> +#include <mpg123.h> + +#include "sad.h" + +static mpg123_handle *hdl; + +static int +mp3init(void) +{ + if (mpg123_init() != MPG123_OK) { + warnx("mpg123_init: failed"); + return -1; + } + hdl = mpg123_new(NULL, NULL); + if (!hdl) { + warnx("mpg123_new: failed"); + return -1; + } + return 0; +} + +static int +mp3open(const char *name) +{ + int r; + long rate; + int channels, encoding, bits; + + r = mpg123_open(hdl, name); + if (r != MPG123_OK) { + warnx("mpg123_open: failed"); + return -1; + } + + r = mpg123_getformat(hdl, &rate, &channels, &encoding); + if (r != MPG123_OK) { + warnx("mpg123_getformat: failed"); + goto err0; + } + + r = output->open(mpg123_encsize(encoding) * 8, rate, channels); + if (r < 0) + goto err0; + + return 0; +err0: + mpg123_close(hdl); + return -1; +} + +static int +mp3decode(void *buf, int nbytes) +{ + size_t actual; + int r; + + r = mpg123_read(hdl, buf, nbytes, &actual); + if (r == MPG123_DONE) + return 0; + else if (r != MPG123_OK) { + warnx("mpg123_read: failed"); + return -1; + } + return actual; +} + +static int +mp3close(void) +{ + int r = 0; + + r = mpg123_close(hdl); + if (r != MPG123_OK) { + warnx("mpg123_close: failed"); + r = -1; + } + if (output->close() < 0) + r = -1; + return r; +} + +static void +mp3exit(void) +{ + if (hdl) { + mpg123_delete(hdl); + mpg123_exit(); + } + hdl = NULL; +} + +Decoder mp3decoder = { + .init = mp3init, + .open = mp3open, + .decode = mp3decode, + .close = mp3close, + .exit = mp3exit +}; diff --git a/sad.c b/sad.c @@ -17,7 +17,6 @@ fd_set master; fd_set rfds; int fdmax; Output *output = &sndiooutput; -Decoder *decoder = &wavdecoder; static int servlisten(const char *name) @@ -65,25 +64,28 @@ servaccept(int listenfd) static void doaudio(void) { - Song *s; - short buf[2048]; - int nbytes; + Song *s; + Decoder *d; + short buf[2048]; + int nbytes; s = getcursong(); if (!s) return; + d = matchdecoder(s->path); + switch (s->state) { case PREPARE: - if (decoder->open(s->path) < 0) { + if (d->open(s->path) < 0) { s->state = NONE; return; } s->state = PLAYING; break; case PLAYING: - if ((nbytes = decoder->decode(buf, sizeof(buf))) <= 0) { - decoder->close(); + if ((nbytes = d->decode(buf, sizeof(buf))) <= 0) { + d->close(); s->state = NONE; } else { output->play(buf, nbytes); @@ -105,7 +107,7 @@ main(void) FD_SET(listenfd, &master); fdmax = listenfd; - decoder->init(); + initdecoders(); while (1) { rfds = master; diff --git a/sad.h b/sad.h @@ -45,7 +45,6 @@ extern fd_set master; extern fd_set rfds; extern int fdmax; extern Output *output; -extern Decoder *decoder; /* cmd.c */ int docmd(int); @@ -65,9 +64,16 @@ void clearplaylist(void); /* wav.c */ extern Decoder wavdecoder; +/* mp3.c */ +extern Decoder mp3decoder; + /* sndio.c */ extern Output sndiooutput; /* tokenizer.c */ int gettokens(char *, char **, int, char *); int tokenize(char *, char **, int); + +/* decoder.c */ +int initdecoders(void); +Decoder *matchdecoder(const char *);