Commit d7a18b97 authored by Led's avatar Led

0.11.0-pre2

parent 887593ce
1) put some sort of error reporting for streaming/inputStream!
*) put some sort of error reporting for streaming/inputStream!
2) Fix charset errors so they don't goto stderr/out
*) Fix charset errors so they don't goto stderr/out
*) compute time of vorbis from actual number of samples played
*) remove previous hack for streams
Post-1.0
--------
......
......@@ -110,6 +110,10 @@ playlistinfo <int song>
displays list of songs in the playlist
_song_ is optional and species a single song to displa info for
plchanges <playlist version>
displays changed songs currently in the playlist since
_playlist version_
previous
plays previous song in playlist
......@@ -198,6 +202,10 @@ at once using a command list. The command list beings with:
command_list_begin
or:
command_list_ok_begin
And ends with:
command_list_end
......@@ -205,4 +213,5 @@ command_list_end
It does not execute any commands until the list has ended. The return
value is whatever the return for a list of commands is. On success
for all commands, OK is returned. If a command fails, no more commands
are executed and the appropriate ACK error is returned.
are executed and the appropriate ACK error is returned. If "command_list_ok_begin is used", "list_OK\n" is returned for each successful command executed
in the command list.
......@@ -13,7 +13,7 @@ mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \
charConv.h permission.h mpd_types.h pcm_utils.h \
signal_check.h utf8.h inputStream.h \
outputBuffer.h replayGain.h inputStream_file.h inputStream_http.h \
inputPlugin.h
inputPlugin.h metadataChunk.h ack.h
mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \
song.c list.c directory.c tables.c utils.c path.c \
tag.c player.c listen.c conf.c volume.c \
......@@ -21,7 +21,7 @@ mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \
charConv.c permission.c pcm_utils.c \
signal_check.c utf8.c inputStream.c outputBuffer.c \
replayGain.c inputStream_file.c inputStream_http.c inputPlugin.c \
$(mpd_headers) $(mpd_inputPlugins)
metadataChunk.c $(mpd_headers) $(mpd_inputPlugins)
mpd_CFLAGS = $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB)
......
......@@ -126,7 +126,7 @@ mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \
charConv.h permission.h mpd_types.h pcm_utils.h \
signal_check.h utf8.h inputStream.h \
outputBuffer.h replayGain.h inputStream_file.h inputStream_http.h \
inputPlugin.h
inputPlugin.h metadataChunk.h ack.h
mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \
song.c list.c directory.c tables.c utils.c path.c \
......@@ -135,7 +135,7 @@ mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \
charConv.c permission.c pcm_utils.c \
signal_check.c utf8.c inputStream.c outputBuffer.c \
replayGain.c inputStream_file.c inputStream_http.c inputPlugin.c \
$(mpd_headers) $(mpd_inputPlugins)
metadataChunk.c $(mpd_headers) $(mpd_inputPlugins)
mpd_CFLAGS = $(MPD_CFLAGS)
......@@ -169,7 +169,7 @@ am_mpd_OBJECTS = mpd-main.$(OBJEXT) mpd-buffer2array.$(OBJEXT) \
mpd-inputStream.$(OBJEXT) mpd-outputBuffer.$(OBJEXT) \
mpd-replayGain.$(OBJEXT) mpd-inputStream_file.$(OBJEXT) \
mpd-inputStream_http.$(OBJEXT) mpd-inputPlugin.$(OBJEXT) \
$(am__objects_1) $(am__objects_2)
mpd-metadataChunk.$(OBJEXT) $(am__objects_1) $(am__objects_2)
mpd_OBJECTS = $(am_mpd_OBJECTS)
mpd_DEPENDENCIES =
mpd_LDFLAGS =
......@@ -198,6 +198,7 @@ am__depfiles_maybe = depfiles
@AMDEP_TRUE@ ./$(DEPDIR)/mpd-list.Po ./$(DEPDIR)/mpd-listen.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mpd-log.Po ./$(DEPDIR)/mpd-ls.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mpd-main.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mpd-metadataChunk.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mpd-mod_plugin.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mpd-mp3_plugin.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mpd-mp4_plugin.Po \
......@@ -307,6 +308,7 @@ mpd-replayGain.$(OBJEXT): replayGain.c
mpd-inputStream_file.$(OBJEXT): inputStream_file.c
mpd-inputStream_http.$(OBJEXT): inputStream_http.c
mpd-inputPlugin.$(OBJEXT): inputPlugin.c
mpd-metadataChunk.$(OBJEXT): metadataChunk.c
mpd-mp3_plugin.$(OBJEXT): inputPlugins/mp3_plugin.c
mpd-ogg_plugin.$(OBJEXT): inputPlugins/ogg_plugin.c
mpd-flac_plugin.$(OBJEXT): inputPlugins/flac_plugin.c
......@@ -344,6 +346,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpd-log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpd-ls.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpd-main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpd-metadataChunk.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpd-mod_plugin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpd-mp3_plugin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpd-mp4_plugin.Po@am__quote@
......@@ -1018,6 +1021,24 @@ mpd-inputPlugin.lo: inputPlugin.c
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mpd_CFLAGS) $(CFLAGS) -c -o mpd-inputPlugin.lo `test -f 'inputPlugin.c' || echo '$(srcdir)/'`inputPlugin.c
mpd-metadataChunk.o: metadataChunk.c
@AMDEP_TRUE@ source='metadataChunk.c' object='mpd-metadataChunk.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/mpd-metadataChunk.Po' tmpdepfile='$(DEPDIR)/mpd-metadataChunk.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mpd_CFLAGS) $(CFLAGS) -c -o mpd-metadataChunk.o `test -f 'metadataChunk.c' || echo '$(srcdir)/'`metadataChunk.c
mpd-metadataChunk.obj: metadataChunk.c
@AMDEP_TRUE@ source='metadataChunk.c' object='mpd-metadataChunk.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/mpd-metadataChunk.Po' tmpdepfile='$(DEPDIR)/mpd-metadataChunk.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mpd_CFLAGS) $(CFLAGS) -c -o mpd-metadataChunk.obj `cygpath -w metadataChunk.c`
mpd-metadataChunk.lo: metadataChunk.c
@AMDEP_TRUE@ source='metadataChunk.c' object='mpd-metadataChunk.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/mpd-metadataChunk.Plo' tmpdepfile='$(DEPDIR)/mpd-metadataChunk.TPlo' @AMDEPBACKSLASH@
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mpd_CFLAGS) $(CFLAGS) -c -o mpd-metadataChunk.lo `test -f 'metadataChunk.c' || echo '$(srcdir)/'`metadataChunk.c
mpd-mp3_plugin.o: inputPlugins/mp3_plugin.c
@AMDEP_TRUE@ source='inputPlugins/mp3_plugin.c' object='mpd-mp3_plugin.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/mpd-mp3_plugin.Po' tmpdepfile='$(DEPDIR)/mpd-mp3_plugin.TPo' @AMDEPBACKSLASH@
......
#ifndef ACK_H
#define ACK_H
#define ACK_ERROR_NOT_LIST 1
#define ACK_ERROR_ARG 2
#define ACK_ERROR_PASSWORD 3
#define ACK_ERROR_PERMISSION 4
#define ACK_ERROR_UNKNOWN 5
#define ACK_ERROR_NO_EXIST 6
#define ACK_ERROR_PLAYLIST_MAX 7
#define ACK_ERROR_SYSTEM 8
#define ACK_ERROR_PLAYLIST_LOAD 9
#define ACK_ERROR_UPDATE_ALREADY 10
#define ACK_ERROR_PLAYER_SYNC 11
#define ACK_ERROR_EXIST 12
#endif
......@@ -38,6 +38,7 @@
#include <unistd.h>
#define COMMAND_PLAY "play"
#define COMMAND_PLAYID "playid"
#define COMMAND_STOP "stop"
#define COMMAND_PAUSE "pause"
#define COMMAND_STATUS "status"
......@@ -45,6 +46,7 @@
#define COMMAND_CLOSE "close"
#define COMMAND_ADD "add"
#define COMMAND_DELETE "delete"
#define COMMAND_DELETEID "deleteid"
#define COMMAND_PLAYLIST "playlist"
#define COMMAND_SHUFFLE "shuffle"
#define COMMAND_CLEAR "clear"
......@@ -53,6 +55,7 @@
#define COMMAND_LSINFO "lsinfo"
#define COMMAND_RM "rm"
#define COMMAND_PLAYLISTINFO "playlistinfo"
#define COMMAND_PLAYLISTID "playlistid"
#define COMMAND_FIND "find"
#define COMMAND_SEARCH "search"
#define COMMAND_UPDATE "update"
......@@ -66,14 +69,19 @@
#define COMMAND_CLEAR_ERROR "clearerror"
#define COMMAND_LIST "list"
#define COMMAND_MOVE "move"
#define COMMAND_MOVEID "moveid"
#define COMMAND_SWAP "swap"
#define COMMAND_SWAPID "swapid"
#define COMMAND_SEEK "seek"
#define COMMAND_SEEKID "seekid"
#define COMMAND_LISTALLINFO "listallinfo"
#define COMMAND_PING "ping"
#define COMMAND_SETVOL "setvol"
#define COMMAND_PASSWORD "password"
#define COMMAND_CROSSFADE "crossfade"
#define COMMAND_URL_HANDLERS "urlhandlers"
#define COMMAND_PLCHANGES "plchanges"
#define COMMAND_CURRENT "current"
#define COMMAND_STATUS_VOLUME "volume"
#define COMMAND_STATUS_STATE "state"
......@@ -82,6 +90,7 @@
#define COMMAND_STATUS_PLAYLIST "playlist"
#define COMMAND_STATUS_PLAYLIST_LENGTH "playlistlength"
#define COMMAND_STATUS_SONG "song"
#define COMMAND_STATUS_SONGID "songid"
#define COMMAND_STATUS_TIME "time"
#define COMMAND_STATUS_BITRATE "bitrate"
#define COMMAND_STATUS_ERROR "error"
......@@ -162,12 +171,40 @@ int handlePlay(FILE * fp, unsigned int * permission, int argArrayLength,
return playPlaylist(fp,song,0);
}
int handlePlayId(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
int id = -1;
char * test;
if(argArrayLength==2) {
id = strtol(argArray[1],&test,10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG,
"need a positive integer");
return -1;
}
}
return playPlaylist(fp, id, 0);
}
int handleStop(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
return stopPlaylist(fp);
}
int handleCurrent(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
int song = getPlaylistCurrentSong();
if(song >= 0) {
return playlistInfo(fp, song);
}
else return 0;
}
int handlePause(FILE * fp, unsigned int * permission,
int argArrayLength, char ** argArray)
{
......@@ -190,6 +227,7 @@ int commandStatus(FILE * fp, unsigned int * permission, int argArrayLength,
int updateJobId;
int song;
/*syncPlayerAndPlaylist();*/
playPlaylistIfPlayerStopped();
switch(getPlayerState()) {
case PLAYER_STATE_STOP:
......@@ -214,7 +252,11 @@ int commandStatus(FILE * fp, unsigned int * permission, int argArrayLength,
myfprintf(fp,"%s: %s\n",COMMAND_STATUS_STATE,state);
song = getPlaylistCurrentSong();
if(song >= 0) myfprintf(fp,"%s: %i\n",COMMAND_STATUS_SONG,song);
if(song >= 0) {
myfprintf(fp,"%s: %i\n", COMMAND_STATUS_SONG, song);
myfprintf(fp,"%s: %i\n", COMMAND_STATUS_SONGID,
getPlaylistSongId(song));
}
if(getPlayerState()!=PLAYER_STATE_STOP) {
myfprintf(fp,"%s: %i:%i\n",COMMAND_STATUS_TIME,getPlayerElapsedTime(),getPlayerTotalTime());
myfprintf(fp,"%s: %li\n",COMMAND_STATUS_BITRATE,getPlayerBitRate(),getPlayerTotalTime());
......@@ -273,6 +315,21 @@ int handleDelete(FILE * fp, unsigned int * permission, int argArrayLength,
return deleteFromPlaylist(fp,song);
}
int handleDeleteId(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
int id;
char * test;
id = strtol(argArray[1],&test,10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG,
"need a positive integer");
return -1;
}
return deleteFromPlaylist(fp, id);
}
int handlePlaylist(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
......@@ -322,6 +379,20 @@ int handleRm(FILE * fp, unsigned int * permission, int argArrayLength,
return deletePlaylist(fp,argArray[1]);
}
int handlePlaylistChanges(FILE * fp, unsigned int * permission,
int argArrayLength, char ** argArray)
{
unsigned long version;
char * test;
version = strtoul(argArray[1], &test, 10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG, "need a positive integer");
return -1;
}
return playlistChanges(fp, version);
}
int handlePlaylistInfo(FILE * fp, unsigned int * permission,
int argArrayLength, char ** argArray)
{
......@@ -339,6 +410,23 @@ int handlePlaylistInfo(FILE * fp, unsigned int * permission,
return playlistInfo(fp,song);
}
int handlePlaylistId(FILE * fp, unsigned int * permission,
int argArrayLength, char ** argArray)
{
int id = -1;
char * test;
if(argArrayLength == 2) {
id = strtol(argArray[1],&test,10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG,
"%s need a positive integer");
return -1;
}
}
return playlistId(fp, id);
}
int handleFind(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
......@@ -513,6 +601,28 @@ int handleMove(FILE * fp, unsigned int * permission, int argArrayLength,
return moveSongInPlaylist(fp,from,to);
}
int handleMoveId(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
int id;
int to;
char * test;
id = strtol(argArray[1],&test,10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG,
"\"%s\" is not a integer", argArray[1]);
return -1;
}
to = strtol(argArray[2],&test,10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG,
"\"%s\" is not a integer", argArray[2]);
return -1;
}
return moveSongInPlaylistById(fp, id, to);
}
int handleSwap(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
......@@ -535,6 +645,28 @@ int handleSwap(FILE * fp, unsigned int * permission, int argArrayLength,
return swapSongsInPlaylist(fp,song1,song2);
}
int handleSwapId(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
int id1;
int id2;
char * test;
id1 = strtol(argArray[1],&test,10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG,
"\"%s\" is not a integer", argArray[1]);
return -1;
}
id2 = strtol(argArray[2],&test,10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG, "\"%s\" is not a integer",
argArray[2]);
return -1;
}
return swapSongsInPlaylist(fp, id1, id2);
}
int handleSeek(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
......@@ -557,6 +689,28 @@ int handleSeek(FILE * fp, unsigned int * permission, int argArrayLength,
return seekSongInPlaylist(fp,song,time);
}
int handleSeekId(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
int id;
int time;
char * test;
id = strtol(argArray[1],&test,10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG,
"\"%s\" is not a integer", argArray[1]);
return -1;
}
time = strtol(argArray[2],&test,10);
if(*test!='\0') {
commandError(fp, ACK_ERROR_ARG,
"\"%s\" is not a integer", argArray[2]);
return -1;
}
return seekSongInPlaylist(fp, id, time);
}
int handleListAllInfo(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
......@@ -605,14 +759,18 @@ void initCommands() {
commandList = makeList(free);
addCommand(COMMAND_PLAY ,PERMISSION_CONTROL, 0, 1,handlePlay,NULL);
addCommand(COMMAND_PLAYID ,PERMISSION_CONTROL, 0, 1,handlePlayId,NULL);
addCommand(COMMAND_STOP ,PERMISSION_CONTROL, 0, 0,handleStop,NULL);
addCommand(COMMAND_CURRENT ,PERMISSION_READ , 0, 0,handleCurrent,NULL);
addCommand(COMMAND_PAUSE ,PERMISSION_CONTROL, 0, 1,handlePause,NULL);
addCommand(COMMAND_STATUS ,PERMISSION_READ, 0, 0,commandStatus,NULL);
addCommand(COMMAND_KILL ,PERMISSION_ADMIN, -1,-1,handleKill,NULL);
addCommand(COMMAND_CLOSE ,0, -1,-1,handleClose,NULL);
addCommand(COMMAND_ADD ,PERMISSION_ADD, 0, 1,handleAdd,NULL);
addCommand(COMMAND_DELETE ,PERMISSION_CONTROL, 1, 1,handleDelete,NULL);
addCommand(COMMAND_DELETEID ,PERMISSION_CONTROL, 1, 1,handleDeleteId,NULL);
addCommand(COMMAND_PLAYLIST ,PERMISSION_READ, 0, 0,handlePlaylist,NULL);
addCommand(COMMAND_PLAYLISTID ,PERMISSION_READ, 0, 0,handlePlaylistId,NULL);
addCommand(COMMAND_SHUFFLE ,PERMISSION_CONTROL, 0, 0,handleShuffle,NULL);
addCommand(COMMAND_CLEAR ,PERMISSION_CONTROL, 0, 0,handleClear,NULL);
addCommand(COMMAND_SAVE ,PERMISSION_CONTROL, 1, 1,handleSave,NULL);
......@@ -633,14 +791,18 @@ void initCommands() {
addCommand(COMMAND_CLEAR_ERROR ,PERMISSION_CONTROL, 0, 0,handleClearError,NULL);
addCommand(COMMAND_LIST ,PERMISSION_READ, 1, 2,handleList,NULL);
addCommand(COMMAND_MOVE ,PERMISSION_CONTROL, 2, 2,handleMove,NULL);
addCommand(COMMAND_MOVEID ,PERMISSION_CONTROL, 2, 2,handleMoveId,NULL);
addCommand(COMMAND_SWAP ,PERMISSION_CONTROL, 2, 2,handleSwap,NULL);
addCommand(COMMAND_SWAPID ,PERMISSION_CONTROL, 2, 2,handleSwapId,NULL);
addCommand(COMMAND_SEEK ,PERMISSION_CONTROL, 2, 2,handleSeek,NULL);
addCommand(COMMAND_SEEKID ,PERMISSION_CONTROL, 2, 2,handleSeekId,NULL);
addCommand(COMMAND_LISTALLINFO ,PERMISSION_READ, 0, 1,handleListAllInfo,NULL);
addCommand(COMMAND_PING ,0, 0, 0,handlePing,NULL);
addCommand(COMMAND_SETVOL ,PERMISSION_CONTROL, 1, 1,handleSetVol,NULL);
addCommand(COMMAND_PASSWORD ,0, 1, 1,handlePassword,NULL);
addCommand(COMMAND_CROSSFADE ,PERMISSION_CONTROL, 1, 1,handleCrossfade,NULL);
addCommand(COMMAND_URL_HANDLERS,PERMISSION_READ, 0, 0,handleUrlHandlers,NULL);
addCommand(COMMAND_PLCHANGES ,PERMISSION_READ, 1, 1,handlePlaylistChanges,NULL);
sortList(commandList);
}
......@@ -770,7 +932,7 @@ int processCommandInternal(FILE * fp, unsigned int * permission,
}
int proccessListOfCommands(FILE * fp, int * permission, int * expired,
List * list)
int listOK, List * list)
{
ListNode * node = list->firstNode;
ListNode * tempNode;
......@@ -788,6 +950,7 @@ int proccessListOfCommands(FILE * fp, int * permission, int * expired,
deleteNodeFromList(list,node);
node = tempNode;
if(ret!=0 || (*expired)!=0) node = NULL;
else if(listOK) myfprintf(fp, "list_OK\n");
command_listNum++;
}
......
......@@ -35,7 +35,7 @@ extern char * current_command;
extern int command_listNum;
int proccessListOfCommands(FILE * fp, int * permission, int * expired,
List * list);
int listOK, List * list);
int processCommand(FILE * fp, unsigned int * permission, char * commandString);
......@@ -54,7 +54,7 @@ void finishCommands();
current_command = NULL; \
} \
else { \
myfprintf(fp, "ACK [%i@%i] " format "\n", \
myfprintf(stderr, "ACK [%i@%i] " format "\n", \
(int)error, command_listNum, \
##__VA_ARGS__); \
} \
......
......@@ -69,7 +69,7 @@
#endif
#endif
char * conf_params[CONF_NUMBER_OF_PARAMS];
static char * conf_params[CONF_NUMBER_OF_PARAMS];
void initConf() {
int i;
......
......@@ -112,17 +112,6 @@ int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
quitDecode(pc,dc); \
return; \
} \
if(pc->metadataState == PLAYER_METADATA_STATE_WRITE && \
dc->metadataSet) \
{ \
memcpy(pc->metadata, dc->metadata, \
DECODE_METADATA_LENGTH); \
pc->metadata[DECODE_METADATA_LENGTH-1] = '\0'; \
pc->title = dc->title; \
pc->artist = dc->artist; \
pc->album = dc->album; \
} \
pc->metadataState = PLAYER_METADATA_STATE_READ; \
pc->totalTime = dc->totalTime; \
pc->sampleRate = dc->audioFormat.sampleRate; \
pc->bits = dc->audioFormat.bits; \
......@@ -184,7 +173,6 @@ int decodeSeek(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
stopDecode(dc);
cb->begin = 0;
cb->end = 0;
cb->wrap = 0;
dc->error = 0;
dc->start = 1;
waitOnDecode(pc,dc,cb,decodeWaitedOn);
......@@ -271,11 +259,7 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
return;
}
dc->metadataSet = 0;
memset(dc->metadata, 0, DECODE_METADATA_LENGTH);
dc->title = -1;
dc->album = -1;
dc->artist = -1;
copyMpdTagToOutputBuffer(cb, NULL);
strncpy(dc->utf8url, pc->utf8url, MAXPATHLEN);
dc->utf8url[MAXPATHLEN] = '\0';
......@@ -302,15 +286,18 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
return;
}
if(inStream.metaTitle) {
strncpy(dc->metadata, inStream.metaTitle,
DECODE_METADATA_LENGTH-1);
dc->title = 0;
dc->metadataSet = 1;
}
/*if(inStream.metaName) {
MpdTag * tag = newMpdTag();
tag->name = strdup(inStream.metaName);
copyMpdTagToOutputBuffer(cb, tag);
freeMpdTag(tag);
}*/
/* reset Metadata in OutputBuffer */
ret = DECODE_ERROR_UNKTYPE;
if(isRemoteUrl(dc->utf8url)) {
cb->acceptMetadata = 1;
plugin = getInputPluginFromMimeType(inStream.mime);
if(plugin == NULL) {
plugin = getInputPluginFromSuffix(
......@@ -328,6 +315,7 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
}
}
else {
cb->acceptMetadata = 0;
plugin = getInputPluginFromSuffix(getSuffix(dc->utf8url));
if(plugin && (plugin->streamTypes && INPUT_PLUGIN_STREAM_FILE))
{
......@@ -399,6 +387,49 @@ int decoderInit(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
return 0;
}
void handleMetadata(OutputBuffer * cb, PlayerControl * pc, int * previous,
int * currentChunkSent, MetadataChunk * currentChunk)
{
if(cb->begin!=cb->end) {
int meta = cb->metaChunk[cb->begin];
if( meta != *previous ) {
DEBUG("player: metadata change\n");
if( meta >= 0 && cb->metaChunkSet[meta]) {
DEBUG("player: new metadata from decoder!\n");
memcpy(currentChunk,
cb->metadataChunks+meta,
sizeof(MetadataChunk));
*currentChunkSent = 0;
cb->metaChunkSet[meta] = 0;
}
}
*previous = meta;
}
if(!(*currentChunkSent) && pc->metadataState ==
PLAYER_METADATA_STATE_WRITE)
{
*currentChunkSent = 1;
memcpy(&(pc->metadataChunk), currentChunk,
sizeof(MetadataChunk));
pc->metadataState = PLAYER_METADATA_STATE_READ;
kill(getppid(), SIGUSR1);
}
}
void advanceOutputBufferTo(OutputBuffer * cb, PlayerControl * pc,
int * previous, int * currentChunkSent, MetadataChunk * currentChunk,
int to)
{
while(cb->begin!=to) {
handleMetadata(cb, pc, previous, currentChunkSent,
currentChunk);
cb->begin++;
if(cb->begin>=buffered_chunks) {
cb->begin = 0;
}
}
}
void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
int pause = 0;
int quit = 0;
......@@ -411,6 +442,9 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
int decodeWaitedOn = 0;
char silence[CHUNK_SIZE];
double sizeToTime = 0.0;
int previousMetadataChunk = -1;
MetadataChunk currentMetadataChunk;
int currentChunkSent = 1;
memset(silence,0,CHUNK_SIZE);
......@@ -420,7 +454,8 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
pc->play = 0;
kill(getppid(),SIGUSR1);
while(*decode_pid>0 && !cb->wrap && cb->end-cb->begin<bbp &&
while(*decode_pid>0 && cb->end-cb->begin<bbp &&
cb->end!=buffered_chunks-1 &&
dc->state!=DECODE_STATE_STOP)
{
processDecodeInput();
......@@ -431,6 +466,8 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
while(!quit) {
processDecodeInput();
handleDecodeStart();
handleMetadata(cb, pc, &previousMetadataChunk,
&currentChunkSent, &currentMetadataChunk);
if(dc->state==DECODE_STATE_STOP &&
pc->queueState==PLAYER_QUEUE_FULL &&
pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
......@@ -456,9 +493,7 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
else doCrossFade = -1;
}
if(pause) my_usleep(10000);
else if((cb->begin!=cb->end || cb->wrap) &&
cb->begin!=cb->next)
{
else if(cb->begin!=cb->end && cb->begin!=cb->next) {
if(doCrossFade==1 && cb->next>=0 &&
((cb->next>cb->begin &&
(fadePosition=cb->next-cb->begin)
......@@ -471,7 +506,7 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
crossFadeChunks = fadePosition;
}
test = cb->end;
if(cb->wrap) test+=buffered_chunks;
if(cb->end < cb->begin) test+=buffered_chunks;
nextChunk = cb->begin+crossFadeChunks;
if(nextChunk<test) {
if(nextChunk>=buffered_chunks)
......@@ -521,20 +556,23 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
cb->begin++;
if(cb->begin>=buffered_chunks) {
cb->begin = 0;
cb->wrap = 0;
}
}
else if(cb->next==cb->begin) {
if(doCrossFade==1 && nextChunk>=0) {
nextChunk = cb->begin+crossFadeChunks;
test = cb->end;
if(cb->wrap) test+=buffered_chunks;
if(cb->end < cb->begin) test+=buffered_chunks;
if(nextChunk<test) {
if(nextChunk>=buffered_chunks)
{
nextChunk -= buffered_chunks;
}
cb->begin = nextChunk;
advanceOutputBufferTo(cb, pc,
&previousMetadataChunk,
&currentChunkSent,
&currentMetadataChunk,
nextChunk);
}
}
while(pc->queueState==PLAYER_QUEUE_DECODE ||
......@@ -589,9 +627,9 @@ void decode() {
cb = &(getPlayerData()->buffer);
clearAllMetaChunkSets(cb);
cb->begin = 0;
cb->end = 0;
cb->wrap = 0;
pc = &(getPlayerData()->playerControl);
dc = &(getPlayerData()->decoderControl);
dc->error = 0;
......@@ -606,31 +644,3 @@ void decode() {
decodeParent(pc, dc, cb);
}
/* this is stuff for inputPlugins to use! */
#define copyStringToMetadata(string, element) { \
if(string && (slen = strlen(string)) && \
pos < DECODE_METADATA_LENGTH-1) \
{ \
strncpy(dc->metadata+pos, string, \
DECODE_METADATA_LENGTH-1-pos); \
element = pos; \
pos += slen+1; \
} \
}
void copyMpdTagToDecoderControlMetadata(DecoderControl * dc, MpdTag * tag) {
int pos = 0;
int slen;
if(dc->metadataSet) return;
if(!tag) return;
memset(dc->metadata, 0, DECODE_METADATA_LENGTH);
copyStringToMetadata(tag->title, dc->title);
copyStringToMetadata(tag->artist, dc->artist);
copyStringToMetadata(tag->album, dc->album);
dc->metadataSet = 1;
}
......@@ -46,8 +46,6 @@
#define DECODE_SUFFIX_MP4 5
#define DECODE_SUFFIX_WAVE 6
#define DECODE_METADATA_LENGTH 4096
typedef struct _DecoderControl {
volatile mpd_sint8 state;
volatile mpd_sint8 stop;
......@@ -61,18 +59,11 @@ typedef struct _DecoderControl {
AudioFormat audioFormat;
char utf8url[MAXPATHLEN+1];
volatile float totalTime;
volatile mpd_sint8 metadataSet;
char metadata[DECODE_METADATA_LENGTH];
volatile mpd_sint16 title;
volatile mpd_sint16 artist;
volatile mpd_sint16 album;
} DecoderControl;
void decodeSigHandler(int sig);
void decode();
void copyMpdTagToDecoderControlMetadata(DecoderControl * dc, MpdTag * tag);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -159,7 +159,7 @@ void readDirectoryDBIfUpdateIsFinished() {
if(directory_reReadDB && 0==directory_updatePid) {
DEBUG("readDirectoryDB since update finished successfully\n");
readDirectoryDB();
incrPlaylistVersion();
playlistVersionChange();
directory_reReadDB = 0;
}
}
......
......@@ -531,6 +531,18 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
default:
mad_synth_frame(&data->synth,&data->frame);
if(data->inStream->metaTitle) {
MpdTag * tag = newMpdTag();
if(data->inStream->metaName) {
tag->name = strdup(data->inStream->metaName);
}
tag->title = strdup(data->inStream->metaTitle);
free(data->inStream->metaTitle);
data->inStream->metaTitle = NULL;
copyMpdTagToOutputBuffer(cb, tag);
freeMpdTag(tag);
}
for(i=0;i<(data->synth).pcm.length;i++) {
mpd_sint16 * sample;
......@@ -643,8 +655,33 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
dc->totalTime = data.totalTime;
if(tag) {
copyMpdTagToDecoderControlMetadata(dc, tag);
if(inStream->metaTitle) {
if(tag) freeMpdTag(tag);
tag = newMpdTag();
tag->title = strdup(inStream->metaTitle);
/* free ths now, so we know we are done with it */
free(inStream->metaTitle);
inStream->metaTitle = NULL;
if(inStream->metaName) {
tag->name = strdup(inStream->metaName);
}
copyMpdTagToOutputBuffer(cb, tag);
freeMpdTag(tag);
}
else if(tag) {
if(inStream->metaName) {
if(tag->name) free(tag->name);
tag->name = strdup(inStream->metaName);
}
copyMpdTagToOutputBuffer(cb, tag);
freeMpdTag(tag);
}
else if(inStream->metaName) {
tag = newMpdTag();
if(inStream->metaName) {
tag->name = strdup(inStream->metaName);
}
copyMpdTagToOutputBuffer(cb, tag);
freeMpdTag(tag);
}
......
......@@ -200,17 +200,28 @@ MpdTag * oggCommentsParse(char ** comments) {
return ret;
}
void putOggCommentsIntoDecoderControlMetadata(DecoderControl * dc,
void putOggCommentsIntoOutputBuffer(OutputBuffer * cb, char * streamName,
char ** comments)
{
MpdTag * tag;
if(dc->metadataSet) return;
tag = oggCommentsParse(comments);
if(!tag && streamName) {
tag = newMpdTag();
}
if(!tag) return;
copyMpdTagToDecoderControlMetadata(dc, tag);
/*if(tag->artist) printf("Artist: %s\n", tag->artist);
if(tag->album) printf("Album: %s\n", tag->album);
if(tag->track) printf("Track: %s\n", tag->track);
if(tag->title) printf("Title: %s\n", tag->title);*/
if(streamName) {
if(tag->name) free(tag->name);
tag->name = strdup(streamName);
}
copyMpdTagToOutputBuffer(cb, tag);
freeMpdTag(tag);
}
......@@ -221,6 +232,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
ov_callbacks callbacks;
OggCallbackData data;
int current_section;
int prev_section = -1;
int eof = 0;
long ret;
#define OGG_CHUNK_SIZE 4096
......@@ -228,7 +240,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
int chunkpos = 0;
long bitRate = 0;
long test;
float replayGainScale;
float replayGainScale = 1.0;
char ** comments;
data.inStream = inStream;
......@@ -252,24 +264,10 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
return 0;
}
{
vorbis_info *vi=ov_info(&vf,-1);
dc->audioFormat.bits = 16;
dc->audioFormat.channels = vi->channels;
dc->audioFormat.sampleRate = vi->rate;
getOutputAudioFormat(&(dc->audioFormat),&(cb->audioFormat));
}
dc->totalTime = ov_time_total(&vf,-1);
if(dc->totalTime < 0) dc->totalTime = 0;
comments = ov_comment(&vf, -1)->user_comments;
putOggCommentsIntoDecoderControlMetadata(dc, comments);
dc->state = DECODE_STATE_DECODE;
replayGainScale = ogg_getReplayGainScale(comments);
dc->audioFormat.bits = 16;
while(!eof) {
if(dc->seek) {
......@@ -285,6 +283,24 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
OGG_DECODE_USE_BIGENDIAN,
2, 1, &current_section);
if(current_section!=prev_section) {
/*printf("new song!\n");*/
vorbis_info *vi=ov_info(&vf,-1);
dc->audioFormat.channels = vi->channels;
dc->audioFormat.sampleRate = vi->rate;
if(dc->state == DECODE_STATE_START) {
getOutputAudioFormat(&(dc->audioFormat),
&(cb->audioFormat));
dc->state = DECODE_STATE_DECODE;
}
comments = ov_comment(&vf, -1)->user_comments;
putOggCommentsIntoOutputBuffer(cb, inStream->metaName,
comments);
replayGainScale = ogg_getReplayGainScale(comments);
}
prev_section = current_section;
if(ret <= 0 && ret != OV_HOLE) {
eof = 1;
break;
......
......@@ -26,6 +26,14 @@
#include <unistd.h>
int openInputStream(InputStream * inStream, char * url) {
inStream->offset = 0;
inStream->size = 0;
inStream->error = 0;
inStream->mime = NULL;
inStream->seekable = 0;
inStream->metaName = NULL;
inStream->metaTitle = NULL;
if(inputStream_fileOpen(inStream,url) == 0) return 0;
if(inputStream_httpOpen(inStream,url) == 0) return 0;
......@@ -43,6 +51,10 @@ size_t readFromInputStream(InputStream * inStream, void * ptr, size_t size,
}
int closeInputStream(InputStream * inStream) {
if(inStream->mime) free(inStream->mime);
if(inStream->metaName) free(inStream->metaName);
if(inStream->metaTitle) free(inStream->metaTitle);
return inStream->closeFunc(inStream);
}
......@@ -53,4 +65,3 @@ int inputStreamAtEOF(InputStream * inStream) {
int bufferInputStream(InputStream * inStream) {
return inStream->bufferFunc(inStream);
}
/* vim:set shiftwidth=8 tabstop=8 expandtab: */
......@@ -45,6 +45,7 @@ struct _InputStream {
InputStreamAtEOFFunc atEOFFunc;
InputStreamBufferFunc bufferFunc;
void * data;
char * metaName;
char * metaTitle;
};
......
......@@ -32,10 +32,7 @@ int inputStream_fileOpen(InputStream * inStream, char * filename) {
return -1;
}
inStream->offset = 0;
inStream->seekable = 1;
inStream->mime = NULL;
inStream->metaTitle = NULL;
fseek(fp,0,SEEK_END);
inStream->size = ftell(fp);
......
......@@ -57,6 +57,7 @@ typedef struct _InputStreemHTTPData {
int timesRedirected;
int icyMetaint;
int prebuffer;
int icyOffset;
} InputStreamHTTPData;
static InputStreamHTTPData * newInputStreamHTTPData() {
......@@ -69,6 +70,7 @@ static InputStreamHTTPData * newInputStreamHTTPData() {
ret->timesRedirected = 0;
ret->icyMetaint = 0;
ret->prebuffer = 0;
ret->icyOffset = 0;
return ret;
}
......@@ -231,7 +233,7 @@ static int finishHTTPInit(InputStream * inStream) {
"Connection: close\r\n"
"User-Agent: %s/%s\r\n"
"Range: bytes=%ld-\r\n"
/*"Icy-Metadata:1\r\n"*/
"Icy-Metadata:1\r\n"
"\r\n",
data->path, data->host, "httpTest", "0.0.0",
inStream->offset);
......@@ -372,20 +374,24 @@ static int getHTTPHello(InputStream * inStream) {
char * temp = strstr(cur+incr,"\r\n");
if(!temp) break;
*temp = '\0';
if(inStream->metaTitle) free(inStream->metaTitle);
if(inStream->metaName) free(inStream->metaName);
while(*(incr+cur) == ' ') incr++;
inStream->metaTitle = strdup(cur+incr);
inStream->metaName = strdup(cur+incr);
*temp = '\r';
DEBUG("inputStream_http: metaName: %s\n",
inStream->metaName);
}
else if(0 == strncmp(cur, "\r\nx-audiocast-name:", 19)) {
int incr = 19;
char * temp = strstr(cur+incr,"\r\n");
if(!temp) break;
*temp = '\0';
if(inStream->metaTitle) free(inStream->metaTitle);
if(inStream->metaName) free(inStream->metaName);
while(*(incr+cur) == ' ') incr++;
inStream->metaTitle = strdup(cur+incr);
inStream->metaName = strdup(cur+incr);
*temp = '\r';
DEBUG("inputStream_http: metaName: %s\n",
inStream->metaName);
}
else if(0 == strncmp(cur, "\r\nContent-Type:", 15)) {
int incr = 15;
......@@ -439,13 +445,6 @@ int inputStream_httpOpen(InputStream * inStream, char * url) {
inStream->atEOFFunc = inputStream_httpAtEOF;
inStream->bufferFunc = inputStream_httpBuffer;
inStream->offset = 0;
inStream->size = 0;
inStream->error = 0;
inStream->mime = NULL;
inStream->seekable = 0;
inStream->metaTitle = NULL;
return 0;
}
......@@ -453,32 +452,89 @@ int inputStream_httpSeek(InputStream * inStream, long offset, int whence) {
return -1;
}
static void parseIcyMetadata(InputStream * inStream, char * metadata,
int size)
{
char * r;
char * s;
char * temp = malloc(size+1);
memcpy(temp, metadata, size);
temp[size] = '\0';
s = strtok_r(temp, ";", &r);
while(s) {
if(0 == strncmp(s, "StreamTitle=", 12)) {
int cur = 12;
if(inStream->metaTitle) free(inStream->metaTitle);
if(*(s+cur) == '\'') cur++;
if(s[strlen(s)-1] == '\'') {
s[strlen(s)-1] = '\0';
}
inStream->metaTitle = strdup(s+cur);
DEBUG("inputStream_http: metaTitle: %s\n",
inStream->metaTitle);
}
s = strtok_r(NULL, ";", &r);
}
free(temp);
}
size_t inputStream_httpRead(InputStream * inStream, void * ptr, size_t size,
size_t nmemb)
{
InputStreamHTTPData * data = (InputStreamHTTPData *)inStream->data;
long tosend = 0;
long inlen = size*nmemb;
long maxToSend = data->buflen;
inputStream_httpBuffer(inStream);
switch(data->connState) {
case HTTP_CONN_STATE_OPEN:
case HTTP_CONN_STATE_CLOSED:
if(data->prebuffer || data->buflen < data->icyMetaint) return 0;
break;
case HTTP_CONN_STATE_CLOSED:
if(data->buflen) break;
default:
return 0;
}
if(data->prebuffer) return 0;
if(data->icyMetaint > 0) {
if(data->icyOffset >= data->icyMetaint) {
int metalen = *(data->buffer);
metalen <<= 4;
if(metalen < 0) metalen = 0;
if(metalen+1 > data->buflen) {
/* damn that's some fucking big metadata! */
if(HTTP_BUFFER_SIZE < metalen+1) {
data->connState =
HTTP_CONN_STATE_CLOSED;
close(data->sock);
data->buflen = 0;
}
return 0;
}
if(metalen > 0) {
parseIcyMetadata(inStream, data->buffer+1,
metalen);
}
data->buflen -= metalen+1;
memmove(data->buffer, data->buffer+metalen+1,
data->buflen);
data->icyOffset = 0;
}
maxToSend = data->icyMetaint-data->icyOffset;
maxToSend = maxToSend > data->buflen ? data->buflen : maxToSend;
}
if(data->buflen > 0) {
tosend = inlen > data->buflen ? data->buflen : inlen;
tosend = inlen > maxToSend ? maxToSend : inlen;
tosend = (tosend/size)*size;
memcpy(ptr, data->buffer, tosend);
/*fwrite(ptr,1,readed,stdout);*/
data->buflen -= tosend;
data->icyOffset+= tosend;
/*fwrite(data->buffer,1,readed,stdout);*/
memmove(data->buffer, data->buffer+tosend, data->buflen);
......@@ -498,7 +554,6 @@ int inputStream_httpClose(InputStream * inStream) {
close(data->sock);
}
if(inStream->mime) free(inStream->mime);
freeInputStreamHTTPData(data);
return 0;
......@@ -538,7 +593,9 @@ int inputStream_httpBuffer(InputStream * inStream) {
return -1;
}
if(data->buflen == 0) data->prebuffer = 1;
if(data->buflen == 0 || data->buflen < data->icyMetaint) {
data->prebuffer = 1;
}
else if(data->buflen > HTTP_PREBUFFER_SIZE) data->prebuffer = 0;
if(data->connState == HTTP_CONN_STATE_OPEN &&
......@@ -563,4 +620,3 @@ int inputStream_httpBuffer(InputStream * inStream) {
return (readed ? 1 : 0);
}
/* vim:set shiftwidth=8 tabstop=8 expandtab: */
......@@ -45,6 +45,7 @@
#define INTERFACE_MAX_BUFFER_LENGTH MAXPATHLEN+1024
#define INTERFACE_LIST_MODE_BEGIN "command_list_begin"
#define INTERFACE_LIST_OK_MODE_BEGIN "command_list_ok_begin"
#define INTERFACE_LIST_MODE_END "command_list_end"
#define INTERFACE_DEFAULT_OUT_BUFFER_SIZE 4096
......@@ -62,6 +63,7 @@ typedef struct _Interface {
unsigned int permission;
time_t lastTime;
List * commandList; /* for when in list mode */
int commandListOK; /* print OK after each command execution */
unsigned long long commandListSize; /* mem commandList consumes */
List * bufferList; /* for output if client is slow */
unsigned long long outputBufferSize; /* mem bufferList consumes */
......@@ -230,6 +232,7 @@ int interfaceReadInput(Interface * interface) {
interface->fp,
&(interface->permission),
&(interface->expired),
interface->commandListOK,
interface->commandList);
DEBUG("interface %i: process command "
"list returned %i\n",
......@@ -281,17 +284,18 @@ int interfaceReadInput(Interface * interface) {
interface->commandList = makeList(free);
interface->commandListSize =
sizeof(List);
interface->commandListOK = 0;
ret = 1;
}
else {
if(strcmp(interface->buffer,
INTERFACE_LIST_MODE_END)
else if(strcmp(interface->buffer,
INTERFACE_LIST_OK_MODE_BEGIN)
==0)
{
commandError(interface->fp,
ACK_ERROR_NOT_LIST,
"not in command list mode");
ret = -1;
interface->commandList = makeList(free);
interface->commandListSize =
sizeof(List);
interface->commandListOK = 1;
ret = 1;
}
else {
DEBUG("interface %i: process command \"%s\"\n",interface->num,interface->buffer);
......@@ -301,7 +305,6 @@ int interfaceReadInput(Interface * interface) {
permission),
interface->buffer);
DEBUG("interface %i: command returned %i\n",interface->num,ret);
}
if(ret==0) {
commandSuccess(interface->fp);
}
......@@ -648,4 +651,3 @@ void printInterfaceOutBuffer(Interface * interface) {
interface->outBuflen = 0;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -87,7 +87,7 @@ void usage(char * argv[]) {
void version() {
LOG("mpd (MPD: Music Player Daemon) %s\n",VERSION);
LOG("\n");
LOG("Copyright (C) 2003 Warren Dukes <shank@mercury.chem.pitt.edu>\n");
LOG("Copyright (C) 2003-2004 Warren Dukes <shank@mercury.chem.pitt.edu>\n");
LOG("This is free software; see the source for copying conditions. There is NO\n");
LOG("warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
LOG("\n");
......@@ -224,7 +224,7 @@ void establishListen(Options * options) {
exit(EXIT_FAILURE);
}
if(!options->createDB && !options->updateDB &&
if(options->createDB <= 0 && !options->updateDB &&
(listenSocket = establish(port))<0)
{
ERROR("error binding port\n");
......
#include "metadataChunk.h"
#include <string.h>
void initMetadataChunk(MetadataChunk * chunk) {
memset(chunk, 0, sizeof(MetadataChunk));
chunk->name = -1;
chunk->artist = -1;
chunk->album = -1;
chunk->title = -1;
}
#define dupElementToTag(string, element) { \
if(element >= 0 && element < METADATA_BUFFER_LENGTH) { \
string = strdup(chunk->buffer+element); \
} \
}
MpdTag * metadataChunkToMpdTagDup(MetadataChunk * chunk) {
MpdTag * ret = newMpdTag();
chunk->buffer[METADATA_BUFFER_LENGTH] = '\0';
dupElementToTag(ret->name, chunk->name);
dupElementToTag(ret->title, chunk->title);
dupElementToTag(ret->artist, chunk->artist);
dupElementToTag(ret->album, chunk->album);
return ret;
}
#define copyStringToChunk(string, element) { \
if(string && (slen = strlen(string)) && \
pos < METADATA_BUFFER_LENGTH-1) \
{ \
strncpy(chunk->buffer+pos, string, \
METADATA_BUFFER_LENGTH-1-pos); \
element = pos; \
pos += slen+1; \
} \
}
void copyMpdTagToMetadataChunk(MpdTag * tag, MetadataChunk * chunk) {
int pos = 0;
int slen;
initMetadataChunk(chunk);
copyStringToChunk(tag->name, chunk->name);
copyStringToChunk(tag->title, chunk->title);
copyStringToChunk(tag->artist, chunk->artist);
copyStringToChunk(tag->album, chunk->album);
}
#ifndef METADATA_CHUNK_H
#define METADATA_CHUNK_H
#define METADATA_BUFFER_LENGTH 1024
#include "tag.h"
typedef struct _MetadataChunk {
int name;
int title;
int artist;
int album;
char buffer[METADATA_BUFFER_LENGTH];
} MetadataChunk;
void initMetadataChunk(MetadataChunk *);
MpdTag * metadataChunkToMpdTagDup(MetadataChunk * chunk);
void copyMpdTagToMetadataChunk(MpdTag * tag, MetadataChunk * chunk);
#endif
......@@ -21,15 +21,38 @@
#include "pcm_utils.h"
#include "playerData.h"
#include "utils.h"
#include "log.h"
#include <string.h>
static mpd_sint16 currentChunk = -1;
static mpd_sint8 currentMetaChunk = -1;
static mpd_sint8 sendMetaChunk = 0;
void clearAllMetaChunkSets(OutputBuffer * cb) {
int i;
for(i=0; i<BUFFERED_METACHUNKS; i++) {
cb->metaChunkSet[i] = 0;
}
}
void clearOutputBuffer(OutputBuffer * cb) {
int currentSet = 1;
currentChunk = -1;
cb->end = cb->begin;
cb->wrap = 0;
/* be sure to reset metaChunkSets cause we are skipping over audio
* audio chunks, and thus skipping over metadata */
if(sendMetaChunk == 0 && currentMetaChunk >= 0) {
currentSet = cb->metaChunkSet[currentChunk];
}
clearAllMetaChunkSets(cb);
if(sendMetaChunk == 0 && currentMetaChunk >= 0) {
cb->metaChunkSet[currentChunk] = currentSet;
}
}
void flushOutputBuffer(OutputBuffer * cb) {
......@@ -37,7 +60,6 @@ void flushOutputBuffer(OutputBuffer * cb) {
cb->end++;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
currentChunk = -1;
}
......@@ -74,8 +96,11 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
while(datalen) {
if(currentChunk != cb->end) {
while(cb->begin==cb->end && cb->wrap && !dc->stop)
{
int next = cb->end+1;
if(next>=buffered_chunks) {
next = 0;
}
while(cb->begin==next && !dc->stop) {
if(dc->seek) {
if(seekable) {
return OUTPUT_BUFFER_DC_SEEK;
......@@ -95,6 +120,13 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
currentChunk = cb->end;
cb->chunkSize[currentChunk] = 0;
if(sendMetaChunk) {
cb->metaChunk[currentChunk] = currentMetaChunk;
}
else cb->metaChunk[currentChunk] = -1;
cb->bitRate[currentChunk] = bitRate;
cb->times[currentChunk] = time;
}
chunkLeft = CHUNK_SIZE-cb->chunkSize[currentChunk];
......@@ -104,9 +136,6 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
cb->chunkSize[currentChunk],
data, dataToSend);
cb->chunkSize[currentChunk]+= dataToSend;
cb->bitRate[currentChunk] = bitRate;
cb->times[currentChunk] = time;
datalen-= dataToSend;
data+= dataToSend;
......@@ -117,4 +146,46 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
return 0;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag) {
int nextChunk;
static MpdTag * last = NULL;
if(!cb->acceptMetadata || !tag) {
sendMetaChunk = 0;
if(last) free(last);
last = NULL;
DEBUG("copyMpdTagToOB: !acceptMetadata || !tag\n");
return 0;
}
if(last && mpdTagsAreEqual(last, tag)) {
DEBUG("copyMpdTagToOB: same as last\n");
return 0;
}
if(last) freeMpdTag(last);
last = NULL;
nextChunk = currentMetaChunk+1;
if(nextChunk >= BUFFERED_METACHUNKS) nextChunk = 0;
if(cb->metaChunkSet[nextChunk]) {
sendMetaChunk = 0;
DEBUG("copyMpdTagToOB: metachunk in use!\n");
return -1;
}
sendMetaChunk = 1;
currentMetaChunk = nextChunk;
last = mpdTagDup(tag);
copyMpdTagToMetadataChunk(tag, &(cb->metadataChunks[currentMetaChunk]));
cb->metaChunkSet[nextChunk] = 1;
DEBUG("copyMpdTagToOB: copiedTag\n");
return 0;
}
......@@ -23,10 +23,13 @@
#include "decode.h"
#include "audio.h"
#include "inputStream.h"
#include "metadataChunk.h"
#define OUTPUT_BUFFER_DC_STOP -1
#define OUTPUT_BUFFER_DC_SEEK -2
#define BUFFERED_METACHUNKS 25
typedef struct _OutputBuffer {
char * volatile chunks;
mpd_uint16 * volatile chunkSize;
......@@ -35,8 +38,11 @@ typedef struct _OutputBuffer {
mpd_sint16 volatile begin;
mpd_sint16 volatile end;
mpd_sint16 volatile next;
mpd_sint8 volatile wrap;
AudioFormat audioFormat;
MetadataChunk metadataChunks[BUFFERED_METACHUNKS];
mpd_sint8 metaChunkSet[BUFFERED_METACHUNKS];
mpd_sint8 * volatile metaChunk;
volatile mpd_sint8 acceptMetadata;
} OutputBuffer;
void clearOutputBuffer(OutputBuffer * cb);
......@@ -49,5 +55,8 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
DecoderControl * dc, int seekable, char * data, long datalen,
float time, mpd_uint16 bitRate);
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag);
void clearAllMetaChunkSets(OutputBuffer * cb);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -281,5 +281,3 @@ size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
return outSize;
}
/* vim:set shiftwidth=8 tabstop=8 expandtab: */
......@@ -55,9 +55,6 @@ static void resetPlayerMetadata() {
if(pc->metadataState == PLAYER_METADATA_STATE_READ) {
pc->metadataState = PLAYER_METADATA_STATE_WRITE;
pc->title = -1;
pc->artist = -1;
pc->album = -1;
}
}
......@@ -75,8 +72,6 @@ void resetPlayer() {
getPlayerData()->playerControl.seek = 0;
getPlayerData()->playerControl.metadataState =
PLAYER_METADATA_STATE_WRITE;
getPlayerData()->playerControl.title = -1;
/* kill decode process if it got left running */
pid = getPlayerData()->playerControl.decode_pid;
if(pid>0) kill(pid,SIGTERM);
getPlayerData()->playerControl.decode_pid = 0;
......@@ -474,31 +469,24 @@ void playerCycleLogFiles() {
/* this actually creates a dupe of the current metadata */
Song * playerCurrentDecodeSong() {
static Song * song = NULL;
static MetadataChunk * prev = NULL;
Song * ret = NULL;
PlayerControl * pc = &(getPlayerData()->playerControl);
if(pc->metadataState == PLAYER_METADATA_STATE_READ &&
(!song || strcmp(song->utf8url, pc->currentUrl)))
{
if(pc->metadataState == PLAYER_METADATA_STATE_READ) {
DEBUG("playerCurrentDecodeSong: caught new metadata!\n");
if(prev) free(prev);
prev = malloc(sizeof(MetadataChunk));
memcpy(prev, &(pc->metadataChunk), sizeof(MetadataChunk));
if(song) freeJustSong(song);
song = newNullSong();
song->tag = newMpdTag();
if(song->utf8url) free(song->utf8url);
song->utf8url = strdup(pc->currentUrl);
if(pc->title >= 0) {
song->tag->title = strdup(pc->title + pc->metadata);
}
if(pc->artist >= 0) {
song->tag->artist = strdup(pc->artist + pc->metadata);
}
if(pc->album >= 0) {
song->tag->album = strdup(pc->album + pc->metadata);
}
song->tag = metadataChunkToMpdTagDup(prev);
validateUtf8Tag(song->tag);
ret = song;
resetPlayerMetadata();
return song;
}
return NULL;
return ret;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -24,6 +24,7 @@
#include "decode.h"
#include "mpd_types.h"
#include "song.h"
#include "metadataChunk.h"
#include <stdio.h>
#include <sys/param.h>
......@@ -84,10 +85,7 @@ typedef struct _PlayerControl {
volatile int decode_pid;
volatile mpd_sint8 cycleLogFiles;
volatile mpd_sint8 metadataState;
char metadata[DECODE_METADATA_LENGTH];
volatile mpd_sint16 title;
volatile mpd_sint16 artist;
volatile mpd_sint16 album;
MetadataChunk metadataChunk;
} PlayerControl;
void clearPlayerPid();
......@@ -157,4 +155,3 @@ void playerCycleLogFiles();
Song * playerCurrentDecodeSong();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -73,6 +73,7 @@ void initPlayerData() {
allocationSize+= buffered_chunks*sizeof(float); /*for times*/
allocationSize+= buffered_chunks*sizeof(mpd_sint16); /*for chunkSize*/
allocationSize+= buffered_chunks*sizeof(mpd_sint16); /*for bitRate*/
allocationSize+= buffered_chunks*sizeof(mpd_sint8); /*for metaChunk*/
allocationSize+= sizeof(PlayerData); /*for playerData struct*/
if((shmid = shmget(IPC_PRIVATE,allocationSize,IPC_CREAT|0600))<0) {
......@@ -95,8 +96,10 @@ void initPlayerData() {
buffered_chunks*CHUNK_SIZE);
buffer->bitRate = (mpd_uint16 *)(((char *)buffer->chunkSize)+
buffered_chunks*sizeof(mpd_sint16));
buffer->times = (float *)(((char *)buffer->bitRate)+
buffer->metaChunk = (mpd_sint8 *)(((char *)buffer->bitRate)+
buffered_chunks*sizeof(mpd_sint16));
buffer->times = (float *)(((char *)buffer->metaChunk)+
buffered_chunks*sizeof(mpd_sint8));
playerData_pd->playerControl.stop = 0;
playerData_pd->playerControl.pause = 0;
......@@ -111,15 +114,10 @@ void initPlayerData() {
memset(playerData_pd->playerControl.utf8url, 0, MAXPATHLEN+1);
memset(playerData_pd->playerControl.erroredUrl, 0, MAXPATHLEN+1);
memset(playerData_pd->playerControl.currentUrl, 0, MAXPATHLEN+1);
memset(playerData_pd->playerControl.metadata, 0,
DECODE_METADATA_LENGTH);
playerData_pd->playerControl.crossFade = crossfade;
playerData_pd->playerControl.softwareVolume = 1000;
playerData_pd->playerControl.totalPlayTime = 0;
playerData_pd->playerControl.decode_pid = 0;
playerData_pd->playerControl.title = -1;
playerData_pd->playerControl.artist = -1;
playerData_pd->playerControl.album = -1;
playerData_pd->playerControl.metadataState =
PLAYER_METADATA_STATE_WRITE;
......@@ -129,12 +127,6 @@ void initPlayerData() {
playerData_pd->decoderControl.seek = 0;
playerData_pd->decoderControl.error = DECODE_ERROR_NOERROR;
memset(playerData_pd->decoderControl.utf8url, 0, MAXPATHLEN+1);
memset(playerData_pd->decoderControl.metadata, 0,
DECODE_METADATA_LENGTH);
playerData_pd->decoderControl.title = -1;
playerData_pd->decoderControl.artist = -1;
playerData_pd->decoderControl.album = -1;
playerData_pd->decoderControl.metadataSet = 0;
}
PlayerData * getPlayerData() {
......@@ -144,4 +136,3 @@ PlayerData * getPlayerData() {
void freePlayerData() {
shmdt(playerData_pd);
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -36,8 +36,6 @@
#include <unistd.h>
#include <time.h>
#define BITS_FOR_VERSION 31
#define PLAYLIST_COMMENT '#'
#define PLAYLIST_STATE_STOP 0
......@@ -60,15 +58,21 @@
#define PLAYLIST_BUFFER_SIZE 2*MAXPATHLEN
#define PLAYLIST_HASH_MULT 4
typedef struct _Playlist {
Song ** songs;
/* holds version a song was modified on */
mpd_uint32 * songMod;
int * order;
int * numToId;
int * idToNum;
int length;
int current;
int queued;
int repeat;
int random;
unsigned long version;
mpd_uint32 version;
} Playlist;
static Playlist playlist;
......@@ -87,10 +91,28 @@ static void swapOrder(int a, int b);
static int playPlaylistOrderNumber(FILE * fp, int orderNum);
static void randomizeOrder(int start, int end);
void incrPlaylistVersion() {
static unsigned long max = ((unsigned long)1<<BITS_FOR_VERSION)-1;
static void incrPlaylistVersion() {
static unsigned long max = ((mpd_uint32)1<<31)-1;
playlist.version++;
if(playlist.version>=max) playlist.version = 0;
if(playlist.version>=max) {
int i;
for(i=0; i<playlist.length; i++) {
playlist.songMod[i] = 0;
}
playlist.version = 1;
}
}
void playlistVersionChange() {
int i = 0;
for(i=0; i<playlist.length; i++) {
playlist.songMod[i] = playlist.version;
}
incrPlaylistVersion();
}
static void incrPlaylistCurrent() {
......@@ -105,10 +127,11 @@ static void incrPlaylistCurrent() {
void initPlaylist() {
char * test;
int i;
playlist.length = 0;
playlist.repeat = 0;
playlist.version = 0;
playlist.version = 1;
playlist.random = 0;
playlist.queued = -1;
playlist.current = -1;
......@@ -136,7 +159,11 @@ void initPlaylist() {
}
playlist.songs = malloc(sizeof(Song *)*playlist_max_length);
playlist.order = malloc(sizeof(Song *)*playlist_max_length);
playlist.songMod = malloc(sizeof(mpd_uint32)*playlist_max_length);
playlist.order = malloc(sizeof(int)*playlist_max_length);
playlist.idToNum = malloc(sizeof(int)*playlist_max_length*
PLAYLIST_HASH_MULT);
playlist.numToId = malloc(sizeof(int)*playlist_max_length);
memset(playlist.songs,0,sizeof(char *)*playlist_max_length);
......@@ -146,6 +173,22 @@ void initPlaylist() {
playlist_stateFile = getConf()[CONF_STATE_FILE];
}
for(i=0; i<playlist_max_length*PLAYLIST_HASH_MULT; i++) {
playlist.idToNum[i] = -1;
}
}
static int getNextId() {
static int cur = 0;
while(playlist.idToNum[cur] != -1) {
cur++;
if(cur >= playlist_max_length*PLAYLIST_HASH_MULT) {
cur = 0;
}
}
return cur;
}
void finishPlaylist() {
......@@ -155,10 +198,19 @@ void finishPlaylist() {
freeJustSong(playlist.songs[i]);
}
}
playlist.length = 0;
free(playlist.songs);
playlist.songs = NULL;
free(playlist.songMod);
playlist.songMod = NULL;
free(playlist.order);
playlist.order = NULL;
free(playlist.idToNum);
playlist.idToNum = NULL;
free(playlist.numToId);
playlist.numToId = NULL;
}
int clearPlaylist(FILE * fp) {
......@@ -170,6 +222,7 @@ int clearPlaylist(FILE * fp) {
if(playlist.songs[i]->type == SONG_TYPE_URL) {
freeJustSong(playlist.songs[i]);
}
playlist.idToNum[playlist.numToId[i]] = -1;
playlist.songs[i] = NULL;
}
playlist.length = 0;
......@@ -364,8 +417,33 @@ void readPlaylistState() {
}
}
int playlistInfo(FILE * fp,int song) {
void printPlaylistSongInfo(FILE * fp, int song) {
MpdTag * tag;
myfprintf(fp, "file: %s\n", (playlist.songs[song])->utf8url);
if((tag = (playlist.songs[song])->tag)) {
printMpdTag(fp, tag);
}
myfprintf(fp, "Num: %i\n", song);
myfprintf(fp, "Id: %i\n", playlist.numToId[song]);
}
int playlistChanges(FILE * fp, mpd_uint32 version) {
int i;
for(i=0; i<playlist.length; i++) {
if(version > playlist.version ||
playlist.songMod[i] >= version ||
playlist.songMod[i] == 0)
{
printPlaylistSongInfo(fp, i);
}
}
return 0;
}
int playlistInfo(FILE * fp, int song) {
int i;
int begin = 0;
int end = playlist.length;
......@@ -380,22 +458,54 @@ int playlistInfo(FILE * fp,int song) {
return -1;
}
for(i=begin;i<end;i++) {
myfprintf(fp,"file: %s\n",(playlist.songs[i])->utf8url);
if((tag = (playlist.songs[i])->tag)) {
printMpdTag(fp,tag);
}
for(i=begin; i<end; i++) printPlaylistSongInfo(fp, i);
return 0;
}
# define checkSongId(id) { \
if(id < 0 || id >= PLAYLIST_HASH_MULT*playlist_max_length || \
playlist.idToNum[id] == -1 ) \
{ \
commandError(fp, ACK_ERROR_NO_EXIST, \
"song id doesn't exist: \"%i\"", id); \
return -1; \
} \
}
int playlistId(FILE * fp, int id) {
int i;
int begin = 0;
int end = playlist.length;
if(id>=0) {
checkSongId(id);
begin = playlist.idToNum[id];
end = begin+1;
}
for(i=begin; i<end; i++) printPlaylistSongInfo(fp, i);
return 0;
}
void swapSongs(int song1, int song2) {
Song * temp;
Song * sTemp;
int iTemp;
temp = playlist.songs[song1];
sTemp = playlist.songs[song1];
playlist.songs[song1] = playlist.songs[song2];
playlist.songs[song2] = temp;
playlist.songs[song2] = sTemp;
playlist.songMod[song1] = playlist.version;
playlist.songMod[song2] = playlist.version;
playlist.idToNum[playlist.numToId[song1]] = song2;
playlist.idToNum[playlist.numToId[song2]] = song1;
iTemp = playlist.numToId[song1];
playlist.numToId[song1] = playlist.numToId[song2];
playlist.numToId[song2] = iTemp;
}
void queueNextSongInPlaylist() {
......@@ -488,7 +598,7 @@ int addToPlaylist(FILE * fp, char * url) {
}
else {
commandError(fp, ACK_ERROR_NO_EXIST,
"\"%s\" is not in the music db or is"
"\"%s\" is not in the music db or is "
"not a valid url\n", url);
return -1;
}
......@@ -512,7 +622,10 @@ int addSongToPlaylist(FILE * fp, Song * song) {
}
playlist.songs[playlist.length] = song;
playlist.songMod[playlist.length] = playlist.version;
playlist.order[playlist.length] = playlist.length;
playlist.numToId[playlist.length] = getNextId();
playlist.idToNum[playlist.numToId[playlist.length]] = playlist.length;
playlist.length++;
if(playlist.random) {
......@@ -548,7 +661,6 @@ int swapSongsInPlaylist(FILE * fp, int song1, int song2) {
return -1;
}
if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=0) {
queuedSong = playlist.order[playlist.queued];
......@@ -586,6 +698,21 @@ int swapSongsInPlaylist(FILE * fp, int song1, int song2) {
return 0;
}
int swapSongsInPlaylistById(FILE * fp, int id1, int id2) {
checkSongId(id1);
checkSongId(id2);
return swapSongsInPlaylist(fp, playlist.idToNum[id1],
playlist.idToNum[id2]);
}
#define moveSongFromTo(from, to) { \
playlist.idToNum[playlist.numToId[from]] = to; \
playlist.numToId[to] = playlist.numToId[from]; \
playlist.songs[to] = playlist.songs[from]; \
playlist.songMod[to] = playlist.version; \
}
int deleteFromPlaylist(FILE * fp, int song) {
int i;
int songOrder;
......@@ -610,9 +737,11 @@ int deleteFromPlaylist(FILE * fp, int song) {
freeJustSong(playlist.songs[song]);
}
playlist.idToNum[playlist.numToId[song]] = -1;
/* delete song from songs array */
for(i=song;i<playlist.length-1;i++) {
playlist.songs[i] = playlist.songs[i+1];
moveSongFromTo(i+1, i);
}
/* now find it in the order array */
for(i=0;i<playlist.length-1;i++) {
......@@ -652,6 +781,12 @@ int deleteFromPlaylist(FILE * fp, int song) {
return 0;
}
int deleteFromPlaylistById(FILE * fp, int id) {
checkSongId(id);
return deleteFromPlaylist(fp, playlist.idToNum[id]);
}
void deleteASongFromPlaylist(Song * song) {
int i;
......@@ -743,15 +878,27 @@ int playPlaylist(FILE * fp, int song, int stopOnError) {
return playPlaylistOrderNumber(fp,i);
}
int playPlaylistById(FILE * fp, int id, int stopOnError) {
if(id == -1) {
return playPlaylist(fp, id, stopOnError);
}
checkSongId(id);
return playPlaylist(fp, playlist.idToNum[id], stopOnError);
}
void syncCurrentPlayerDecodeMetadata() {
Song * songPlayer = playerCurrentDecodeSong();
Song * song;
int songNum;
if(!songPlayer) return;
if(playlist_state!=PLAYLIST_STATE_PLAY) return;
song = playlist.songs[playlist.order[playlist.current]];
songNum = playlist.order[playlist.current];
song = playlist.songs[songNum];
if(song->type == SONG_TYPE_URL &&
0 == strcmp(song->utf8url, songPlayer->utf8url) &&
......@@ -759,6 +906,7 @@ void syncCurrentPlayerDecodeMetadata() {
{
if(song->tag) freeMpdTag(song->tag);
song->tag = mpdTagDup(songPlayer->tag);
playlist.songMod[songNum] = playlist.version;
incrPlaylistVersion();
}
}
......@@ -859,6 +1007,7 @@ int setPlaylistRepeatStatus(FILE * fp, int status) {
int moveSongInPlaylist(FILE * fp, int from, int to) {
int i;
Song * tmpSong;
int tmpId;
int queuedSong = -1;
int currentSong = -1;
......@@ -890,12 +1039,20 @@ int moveSongInPlaylist(FILE * fp, int from, int to) {
}
tmpSong = playlist.songs[from];
tmpId = playlist.numToId[from];
/* move songs to one less in from->to */
for(i=from;i<to;i++) playlist.songs[i] = playlist.songs[i+1];
for(i=from;i<to;i++) {
moveSongFromTo(i+1, i);
}
/* move songs to one more in to->from */
for(i=from;i>to;i--) playlist.songs[i] = playlist.songs[i-1];
for(i=from;i>to;i--) {
moveSongFromTo(i-1, i);
}
/* put song at _to_ */
playlist.idToNum[playlist.numToId[tmpId]] = to;
playlist.numToId[to] = tmpId;
playlist.songs[to] = tmpSong;
playlist.songMod[to] = playlist.version;
/* now deal with order */
if(playlist.random) {
for(i=0;i<playlist.length;i++) {
......@@ -924,6 +1081,12 @@ int moveSongInPlaylist(FILE * fp, int from, int to) {
return 0;
}
int moveSongInPlaylistById(FILE * fp, int id1, int to) {
checkSongId(id1);
return moveSongInPlaylist(fp, playlist.idToNum[id1], to);
}
void orderPlaylist() {
int i;
......@@ -984,11 +1147,16 @@ int setPlaylistRandomStatus(FILE * fp, int status) {
if(status!=statusWas) {
if(playlist.random) {
if(playlist_state==PLAYLIST_STATE_PLAY) {
/*if(playlist_state==PLAYLIST_STATE_PLAY) {
randomizeOrder(playlist.current+1,
playlist.length-1);
}
else randomizeOrder(0,playlist.length-1);
else */randomizeOrder(0,playlist.length-1);
if(playlist.current >= 0 &&
playlist.current < playlist.length)
{
swapOrder(playlist.current, 0);
}
}
else orderPlaylist();
}
......@@ -1115,8 +1283,8 @@ int savePlaylist(FILE * fp, char * utf8file) {
free(rfile);
if(0==stat(actualFile,&st)) {
myfprintf(fp, "a file or directory already exists with the name"
" \"%s\"", utf8file);
commandError(fp, ACK_ERROR_EXIST, "a file or directory already "
"exists with the name \"%s\"", utf8file);
return -1;
}
......@@ -1285,3 +1453,13 @@ int seekSongInPlaylist(FILE * fp, int song, float time) {
return playerSeek(fp, playlist.songs[playlist.order[i]], time);
}
int seekSongInPlaylistById(FILE * fp, int id, float time) {
checkSongId(id);
return seekSongInPlaylist(fp, playlist.idToNum[id], time);
}
int getPlaylistSongId(int song) {
return playlist.numToId[song];
}
......@@ -22,6 +22,7 @@
#include "../config.h"
#include "song.h"
#include "mpd_types.h"
#include <stdio.h>
#include <sys/param.h>
......@@ -49,12 +50,18 @@ int showPlaylist(FILE * fp);
int deleteFromPlaylist(FILE * fp, int song);
int deleteFromPlaylistById(FILE * fp, int song);
int playlistInfo(FILE * fp, int song);
int playlistId(FILE * fp, int song);
int stopPlaylist(FILE * fp);
int playPlaylist(FILE * fp, int song, int stopOnError);
int playPlaylistById(FILE * fp, int song, int stopOnError);
int nextSongInPlaylist(FILE * fp);
void syncPlayerAndPlaylist();
......@@ -67,12 +74,18 @@ int savePlaylist(FILE * fp, char * utf8file);
int deletePlaylist(FILE * fp, char * utf8file);
int deletePlaylistById(FILE * fp, char * utf8file);
void deleteASongFromPlaylist(Song * song);
int moveSongInPlaylist(FILE * fp, int from, int to);
int moveSongInPlaylistById(FILE * fp, int id, int to);
int swapSongsInPlaylist(FILE * fp, int song1, int song2);
int swapSongsInPlaylistById(FILE * fp, int id1, int id2);
int loadPlaylist(FILE * fp, char * utf8file);
int getPlaylistRepeatStatus();
......@@ -85,6 +98,8 @@ int setPlaylistRandomStatus(FILE * fp, int status);
int getPlaylistCurrentSong();
int getPlaylistSongId(int song);
int getPlaylistLength();
unsigned long getPlaylistVersion();
......@@ -93,7 +108,11 @@ void playPlaylistIfPlayerStopped();
int seekSongInPlaylist(FILE * fp, int song, float time);
void incrPlaylistVersion();
int seekSongInPlaylistById(FILE * fp, int id, float time);
void playlistVersionChange();
int playlistChanges(FILE * fp, mpd_uint32 version);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c) 2004 Nick Welch (mack@incise.org)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -43,7 +44,7 @@ int handlePendingSignals() {
signal_clear(SIGHUP);
if(!isUpdatingDB()) {
readDirectoryDB();
incrPlaylistVersion();
playlistVersionChange();
}
if(myfprintfCloseAndOpenLogFile()<0) return COMMAND_RETURN_KILL;
playerCycleLogFiles();
......
......@@ -34,6 +34,7 @@
#define SONG_ALBUM "Album: "
#define SONG_TRACK "Track: "
#define SONG_TITLE "Title: "
#define SONG_NAME "Name: "
#define SONG_TIME "Time: "
#define SONG_MTIME "mtime: "
......@@ -235,6 +236,10 @@ void readSongInfoIntoList(FILE * fp, SongList * list) {
if(!song->tag) song->tag = newMpdTag();
song->tag->title = strdup(&(buffer[strlen(SONG_TITLE)]));
}
else if(0==strncmp(SONG_NAME,buffer,strlen(SONG_NAME))) {
if(!song->tag) song->tag = newMpdTag();
song->tag->name = strdup(&(buffer[strlen(SONG_NAME)]));
}
else if(0==strncmp(SONG_TIME,buffer,strlen(SONG_TIME))) {
if(!song->tag) song->tag = newMpdTag();
song->tag->time = atoi(&(buffer[strlen(SONG_TIME)]));
......
......@@ -43,6 +43,7 @@ void printMpdTag(FILE * fp, MpdTag * tag) {
if(tag->album) myfprintf(fp,"Album: %s\n",tag->album);
if(tag->track) myfprintf(fp,"Track: %s\n",tag->track);
if(tag->title) myfprintf(fp,"Title: %s\n",tag->title);
if(tag->name) myfprintf(fp,"Name: %s\n",tag->name);
if(tag->time>=0) myfprintf(fp,"Time: %i\n",tag->time);
}
......@@ -62,6 +63,7 @@ void validateUtf8Tag(MpdTag * tag) {
fixUtf8(tag->album);
fixUtf8(tag->track);
fixUtf8(tag->title);
fixUtf8(tag->name);
}
#ifdef HAVE_ID3TAG
......@@ -158,6 +160,7 @@ MpdTag * newMpdTag() {
ret->artist = NULL;
ret->title = NULL;
ret->track = NULL;
ret->name = NULL;
ret->time = -1;
return ret;
}
......@@ -166,6 +169,7 @@ void clearMpdTag(MpdTag * tag) {
if(tag->artist) free(tag->artist);
if(tag->album) free(tag->album);
if(tag->title) free(tag->title);
if(tag->name) free(tag->name);
if(tag->track) free(tag->track);
}
......@@ -183,6 +187,7 @@ MpdTag * mpdTagDup(MpdTag * tag) {
if(tag->album) ret->album = strdup(tag->album);
if(tag->title) ret->title = strdup(tag->title);
if(tag->track) ret->track = strdup(tag->track);
if(tag->name) ret->name = strdup(tag->name);
ret->time = tag->time;
}
......@@ -200,7 +205,7 @@ int mpdTagStringsAreEqual(char * s1, char * s2) {
int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2) {
if(tag1 == NULL && tag2 == NULL) return 1;
else if(!tag1 || ! !tag2) return 0;
else if(!tag1 || !tag2) return 0;
if(tag1->time != tag2->time) return 0;
......@@ -208,6 +213,7 @@ int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2) {
if(!mpdTagStringsAreEqual(tag1->album, tag2->album)) return 0;
if(!mpdTagStringsAreEqual(tag1->track, tag2->track)) return 0;
if(!mpdTagStringsAreEqual(tag1->title, tag2->title)) return 0;
if(!mpdTagStringsAreEqual(tag1->name, tag2->name)) return 0;
return 1;
}
......@@ -35,6 +35,7 @@ typedef struct _MpdTag {
char * album;
char * track;
char * title;
char * name;
int time;
} MpdTag;
......@@ -59,4 +60,3 @@ void validateUtf8Tag(MpdTag * tag);
int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
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