[xiph-commits] r12707 - in trunk/ezstream: . doc src

moritz at svn.xiph.org moritz at svn.xiph.org
Sat Mar 10 11:03:13 PST 2007


Author: moritz
Date: 2007-03-10 11:03:07 -0800 (Sat, 10 Mar 2007)
New Revision: 12707

Modified:
   trunk/ezstream/NEWS
   trunk/ezstream/doc/ezstream.1.in
   trunk/ezstream/src/configfile.c
   trunk/ezstream/src/configfile.h
   trunk/ezstream/src/ezstream.c
   trunk/ezstream/src/metadata.c
   trunk/ezstream/src/metadata.h
Log:
More metadata featuritis, add <metadata_format/> and implement support for
'@a@', '@t@' and '@s@'.


Modified: trunk/ezstream/NEWS
===================================================================
--- trunk/ezstream/NEWS	2007-03-10 17:50:46 UTC (rev 12706)
+++ trunk/ezstream/NEWS	2007-03-10 19:03:07 UTC (rev 12707)
@@ -25,6 +25,10 @@
    - [ADD]   New runtime control via the SIGUSR2 signal, which triggers reading
              of fresh metadata information from <metadata_progname> (metadata
              is always read at song changes.)
+   - [ADD]   New <metadata_format> configuration option, to customize metadata
+             strings when used with the new <metadata_progname> feature.
+   - [ADD]   New '@a@' and '@t@' placeholders for separate artist and title
+             metadata in de-/encoder commands.
 
 
 

Modified: trunk/ezstream/doc/ezstream.1.in
===================================================================
--- trunk/ezstream/doc/ezstream.1.in	2007-03-10 17:50:46 UTC (rev 12706)
+++ trunk/ezstream/doc/ezstream.1.in	2007-03-10 19:03:07 UTC (rev 12707)
@@ -215,6 +215,17 @@
 See the
 .Sy SCRIPTING
 section for details on how the metadata program must behave.
+.It Sy \&<metadata_format\ /\&>
+.Pq Optional.
+Set the format of the string that should be used for the
+.Sq @M@
+placeholder when setting metadata with an external program or script via
+\&<metadata_progname/\&>.
+.Pp
+See the
+.Sy METADATA
+section for details on how metadata is handled by
+.Nm .
 .It Sy \&<stream_once\ /\&>
 Set to
 .Sy 1
@@ -339,16 +350,17 @@
 it to standard output.
 During runtime, the placeholder
 .Sq Li @T@
-is replaced with the fully qualified name of the media file, as specified in
-the \&<filename/\&> element or a playlist file.
+is replaced with the name of the media file, as it is specified in the
+\&<filename/\&> element or contained in a playlist file.
 It should always be enclosed in quotes, to prevent problems with filenames that
 contain whitespaces.
 .Pp
-The metadata placeholder,
-.Sq @M@ ,
-is also available in the \&<decode/\&> element.
-That way it can be used for combined de-/encoder programs that produce readily
-streamable data.
+Metadata placeholders can be used in the \&<decode/\&> element as well, for
+combined de-/encoder programs that produce streamable data.
+See the
+.Sy METADATA
+section for details on how metadata is handled by
+.Nm .
 .Pp
 For example, to decode Ogg Vorbis files using the
 .Cm oggdec
@@ -358,16 +370,14 @@
 .It Sy \&<encode\ /\&>
 Set the command to encode raw data, received from standard input, to the
 specified stream format.
-During runtime, the placeholder
-.Sq Li @M@
-is replaced with the metadata
-.Po
-e.g.
-.Dq Artist - Title
-.Pc
-for the current track.
-It also should be enclosed in quotes at all times.
 .Pp
+Metadata placeholders can be used in the \&<encode/\&> element.
+For details about using metadata in
+.Nm ,
+see below in the
+.Sy METADATA
+section.
+.Pp
 For example, to encode an Ogg Vorbis stream using the quality setting 1.5 with
 the
 .Cm oggenc
@@ -423,11 +433,89 @@
 the program should return only the title information of the metadata.
 .Pq Optional.
 .El
