Commit 82ba78e0 authored by Led's avatar Led

0.6.2

parent 026cefdb
......@@ -40,6 +40,9 @@ find <string type> <string what>
kill
kill mpd
listall
lists all available songs (without tag info)
load <string name>
loads the playlist _name_.m3u from the playlist directory
......@@ -51,11 +54,14 @@ ls <string directory>
lsinfo <string directory>
list contents of _directory_, from the db. _directory_ is optional
next
plays next song in playlist
pause
pause/resume playing
play <int song>
being playling playlist at song number _song_
begin playling playlist at song number _song_, _song_ is optiional
playlist
displays the current playlist
......@@ -64,6 +70,9 @@ playlist
playlistinfo
displays information about the current playlist
previous
plays previous song in playlist
rm <string name>
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)
1) Add conf file support
2) Fix a bug when doing mp3stop (do wait3(NULL,WNOHANG|WUNTRACED,NULL))
......
......@@ -16,7 +16,7 @@ DFLAGS = -MM $(INCLUDES) $(HAVE_OGG)
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/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)
DEPENDFILE = Makefile.depend
......
1) Search by Filename
2) buffer support for OGG
3) use autoconf and automake
4) broadcast messages (including status changes/updates)
5) store song times (possibly after playing)
6) add a set a flags (such as BAD MP3)
1) make timeout and max connections configurabe via config file
2) volume control
3) use mpglib from mpg123 for mp3 support
4) use autoconf and automake
5) broadcast messages (including status changes/updates)
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 @@
#define COMMAND_FIND "find"
#define COMMAND_SEARCH "search"
#define COMMAND_UPDATE "update"
#define COMMAND_NEXT "next"
#define COMMAND_PREVIOUS "previous"
#define COMMAND_LISTALL "listall"
extern Playlist playlist;
......@@ -89,15 +92,18 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
if(0==strcmp(argArray[0],COMMAND_PLAY)) {
int song;
char * test;
if(argArrayLength!=2) {
if(argArrayLength>2) {
fprintf(fp,"%s too many arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
song = strtol(argArray[1],&test,10);
if(*test!='\0') {
fprintf(fp,"%s need a positive integer\n",COMMAND_RESPOND_ERROR);
return -1;
if(argArrayLength==2) {
song = strtol(argArray[1],&test,10);
if(*test!='\0') {
fprintf(fp,"%s need a positive integer\n",COMMAND_RESPOND_ERROR);
return -1;
}
}
else song = 0;
return playPlaylist(fp,song);
}
else if(0==strcmp(argArray[0],COMMAND_STOP)) {
......@@ -273,6 +279,27 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
}
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 {
fprintf(fp,"%s Unknown command \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
......
......@@ -28,11 +28,14 @@
#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_REQUIRED 5
#define CONF_MPG123_COMMAND_DEFAULT "mpg123 -b 2048 -R foo"
#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] = {
"mpg123_command",
......@@ -41,7 +44,9 @@ char conf_strings[CONF_NUMBER_OF_PARAMS][24] = {
"playlist_directory",
"log_file",
"error_file",
"mpg123_process"
"mpg123_process",
"mpg123_ignore_junk",
"connection_timeout"
};
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
......@@ -51,6 +56,14 @@ int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
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];
void initConf() {
......@@ -61,6 +74,8 @@ void initConf() {
/* we don't specify these on the command line */
conf_params[CONF_MPG123_COMMAND] = strdup(CONF_MPG123_COMMAND_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) {
......@@ -69,12 +84,6 @@ char ** readConf(char * file) {
char ** array;
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"))) {
fprintf(stderr,"problems opening file %s for reading\n",file);
exit(-1);
......@@ -92,8 +101,7 @@ char ** readConf(char * file) {
exit(-1);
}
if(conf_params[i]!=NULL) {
fprintf(stderr,"%s has already been assigned\n",conf_strings[i]);
exit(-1);
free(conf_params[i]);
}
conf_params[i] = strdup(array[1]);
free(array[0]);
......@@ -103,9 +111,9 @@ char ** readConf(char * file) {
fclose(fp);
for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) {
if(conf_params[i] == NULL) {
fprintf(stderr,"%s is unassinged in conf file\n",conf_strings[i]);
for(i=0;i<CONF_NUMBER_OF_REQUIRED;i++) {
if(conf_params[conf_required[i]] == NULL) {
fprintf(stderr,"%s is unassinged in conf file\n",conf_strings[conf_required[i]]);
exit(-1);
}
}
......
......@@ -26,6 +26,8 @@
#define CONF_LOG_FILE 4
#define CONF_ERROR_FILE 5
#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 */
char ** readConf(char * file);
......
......@@ -19,6 +19,7 @@
#include "interface.h"
#include "buffer2array.h"
#include "command.h"
#include "conf.h"
#include <unistd.h>
#include <stdio.h>
......@@ -29,14 +30,14 @@
#include <string.h>
#include <fcntl.h>
#define VERSION "0.6.1"
#define VERSION "0.6.2"
#define GREETING "MPD"
#define INTERFACE_MAX_BUFFER_LENGTH 1024
#define INTERFACE_MAX_CONNECTIONS 5
#define INTERFACE_TIMEOUT 60
int interface_timeout;
typedef struct _Interface {
char buffer[INTERFACE_MAX_BUFFER_LENGTH+1];
......@@ -167,10 +168,17 @@ int readInputFromInterfaces() {
void initInterfaces() {
int i;
char * test;
for(i=0;i<INTERFACE_MAX_CONNECTIONS;i++) {
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() {
......@@ -197,7 +205,7 @@ void closeOldInterfaces() {
int 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]));
}
}
......
......@@ -50,11 +50,6 @@ int main(int argc, char * argv[]) {
char * logFile;
char * errorFile;
if(argc!=6 && argc!=2) {
usage(argv);
return -1;
}
initConf();
if(argc==6) {
......@@ -72,6 +67,11 @@ int main(int argc, char * argv[]) {
logFile = conf[CONF_LOG_FILE];
errorFile = conf[CONF_ERROR_FILE];
}
else {
usage(argv);
return -1;
}
if((port = atoi(portStr))<0) {
fprintf(stderr,"problem with port number\n");
......@@ -104,8 +104,8 @@ int main(int argc, char * argv[]) {
getcwd(playlistDir,MAXPATHLEN-strlen(playlistDirArg)-1);
strcat(playlistDir,"/");
strcat(playlistDir,playlistDirArg);
strcat(playlistDir,"/");
}
strcat(playlistDir,"/");
if((stat(playlistDir,&st))<0) {
fprintf(stderr,"problem stat'ing \"%s\"\n",playlistDirArg);
return -1;
......
......@@ -5,3 +5,5 @@ log_file "/home/shank/mpd.log"
error_file "/home/shank/mpd.error"
mpg123_command "mpg123 -b 2048 -R foo"
mpg123_process "mpg123"
mpg123_ignore_junk "yes"
connection_timeout "60"
......@@ -53,6 +53,7 @@ int mpg123_leavePlay = 0;
int mpg123_leavePause = 0;
int mpg123_error = 0;
int mpg123_lastFrame = 0;
int mpg123_done = 0;
char mpg123_currentSong[MAXPATHLEN+1] = "\0";
int mpg123readline();
......@@ -80,6 +81,7 @@ int mpg123init() {
int fd_send[2], fd_recv[2], fd_stderr[2];
mpg123_error = 0;
mpg123_done = 0;
mpg123_currentSong[0] = '\0';
if(socketpair(AF_UNIX,SOCK_STREAM,0,fd_send)<0) {
......@@ -218,8 +220,8 @@ int mpg123stop(FILE * fp) {
fprintf(fp,"%s problems write'ing\n",COMMAND_RESPOND_ERROR);
return -1;
}
/* wait upto 1 s to get SIGCHLD */
while(i<10 && mpg123_pid>0) {
/* wait upto 3 s to get SIGCHLD */
while(i<30 && mpg123_pid>0) {
usleep(100000); /* wait for 10ms for mpg123 to die */
wait3(NULL,WNOHANG|WUNTRACED,NULL);
while(mpg123readline());
......@@ -239,7 +241,9 @@ int mpg123stop(FILE * fp) {
int mpg123pause(FILE * fp) {
char string[1024];
if(mpg123_pid>0) {
mpg123processMessages();
if(mpg123_pid>0 && !mpg123_done) {
sprintf(string,"PAUSE\n");
if(write(mpg123_send,string,strlen(string))<0) {
fprintf(fp,"%s problems write'ing\n",COMMAND_RESPOND_ERROR);
......@@ -309,10 +313,13 @@ int mpg123gotErrors() {
if(errorBuffer[errorBufferLength]=='\0' || errorBuffer[errorBufferLength]=='\n' || errorBufferLength == MAX_BUFFER_LENGTH) {
errorBuffer[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!=strcmp("yes",(getConf())[CONF_MPG123_IGNORE_JUNK])) {
fprintf(stderr,"%s file: \"%s\" : %s\n",COMMAND_RESPOND_ERROR,mpg123_currentSong,errorBuffer);
}
return 0;
}
fprintf(stderr,"%s file: \"%s\" : %s\n",COMMAND_RESPOND_ERROR,mpg123_currentSong,errorBuffer);
mpg123kill();
return 1;
}
......@@ -344,6 +351,7 @@ int mpg123processMessages() {
if(!mpg123_leavePlay) {
mpg123_leavePlay=1; mpg123_error=1;
}
mpg123_done = 1;
}
else if(mpg123_state==PLAYER_STATE_PLAY && atoi(c[1])==PLAYER_STATE_PAUSE) {
mpg123_leavePause = 1;
......@@ -365,6 +373,7 @@ int mpg123processMessages() {
mpg123_error = 1;
mpg123_leavePlay = 1;
}
if(mpg123_state==PLAYER_STATE_PAUSE) mpg123_lastFrame = time(NULL);
mpg123_elapsedTime = mpg123_reportedElapsedTime+time(NULL)-mpg123_lastFrame;
if(!mpg123_error && mpg123_leavePlay && mpg123_elapsedTime>=mpg123_totalTime) {
mpg123stop(stderr);
......
......@@ -18,6 +18,7 @@
#ifdef HAVE_OGG
#include "ogg.h"
#include "ogg_decode.h"
#include "command.h"
#include "interface.h"
#include "playlist.h"
......@@ -38,22 +39,8 @@
#include <vorbis/vorbisfile.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
char pcmout[64];
char input[INPUT_BUFFER_SIZE+1];
int ogg_pid = 0;
int ogg_state = PLAYER_STATE_STOP;
int ogg_elapsedTime = 0;
......@@ -66,93 +53,6 @@ char ogg_buffer[MAX_BUFFER_LENGTH+1];
int ogg_bufferLength = 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) {
if(signal==SIGCHLD) {
wait3(NULL,WNOHANG,NULL);
......@@ -200,7 +100,7 @@ int oggInit(char * file) {
in = fdopen(fd_send[1],"r");
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);
fclose(in);
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
......@@ -30,8 +30,12 @@
#include <unistd.h>
#include <time.h>
#define PLAYLIST_STATE_STOP 0
#define PLAYLIST_STATE_PLAY 1
#define PLAYLIST_STATE_STOP 0
#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;
char playlistDir[MAXPATHLEN+1];
......@@ -180,6 +184,11 @@ void nextSongInPlaylistIfPlayerStopped() {
}
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) {
return playPlaylist(fp,playlist.current+1);
}
......@@ -188,6 +197,27 @@ int nextSongInPlaylist(FILE * fp) {
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 i;
int ri;
......@@ -255,7 +285,7 @@ int loadPlaylist(FILE * fp, char * file) {
int slength = 0;
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;
}
......
......@@ -53,6 +53,8 @@ int playPlaylist(FILE * fp, int song);
int nextSongInPlaylist(FILE * fp);
int previousSongInPlaylist(FILE * fp);
int shufflePlaylist(FILE * fp);
int savePlaylist(FILE * fp, char * file);
......
......@@ -27,21 +27,22 @@
#define TABLES_ALBUM "album"
#define TABLES_ARTIST "artist"
#define TABLES_TITLE "title"
#define TABLES_FILENAME "filename"
List * albumTable;
List * artistTable;
List * titleTable;
List * songTable;
void initTables() {
albumTable = makeList(freeList);
artistTable = makeList(freeList);
titleTable = makeList(NULL);
songTable = makeList(NULL);
}
void closeTables() {
freeList(albumTable);
freeList(artistTable);
freeList(titleTable);
freeList(songTable);
}
void addSongToAlbumTable(Song * song) {
......@@ -73,9 +74,7 @@ void addSongToArtistTable(Song * song) {
}
void addSongToSongTable(Song * song) {
if(!song->tag) return;
if(!song->tag->title) return;
insertInList(titleTable,song->file,song);
insertInList(songTable,song->file,song);
}
void addSongToTables(Song * song) {
......@@ -172,15 +171,17 @@ int searchForSongsInArtistTable(FILE * fp,char * search) {
return ret;
}
int searchForSongsInTitleTable(FILE * fp,char * search) {
int searchForSongsInSongTableByTitle(FILE * fp,char * search) {
Song * song;
ListNode * node = titleTable->firstNode;
ListNode * node = songTable->firstNode;
int ret = -1;
char * dup;
char * dupSearch = strDupToUpper(search);
while(node) {
song = (Song *)node->data;
if(!song->tag) break;
if(!song->tag->title) break;
dup = strDupToUpper(song->tag->title);
if(strstr(dup,dupSearch)) {
if(printSongInfo(fp,song)<0) {
......@@ -200,6 +201,34 @@ int searchForSongsInTitleTable(FILE * fp,char * search) {
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) {
if(strcmp(table,TABLES_ALBUM)==0) {
return searchForSongsInAlbumTable(fp,search);
......@@ -208,7 +237,10 @@ int searchForSongsInTable(FILE * fp, char * table, char * search) {
return searchForSongsInArtistTable(fp,search);
}
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);
......@@ -241,14 +273,14 @@ void removeSongFromArtistTable(Song * song) {
}
}
void removeSongFromTitleTable(Song * song) {
deleteFromList(titleTable,song->file);
void removeSongFromSongTable(Song * song) {
deleteFromList(songTable,song->file);
}
void removeASongFromTables(Song * song) {
removeSongFromAlbumTable(song);
removeSongFromArtistTable(song);
removeSongFromTitleTable(song);
removeSongFromSongTable(song);
}
void removeSongsFromTables(SongList * songList) {
......@@ -261,3 +293,16 @@ void removeSongsFromTables(SongList * songList) {
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;
}
......@@ -30,10 +30,12 @@ void addSongToTables(Song * song);
int findAndPrintSongsInTable(FILE * fp, char * table, char * find);
int searchForSongsInTable(FILE * fp, char * table, char * find);
int searchForSongsInTable(FILE * fp, char * table, char * find);
void removeSongsFromTables(SongList * songList);
void removeASongFromTables(Song * song);
int printAllSongsInSongTable(FILE * fp);
#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