Recently Written · git

sad

sad (2f30.org simple audio daemon) with a Cygwin/OSS port on branch cygwin

git clone https://github.com/equwal/sad

Log | Files | Refs


commit 5f931616f8e73c9122997ae57356c5cc2cdf7e46
sin <sin@2f30.org>
2014-12-28 11:11:35 +0000

Add initial library code

 Makefile   |   1 +
 PROTOCOL   |  27 ++++++++++-----
 cmd.c      |  46 +++++++++++++++++++-------
 library.c  | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 output.c   |  11 +++++--
 playlist.c |  69 ++++----------------------------------
 sad.c      |   5 ++-
 sad.h      |  17 ++++++++--
 8 files changed, 195 insertions(+), 91 deletions(-)
diff --git a/Makefile b/Makefile
index 2c90e7c..c8a998a 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ OBJ =\
 	cmd.o\
 	decoder.o\
 	fifo.o\
+	library.o\
 	mp3.o\
 	output.o\
 	playlist.o\
diff --git a/PROTOCOL b/PROTOCOL
index 35edbd6..25be901 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -25,9 +25,6 @@ Pause currently playing song.
 
 play [ID]
 Play the song with the given ID or the current song if no ID is provided.
-When the playlist gets populated initially, the first song added is the current song.
-A song ID is just a unique integer identifying the song.  ID rolls back at 0 when
-the playlist is cleared.
 
 prev
 Play previous song.
@@ -35,23 +32,35 @@ Play previous song.
 stop
 Stop playback.
 
-add file
-Add a file to the playlist.  Directories are not handled.
+add [ID]
+Add the given song ID from the library to the playlist.  If not ID
+is provided, all songs in the library are added.
 
 clear
 Clear playlist and stop playback.  The next file added will have a song ID
 equal to 0.
 
-delete [ID]
-Delete the song with the given ID or the currently selected song.
+remove [ID]
+Delete the song with the given ID or the currently selected song from
+the playlist.
 
 playlist
 Dump the current playlist.  The output has the following form:
 "%d: %s\n", id, filepath
 
+playlist
+Dump the library.  The output has the following form:
+"%d: %s\n", id, filepath
+
 search regex
-Search for a song matching the given regex.  At the moment it will only
-consider file names.
+Search for a song matching the given regex in the library.  At the moment it
+will only consider file names.
+
+learn path
+Add the path to library.
+
+forget ID
+Forget the song with the given ID from the library.
 
 close
 Force the daemon to close the client connection.
diff --git a/cmd.c b/cmd.c
index e204a62..e72dc3c 100644
--- a/cmd.c
+++ b/cmd.c
@@ -122,6 +122,7 @@ cmdplay(int fd, char *arg)
 	}
 
 	playsong(s);
+	dprintf(fd, "OK\n");
 }
 
 static void
@@ -167,21 +168,16 @@ cmdstop(int fd, char *arg)
 static void
 cmdadd(int fd, char *arg)
 {
-	Song *s;
-
 	if (!arg[0]) {
-		dprintf(fd, "ERR expected file path\n");
+		dprintf(fd, "ERR expected ID\n");
 		return;
 	}
-	if (access(arg, F_OK) < 0) {
-		dprintf(fd, "ERR file doesn't exist: %s\n", arg);
-		return;
-	}
-	s = addplaylist(arg);
-	if (!s) {
-		dprintf(fd, "ERR cannot add file: %s\n", arg);
+
+	if (!addplaylist(atoi(arg))) {
+		dprintf(fd, "ERR cannot add song to playlist\n");
 		return;
 	}
+
 	dprintf(fd, "OK\n");
 }
 
@@ -214,6 +210,31 @@ cmdplaylist(int fd, char *arg)
 	dprintf(fd, "OK\n");
 }
 
+static void
+cmdlibrary(int fd, char *arg)
+{
+	if (arg[0]) {
+		dprintf(fd, "ERR unexpected argument\n");
+		return;
+	}
+	dumplibrary(fd);
+	dprintf(fd, "OK\n");
+}
+
+static void
+cmdlearn(int fd, char *arg)
+{
+	if (!arg[0]) {
+		dprintf(fd, "ERR expected argument file path\n");
+		return;
+	}
+	if (!addlibrary(arg)) {
+		dprintf(fd, "ERR failed to add song to library\n");
+		return;
+	}
+	dprintf(fd, "OK\n");
+}
+
 static void
 cmdclose(int fd, char *arg)
 {
@@ -226,6 +247,7 @@ cmdkill(int fd, char *arg)
 		dprintf(fd, "ERR unexpected argument\n");
 		return;
 	}