+.Sh METADATA
+The main tool for handling metadata with
+.Nm
+is placeholders in decoder and encoder commands that are replaced with real
+content during runtime.
+The tricky part about is that one placeholders has to be handled differently
+depending on where the metadata comes from.
+This section will explain each possible scenario.
+.Ss Metadata Placeholders
+.Bl -tag -width -Ds
+.It Sy @T@
+Replaced with the media file name.
+Required in \&<decode/\&> and is available in \&<metadata_format/\&>.
+.It Sy @M@
+Replaced with a metadata string.
+See below for a detailed explanation.
+Available in \&<decode/\&> and \&<encode/\&>.
+.It Sy @a@
+Replaced with the artist information.
+Available in \&<decode/\&>, \&<encode/\&> and \&<metadata_format/\&>.
+.It Sy @t@
+Replaced with the title information.
+Available in \&<decode/\&>, \&<encode/\&> and \&<metadata_format/\&>.
+.It Sy @s@
+Replaced with the string returned by \&<metadata_progname/\&> when called
+without any command line parameters.
+Available only in \&<metadata_format/\&>.
+.El
+.Ss The @M@ Placeholder
+While all other placeholders are simply replaced with whatever data they are
+associated with,
+.Sq @M@
+is context-sensitive.
+The logic used by
+.Nm
+is the following:
+.Bd -literal -offset indent
+If ('@M@ is present')
+    If ('\&<metadata_progname/\&>' AND '\&<metadata_format/\&>')
+        Replace with format string result.
+    Else
+        If (NOT '\&<metadata_progname/\&>' AND '@t@ is present')
+            Replace with empty string.
+        else
+            Replace with generated metadata string.
+        Endif
+    Endif
+Endif
+.Ed
+.Pp
+The generated metadata string for
+.Sq @M@
+is of the format
+.Dq Artist - Title ,
+if both artist and title information is available.
+If one of the two is missing, the available one is displayed without a leading
+or trailing dash, e.g. just
+.Dq Artist .
+If neither artist nor title are available, the name of the media file, without
+its file extension, is used.
+.Ss Metadata Caveats
+It is possible to generate strange results with odd combinations of
+placeholders, external metadata programs and updates during runtime via
+.Sy SIGUSR2 .
+If things start to become just confusing, simplify.
+.Pp
+Metadata updates during runtime are done with a relatively broken feature of
+libshout.
+Additional metadata information that is already present in the stream sent via
+.Nm
+is usually destroyed and replaced with the new data.
+It is not possible to properly discern between artist and title information,
+which means that anything set with the
+.Sy SIGUSR2
+feature will continue to end up entirely in the
+.Qq Title
+field of a stream.
 .Sh FILES
 .Bl -tag -width "!!EXAMPLES_DIR!!" -compact
 .It Pa !!EXAMPLES_DIR!!
 Directory containing example configuration files for various uses of
-.Nm .
+.Nm ,
+as well as example playlist and metadata scripts.
 .El
 .Sh AUTHORS
 .Nm

Modified: trunk/ezstream/src/configfile.c
===================================================================
--- trunk/ezstream/src/configfile.c	2007-03-10 17:50:46 UTC (rev 12706)
+++ trunk/ezstream/src/configfile.c	2007-03-10 19:03:07 UTC (rev 12707)
@@ -39,6 +39,7 @@
 void	        freeConfig(EZCONFIG *);
 unsigned int	checkDecoderLine(const char *, const char *, long);
 unsigned int	checkEncoderLine(const char *, const char *, long);
+unsigned int	checkFormatLine(const char *, const char *, long);
 
 EZCONFIG *
 getEZConfig(void)
@@ -198,6 +199,27 @@
 				xmlFree(ls_xmlContentPtr);
 			}
 		}
