From ce10ba4b119faac3eb7c5d1251b1a875d28056c1 Mon Sep 17 00:00:00 2001
From: Warren Dukes <warren.dukes@gmail.com>
Date: Mon, 25 Oct 2004 20:09:03 +0000
Subject: fix a big time bug in metadataChunk (off by one in an array
 assignment) also, now we have metadata in our streams

git-svn-id: https://svn.musicpd.org/mpd/trunk@2337 09075e82-0dd4-0310-85a5-a0d7c8717e4f
---
 src/audio.c             |  6 +++-
 src/audio.h             |  5 +++
 src/audioOutput.c       |  6 ++++
 src/audioOutput.h       |  9 +++--
 src/audioOutput_ao.c    |  3 +-
 src/audioOutput_shout.c | 96 +++++++++++++++++++++++++++++++++++++------------
 src/decode.c            | 10 +++++-
 src/metadataChunk.c     |  4 ++-
 src/player.c            |  6 ++++
 src/player.h            |  1 +
 10 files changed, 116 insertions(+), 30 deletions(-)

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 <stdio.h>
 
@@ -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();
-- 
cgit v1.2.3