diff --git a/src/audio.c b/src/audio.c index 75d833be3..f66d25c98 100644 --- a/src/audio.c +++ b/src/audio.c @@ -34,7 +34,7 @@ static AudioFormat * audio_configFormat = NULL; static AudioOutput * aoOutput = NULL; static AudioOutput * shoutOutput = NULL; -static void copyAudioFormat(AudioFormat * dest, AudioFormat * src) { +void copyAudioFormat(AudioFormat * dest, AudioFormat * src) { if(!src) return; dest->sampleRate = src->sampleRate; @@ -182,3 +182,7 @@ void closeAudioDevice() { if(shoutOutput) closeAudioOutput(shoutOutput); closeAudioOutput(aoOutput); } + +void sendMetdataToAudioDevice(MpdTag * tag) { + if(shoutOutput) sendMetadataToAudioOutput(shoutOutput, tag); +} diff --git a/src/audio.h b/src/audio.h index 7a1209c1b..cda95c7d8 100644 --- a/src/audio.h +++ b/src/audio.h @@ -22,6 +22,7 @@ #include "../config.h" #include "mpd_types.h" +#include "tag.h" #include @@ -33,6 +34,8 @@ typedef struct _AudioFormat { volatile mpd_sint8 bits; } AudioFormat; +void copyAudioFormat(AudioFormat * dest, AudioFormat * src); + void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat); int parseAudioConfig(AudioFormat * audioFormat, char * conf); @@ -55,4 +58,6 @@ int isAudioDeviceOpen(); int isCurrentAudioFormat(AudioFormat * audioFormat); +void sendMetdataToAudioDevice(MpdTag * tag); + #endif diff --git a/src/audioOutput.c b/src/audioOutput.c index 24899e814..2963b7497 100644 --- a/src/audioOutput.c +++ b/src/audioOutput.c @@ -32,6 +32,7 @@ AudioOutput * newAudioOutput(char * name) { ret->openDeviceFunc = plugin->openDeviceFunc; ret->playFunc = plugin->playFunc; ret->closeDeviceFunc = plugin->closeDeviceFunc; + ret->sendMetdataFunc = plugin->sendMetdataFunc; ret->open = 0; if(plugin->initDriverFunc(ret) != 0) { @@ -62,3 +63,8 @@ void finishAudioOutput(AudioOutput * audioOutput) { audioOutput->finishDriverFunc(audioOutput); free(audioOutput); } + +void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag) { + if(!audioOutput->open || !audioOutput->sendMetdataFunc) return; + audioOutput->sendMetdataFunc(audioOutput, tag); +} diff --git a/src/audioOutput.h b/src/audioOutput.h index 92387b7da..ec43e9e7c 100644 --- a/src/audioOutput.h +++ b/src/audioOutput.h @@ -23,6 +23,7 @@ #include "mpd_types.h" #include "audio.h" +#include "tag.h" #define AUDIO_AO_DRIVER_DEFAULT "default" @@ -40,7 +41,8 @@ typedef int (* AudioOutputPlayFunc) (AudioOutput * audioOutput, typedef void (* AudioOutputCloseDeviceFunc) (AudioOutput * audioOutput); -typedef int (* AudioOutputKeepAliveFunc) (AudioOutput * audioOutput, int ms); +typedef void (* AudioOutputSendMetadataFunc) (AudioOutput * audioOutput, + MpdTag * tag); struct _AudioOutput { int open; @@ -49,7 +51,7 @@ struct _AudioOutput { AudioOutputOpenDeviceFunc openDeviceFunc; AudioOutputPlayFunc playFunc; AudioOutputCloseDeviceFunc closeDeviceFunc; - AudioOutputKeepAliveFunc keepAliveFunc; + AudioOutputSendMetadataFunc sendMetdataFunc; void * data; }; @@ -62,7 +64,7 @@ typedef struct _AudioOutputPlugin { AudioOutputOpenDeviceFunc openDeviceFunc; AudioOutputPlayFunc playFunc; AudioOutputCloseDeviceFunc closeDeviceFunc; - AudioOutputKeepAliveFunc keepAliveFunc; + AudioOutputSendMetadataFunc sendMetdataFunc; } AudioOutputPlugin; void initAudioOutputPlugins(); @@ -77,5 +79,6 @@ int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size); void closeAudioOutput(AudioOutput * audioOutput); void finishAudioOutput(AudioOutput * audioOutput); int keepAudioOutputAlive(AudioOutput * audioOutput, int ms); +void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag); #endif diff --git a/src/audioOutput_ao.c b/src/audioOutput_ao.c index 95f0f1a98..7c997c99e 100644 --- a/src/audioOutput_ao.c +++ b/src/audioOutput_ao.c @@ -225,5 +225,6 @@ AudioOutputPlugin aoPlugin = audioOutputAo_finishDriver, audioOutputAo_openDevice, audioOutputAo_play, - audioOutputAo_closeDevice + audioOutputAo_closeDevice, + NULL /* sendMetadataFunc */ }; diff --git a/src/audioOutput_shout.c b/src/audioOutput_shout.c index c650a74e5..514fbbe68 100644 --- a/src/audioOutput_shout.c +++ b/src/audioOutput_shout.c @@ -54,8 +54,6 @@ typedef struct _ShoutData { vorbis_info vi; vorbis_comment vc; - int serialno; - float quality; AudioFormat outAudioFormat; AudioFormat inAudioFormat; @@ -72,7 +70,6 @@ static ShoutData * newShoutData() { ShoutData * ret = malloc(sizeof(ShoutData)); ret->shoutConn = shout_new(); - ret->serialno = rand(); ret->convBuffer = NULL; ret->convBufferLen = 0; ret->opened = 0; @@ -190,6 +187,14 @@ static int shout_initDriver(AudioOutput * audioOutput) { return 0; } +static void clearEncoder(ShoutData * sd) { + ogg_stream_clear(&(sd->os)); + vorbis_block_clear(&(sd->vb)); + vorbis_dsp_clear(&(sd->vd)); + vorbis_comment_clear(&(sd->vc)); + vorbis_info_clear(&(sd->vi)); +} + static void shout_closeShoutConn(ShoutData * sd) { if(sd->opened) { if(shout_close(sd->shoutConn) != SHOUTERR_SUCCESS) { @@ -197,11 +202,7 @@ static void shout_closeShoutConn(ShoutData * sd) { "%s\n", shout_get_error(sd->shoutConn)); } - ogg_stream_clear(&(sd->os)); - vorbis_block_clear(&(sd->vb)); - vorbis_dsp_clear(&(sd->vd)); - vorbis_comment_clear(&(sd->vc)); - vorbis_info_clear(&(sd->vi)); + clearEncoder(sd); } sd->opened = 0; @@ -250,6 +251,27 @@ static void write_page(ShoutData * sd) { /*shout_sync(sd->shoutConn);*/ } +static int initEncoder(ShoutData * sd) { + vorbis_info_init(&(sd->vi)); + + if( 0 != vorbis_encode_init_vbr(&(sd->vi), sd->outAudioFormat.channels, + sd->outAudioFormat.sampleRate, sd->quality) ) + { + ERROR("problem seting up vorbis encoder for shout\n"); + vorbis_info_clear(&(sd->vi)); + return -1; + } + + vorbis_analysis_init(&(sd->vd), &(sd->vi)); + vorbis_block_init (&(sd->vd), &(sd->vb)); + + ogg_stream_init(&(sd->os), rand()); + + vorbis_comment_init(&(sd->vc)); + + return 0; +} + static int shout_openDevice(AudioOutput * audioOutput, AudioFormat * audioFormat) { @@ -277,24 +299,12 @@ static int shout_openDevice(AudioOutput * audioOutput, return -1; } - vorbis_info_init(&(sd->vi)); - - if( 0 != vorbis_encode_init_vbr(&(sd->vi), sd->outAudioFormat.channels, - sd->outAudioFormat.sampleRate, sd->quality) ) - { - ERROR("problem seting up vorbis encoder for shout\n"); - vorbis_info_clear(&(sd->vi)); + if(initEncoder(sd) < 0) { shout_close(sd->shoutConn); - audioOutput->open = 0; + audioOutput->open = 1; return -1; } - vorbis_analysis_init(&(sd->vd), &(sd->vi)); - vorbis_block_init (&(sd->vd), &(sd->vb)); - - ogg_stream_init(&(sd->os), sd->serialno); - - vorbis_comment_init(&(sd->vc)); vorbis_analysis_headerout(&(sd->vd), &(sd->vc), &(sd->header_main), &(sd->header_comments), &(sd->header_codebooks)); @@ -375,6 +385,44 @@ static int shout_play(AudioOutput * audioOutput, char * playChunk, int size) { return 0; } +#define addTag(name, value) { \ + if(value) vorbis_comment_add_tag(&(sd->vc), name, value); \ +} + +static void shout_sendMetadata(AudioOutput * audioOutput, MpdTag * tag) { + ShoutData * sd = (ShoutData *)audioOutput->data; + ogg_int64_t granulepos = sd->vd.granulepos; + + clearEncoder(sd); + if(initEncoder(sd) < 0) return; + + sd->vd.granulepos = granulepos; + + if(tag) { + addTag("ARTIST", tag->artist); + addTag("ALBUM", tag->album); + addTag("TITLE", tag->title); + + } + + DEBUG("shout: got tag\n"); + + vorbis_analysis_headerout(&(sd->vd), &(sd->vc), &(sd->header_main), + &(sd->header_comments), &(sd->header_codebooks)); + + ogg_stream_packetin(&(sd->os), &(sd->header_main)); + ogg_stream_packetin(&(sd->os), &(sd->header_comments)); + ogg_stream_packetin(&(sd->os), &(sd->header_codebooks)); + + /*vorbis_commentheader_out(&(sd->vc), &(sd->header_comments)); + ogg_stream_packetin(&(sd->os), &(sd->header_comments));*/ + + while(ogg_stream_flush(&(sd->os), &(sd->og))) + { + write_page(sd); + } +} + AudioOutputPlugin shoutPlugin = { "shout", @@ -382,7 +430,8 @@ AudioOutputPlugin shoutPlugin = shout_finishDriver, shout_openDevice, shout_play, - shout_closeDevice + shout_closeDevice, + shout_sendMetadata }; #else @@ -396,6 +445,7 @@ AudioOutputPlugin shoutPlugin = NULL, NULL, NULL, + NULL, NULL }; diff --git a/src/decode.c b/src/decode.c index 7296e154c..55252c46e 100644 --- a/src/decode.c +++ b/src/decode.c @@ -145,6 +145,7 @@ int waitOnDecode(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb, { strncpy(pc->currentUrl, pc->utf8url, MAXPATHLEN); pc->currentUrl[MAXPATHLEN] = '\0'; + MpdTag * tag = NULL; while(decode_pid && *decode_pid>0 && dc->start) my_usleep(10000); @@ -156,8 +157,14 @@ int waitOnDecode(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb, return -1; } + if((tag = metadataChunkToMpdTagDup(&(pc->fileMetadataChunk)))) { + sendMetdataToAudioDevice(tag); + printMpdTag(stdout, tag); + freeMpdTag(tag); + tag = NULL; + } + pc->totalTime = pc->fileTime; - pc->elapsedTime = 0; pc->bitRate = 0; pc->sampleRate = 0; pc->bits = 0; @@ -465,6 +472,7 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) { if(waitOnDecode(pc,dc,cb,&decodeWaitedOn)<0) return; + pc->elapsedTime = 0; pc->state = PLAYER_STATE_PLAY; pc->play = 0; kill(getppid(),SIGUSR1); diff --git a/src/metadataChunk.c b/src/metadataChunk.c index 49cba9d90..84817eb0e 100644 --- a/src/metadataChunk.c +++ b/src/metadataChunk.c @@ -38,7 +38,7 @@ void initMetadataChunk(MetadataChunk * chunk) { MpdTag * metadataChunkToMpdTagDup(MetadataChunk * chunk) { MpdTag * ret = newMpdTag(); - chunk->buffer[METADATA_BUFFER_LENGTH] = '\0'; + chunk->buffer[METADATA_BUFFER_LENGTH-1] = '\0'; dupElementToTag(ret->name, chunk->name); dupElementToTag(ret->title, chunk->title); @@ -65,6 +65,8 @@ void copyMpdTagToMetadataChunk(MpdTag * tag, MetadataChunk * chunk) { initMetadataChunk(chunk); + if(!tag) return; + copyStringToChunk(tag->name, chunk->name); copyStringToChunk(tag->title, chunk->title); copyStringToChunk(tag->artist, chunk->artist); diff --git a/src/player.c b/src/player.c index 8c9d0df45..f38b9384c 100644 --- a/src/player.c +++ b/src/player.c @@ -187,6 +187,8 @@ int playerPlay(FILE * fp, Song * song) { if(song->tag) pc->fileTime = song->tag->time; else pc->fileTime = 0; + copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk)); + strncpy(pc->utf8url, song->utf8url, MAXPATHLEN); pc->utf8url[MAXPATHLEN] = '\0'; @@ -338,6 +340,8 @@ int queueSong(Song * song) { if(song->tag) pc->fileTime = song->tag->time; else pc->fileTime = 0; + copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk)); + pc->queueState = PLAYER_QUEUE_FULL; return 0; } @@ -390,6 +394,8 @@ int playerSeek(FILE * fp, Song * song, float time) { if(song->tag) pc->fileTime = song->tag->time; else pc->fileTime = 0; + copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk)); + strncpy(pc->utf8url, song->utf8url, MAXPATHLEN); pc->utf8url[MAXPATHLEN] = '\0'; } diff --git a/src/player.h b/src/player.h index e869d1fa9..8ab4a4513 100644 --- a/src/player.h +++ b/src/player.h @@ -86,6 +86,7 @@ typedef struct _PlayerControl { volatile mpd_sint8 cycleLogFiles; volatile mpd_sint8 metadataState; MetadataChunk metadataChunk; + MetadataChunk fileMetadataChunk; } PlayerControl; void clearPlayerPid();