+	dprintf(fd, "OK\n");
 	raise(SIGTERM);
 }
 
@@ -246,7 +268,7 @@ cmdsearch(int fd, char *arg)
 		dprintf(fd, "ERR expectede search string\n");
 		return;
 	}
-	if (searchplaylist(fd, arg) != -1)
+	if (searchlibrary(fd, arg) != -1)
 		dprintf(fd, "OK\n");
 }
 
@@ -272,6 +294,8 @@ static Cmd cmds[] = {
 	{ "clear",    cmdclear    },
 	{ "delete",   cmddelete   },
 	{ "playlist", cmdplaylist },
+	{ "library",  cmdlibrary  },
+	{ "learn",    cmdlearn    },
 	{ "close",    cmdclose    },
 	{ "kill",     cmdkill     },
 	{ "ping",     cmdping     },
diff --git a/library.c b/library.c
new file mode 100644
index 0000000..7775f2e
--- /dev/null
+++ b/library.c
@@ -0,0 +1,110 @@
+#include <sys/select.h>
+#include <sys/types.h>
+
+#include <err.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sad.h"
+
+static Library  library;
+static int      rollingid;
+
+Song *
+addlibrary(const char *path)
+{
+	Decoder *d;
+	Song    *s;
+
+	d = matchdecoder(path);
+	if (!d)
+		return NULL;
+
+	if (!library.nsongs || library.nsongs + 1 > library.maxsongs) {
+		library.maxsongs += 4096;
+		library.songs = reallocarray(library.songs, library.maxsongs, sizeof(Song *));
+		if (!library.songs)
+			err(1, "reallocarray");
+	}
+
+	s = malloc(sizeof(*s));
+	if (!s)
+		err(1, "malloc");
+
+	library.songs[library.nsongs] = s;
+	strlcpy(s->path, path, sizeof(s->path));
+	s->id = rollingid++;
+	s->state = NONE;
+	s->decoder = d;
+	library.nsongs++;
+	return s;
+}
+
+Song *
+findsongid(int id)
+{
+	Song *s;
+	int   i;
+
+	for (i = 0; i < library.nsongs; i++) {
+		s = library.songs[i];
+		if (s->id == id)
+			return s;
+	}
+	return NULL;
+}
+
+void
+dumplibrary(int fd)
+{
+	Song *s;
+	int   i;
+
+	for (i = 0; i < library.nsongs; i++) {
+		s = library.songs[i];
+		dprintf(fd, "%d: %s\n", s->id, s->path);
+	}
+}
+
+static int
+wregcomp(int fd, regex_t *preg, const char *regex, int cflags)
+{
+        char errbuf[BUFSIZ] = "";
+        int r;
+
+        if ((r = regcomp(preg, regex, cflags)) == 0)
+                return r;
+
+        regerror(r, preg, errbuf, sizeof(errbuf));
+        dprintf(fd, "ERR invalid regex: %s\n", errbuf);
+        return r;
+}
+
+int
+searchlibrary(int fd, const char *search)
+{
+	Song *s;
+	int   i;
+	regex_t re;
+
+	if (wregcomp(fd, &re, search, REG_EXTENDED | REG_ICASE))
+		return -1; /* invalid regex */
+
+	for (i = 0; i < library.nsongs; i++) {
+		s = library.songs[i];
+		if (!regexec(&re, s->path, 0, NULL, REG_NOSUB))
+			dprintf(fd, "%d: %s\n", s->id, s->path);
+	}
+	regfree(&re);
+	return 0;
+}
+
+void
+clearlibrary(void)
+{
+	library.nsongs = 0;
+	rollingid = 0;
+}
diff --git a/output.c b/output.c
index 0594401..9f502ea 100644
--- a/output.c
+++ b/output.c
@@ -35,9 +35,14 @@ openoutput(const char *name)
 			continue;
 		if (strcmp(desc->name, name))
 			continue;
-		return desc->output->open(desc->bits,
-		                          desc->rate,
-		                          desc->channels);
+		if (desc->output->open(desc->bits,
+		                       desc->rate,
+		                       desc->channels) < 0) {
+			printf("Disabling %s output\n",
+			       desc->name);
+			desc->enabled = 0;
+			return -1;
+		}
 	}
 	return -1;
 }
diff --git a/playlist.c b/playlist.c
index f934e83..31af398 100644
--- a/playlist.c
+++ b/playlist.c
@@ -3,7 +3,6 @@
 
 #include <err.h>
 #include <limits.h>
-#include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -14,49 +13,28 @@ static Playlist playlist;
 static int      rollingid;
 
 Song *
-addplaylist(const char *path)
+addplaylist(int id)
 {
-	Decoder *d;
-	Song    *s;
+	Song *s;
 
-	d = matchdecoder(path);
-	if (!d)
+	s = findsongid(id);
+	if (!s)
 		return NULL;
 
 	if (!playlist.nsongs || playlist.nsongs + 1 > playlist.maxsongs) {
 		playlist.maxsongs += 4096;
-		if (!(playlist.songs = reallocarray(playlist.songs, playlist.maxsongs, sizeof(Song *))))
+		playlist.songs = reallocarray(playlist.songs, playlist.maxsongs, sizeof(Song *));
+		if (!playlist.songs)
 			err(1, "reallocarray");
 	}
-	if (!(s = calloc(1, sizeof(Song))))
-		err(1, "calloc");
 
 	playlist.songs[playlist.nsongs] = s;
-	strncpy(s->path, path, sizeof(s->path));
-	s->path[sizeof(s->path) - 1] = '\0';
-	s->id = rollingid++;
-	s->state = 0;
-	s->decoder = d;
-	if (!s->id)
+	if (!playlist.nsongs)
 		playlist.cursong = s;
 	playlist.nsongs++;
 	return s;
 }
 
-Song *
-findsongid(int id)
-{
-	Song *s;
-	int   i;
-
-	for (i = 0; i < playlist.nsongs; i++) {
-		s = playlist.songs[i];
-		if (s->id == id)
-			return s;
-	}
-	return NULL;
-}
-
 Song *
 getnextsong(void)
 {
@@ -123,39 +101,6 @@ dumpplaylist(int fd)
 	}
 }
 
-static int
-wregcomp(int fd, regex_t *preg, const char *regex, int cflags)
-{
-        char errbuf[BUFSIZ] = "";
-        int r;
-
-        if ((r = regcomp(preg, regex, cflags)) == 0)
-                return r;
-
-        regerror(r, preg, errbuf, sizeof(errbuf));
-        dprintf(fd, "ERR invalid regex: %s\n", errbuf);
-        return r;
-}
-
-int
-searchplaylist(int fd, const char *search)
-{
-	Song *s;
-	int   i;
-	regex_t re;
-
-	if (wregcomp(fd, &re, search, REG_EXTENDED | REG_ICASE))
-		return -1; /* invalid regex */
-
-	for (i = 0; i < playlist.nsongs; i++) {
-		s = playlist.songs[i];
-		if (!regexec(&re, s->path, 0, NULL, REG_NOSUB))
-			dprintf(fd, "%d: %s\n", s->id, s->path);
-	}
-	regfree(&re);
-	return 0;
-}
-
 void
 clearplaylist(void)
 {
diff --git a/sad.c b/sad.c
index a3f6178..747be17 100644
--- a/sad.c
+++ b/sad.c
@@ -82,11 +82,10 @@ playaudio(void)
 		s->state = PLAYING;
 		break;
 	case PLAYING:
-		if ((nbytes = s->decoder->decode(buf, sizeof(buf))) <= 0) {
+		if ((nbytes = s->decoder->decode(buf, sizeof(buf))) <= 0)
 			playnextsong();
-		} else {
+		else
 			playoutput(buf, nbytes);
-		}
 		break;
 	}
 }
diff --git a/sad.h b/sad.h
index f7b9c06..4bcd3a6 100644
--- a/sad.h
+++ b/sad.h
@@ -46,6 +46,12 @@ typedef struct {
 	size_t maxsongs;
 } Playlist;
 
+typedef struct {
+	Song **songs;
+	size_t nsongs;
+	size_t maxsongs;
+} Library;
+
 /* sad.c */
 extern fd_set   master;
 extern fd_set   rfds;
@@ -55,20 +61,25 @@ extern int      fdmax;
 int docmd(int);
 
 /* playlist.c */
-Song *addplaylist(const char *);
-Song *findsongid(int);
+Song *addplaylist(int);
 Song *getnextsong(void);
 Song *getprevsong(void);
 Song *getcursong(void);
 void putcursong(Song *);
 void dumpplaylist(int);
 void clearplaylist(void);
-int searchplaylist(int, const char *);
 Song *playnextsong(void);
 Song *playprevsong(void);
 void playsong(Song *);
 void stopsong(Song *);
 
+/* library.c */
+Song *addlibrary(const char *);
+Song *findsongid(int);
+void dumplibrary(int);
+int searchlibrary(int, const char *);
+void clearlibrary(void);
+
 /* wav.c */
 extern Decoder wavdecoder;