+		if (!xmlStrcmp(cur->name, BAD_CAST "metadata_format")) {
+			if (ezConfig.metadataFormat != NULL) {
+				printf("%s[%ld]: Error: Cannot have multiple <metadata_format> elements\n",
+				       fileName, xmlGetLineNo(cur));
+				config_error++;
+				continue;
+			}
+			if (cur->xmlChildrenNode != NULL) {
+				unsigned int	ret;
+
+				ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+				ezConfig.metadataFormat = xstrdup(ls_xmlContentPtr);
+				xmlFree(ls_xmlContentPtr);
+				if ((ret = checkFormatLine(ezConfig.metadataFormat,
+							   fileName, xmlGetLineNo(cur)))
+				    > 0) {
+					config_error += ret;
+					continue;
+				}
+			}
+		}
 		if (!xmlStrcmp(cur->name, BAD_CAST "playlist_program")) {
 			if (program_set) {
 				printf("%s[%ld]: Error: Cannot have multiple <playlist_program> elements\n",
@@ -564,6 +586,8 @@
 		xfree(cfg->fileName);
 	if (cfg->metadataProgram != NULL)
 		xfree(cfg->metadataProgram);
+	if (cfg->metadataFormat != NULL)
+		xfree(cfg->metadataFormat);
 	if (cfg->serverName != NULL)
 		xfree(cfg->serverName);
 	if (cfg->serverURL != NULL)
@@ -604,15 +628,22 @@
 {
 	unsigned int	  errors;
 	char		 *p;
+	int		  have_track = 0;
 
 	errors = 0;
+	if ((p = strstr(str, STRING_PLACEHOLDER)) != NULL) {
+		printf("%s[%ld]: Error: `%s' placeholder not allowed in decoder command\n",
+		       file, line, STRING_PLACEHOLDER);
+		errors++;
+	}
 	if ((p = strstr(str, TRACK_PLACEHOLDER)) != NULL) {
 		p += strlen(TRACK_PLACEHOLDER);
 		if ((p = strstr(p, TRACK_PLACEHOLDER)) != NULL) {
 			printf("%s[%ld]: Error: Multiple `%s' placeholders in decoder command\n",
 			       file, line, TRACK_PLACEHOLDER);
 			errors++;
-		}
+		} else
+			have_track = 1;
 	}
 	if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
 		p += strlen(METADATA_PLACEHOLDER);
@@ -639,6 +670,12 @@
 		}
 	}
 
+	if (!have_track) {
+		printf("%s[%ld]: Error: The decoder command requires the '%s' track placeholder\n",
+		       file, line, TRACK_PLACEHOLDER);
+		errors++;
+	}
+
 	return (errors);
 }
 
@@ -654,6 +691,11 @@
 		       file, line, TRACK_PLACEHOLDER);
 		errors++;
 	}
+	if ((p = strstr(str, STRING_PLACEHOLDER)) != NULL) {
+		printf("%s[%ld]: Error: `%s' placeholder not allowed in encoder command\n",
+		       file, line, STRING_PLACEHOLDER);
+		errors++;
+	}
 	if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
 		p += strlen(METADATA_PLACEHOLDER);
 		if ((p = strstr(p, METADATA_PLACEHOLDER)) != NULL) {
@@ -681,3 +723,51 @@
 
 	return (errors);
 }
+
+unsigned int
+checkFormatLine(const char *str, const char *file, long line)
+{
+	unsigned int	   errors;
+	char		  *p;
+
+	errors = 0;
+	if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
+		printf("%s[%ld]: Error: `%s' placeholder not allowed in <metadata_format>\n",
+		       file, line, METADATA_PLACEHOLDER);
+		errors++;
+	}
+	if ((p = strstr(str, TRACK_PLACEHOLDER)) != NULL) {
+		p += strlen(TRACK_PLACEHOLDER);
+		if ((p = strstr(p, TRACK_PLACEHOLDER)) != NULL) {
+			printf("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
+			       file, line, TRACK_PLACEHOLDER);
+			errors++;
+		}
+	}
+	if ((p = strstr(str, STRING_PLACEHOLDER)) != NULL) {
+		p += strlen(STRING_PLACEHOLDER);
+		if ((p = strstr(p, STRING_PLACEHOLDER)) != NULL) {
+			printf("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
+			       file, line, STRING_PLACEHOLDER);
+			errors++;
+		}
+	}
+	if ((p = strstr(str, ARTIST_PLACEHOLDER)) != NULL) {
+		p += strlen(ARTIST_PLACEHOLDER);
+		if ((p = strstr(p, ARTIST_PLACEHOLDER)) != NULL) {
+			printf("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
+			       file, line, ARTIST_PLACEHOLDER);
+			errors++;
+		}
+	}
+	if ((p = strstr(str, TITLE_PLACEHOLDER)) != NULL) {
+		p += strlen(TITLE_PLACEHOLDER);
+		if ((p = strstr(p, TITLE_PLACEHOLDER)) != NULL) {
+			printf("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
+			       file, line, TITLE_PLACEHOLDER);
+			errors++;
+		}
+	}
+
+	return (errors);
+}

Modified: trunk/ezstream/src/configfile.h
===================================================================
--- trunk/ezstream/src/configfile.h	2007-03-10 17:50:46 UTC (rev 12706)
+++ trunk/ezstream/src/configfile.h	2007-03-10 19:03:07 UTC (rev 12707)
@@ -33,6 +33,7 @@
 #define METADATA_PLACEHOLDER	"@M@"
 #define ARTIST_PLACEHOLDER	"@a@"
 #define TITLE_PLACEHOLDER	"@t@"
+#define STRING_PLACEHOLDER	"@s@"
 
 typedef struct tag_FORMAT_ENCDEC {
 	char	*format;
@@ -47,6 +48,7 @@
 	char		*format;
 	char		*fileName;
 	char		*metadataProgram;
+	char		*metadataFormat;
 	char		*serverName;
 	char		*serverURL;
 	char		*serverGenre;

Modified: trunk/ezstream/src/ezstream.c
===================================================================
--- trunk/ezstream/src/ezstream.c	2007-03-10 17:50:46 UTC (rev 12706)
+++ trunk/ezstream/src/ezstream.c	2007-03-10 19:03:07 UTC (rev 12707)
@@ -112,6 +112,7 @@
 int		urlParse(const char *, char **, int *, 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 *);
@@ -247,14 +248,61 @@
 	newDecoder = xcalloc(1, newDecoderLen);
 	replaceString(decoder, newDecoder, newDecoderLen, TRACK_PLACEHOLDER,
 		      fileName);
-	if (strstr(decoder, METADATA_PLACEHOLDER) != NULL) {
-		size_t tmpLen = strlen(newDecoder) + strlen(metadata_get_string(mdata)) + 1;
+	if (strstr(decoder, ARTIST_PLACEHOLDER) != NULL) {
+		size_t tmpLen = strlen(newDecoder) + strlen(metadata_get_artist(mdata)) + 1;
 		char *tmpStr = xcalloc(1, tmpLen);
-		replaceString(newDecoder, tmpStr, tmpLen, METADATA_PLACEHOLDER,
-			      metadata_get_string(mdata));
+		replaceString(newDecoder, tmpStr, tmpLen, ARTIST_PLACEHOLDER,
+			      metadata_get_artist(mdata));
 		xfree(newDecoder);
 		newDecoder = tmpStr;
 	}
+	if (strstr(decoder, TITLE_PLACEHOLDER) != NULL) {
+		size_t tmpLen = strlen(newDecoder) + strlen(metadata_get_title(mdata)) + 1;
+		char *tmpStr = xcalloc(1, tmpLen);
+		replaceString(newDecoder, tmpStr, tmpLen, TITLE_PLACEHOLDER,
+			      metadata_get_title(mdata));
+		xfree(newDecoder);
+		newDecoder = tmpStr;
+	}
+	/*
+	 * if meta
+	 *   if (prog && format)
+	 *      metatoformat
+	 *   else
+	 *     if (!prog && title)
+	 *       emptymeta
+	 *     else
+	 *       replacemeta
+	 */
+	if (strstr(decoder, METADATA_PLACEHOLDER) != NULL) {
+		if (metadataFromProgram && pezConfig->metadataFormat != NULL) {
+			char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata);
+			size_t tmpLen = strlen(newDecoder) + strlen(mdataString) + 1;
+			char *tmpStr = xcalloc(1, tmpLen);
+			replaceString(newDecoder, tmpStr, tmpLen,
+				      METADATA_PLACEHOLDER, mdataString);
+			xfree(newDecoder);
+			xfree(mdataString);
+			newDecoder = tmpStr;
+		} else {
+			if (!metadataFromProgram && strstr(decoder, TITLE_PLACEHOLDER) != NULL) {
+				size_t tmpLen = strlen(newDecoder) + 1;
+				char *tmpStr = xcalloc(1, tmpLen);
+				replaceString(newDecoder, tmpStr, tmpLen,
+					      METADATA_PLACEHOLDER, "");
+				xfree(newDecoder);
+				newDecoder = tmpStr;
+			} else {
+				size_t tmpLen = strlen(newDecoder) + strlen(metadata_get_string(mdata)) + 1;
+				char *tmpStr = xcalloc(1, tmpLen);
+				replaceString(newDecoder, tmpStr, tmpLen,
+					      METADATA_PLACEHOLDER,
+					      metadata_get_string(mdata));
+				xfree(newDecoder);
+				newDecoder = tmpStr;
+			}
+		}
+	}
 
 	encoder = xstrdup(getFormatEncoder(pezConfig->format));
 	if (strlen(encoder) == 0) {
@@ -272,10 +320,47 @@
 		return (commandString);
 	}
 
-	newEncoderLen = strlen(encoder) + strlen(metadata_get_string(mdata)) + 1;
+	newEncoderLen = strlen(encoder) + strlen(metadata_get_artist(mdata)) + 1;
 	newEncoder = xcalloc(1, newEncoderLen);
-	replaceString(encoder, newEncoder, newEncoderLen, METADATA_PLACEHOLDER,
-		      metadata_get_string(mdata));
+	replaceString(encoder, newEncoder, newEncoderLen, ARTIST_PLACEHOLDER,
+		      metadata_get_artist(mdata));
+	if (strstr(encoder, TITLE_PLACEHOLDER) != NULL) {
+		size_t tmpLen = strlen(newEncoder) + strlen(metadata_get_title(mdata)) + 1;
+		char *tmpStr = xcalloc(1, tmpLen);
+		replaceString(newEncoder, tmpStr, tmpLen, TITLE_PLACEHOLDER,
+			      metadata_get_title(mdata));
+		xfree(newEncoder);
+		newEncoder = tmpStr;
+	}
+	if (strstr(encoder, METADATA_PLACEHOLDER) != NULL) {
+		if (metadataFromProgram && pezConfig->metadataFormat != NULL) {
+			char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata);
+			size_t tmpLen = strlen(newEncoder) + strlen(mdataString) + 1;
+			char *tmpStr = xcalloc(1, tmpLen);
+			replaceString(newEncoder, tmpStr, tmpLen,
+				      METADATA_PLACEHOLDER, mdataString);
+			xfree(newEncoder);
+			xfree(mdataString);
+			newEncoder = tmpStr;
+		} else {
+			if (!metadataFromProgram && strstr(encoder, TITLE_PLACEHOLDER) != NULL) {
+				size_t tmpLen = strlen(newEncoder) + 1;
+				char *tmpStr = xcalloc(1, tmpLen);
+				replaceString(newEncoder, tmpStr, tmpLen,
+					      METADATA_PLACEHOLDER, "");
+				xfree(newEncoder);
+				newEncoder = tmpStr;
+			} else {
+				size_t tmpLen = strlen(newEncoder) + strlen(metadata_get_string(mdata)) + 1;
+				char *tmpStr = xcalloc(1, tmpLen);
+				replaceString(newEncoder, tmpStr, tmpLen,
+					      METADATA_PLACEHOLDER,
+					      metadata_get_string(mdata));
+				xfree(newEncoder);
+				newEncoder = tmpStr;
+			}
+		}
+	}
 
 	commandStringLen = strlen(newDecoder) + strlen(" | ") +
 		strlen(newEncoder) + 1;
