[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