commit 2a2c264897eb9efdfe1884a57e3b1c2756666446
parent e23111d682e7577e34ac5a8b702b685bee97ede0
Author: sin <sin@2f30.org>
Date: Fri, 26 Dec 2014 13:52:59 +0000
Add mp3 decoder
Diffstat:
M | Makefile | | | 6 | ++++-- |
M | cmd.c | | | 11 | +++++------ |
A | decoder.c | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
A | mp3.c | | | 103 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | sad.c | | | 18 | ++++++++++-------- |
M | sad.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 *);