@@ -291,6 +376,59 @@
 	return (commandString);
 }
 
+char *
+getMetadataString(const char *format, metadata_t *mdata)
+{
+	char	*tmp, *str;
+	size_t	 siz;
+
+	if (mdata == NULL) {
+		printf("%s: getMetadataString(): Internal error: NULL metadata_t\n",
+		       __progname);
+		abort();
+	}
+
+	if (format == NULL)
+		return (NULL);
+
+	str = xstrdup(format);
+
+	if (strstr(format, ARTIST_PLACEHOLDER) != NULL) {
+		siz = strlen(str) + strlen(metadata_get_artist(mdata)) + 1;
+		tmp = xcalloc(1, siz);
+		replaceString(str, tmp, siz, ARTIST_PLACEHOLDER,
+			      metadata_get_artist(mdata));
+		xfree(str);
+		str = tmp;
+	}
+	if (strstr(format, TITLE_PLACEHOLDER) != NULL) {
+		siz = strlen(str) + strlen(metadata_get_title(mdata)) + 1;
+		tmp = xcalloc(1, siz);
+		replaceString(str, tmp, siz, TITLE_PLACEHOLDER,
+			      metadata_get_title(mdata));
+		xfree(str);
+		str = tmp;
+	}
+	if (strstr(format, STRING_PLACEHOLDER) != NULL) {
+		siz = strlen(str) + strlen(metadata_get_string(mdata)) + 1;
+		tmp = xcalloc(1, siz);
+		replaceString(str, tmp, siz, STRING_PLACEHOLDER,
+			      metadata_get_string(mdata));
+		xfree(str);
+		str = tmp;
+	}
+	if (strstr(format, TRACK_PLACEHOLDER) != NULL) {
+		siz = strlen(str) + strlen(metadata_get_filename(mdata)) + 1;
+		tmp = xcalloc(1, siz);
+		replaceString(str, tmp, siz, TRACK_PLACEHOLDER,
+			      metadata_get_filename(mdata));
+		xfree(str);
+		str = tmp;
+	}
+
+	return (str);
+}
+
 metadata_t *
 getMetadata(const char *fileName)
 {
@@ -339,10 +477,13 @@
 		exit(1);
 	}
 
