Commit 82ba78e0 authored by Led's avatar Led

0.6.2

parent 026cefdb
...@@ -40,6 +40,9 @@ find <string type> <string what> ...@@ -40,6 +40,9 @@ find <string type> <string what>
kill kill
kill mpd kill mpd
listall
lists all available songs (without tag info)
load <string name> load <string name>
loads the playlist _name_.m3u from the playlist directory loads the playlist _name_.m3u from the playlist directory
...@@ -51,11 +54,14 @@ ls <string directory> ...@@ -51,11 +54,14 @@ ls <string directory>
lsinfo <string directory> lsinfo <string directory>
list contents of _directory_, from the db. _directory_ is optional list contents of _directory_, from the db. _directory_ is optional
next
plays next song in playlist
pause pause
pause/resume playing pause/resume playing
play <int song> play <int song>
being playling playlist at song number _song_ begin playling playlist at song number _song_, _song_ is optiional
playlist playlist
displays the current playlist displays the current playlist
...@@ -64,6 +70,9 @@ playlist ...@@ -64,6 +70,9 @@ playlist
playlistinfo playlistinfo
displays information about the current playlist displays information about the current playlist
previous
plays previous song in playlist
rm <string name> rm <string name>
removes the playlist <name>.m3u from the playlist directory removes the playlist <name>.m3u from the playlist directory
......
ver 0.6.2 (2003/6/11)
1) Buffer support for ogg
2) new config file options: "connection_timeout" and "mpg123_ignore_junk"
3) new commands: "next", "previous", and "listall"
4) Search by filename
5) bug fix for pause when playing mp3's
ver 0.6.1 (2003/5/29) ver 0.6.1 (2003/5/29)
1) Add conf file support 1) Add conf file support
2) Fix a bug when doing mp3stop (do wait3(NULL,WNOHANG|WUNTRACED,NULL)) 2) Fix a bug when doing mp3stop (do wait3(NULL,WNOHANG|WUNTRACED,NULL))
......
...@@ -16,7 +16,7 @@ DFLAGS = -MM $(INCLUDES) $(HAVE_OGG) ...@@ -16,7 +16,7 @@ DFLAGS = -MM $(INCLUDES) $(HAVE_OGG)
SOURCES = main.c buffer2array.c mpg123.c interface.c command.c playlist.c ls.c \ SOURCES = main.c buffer2array.c mpg123.c interface.c command.c playlist.c ls.c \
id3v2lib/charset.c id3v2lib/lib_id3v2.3.c id3v1lib/lib_id3v1.c \ id3v2lib/charset.c id3v2lib/lib_id3v2.3.c id3v1lib/lib_id3v1.c \
id3v2lib/lib_id3v2.2.c song.c list.c directory.c tables.c utils.c \ id3v2lib/lib_id3v2.2.c song.c list.c directory.c tables.c utils.c \
tag.c player.c ogg.c listen.c conf.c tag.c player.c ogg.c listen.c conf.c ogg_decode.c
OBJECTS = $(SOURCES:.c=.o) OBJECTS = $(SOURCES:.c=.o)
DEPENDFILE = Makefile.depend DEPENDFILE = Makefile.depend
......
1) Search by Filename 1) make timeout and max connections configurabe via config file
2) buffer support for OGG 2) volume control
3) use autoconf and automake 3) use mpglib from mpg123 for mp3 support
4) broadcast messages (including status changes/updates) 4) use autoconf and automake
5) store song times (possibly after playing) 5) broadcast messages (including status changes/updates)
6) add a set a flags (such as BAD MP3) 6) store song times (possibly after playing)
7) add a set a flags (such as BAD MP3)
possibly:
---------
reference songs by an id #
...@@ -47,6 +47,9 @@ ...@@ -47,6 +47,9 @@
#define COMMAND_FIND "find" #define COMMAND_FIND "find"
#define COMMAND_SEARCH "search" #define COMMAND_SEARCH "search"
#define COMMAND_UPDATE "update" #define COMMAND_UPDATE "update"
#define COMMAND_NEXT "next"
#define COMMAND_PREVIOUS "previous"
#define COMMAND_LISTALL "listall"
extern Playlist playlist; extern Playlist playlist;
...@@ -89,15 +92,18 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -89,15 +92,18 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
if(0==strcmp(argArray[0],COMMAND_PLAY)) { if(0==strcmp(argArray[0],COMMAND_PLAY)) {
int song; int song;
char * test; char * test;
if(argArrayLength!=2) { if(argArrayLength>2) {
fprintf(fp,"%s too many arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]); fprintf(fp,"%s too many arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1; return -1;
} }
if(argArrayLength==2) {
song = strtol(argArray[1],&test,10); song = strtol(argArray[1],&test,10);
if(*test!='\0') { if(*test!='\0') {
fprintf(fp,"%s need a positive integer\n",COMMAND_RESPOND_ERROR); fprintf(fp,"%s need a positive integer\n",COMMAND_RESPOND_ERROR);
return -1; return -1;
} }
}
else song = 0;
return playPlaylist(fp,song); return playPlaylist(fp,song);
} }
else if(0==strcmp(argArray[0],COMMAND_STOP)) { else if(0==strcmp(argArray[0],COMMAND_STOP)) {
...@@ -273,6 +279,27 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -273,6 +279,27 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
} }
return updateMp3Directory(fp); return updateMp3Directory(fp);
} }
else if(0==strcmp(argArray[0],COMMAND_NEXT)) {
if(argArrayLength!=1) {
fprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
return nextSongInPlaylist(fp);
}
else if(0==strcmp(argArray[0],COMMAND_PREVIOUS)) {
if(argArrayLength!=1) {
fprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
return previousSongInPlaylist(fp);
}
else if(0==strcmp(argArray[0],COMMAND_LISTALL)) {
if(argArrayLength!=1) {
fprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
return printAllSongsInSongTable(fp);
}
else { else {
fprintf(fp,"%s Unknown command \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]); fprintf(fp,"%s Unknown command \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1; return -1;
......
...@@ -28,11 +28,14 @@ ...@@ -28,11 +28,14 @@
#define MAX_STRING_SIZE MAXPATHLEN+80 #define MAX_STRING_SIZE MAXPATHLEN+80
#define CONF_NUMBER_OF_PARAMS 7 #define CONF_NUMBER_OF_PARAMS 9
#define CONF_NUMBER_OF_PATHS 4 #define CONF_NUMBER_OF_PATHS 4
#define CONF_NUMBER_OF_REQUIRED 5
#define CONF_MPG123_COMMAND_DEFAULT "mpg123 -b 2048 -R foo" #define CONF_MPG123_COMMAND_DEFAULT "mpg123 -b 2048 -R foo"
#define CONF_MPG123_PROCESS_DEFAULT "mpg123" #define CONF_MPG123_PROCESS_DEFAULT "mpg123"
#define CONF_MPG123_IGNORE_JUNK_DEFAULT "yes"
#define CONF_CONNECTION_TIMEOUT_DEFAULT "60"
char conf_strings[CONF_NUMBER_OF_PARAMS][24] = { char conf_strings[CONF_NUMBER_OF_PARAMS][24] = {
"mpg123_command", "mpg123_command",
...@@ -41,7 +44,9 @@ char conf_strings[CONF_NUMBER_OF_PARAMS][24] = { ...@@ -41,7 +44,9 @@ char conf_strings[CONF_NUMBER_OF_PARAMS][24] = {
"playlist_directory", "playlist_directory",
"log_file", "log_file",
"error_file", "error_file",
"mpg123_process" "mpg123_process",
"mpg123_ignore_junk",
"connection_timeout"
}; };
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = { int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
...@@ -51,6 +56,14 @@ int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = { ...@@ -51,6 +56,14 @@ int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
CONF_ERROR_FILE CONF_ERROR_FILE
}; };
int conf_required[CONF_NUMBER_OF_REQUIRED] = {
CONF_MUSIC_DIRECTORY,
CONF_PLAYLIST_DIRECTORY,
CONF_LOG_FILE,
CONF_ERROR_FILE,
CONF_PORT
};
char * conf_params[CONF_NUMBER_OF_PARAMS]; char * conf_params[CONF_NUMBER_OF_PARAMS];
void initConf() { void initConf() {
...@@ -61,6 +74,8 @@ void initConf() { ...@@ -61,6 +74,8 @@ void initConf() {
/* we don't specify these on the command line */ /* we don't specify these on the command line */
conf_params[CONF_MPG123_COMMAND] = strdup(CONF_MPG123_COMMAND_DEFAULT); conf_params[CONF_MPG123_COMMAND] = strdup(CONF_MPG123_COMMAND_DEFAULT);
conf_params[CONF_MPG123_PROCESS] = strdup(CONF_MPG123_PROCESS_DEFAULT); conf_params[CONF_MPG123_PROCESS] = strdup(CONF_MPG123_PROCESS_DEFAULT);
conf_params[CONF_MPG123_IGNORE_JUNK] = strdup(CONF_MPG123_IGNORE_JUNK_DEFAULT);
conf_params[CONF_CONNECTION_TIMEOUT] = strdup(CONF_CONNECTION_TIMEOUT_DEFAULT);
} }
char ** readConf(char * file) { char ** readConf(char * file) {
...@@ -69,12 +84,6 @@ char ** readConf(char * file) { ...@@ -69,12 +84,6 @@ char ** readConf(char * file) {
char ** array; char ** array;
int i; int i;
/* we don't specify these on the command line */
free(conf_params[CONF_MPG123_COMMAND]);
free(conf_params[CONF_MPG123_PROCESS]);
conf_params[CONF_MPG123_COMMAND] = NULL;
conf_params[CONF_MPG123_PROCESS] = NULL;
if(!(fp=fopen(file,"r"))) { if(!(fp=fopen(file,"r"))) {
fprintf(stderr,"problems opening file %s for reading\n",file); fprintf(stderr,"problems opening file %s for reading\n",file);
exit(-1); exit(-1);
...@@ -92,8 +101,7 @@ char ** readConf(char * file) { ...@@ -92,8 +101,7 @@ char ** readConf(char * file) {
exit(-1); exit(-1);
} }
if(conf_params[i]!=NULL) { if(conf_params[i]!=NULL) {
fprintf(stderr,"%s has already been assigned\n",conf_strings[i]); free(conf_params[i]);
exit(-1);
} }
conf_params[i] = strdup(array[1]); conf_params[i] = strdup(array[1]);
free(array[0]); free(array[0]);
...@@ -103,9 +111,9 @@ char ** readConf(char * file) { ...@@ -103,9 +111,9 @@ char ** readConf(char * file) {
fclose(fp); fclose(fp);
for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) { for(i=0;i<CONF_NUMBER_OF_REQUIRED;i++) {
if(conf_params[i] == NULL) { if(conf_params[conf_required[i]] == NULL) {
fprintf(stderr,"%s is unassinged in conf file\n",conf_strings[i]); fprintf(stderr,"%s is unassinged in conf file\n",conf_strings[conf_required[i]]);
exit(-1); exit(-1);
} }
} }
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#define CONF_LOG_FILE 4 #define CONF_LOG_FILE 4
#define CONF_ERROR_FILE 5 #define CONF_ERROR_FILE 5
#define CONF_MPG123_PROCESS 6 #define CONF_MPG123_PROCESS 6
#define CONF_MPG123_IGNORE_JUNK 7
#define CONF_CONNECTION_TIMEOUT 8
/* do not free the return value, it is a static variable */ /* do not free the return value, it is a static variable */
char ** readConf(char * file); char ** readConf(char * file);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "interface.h" #include "interface.h"
#include "buffer2array.h" #include "buffer2array.h"
#include "command.h" #include "command.h"
#include "conf.h"
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
...@@ -29,14 +30,14 @@ ...@@ -29,14 +30,14 @@
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#define VERSION "0.6.1" #define VERSION "0.6.2"
#define GREETING "MPD" #define GREETING "MPD"
#define INTERFACE_MAX_BUFFER_LENGTH 1024 #define INTERFACE_MAX_BUFFER_LENGTH 1024
#define INTERFACE_MAX_CONNECTIONS 5 #define INTERFACE_MAX_CONNECTIONS 5
#define INTERFACE_TIMEOUT 60 int interface_timeout;
typedef struct _Interface { typedef struct _Interface {
char buffer[INTERFACE_MAX_BUFFER_LENGTH+1]; char buffer[INTERFACE_MAX_BUFFER_LENGTH+1];
...@@ -167,10 +168,17 @@ int readInputFromInterfaces() { ...@@ -167,10 +168,17 @@ int readInputFromInterfaces() {
void initInterfaces() { void initInterfaces() {
int i; int i;
char * test;
for(i=0;i<INTERFACE_MAX_CONNECTIONS;i++) { for(i=0;i<INTERFACE_MAX_CONNECTIONS;i++) {
interfaces[i].open = 0; interfaces[i].open = 0;
} }
interface_timeout = strtol((getConf())[CONF_CONNECTION_TIMEOUT],&test,10);
if(*test!='\0') {
fprintf(stderr,"connection timeout \"%s\" is not an integer\n",(getConf())[CONF_CONNECTION_TIMEOUT]);
exit(-1);
}
} }
void closeAllInterfaces() { void closeAllInterfaces() {
...@@ -197,7 +205,7 @@ void closeOldInterfaces() { ...@@ -197,7 +205,7 @@ void closeOldInterfaces() {
int i; int i;
for(i=0;i<INTERFACE_MAX_CONNECTIONS;i++) { for(i=0;i<INTERFACE_MAX_CONNECTIONS;i++) {
if(interfaces[i].open && (time(NULL)-interfaces[i].lastTime>INTERFACE_TIMEOUT)) { if(interfaces[i].open && (time(NULL)-interfaces[i].lastTime>interface_timeout)) {
closeInterface(&(interfaces[i])); closeInterface(&(interfaces[i]));
} }
} }
......
...@@ -50,11 +50,6 @@ int main(int argc, char * argv[]) { ...@@ -50,11 +50,6 @@ int main(int argc, char * argv[]) {
char * logFile; char * logFile;
char * errorFile; char * errorFile;
if(argc!=6 && argc!=2) {
usage(argv);
return -1;
}
initConf(); initConf();
if(argc==6) { if(argc==6) {
...@@ -72,6 +67,11 @@ int main(int argc, char * argv[]) { ...@@ -72,6 +67,11 @@ int main(int argc, char * argv[]) {
logFile = conf[CONF_LOG_FILE]; logFile = conf[CONF_LOG_FILE];
errorFile = conf[CONF_ERROR_FILE]; errorFile = conf[CONF_ERROR_FILE];
} }
else {
usage(argv);
return -1;
}
if((port = atoi(portStr))<0) { if((port = atoi(portStr))<0) {
fprintf(stderr,"problem with port number\n"); fprintf(stderr,"problem with port number\n");
...@@ -104,8 +104,8 @@ int main(int argc, char * argv[]) { ...@@ -104,8 +104,8 @@ int main(int argc, char * argv[]) {
getcwd(playlistDir,MAXPATHLEN-strlen(playlistDirArg)-1); getcwd(playlistDir,MAXPATHLEN-strlen(playlistDirArg)-1);
strcat(playlistDir,"/"); strcat(playlistDir,"/");
strcat(playlistDir,playlistDirArg); strcat(playlistDir,playlistDirArg);
strcat(playlistDir,"/");
} }
strcat(playlistDir,"/");
if((stat(playlistDir,&st))<0) { if((stat(playlistDir,&st))<0) {
fprintf(stderr,"problem stat'ing \"%s\"\n",playlistDirArg); fprintf(stderr,"problem stat'ing \"%s\"\n",playlistDirArg);
return -1; return -1;
......
...@@ -5,3 +5,5 @@ log_file "/home/shank/mpd.log" ...@@ -5,3 +5,5 @@ log_file "/home/shank/mpd.log"
error_file "/home/shank/mpd.error" error_file "/home/shank/mpd.error"
mpg123_command "mpg123 -b 2048 -R foo" mpg123_command "mpg123 -b 2048 -R foo"
mpg123_process "mpg123" mpg123_process "mpg123"
mpg123_ignore_junk "yes"
connection_timeout "60"
...@@ -53,6 +53,7 @@ int mpg123_leavePlay = 0; ...@@ -53,6 +53,7 @@ int mpg123_leavePlay = 0;
int mpg123_leavePause = 0; int mpg123_leavePause = 0;
int mpg123_error = 0; int mpg123_error = 0;
int mpg123_lastFrame = 0; int mpg123_lastFrame = 0;
int mpg123_done = 0;
char mpg123_currentSong[MAXPATHLEN+1] = "\0"; char mpg123_currentSong[MAXPATHLEN+1] = "\0";
int mpg123readline(); int mpg123readline();
...@@ -80,6 +81,7 @@ int mpg123init() { ...@@ -80,6 +81,7 @@ int mpg123init() {
int fd_send[2], fd_recv[2], fd_stderr[2]; int fd_send[2], fd_recv[2], fd_stderr[2];
mpg123_error = 0; mpg123_error = 0;
mpg123_done = 0;
mpg123_currentSong[0] = '\0'; mpg123_currentSong[0] = '\0';
if(socketpair(AF_UNIX,SOCK_STREAM,0,fd_send)<0) { if(socketpair(AF_UNIX,SOCK_STREAM,0,fd_send)<0) {
...@@ -218,8 +220,8 @@ int mpg123stop(FILE * fp) { ...@@ -218,8 +220,8 @@ int mpg123stop(FILE * fp) {
fprintf(fp,"%s problems write'ing\n",COMMAND_RESPOND_ERROR); fprintf(fp,"%s problems write'ing\n",COMMAND_RESPOND_ERROR);
return -1; return -1;
} }
/* wait upto 1 s to get SIGCHLD */ /* wait upto 3 s to get SIGCHLD */
while(i<10 && mpg123_pid>0) { while(i<30 && mpg123_pid>0) {
usleep(100000); /* wait for 10ms for mpg123 to die */ usleep(100000); /* wait for 10ms for mpg123 to die */
wait3(NULL,WNOHANG|WUNTRACED,NULL); wait3(NULL,WNOHANG|WUNTRACED,NULL);
while(mpg123readline()); while(mpg123readline());
...@@ -239,7 +241,9 @@ int mpg123stop(FILE * fp) { ...@@ -239,7 +241,9 @@ int mpg123stop(FILE * fp) {
int mpg123pause(FILE * fp) { int mpg123pause(FILE * fp) {
char string[1024]; char string[1024];
if(mpg123_pid>0) { mpg123processMessages();
if(mpg123_pid>0 && !mpg123_done) {
sprintf(string,"PAUSE\n"); sprintf(string,"PAUSE\n");
if(write(mpg123_send,string,strlen(string))<0) { if(write(mpg123_send,string,strlen(string))<0) {
fprintf(fp,"%s problems write'ing\n",COMMAND_RESPOND_ERROR); fprintf(fp,"%s problems write'ing\n",COMMAND_RESPOND_ERROR);
...@@ -309,10 +313,13 @@ int mpg123gotErrors() { ...@@ -309,10 +313,13 @@ int mpg123gotErrors() {
if(errorBuffer[errorBufferLength]=='\0' || errorBuffer[errorBufferLength]=='\n' || errorBufferLength == MAX_BUFFER_LENGTH) { if(errorBuffer[errorBufferLength]=='\0' || errorBuffer[errorBufferLength]=='\n' || errorBufferLength == MAX_BUFFER_LENGTH) {
errorBuffer[errorBufferLength] = '\0'; errorBuffer[errorBufferLength] = '\0';
errorBufferLength = 0; errorBufferLength = 0;
fprintf(stderr,"%s file: \"%s\" : %s\n",COMMAND_RESPOND_ERROR,mpg123_currentSong,errorBuffer);
if(0==strncmp("Junk at the beginning",errorBuffer,strlen("Junk"))) { if(0==strncmp("Junk at the beginning",errorBuffer,strlen("Junk"))) {
if(0!=strcmp("yes",(getConf())[CONF_MPG123_IGNORE_JUNK])) {
fprintf(stderr,"%s file: \"%s\" : %s\n",COMMAND_RESPOND_ERROR,mpg123_currentSong,errorBuffer);
}
return 0; return 0;
} }
fprintf(stderr,"%s file: \"%s\" : %s\n",COMMAND_RESPOND_ERROR,mpg123_currentSong,errorBuffer);
mpg123kill(); mpg123kill();
return 1; return 1;
} }
...@@ -344,6 +351,7 @@ int mpg123processMessages() { ...@@ -344,6 +351,7 @@ int mpg123processMessages() {
if(!mpg123_leavePlay) { if(!mpg123_leavePlay) {
mpg123_leavePlay=1; mpg123_error=1; mpg123_leavePlay=1; mpg123_error=1;
} }
mpg123_done = 1;
} }
else if(mpg123_state==PLAYER_STATE_PLAY && atoi(c[1])==PLAYER_STATE_PAUSE) { else if(mpg123_state==PLAYER_STATE_PLAY && atoi(c[1])==PLAYER_STATE_PAUSE) {
mpg123_leavePause = 1; mpg123_leavePause = 1;
...@@ -365,6 +373,7 @@ int mpg123processMessages() { ...@@ -365,6 +373,7 @@ int mpg123processMessages() {
mpg123_error = 1; mpg123_error = 1;
mpg123_leavePlay = 1; mpg123_leavePlay = 1;
} }
if(mpg123_state==PLAYER_STATE_PAUSE) mpg123_lastFrame = time(NULL);
mpg123_elapsedTime = mpg123_reportedElapsedTime+time(NULL)-mpg123_lastFrame; mpg123_elapsedTime = mpg123_reportedElapsedTime+time(NULL)-mpg123_lastFrame;
if(!mpg123_error && mpg123_leavePlay && mpg123_elapsedTime>=mpg123_totalTime) { if(!mpg123_error && mpg123_leavePlay && mpg123_elapsedTime>=mpg123_totalTime) {
mpg123stop(stderr); mpg123stop(stderr);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#ifdef HAVE_OGG #ifdef HAVE_OGG
#include "ogg.h" #include "ogg.h"
#include "ogg_decode.h"
#include "command.h" #include "command.h"
#include "interface.h" #include "interface.h"
#include "playlist.h" #include "playlist.h"
...@@ -38,22 +39,8 @@ ...@@ -38,22 +39,8 @@
#include <vorbis/vorbisfile.h> #include <vorbis/vorbisfile.h>
#include <ao/ao.h> #include <ao/ao.h>
#define OGG_ERROR "@ERROR"
#define OGG_START "@START"
#define OGG_TIME "@TIME"
#define OGG_DONE "@DONE"
#define OGG_PAUSE_GOT "@PAUSE_GOT"
#define OGG_STOP "stop"
#define OGG_PAUSE "pause"
#define INPUT_BUFFER_SIZE 80
#define MAX_BUFFER_LENGTH 1024 #define MAX_BUFFER_LENGTH 1024
char pcmout[64];
char input[INPUT_BUFFER_SIZE+1];
int ogg_pid = 0; int ogg_pid = 0;
int ogg_state = PLAYER_STATE_STOP; int ogg_state = PLAYER_STATE_STOP;
int ogg_elapsedTime = 0; int ogg_elapsedTime = 0;
...@@ -66,93 +53,6 @@ char ogg_buffer[MAX_BUFFER_LENGTH+1]; ...@@ -66,93 +53,6 @@ char ogg_buffer[MAX_BUFFER_LENGTH+1];
int ogg_bufferLength = 0; int ogg_bufferLength = 0;
char ogg_currentSong[MAXPATHLEN+1] = "\0"; char ogg_currentSong[MAXPATHLEN+1] = "\0";
int ogg_GO(char * file, FILE * in, FILE * out) {
OggVorbis_File vf;
int eof=0;
int current_section;
ao_device *device;
ao_sample_format format;
int default_driver;
FILE * oggfp;
int pause=0;
long ret;
float last_tell = 0;
ao_initialize();
default_driver = ao_default_driver_id();
if(!(oggfp = fopen(file,"r")) || ov_open(oggfp, &vf, NULL, 0) < 0) {
fprintf(out,"%s Input does not appear to be an Ogg bitstream.\n",OGG_ERROR);
fflush(out);
return -1;
}
{
vorbis_info *vi=ov_info(&vf,-1);
format.bits = 16;
format.channels = vi->channels;
format.rate = vi->rate;
format.byte_format = AO_FMT_LITTLE;
}
device = ao_open_live(default_driver,&format,NULL);
if(device == NULL) {
fprintf(out, "%s Error opening device.\n",OGG_ERROR);
fflush(out);
return -1;
}
fprintf(out,"%s\n",OGG_START);
fprintf(out,"%s %f %f\n",OGG_TIME,last_tell,ov_time_total(&vf,-1));
while(!eof) {
if(!pause) ret=ov_read(&vf,pcmout,sizeof(pcmout),0,2,1,&current_section);
if(ret==0) {
eof=1;
}
else if(ret<0) {
}
else if(!pause) {
ao_play(device,pcmout,sizeof(pcmout));
if(ov_time_tell(&vf)-last_tell>=0.2) {
last_tell = ov_time_tell(&vf);
fprintf(out,"%s %f %f\n",OGG_TIME,last_tell,ov_time_total(&vf,-1));
fflush(out);
}
}
{
static fd_set fds;
static struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fileno(in),&fds);
fflush(in);
if(select(fileno(in)+1,&fds,NULL,NULL,&tv)) {
myFgets(input,INPUT_BUFFER_SIZE,in);
if(strcasecmp(OGG_STOP,input)==0) {
eof=1;
}
else if(strcasecmp(OGG_PAUSE,input)==0) {
fprintf(out,"%s\n",OGG_PAUSE_GOT);
fflush(out);
pause = !pause;;
}
}
}
if(pause) usleep(1000);
}
ao_close(device);
ao_shutdown();
ov_clear(&vf);
fprintf(out,"%s\n",OGG_DONE);
return 0;
}
void ogg_sigHandler(int signal) { void ogg_sigHandler(int signal) {
if(signal==SIGCHLD) { if(signal==SIGCHLD) {
wait3(NULL,WNOHANG,NULL); wait3(NULL,WNOHANG,NULL);
...@@ -200,7 +100,7 @@ int oggInit(char * file) { ...@@ -200,7 +100,7 @@ int oggInit(char * file) {
in = fdopen(fd_send[1],"r"); in = fdopen(fd_send[1],"r");
out = fdopen(fd_recv[1],"w"); out = fdopen(fd_recv[1],"w");
if(ogg_GO(file,in,out)<0) { if(ogg_decode(file,in,out)<0) {
fprintf(stderr,"%s Problems spawning ogg\n",COMMAND_RESPOND_ERROR); fprintf(stderr,"%s Problems spawning ogg\n",COMMAND_RESPOND_ERROR);
fclose(in); fclose(in);
fclose(out); fclose(out);
......
/* the Music Player Daemon (MPD)
* (c)2003 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://musicpd.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_OGG
#include "ogg_decode.h"
#include "command.h"
#include "utils.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <vorbis/vorbisfile.h>
#include <ao/ao.h>
#define CHUNK_SIZE 256
#define BUFFERED_CHUNKS 8192 /* 2 MB of buffer */
#define PLAY_SIZE 64
#define TIME_TELL_INTERVAL 0.2
#define INPUT_BUFFER_SIZE 80
int decode_pid = 0;
int decode_done = 0;
void ogg_decode_parentSigHandler(int sig) {
if(sig==SIGCHLD) {
wait3(NULL,WNOHANG,NULL);
decode_pid = 0;
decode_done = 1;
}
}
/* ogg_decode w/ buffering
* this will fork another process
* child process does decoding
* parent process does buffering && playing audio
*/
int ogg_decode(char * file, FILE * in, FILE * out) {
OggVorbis_File vf;
ao_device *device;
ao_sample_format format;
int default_driver;
float time_total;
FILE * oggfp;
int fd_chunks[2], fd_times[2];
if(!(oggfp = fopen(file,"r")) || ov_open(oggfp, &vf, NULL, 0) < 0) {
fprintf(out,"%s Input does not appear to be an Ogg bitstream.\n",OGG_ERROR);
fflush(out);
return -1;
}
{
vorbis_info *vi=ov_info(&vf,-1);
format.bits = 16;
format.channels = vi->channels;
format.rate = vi->rate;
format.byte_format = AO_FMT_LITTLE;
}
time_total = ov_time_total(&vf,-1);
if(socketpair(AF_UNIX,SOCK_STREAM,0,fd_chunks)<0) {
fprintf(stderr,"%s ogg_decode Problems socketpair'ing\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(socketpair(AF_UNIX,SOCK_STREAM,0,fd_times)<0) {
fprintf(stderr,"%s ogg_decode Problems socketpair'ing\n",COMMAND_RESPOND_ERROR);
return -1;
}
signal(SIGPIPE,SIG_IGN);
signal(SIGCHLD,ogg_decode_parentSigHandler);
fflush(NULL);
decode_pid = fork();
if(decode_pid==0) {
/* CHILD */
char chunk[CHUNK_SIZE];
float time;
int current_section;
int eof = 0;
fd_set fds;
struct timeval tv;
int start=1;
long ret;
tv.tv_sec = 0;
tv.tv_usec = 0;
fclose(in);
fclose(out);
close(fd_chunks[0]);
close(fd_times[0]);
while(!eof) {
ret = ov_read(&vf,chunk,CHUNK_SIZE,0,2,1,&current_section);
time = ov_time_tell(&vf);
if(ret==0) eof = 1;
FD_ZERO(&fds);
FD_SET(fd_chunks[1],&fds);
FD_SET(fd_times[1],&fds);
while(!start && 2!=select(FD_SETSIZE,NULL,&fds,NULL,&tv)) {
usleep(100);
FD_ZERO(&fds);
FD_SET(fd_chunks[1],&fds);
FD_SET(fd_times[1],&fds);
}
start = 0;
if(write(fd_chunks[1],chunk,CHUNK_SIZE)<0) {
fprintf(stderr,"%s ogg_decode child problems writing\n",COMMAND_RESPOND_ERROR);
exit(-1);
}
if(write(fd_times[1],&(time),sizeof(float))<0) {
fprintf(stderr,"%s ogg_decode child problems writing\n",COMMAND_RESPOND_ERROR);
exit(-1);
}
}
time = -1;
if(write(fd_times[1],&(time),sizeof(float))<0) {
fprintf(stderr,"%s ogg_decode child problems writing\n",COMMAND_RESPOND_ERROR);
exit(-1);
}
ov_clear(&vf);
close(fd_times[1]);
close(fd_chunks[1]);
exit(0);
/* END OF CHILD */
}
else if(decode_pid<0) {
fprintf(stderr,"%s ogg_decode Problems fork'ing\n",COMMAND_RESPOND_ERROR);
return -1;
}
{
/* PARENT */
float elapsed;
float last_tell = 0;
int pause = 0;
char input[INPUT_BUFFER_SIZE+1];
char ** buffer;
float time[BUFFERED_CHUNKS];
int begin = 0;
int end = 0;
int wrap = 0;
int playsPerChunk = CHUNK_SIZE/PLAY_SIZE;
int currentPlayChunk = 0;
int i;
int quit = 0;
close(fd_chunks[1]);
close(fd_times[1]);
ov_clear(&vf);
ao_initialize();
default_driver = ao_default_driver_id();
device = ao_open_live(default_driver,&format,NULL);
if(device == NULL) {
fprintf(out, "%s Error opening device.\n",OGG_ERROR);
fflush(out);
close(fd_chunks[0]);
close(fd_times[0]);
kill(decode_pid,SIGTERM);
wait(NULL);
return -1;
}
buffer = malloc(sizeof(char *)*BUFFERED_CHUNKS);
for(i=0;i<BUFFERED_CHUNKS;i++) {
buffer[i] = malloc(sizeof(char)*CHUNK_SIZE);
}
fprintf(out,"%s\n",OGG_START);
fprintf(out,"%s %f %f\n",OGG_TIME,last_tell,time_total);
while(!quit) {
if((begin!=end || !wrap) && !decode_done) {
static fd_set fds;
static struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fd_times[0],&fds);
if(select(FD_SETSIZE,&fds,NULL,NULL,&tv)) {
read(fd_times[0],&(time[end]),sizeof(float));
if(time[end]<0) decode_done = 1;
else {
read(fd_chunks[0],buffer[end],CHUNK_SIZE);
}
end++;
if(end>=BUFFERED_CHUNKS) {
end = 0;
wrap = 1;
}
}
}
if(begin==end && !wrap && decode_done) quit = 1;
if((begin!=end || wrap) && !pause) {
if(currentPlayChunk==0) elapsed = time[begin];
ao_play(device,buffer[begin]+currentPlayChunk*PLAY_SIZE,PLAY_SIZE);
currentPlayChunk++;
if(currentPlayChunk>=playsPerChunk) {
currentPlayChunk=0;
begin++;
if(begin>=BUFFERED_CHUNKS) {
begin = 0;
wrap = 0;
}
}
if(elapsed-last_tell>=TIME_TELL_INTERVAL) {
last_tell = elapsed;
fprintf(out,"%s %f %f\n",OGG_TIME,last_tell,time_total);
fflush(out);
}
}
{
static fd_set fds;
static struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fileno(in),&fds);
fflush(in);
if(select(fileno(in)+1,&fds,NULL,NULL,&tv)) {
myFgets(input,INPUT_BUFFER_SIZE,in);
if(strcasecmp(OGG_STOP,input)==0) {
quit = 1;
}
else if(strcasecmp(OGG_PAUSE,input)==0) {
fprintf(out,"%s\n",OGG_PAUSE_GOT);
fflush(out);
pause = !pause;
}
}
}
if(pause) usleep(1000);
}
if(decode_pid>0) {
kill(decode_pid,SIGTERM);
wait(NULL);
}
for(i=0;i<BUFFERED_CHUNKS;i++) {
free(buffer[i]);
}
free(buffer);
close(fd_times[0]);
close(fd_chunks[0]);
fprintf(out,"%s\n",OGG_DONE);
/* END OF PARENT */
}
return 0;
}
#endif
/* the Music Player Daemon (MPD)
* (c)2003 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://musicpd.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef OGG_DECODE_H
#define OGG_DECODE_H
#include <stdio.h>
#define OGG_ERROR "@ERROR"
#define OGG_START "@START"
#define OGG_TIME "@TIME"
#define OGG_DONE "@DONE"
#define OGG_PAUSE_GOT "@PAUSE_GOT"
#define OGG_STOP "stop"
#define OGG_PAUSE "pause"
int ogg_decode(char * file, FILE * in, FILE * out);
#endif
...@@ -32,6 +32,10 @@ ...@@ -32,6 +32,10 @@
#define PLAYLIST_STATE_STOP 0 #define PLAYLIST_STATE_STOP 0
#define PLAYLIST_STATE_PLAY 1 #define PLAYLIST_STATE_PLAY 1
#define PLAYLIST_PREV_UNLESS_ELAPSED 10
/* if a song is played more than PREV_UNLESS_ELAPSED seconds,
* 'previous' restarts playing this song ('play it again, sam')
* */
Playlist playlist; Playlist playlist;
char playlistDir[MAXPATHLEN+1]; char playlistDir[MAXPATHLEN+1];
...@@ -180,6 +184,11 @@ void nextSongInPlaylistIfPlayerStopped() { ...@@ -180,6 +184,11 @@ void nextSongInPlaylistIfPlayerStopped() {
} }
int nextSongInPlaylist(FILE * fp) { int nextSongInPlaylist(FILE * fp) {
if(playlist_state!=PLAYLIST_STATE_PLAY) {
fprintf(fp,"%s not currently playing\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(playlist.current<playlist.length-1) { if(playlist.current<playlist.length-1) {
return playPlaylist(fp,playlist.current+1); return playPlaylist(fp,playlist.current+1);
} }
...@@ -188,6 +197,27 @@ int nextSongInPlaylist(FILE * fp) { ...@@ -188,6 +197,27 @@ int nextSongInPlaylist(FILE * fp) {
return 0; return 0;
} }
int previousSongInPlaylist(FILE * fp) {
if(playlist_state!=PLAYLIST_STATE_PLAY) {
fprintf(fp,"%s not currently playing\n",COMMAND_RESPOND_ERROR);
return -1;
}
if (getPlayerElapsedTime()>PLAYLIST_PREV_UNLESS_ELAPSED) {
return playPlaylist(fp,playlist.current);
}
else {
if(playlist.current>0) {
return playPlaylist(fp,playlist.current-1);
}
else {
return playPlaylist(fp,playlist.current);
}
}
return 0;
}
int shufflePlaylist(FILE * fp) { int shufflePlaylist(FILE * fp) {
int i; int i;
int ri; int ri;
...@@ -255,7 +285,7 @@ int loadPlaylist(FILE * fp, char * file) { ...@@ -255,7 +285,7 @@ int loadPlaylist(FILE * fp, char * file) {
int slength = 0; int slength = 0;
if((fileP = fopen(file,"r"))==NULL) { if((fileP = fopen(file,"r"))==NULL) {
fprintf(fp,"%s Problems opening file\n",COMMAND_RESPOND_ERROR); fprintf(fp,"%s Problems opening file \"%s\"\n",COMMAND_RESPOND_ERROR,file);
return -1; return -1;
} }
......
...@@ -53,6 +53,8 @@ int playPlaylist(FILE * fp, int song); ...@@ -53,6 +53,8 @@ int playPlaylist(FILE * fp, int song);
int nextSongInPlaylist(FILE * fp); int nextSongInPlaylist(FILE * fp);
int previousSongInPlaylist(FILE * fp);
int shufflePlaylist(FILE * fp); int shufflePlaylist(FILE * fp);
int savePlaylist(FILE * fp, char * file); int savePlaylist(FILE * fp, char * file);
......
...@@ -27,21 +27,22 @@ ...@@ -27,21 +27,22 @@
#define TABLES_ALBUM "album" #define TABLES_ALBUM "album"
#define TABLES_ARTIST "artist" #define TABLES_ARTIST "artist"
#define TABLES_TITLE "title" #define TABLES_TITLE "title"
#define TABLES_FILENAME "filename"
List * albumTable; List * albumTable;
List * artistTable; List * artistTable;
List * titleTable; List * songTable;
void initTables() { void initTables() {
albumTable = makeList(freeList); albumTable = makeList(freeList);
artistTable = makeList(freeList); artistTable = makeList(freeList);
titleTable = makeList(NULL); songTable = makeList(NULL);
} }
void closeTables() { void closeTables() {
freeList(albumTable); freeList(albumTable);
freeList(artistTable); freeList(artistTable);
freeList(titleTable); freeList(songTable);
} }
void addSongToAlbumTable(Song * song) { void addSongToAlbumTable(Song * song) {
...@@ -73,9 +74,7 @@ void addSongToArtistTable(Song * song) { ...@@ -73,9 +74,7 @@ void addSongToArtistTable(Song * song) {
} }
void addSongToSongTable(Song * song) { void addSongToSongTable(Song * song) {
if(!song->tag) return; insertInList(songTable,song->file,song);
if(!song->tag->title) return;
insertInList(titleTable,song->file,song);
} }
void addSongToTables(Song * song) { void addSongToTables(Song * song) {
...@@ -172,15 +171,17 @@ int searchForSongsInArtistTable(FILE * fp,char * search) { ...@@ -172,15 +171,17 @@ int searchForSongsInArtistTable(FILE * fp,char * search) {
return ret; return ret;
} }
int searchForSongsInTitleTable(FILE * fp,char * search) { int searchForSongsInSongTableByTitle(FILE * fp,char * search) {
Song * song; Song * song;
ListNode * node = titleTable->firstNode; ListNode * node = songTable->firstNode;
int ret = -1; int ret = -1;
char * dup; char * dup;
char * dupSearch = strDupToUpper(search); char * dupSearch = strDupToUpper(search);
while(node) { while(node) {
song = (Song *)node->data; song = (Song *)node->data;
if(!song->tag) break;
if(!song->tag->title) break;
dup = strDupToUpper(song->tag->title); dup = strDupToUpper(song->tag->title);
if(strstr(dup,dupSearch)) { if(strstr(dup,dupSearch)) {
if(printSongInfo(fp,song)<0) { if(printSongInfo(fp,song)<0) {
...@@ -200,6 +201,34 @@ int searchForSongsInTitleTable(FILE * fp,char * search) { ...@@ -200,6 +201,34 @@ int searchForSongsInTitleTable(FILE * fp,char * search) {
return ret; return ret;
} }
int searchForSongsInSongTableByFilename(FILE * fp,char * search) {
Song * song;
ListNode * node = songTable->firstNode;
int ret = -1;
char * dup;
char * dupSearch = strDupToUpper(search);
while(node) {
song = (Song *)node->data;
dup = strDupToUpper(song->file);
if(strstr(dup,dupSearch)) {
if(printSongInfo(fp,song)<0) {
free(dup);
free(dupSearch);
return -1;
}
ret = 0;
}
free(dup);
node = node->nextNode;
}
free(dupSearch);
if(ret<0) fprintf(fp,"%s no songs found\n",COMMAND_RESPOND_ERROR);
return ret;
}
int searchForSongsInTable(FILE * fp, char * table, char * search) { int searchForSongsInTable(FILE * fp, char * table, char * search) {
if(strcmp(table,TABLES_ALBUM)==0) { if(strcmp(table,TABLES_ALBUM)==0) {
return searchForSongsInAlbumTable(fp,search); return searchForSongsInAlbumTable(fp,search);
...@@ -208,7 +237,10 @@ int searchForSongsInTable(FILE * fp, char * table, char * search) { ...@@ -208,7 +237,10 @@ int searchForSongsInTable(FILE * fp, char * table, char * search) {
return searchForSongsInArtistTable(fp,search); return searchForSongsInArtistTable(fp,search);
} }
else if(strcmp(table,TABLES_TITLE)==0) { else if(strcmp(table,TABLES_TITLE)==0) {
return searchForSongsInTitleTable(fp,search); return searchForSongsInSongTableByTitle(fp,search);
}
else if(strcmp(table,TABLES_FILENAME)==0) {
return searchForSongsInSongTableByFilename(fp,search);
} }
fprintf(fp,"%s unkown table\n",COMMAND_RESPOND_ERROR); fprintf(fp,"%s unkown table\n",COMMAND_RESPOND_ERROR);
...@@ -241,14 +273,14 @@ void removeSongFromArtistTable(Song * song) { ...@@ -241,14 +273,14 @@ void removeSongFromArtistTable(Song * song) {
} }
} }
void removeSongFromTitleTable(Song * song) { void removeSongFromSongTable(Song * song) {
deleteFromList(titleTable,song->file); deleteFromList(songTable,song->file);
} }
void removeASongFromTables(Song * song) { void removeASongFromTables(Song * song) {
removeSongFromAlbumTable(song); removeSongFromAlbumTable(song);
removeSongFromArtistTable(song); removeSongFromArtistTable(song);
removeSongFromTitleTable(song); removeSongFromSongTable(song);
} }
void removeSongsFromTables(SongList * songList) { void removeSongsFromTables(SongList * songList) {
...@@ -261,3 +293,16 @@ void removeSongsFromTables(SongList * songList) { ...@@ -261,3 +293,16 @@ void removeSongsFromTables(SongList * songList) {
node = node->nextNode; node = node->nextNode;
} }
} }
int printAllSongsInSongTable(FILE * fp) {
Song * song;
ListNode * node = songTable->firstNode;
while(node) {
song = (Song *)node->data;
fprintf(fp,"file: %s\n",song->file);
node = node->nextNode;
}
return 0;
}
...@@ -36,4 +36,6 @@ void removeSongsFromTables(SongList * songList); ...@@ -36,4 +36,6 @@ void removeSongsFromTables(SongList * songList);
void removeASongFromTables(Song * song); void removeASongFromTables(Song * song);
int printAllSongsInSongTable(FILE * fp);
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment