diff --git a/NEWS b/NEWS index ca2cb91..b0e9225 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,8 @@ Changes in 0.4.0, (SVN trunk): * various: - [ADD] Allow ezstream to use TagLib for reading metadata from media files. TagLib (libtag_c) is now an optional dependency. + - [ADD] When built with TagLib support, include the song length in the + "real-time" information line, if available. - [ADD] New configuration option, which causes metadata to be read from the output of an external program or script. diff --git a/src/ezstream.c b/src/ezstream.c index 2f3c169..e0aa29f 100644 --- a/src/ezstream.c +++ b/src/ezstream.c @@ -110,14 +110,18 @@ typedef struct tag_ID3Tag { } ID3Tag; int urlParse(const char *, char **, int *, char **); -void replaceString(const char *, char *, size_t, const char *, const char *); +void replaceString(const char *, char *, size_t, const char *, + const char *); char * buildCommandString(const char *, const char *, metadata_t *); char * getMetadataString(const char *, metadata_t *); metadata_t * getMetadata(const char *); int setMetadata(shout_t *, metadata_t *, char **); -FILE * openResource(shout_t *, const char *, int *, char **, int *); +FILE * openResource(shout_t *, const char *, int *, char **, int *, + int *); int reconnectServer(shout_t *, int); -int sendStream(shout_t *, FILE *, const char *, int, void *); +const char * getTimeString(int); +int sendStream(shout_t *, FILE *, const char *, int, const char *, + void *); int streamFile(shout_t *, const char *); int streamPlaylist(shout_t *, const char *); char * getProgname(const char *); @@ -505,7 +509,7 @@ setMetadata(shout_t *shout, metadata_t *mdata, char **mdata_copy) FILE * openResource(shout_t *shout, const char *fileName, int *popenFlag, - char **metaCopy, int *isStdin) + char **metaCopy, int *isStdin, int *songLen) { FILE *filep = NULL; char extension[25]; @@ -561,6 +565,8 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag, } if (metaCopy != NULL) *metaCopy = metadata_assemble_string(mdata); + if (songLen != NULL) + *songLen = metadata_get_length(mdata); *popenFlag = 0; if (pezConfig->reencode) { @@ -661,9 +667,28 @@ reconnectServer(shout_t *shout, int closeConn) return (0); } +const char * +getTimeString(int seconds) +{ + static char str[20]; + int secs, mins, hours; + + if (seconds < 0) + return (NULL); + + secs = seconds; + hours = secs / 3600; + secs %= 3600; + mins = secs / 60; + secs %= 60; + + snprintf(str, sizeof(str), "%uh%02um%02us", hours, mins, secs); + return ((const char *)str); +} + int sendStream(shout_t *shout, FILE *filepstream, const char *fileName, - int isStdin, void *tv) + int isStdin, const char *songLenStr, void *tv) { unsigned char buff[4096]; size_t read, total, oldTotal; @@ -728,7 +753,6 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName, #ifdef HAVE_GETTIMEOFDAY struct timeval tv; double oldTime, newTime; - unsigned int hrs, mins, secs; #endif /* HAVE_GETTIMEOFDAY */ if (!isStdin && playlistMode) { @@ -749,18 +773,19 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName, gettimeofday(&tv, NULL); newTime = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; - secs = tv.tv_sec - startTime->tv_sec; - hrs = secs / 3600; - secs %= 3600; - mins = secs / 60; - secs %= 60; + if (songLenStr == NULL) + printf(" [ %s]", + getTimeString(tv.tv_sec - startTime->tv_sec)); + else + printf(" [ %s/%s]", + getTimeString(tv.tv_sec - startTime->tv_sec), + songLenStr); if (newTime - oldTime >= 1.0) { kbps = (((double)(total - oldTotal) / (newTime - oldTime)) * 8.0) / 1000.0; timeStamp.tv_sec = tv.tv_sec; timeStamp.tv_usec = tv.tv_usec; oldTotal = total; } - printf(" [ %uh%02um%02us]", hrs, mins, secs); if (kbps < 0) printf(" "); else @@ -788,15 +813,15 @@ streamFile(shout_t *shout, const char *fileName) { FILE *filepstream = NULL; int popenFlag = 0; - char *metaData = NULL; + char *metaData = NULL, *songLenStr = NULL; int isStdin = 0; - int ret, retval = 0; + int ret, retval = 0, songLen; #ifdef HAVE_GETTIMEOFDAY struct timeval startTime; #endif if ((filepstream = openResource(shout, fileName, &popenFlag, - &metaData, &isStdin)) + &metaData, &isStdin, &songLen)) == NULL) { return (retval); } @@ -811,13 +836,15 @@ streamFile(shout_t *shout, const char *fileName) } #ifdef HAVE_GETTIMEOFDAY + if (songLen >= 0) + songLenStr = xstrdup(getTimeString(songLen)); gettimeofday(&startTime, NULL); do { ret = sendStream(shout, filepstream, fileName, isStdin, - (void *)&startTime); + songLenStr, (void *)&startTime); #else do { - ret = sendStream(shout, filepstream, fileName, isStdin, NULL); + ret = sendStream(shout, filepstream, fileName, isStdin, NULL, NULL); #endif if (ret != STREAM_DONE) { if ((skipTrack && rereadPlaylist) || @@ -875,6 +902,9 @@ streamFile(shout_t *shout, const char *fileName) else fclose(filepstream); + if (songLenStr != NULL) + xfree(songLenStr); + return (retval); } diff --git a/src/metadata.c b/src/metadata.c index 3a3e07d..d8a6d23 100644 --- a/src/metadata.c +++ b/src/metadata.c @@ -53,6 +53,7 @@ struct metadata { char *string; char *artist; char *title; + int songLen; int program; }; @@ -81,6 +82,7 @@ metadata_create(const char *filename) md = xcalloc(1, sizeof(metadata_t)); md->filename = xstrdup(filename); + md->songLen = -1; return (md); } @@ -89,9 +91,10 @@ void metadata_use_taglib(metadata_t *md, FILE **filep) #ifdef HAVE_TAGLIB { - TagLib_File *tf; - TagLib_Tag *tt; - char *str; + TagLib_File *tf; + TagLib_Tag *tt; + TagLib_AudioProperties *ta; + char *str; if (md == NULL || md->filename == NULL) { printf("%s: metadata_use_taglib(): Internal error: Bad arguments\n", @@ -113,7 +116,9 @@ metadata_use_taglib(metadata_t *md, FILE **filep) md->string = metadata_get_name(md->filename); return; } + tt = taglib_file_tag(tf); + ta = taglib_file_audioproperties(tf); str = taglib_tag_artist(tt); if (str != NULL) { @@ -129,6 +134,8 @@ metadata_use_taglib(metadata_t *md, FILE **filep) xfree(str); } + md->songLen = taglib_audioproperties_length(ta); + taglib_file_free(tf); } #else @@ -602,6 +609,18 @@ metadata_get_filename(metadata_t *md) return (md->filename); } +int +metadata_get_length(metadata_t *md) +{ + if (md == NULL) { + printf("%s: metadata_get_length(): Internal error: Bad arguments\n", + __progname); + abort(); + } + + return (md->songLen); +} + char * metadata_assemble_string(metadata_t *md) { diff --git a/src/metadata.h b/src/metadata.h index a80ab97..ba9d276 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -96,6 +96,12 @@ const char * metadata_get_title(metadata_t *); */ const char * metadata_get_filename(metadata_t *); +/* + * Returns the length of the song, in seconds, or -1 if the information is not + * available. + */ +int metadata_get_length(metadata_t *); + /* * Allocates and returns a meaningful string based on a metadata handle's * content. The result is what metadata_get_string() defaults to if an external