sad

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

commit 5f931616f8e73c9122997ae57356c5cc2cdf7e46
parent f7f577b0b1dfdb99d96ae8208de822fd6234d5a9
Author: sin <sin@2f30.org>
Date:   Sun, 28 Dec 2014 11:11:35 +0000

Add initial library code

Diffstat:
MMakefile | 1+
MPROTOCOL | 27++++++++++++++++++---------
Mcmd.c | 46+++++++++++++++++++++++++++++++++++-----------
Alibrary.c | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Moutput.c | 11++++++++---
Mplaylist.c | 69+++++++--------------------------------------------------------------
Msad.c | 5++---
Msad.h | 17++++++++++++++---
8 files changed, 195 insertions(+), 91 deletions(-)

diff --git 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 @@ -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 @@ -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"); } @@ -215,6 +211,31 @@ cmdplaylist(int fd, char *arg) } 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 @@ -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 @@ -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 @@ -3,7 +3,6 @@ #include <err.h> #include <limits.h> -#include <regex.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -14,50 +13,29 @@ 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) { Song *s, *cur; @@ -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 @@ -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 @@ -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;