-	if (metadata_get_artist(mdata) == NULL && metadata_get_title(mdata) == NULL)
-		songInfo = xstrdup(metadata_get_string(mdata));
-	else
-		songInfo = metadata_assemble_string(mdata);
+	if ((songInfo = getMetadataString(pezConfig->metadataFormat, mdata)) == NULL) {
+		if (strlen(metadata_get_artist(mdata)) == 0 &&
+		    strlen(metadata_get_title(mdata)) == 0)
+			songInfo = xstrdup(metadata_get_string(mdata));
+		else
+			songInfo = metadata_assemble_string(mdata);
+	}
 
 	if (shout_metadata_add(shout_mdata, "song", songInfo) != SHOUTERR_SUCCESS) {
 		/* Assume SHOUTERR_MALLOC */

Modified: trunk/ezstream/src/metadata.c
===================================================================
--- trunk/ezstream/src/metadata.c	2007-03-10 17:50:46 UTC (rev 12706)
+++ trunk/ezstream/src/metadata.c	2007-03-10 19:03:07 UTC (rev 12707)
@@ -43,9 +43,11 @@
 #include "strfctns.h"
 #include "util.h"
 
-extern char	*__progname;
-extern int	 vFlag;
+extern char		*__progname;
+extern int		 vFlag;
 
+static const char	*blankString = "";
+
 struct metadata {
 	char	*filename;
 	char	*string;
@@ -563,7 +565,10 @@
 		abort();
 	}
 
-	return (md->artist);
+	if (md->artist == NULL)
+		return (blankString);
+	else
+		return (md->artist);
 }
 
 const char *
@@ -575,9 +580,28 @@
 		abort();
 	}
 
-	return (md->title);
+	if (md->title == NULL)
+		return (blankString);
+	else
+		return (md->title);
 }
 
+const char *
+metadata_get_filename(metadata_t *md)
+{
+	if (md == NULL) {
+		printf("%s: metadata_get_filename(): Internal error: Bad arguments\n",
+		       __progname);
+		abort();
+	}
+
+	if (md->filename == NULL)
+		/* Should never happen: */
+		return (blankString);
+	else
+		return (md->filename);
+}
+
 char *
 metadata_assemble_string(metadata_t *md)
 {

Modified: trunk/ezstream/src/metadata.h
===================================================================
--- trunk/ezstream/src/metadata.h	2007-03-10 17:50:46 UTC (rev 12706)
+++ trunk/ezstream/src/metadata.h	2007-03-10 19:03:07 UTC (rev 12707)
@@ -75,24 +75,28 @@
 /*
  * Returns a pointer to a metadata string ``artist - title'', or just
  * ``artist'' or ``title'' if one of the two is not available. If neither
- * are present, it usually returns the filename without the extension.
- * This function never returns NULL.
+ * are present, it returns the filename without the extension. An empty string
+ * is returned for metadata_program() handles that didn't supply any generic
+ * information.
  */
 const char *	metadata_get_string(metadata_t *);
 
 /*
- * Returns a pointer to the artist string, or NULL if the file did not
- * contain any artist information.
+ * Returns a pointer to the artist string, which may be empty.
  */
 const char *	metadata_get_artist(metadata_t *);
 
 /*
- * Returns a pointer to the title string, or NULL if the file did not
- * contain any title information.
+ * Returns a pointer to the title string, which may be empty.
  */
 const char *	metadata_get_title(metadata_t *);
 
 /*
+ * Returns a pointer to the filename used in the metadata handle.
+ */
+const char *	metadata_get_filename(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
  * program is not used.



More information about the commits mailing list