1
0
mirror of https://gitlab.xiph.org/xiph/ezstream.git synced 2024-11-03 04:17:18 -05:00

Commit work-in-progress towards more fine-grained control over metadata. This

has not been checked for changes to previous behavior and isn't complete, yet.
More to come.


git-svn-id: https://svn.xiph.org/trunk/ezstream@12701 0101bb08-14d6-0310-b084-bc0e0c8e3800
This commit is contained in:
moritz 2007-03-10 02:27:48 +00:00
parent bc6ae77abd
commit 6f779c21f3
5 changed files with 305 additions and 161 deletions

View File

@ -36,7 +36,9 @@ extern char *__progname;
static EZCONFIG ezConfig;
static const char *blankString = "";
void freeConfig(EZCONFIG *);
void freeConfig(EZCONFIG *);
unsigned int checkDecoderLine(const char *, const char *, long);
unsigned int checkEncoderLine(const char *, const char *, long);
EZCONFIG *
getEZConfig(void)
@ -82,59 +84,6 @@ getFormatDecoder(const char *match)
return (blankString);
}
void
freeConfig(EZCONFIG *cfg)
{
unsigned int i;
if (cfg == NULL)
return;
if (cfg->URL != NULL)
xfree(cfg->URL);
if (cfg->password != NULL)
xfree(cfg->password);
if (cfg->format != NULL)
xfree(cfg->format);
if (cfg->fileName != NULL)
xfree(cfg->fileName);
if (cfg->metadataProgram != NULL)
xfree(cfg->metadataProgram);
if (cfg->serverName != NULL)
xfree(cfg->serverName);
if (cfg->serverURL != NULL)
xfree(cfg->serverURL);
if (cfg->serverGenre != NULL)
xfree(cfg->serverGenre);
if (cfg->serverDescription != NULL)
xfree(cfg->serverDescription);
if (cfg->serverBitrate != NULL)
xfree(cfg->serverBitrate);
if (cfg->serverChannels != NULL)
xfree(cfg->serverChannels);
if (cfg->serverSamplerate != NULL)
xfree(cfg->serverSamplerate);
if (cfg->serverQuality != NULL)
xfree(cfg->serverQuality);
if (cfg->encoderDecoders != NULL) {
for (i = 0; i < MAX_FORMAT_ENCDEC; i++) {
if (cfg->encoderDecoders[i] != NULL) {
if (cfg->encoderDecoders[i]->format != NULL)
xfree(cfg->encoderDecoders[i]->format);
if (cfg->encoderDecoders[i]->match != NULL)
xfree(cfg->encoderDecoders[i]->match);
if (cfg->encoderDecoders[i]->encoder != NULL)
xfree(cfg->encoderDecoders[i]->encoder);
if (cfg->encoderDecoders[i]->decoder != NULL)
xfree(cfg->encoderDecoders[i]->decoder);
xfree(cfg->encoderDecoders[i]);
}
}
}
memset(cfg, 0, sizeof(EZCONFIG));
}
int
parseConfig(const char *fileName)
{
@ -496,7 +445,6 @@ parseConfig(const char *fileName)
if (!xmlStrcmp(cur2->name, BAD_CAST "encdec")) {
xmlNodePtr cur3;
FORMAT_ENCDEC *pformatEncDec;
char *p;
pformatEncDec = xcalloc(1, sizeof(FORMAT_ENCDEC));
@ -544,26 +492,16 @@ parseConfig(const char *fileName)
continue;
}
if (cur3->xmlChildrenNode != NULL) {
unsigned int ret;
ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
pformatEncDec->decoder = xstrdup(ls_xmlContentPtr);
xmlFree(ls_xmlContentPtr);
if ((p = strstr(pformatEncDec->decoder, 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",
fileName, xmlGetLineNo(cur3), TRACK_PLACEHOLDER);
config_error++;
continue;
}
}
if ((p = strstr(pformatEncDec->decoder, METADATA_PLACEHOLDER)) != NULL) {
p += strlen(METADATA_PLACEHOLDER);
if ((p = strstr(p, METADATA_PLACEHOLDER)) != NULL) {
printf("%s[%ld]: Error: Multiple `%s' placeholders in decoder command\n",
fileName, xmlGetLineNo(cur3), METADATA_PLACEHOLDER);
config_error++;
continue;
}
if ((ret = checkDecoderLine(pformatEncDec->decoder,
fileName, xmlGetLineNo(cur3)))
> 0) {
config_error += ret;
continue;
}
}
}
@ -575,24 +513,17 @@ parseConfig(const char *fileName)
continue;
}
if (cur3->xmlChildrenNode != NULL) {
unsigned int ret;
ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
pformatEncDec->encoder = xstrdup(ls_xmlContentPtr);
xmlFree(ls_xmlContentPtr);
if ((p = strstr(pformatEncDec->encoder, TRACK_PLACEHOLDER)) != NULL) {
printf("%s[%ld]: Error: `%s' placeholder not allowed in encoder command\n",
fileName, xmlGetLineNo(cur3), TRACK_PLACEHOLDER);
config_error++;
if ((ret = checkEncoderLine(pformatEncDec->encoder,
fileName, xmlGetLineNo(cur3)))
> 0) {
config_error += ret;
continue;
}
if ((p = strstr(pformatEncDec->encoder, METADATA_PLACEHOLDER)) != NULL) {
p += strlen(METADATA_PLACEHOLDER);
if ((p = strstr(p, METADATA_PLACEHOLDER)) != NULL) {
printf("%s[%ld]: Error: Multiple `%s' placeholders in encoder command\n",
fileName, xmlGetLineNo(cur3), METADATA_PLACEHOLDER);
config_error++;
continue;
}
}
}
}
}
@ -614,3 +545,139 @@ parseConfig(const char *fileName)
return (0);
}
void
freeConfig(EZCONFIG *cfg)
{
unsigned int i;
if (cfg == NULL)
return;
if (cfg->URL != NULL)
xfree(cfg->URL);
if (cfg->password != NULL)
xfree(cfg->password);
if (cfg->format != NULL)
xfree(cfg->format);
if (cfg->fileName != NULL)
xfree(cfg->fileName);
if (cfg->metadataProgram != NULL)
xfree(cfg->metadataProgram);
if (cfg->serverName != NULL)
xfree(cfg->serverName);
if (cfg->serverURL != NULL)
xfree(cfg->serverURL);
if (cfg->serverGenre != NULL)
xfree(cfg->serverGenre);
if (cfg->serverDescription != NULL)
xfree(cfg->serverDescription);
if (cfg->serverBitrate != NULL)
xfree(cfg->serverBitrate);
if (cfg->serverChannels != NULL)
xfree(cfg->serverChannels);
if (cfg->serverSamplerate != NULL)
xfree(cfg->serverSamplerate);
if (cfg->serverQuality != NULL)
xfree(cfg->serverQuality);
if (cfg->encoderDecoders != NULL) {
for (i = 0; i < MAX_FORMAT_ENCDEC; i++) {
if (cfg->encoderDecoders[i] != NULL) {
if (cfg->encoderDecoders[i]->format != NULL)
xfree(cfg->encoderDecoders[i]->format);
if (cfg->encoderDecoders[i]->match != NULL)
xfree(cfg->encoderDecoders[i]->match);
if (cfg->encoderDecoders[i]->encoder != NULL)
xfree(cfg->encoderDecoders[i]->encoder);
if (cfg->encoderDecoders[i]->decoder != NULL)
xfree(cfg->encoderDecoders[i]->decoder);
xfree(cfg->encoderDecoders[i]);
}
}
}
memset(cfg, 0, sizeof(EZCONFIG));
}
unsigned int
checkDecoderLine(const char *str, const char *file, long line)
{
unsigned int errors;
char *p;
errors = 0;
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++;
}
}
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
p += strlen(METADATA_PLACEHOLDER);
if ((p = strstr(p, METADATA_PLACEHOLDER)) != NULL) {
printf("%s[%ld]: Error: Multiple `%s' placeholders in decoder command\n",
file, line, METADATA_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 decoder command\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 decoder command\n",
file, line, TITLE_PLACEHOLDER);
errors++;
}
}
return (errors);
}
unsigned int
checkEncoderLine(const char *str, const char *file, long line)
{
unsigned int errors;
char *p;
errors = 0;
if ((p = strstr(str, TRACK_PLACEHOLDER)) != NULL) {
printf("%s[%ld]: Error: `%s' placeholder not allowed in encoder command\n",
file, line, TRACK_PLACEHOLDER);
errors++;
}
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
p += strlen(METADATA_PLACEHOLDER);
if ((p = strstr(p, METADATA_PLACEHOLDER)) != NULL) {
printf("%s[%ld]: Error: Multiple `%s' placeholders in encoder command\n",
file, line, METADATA_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 encoder command\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 encoder command\n",
file, line, TITLE_PLACEHOLDER);
errors++;
}
}
return (errors);
}

View File

@ -31,6 +31,8 @@
#define TRACK_PLACEHOLDER "@T@"
#define METADATA_PLACEHOLDER "@M@"
#define ARTIST_PLACEHOLDER "@a@"
#define TITLE_PLACEHOLDER "@t@"
typedef struct tag_FORMAT_ENCDEC {
char *format;

View File

@ -82,7 +82,6 @@ int vFlag;
int metadataFromProgram;
EZCONFIG *pezConfig = NULL;
static const char *blankString = "";
playlist_t *playlist = NULL;
int playlistMode = 0;
@ -110,18 +109,19 @@ typedef struct tag_ID3Tag {
char genre;
} ID3Tag;
int urlParse(const char *, char **, int *, char **);
void replaceString(const char *, char *, size_t, const char *, const char *);
char * buildCommandString(const char *, const char *, const char *);
char * processMetadata(shout_t *, const char *);
FILE * openResource(shout_t *, const char *, int *, char **, int *);
int reconnectServer(shout_t *, int);
int sendStream(shout_t *, FILE *, const char *, int, void *);
int streamFile(shout_t *, const char *);
int streamPlaylist(shout_t *, const char *);
char * getProgname(const char *);
void usage(void);
void usageHelp(void);
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 *);
metadata_t * getMetadata(const char *);
int setMetadata(shout_t *, metadata_t *, char **);
FILE * openResource(shout_t *, const char *, int *, char **, int *);
int reconnectServer(shout_t *, int);
int sendStream(shout_t *, FILE *, const char *, int, void *);
int streamFile(shout_t *, const char *);
int streamPlaylist(shout_t *, const char *);
char * getProgname(const char *);
void usage(void);
void usageHelp(void);
#ifdef HAVE_SIGNALS
void sig_handler(int);
@ -225,7 +225,7 @@ replaceString(const char *source, char *dest, size_t size,
char *
buildCommandString(const char *extension, const char *fileName,
const char *metadata)
metadata_t *mdata)
{
char *commandString = NULL;
size_t commandStringLen = 0;
@ -248,10 +248,10 @@ buildCommandString(const char *extension, const char *fileName,
replaceString(decoder, newDecoder, newDecoderLen, TRACK_PLACEHOLDER,
fileName);
if (strstr(decoder, METADATA_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newDecoder) + strlen(metadata) + 1;
size_t tmpLen = strlen(newDecoder) + strlen(metadata_get_string(mdata)) + 1;
char *tmpStr = xcalloc(1, tmpLen);
replaceString(newDecoder, tmpStr, tmpLen, METADATA_PLACEHOLDER,
metadata);
metadata_get_string(mdata));
xfree(newDecoder);
newDecoder = tmpStr;
}
@ -272,10 +272,10 @@ buildCommandString(const char *extension, const char *fileName,
return (commandString);
}
newEncoderLen = strlen(encoder) + strlen(metadata) + 1;
newEncoderLen = strlen(encoder) + strlen(metadata_get_string(mdata)) + 1;
newEncoder = xcalloc(1, newEncoderLen);
replaceString(encoder, newEncoder, newEncoderLen, METADATA_PLACEHOLDER,
metadata);
metadata_get_string(mdata));
commandStringLen = strlen(newDecoder) + strlen(" | ") +
strlen(newEncoder) + 1;
@ -291,21 +291,18 @@ buildCommandString(const char *extension, const char *fileName,
return (commandString);
}
char *
processMetadata(shout_t *shout, const char *fileName)
metadata_t *
getMetadata(const char *fileName)
{
char *songInfo = NULL;
shout_metadata_t *shout_mdata = NULL;
metadata_t *mdata = NULL;
metadata_t *mdata;
if (metadataFromProgram) {
if ((mdata = metadata_program(fileName)) == NULL)
return (NULL);
if (!metadata_program_update(mdata, METADATA_STRING)) {
if (!metadata_program_update(mdata, METADATA_ALL)) {
metadata_free(&mdata);
songInfo = xstrdup(blankString);
return (songInfo);
return (NULL);
}
} else {
if ((mdata = metadata_file(fileName)) == NULL)
@ -313,40 +310,78 @@ processMetadata(shout_t *shout, const char *fileName)
if (!metadata_file_update(mdata)) {
metadata_free(&mdata);
songInfo = xstrdup(blankString);
return (songInfo);
return (NULL);
}
}
songInfo = xstrdup(metadata_get_string(mdata));
metadata_free(&mdata);
return (mdata);
}
int
setMetadata(shout_t *shout, metadata_t *mdata, char **mdata_copy)
{
shout_metadata_t *shout_mdata = NULL;
char *songInfo;
int ret = SHOUTERR_SUCCESS;
if (shout == NULL) {
printf("%s: setMetadata(): Internal error: NULL shout_t\n",
__progname);
abort();
}
if (mdata == NULL)
return 1;
if ((shout_mdata = shout_metadata_new()) == NULL) {
printf("%s: shout_metadata_new(): %s\n", __progname,
strerror(ENOMEM));
exit(1);
}
shout_metadata_add(shout_mdata, "song", songInfo);
shout_set_metadata(shout, shout_mdata);
shout_metadata_free(shout_mdata);
return (songInfo);
if (metadata_get_artist(mdata) == NULL && metadata_get_title(mdata) == NULL)
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 */
printf("%s: shout_metadata_add(): %s\n", __progname,
strerror(ENOMEM));
exit(1);
}
if ((ret = shout_set_metadata(shout, shout_mdata)) != SHOUTERR_SUCCESS)
printf("%s: shout_set_metadata(): %s\n",
__progname, shout_get_error(shout));
shout_metadata_free(shout_mdata);
if (ret == SHOUTERR_SUCCESS &&
mdata_copy != NULL && *mdata_copy == NULL)
*mdata_copy = xstrdup(songInfo);
xfree(songInfo);
return (ret);
}
FILE *
openResource(shout_t *shout, const char *fileName, int *popenFlag,
char **metaCopy, int *isStdin)
{
FILE *filep = NULL;
char extension[25];
char *p = NULL;
char *pMetadata = NULL;
char *pCommandString = NULL;
FILE *filep = NULL;
char extension[25];
char *p = NULL;
char *pCommandString = NULL;
metadata_t *mdata;
if (strcmp(fileName, "stdin") == 0) {
if (metadataFromProgram &&
processMetadata(shout, pezConfig->metadataProgram) == NULL)
return (filep);
if (metadataFromProgram) {
if ((mdata = getMetadata(pezConfig->metadataProgram)) == NULL)
return (NULL);
if (setMetadata(shout, mdata, metaCopy) != SHOUTERR_SUCCESS) {
metadata_free(&mdata);
return (NULL);
}
metadata_free(&mdata);
}
if (vFlag)
printf("%s: Reading from standard input\n",
@ -359,6 +394,7 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
filep = stdin;
return (filep);
}
if (isStdin != NULL)
*isStdin = 0;
@ -375,20 +411,22 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
return (filep);
}
if (metadataFromProgram)
pMetadata = processMetadata(shout, pezConfig->metadataProgram);
else
pMetadata = processMetadata(shout, fileName);
if (pMetadata == NULL)
return (filep);
if (metadataFromProgram) {
if ((mdata = getMetadata(pezConfig->metadataProgram)) == NULL)
return (NULL);
} else {
if ((mdata = getMetadata(fileName)) == NULL)
return (NULL);
}
if (metaCopy != NULL)
*metaCopy = xstrdup(pMetadata);
*metaCopy = metadata_assemble_string(mdata);
*popenFlag = 0;
if (pezConfig->reencode) {
int stderr_fd = dup(fileno(stderr));
pCommandString = buildCommandString(extension, fileName, pMetadata);
pCommandString = buildCommandString(extension, fileName, mdata);
metadata_free(&mdata);
if (vFlag > 1)
printf("%s: Running command `%s`\n", __progname,
pCommandString);
@ -428,11 +466,10 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
if (qFlag)
dup2(stderr_fd, fileno(stderr));
xfree(pMetadata);
return (filep);
}
xfree(pMetadata);
metadata_free(&mdata);
if ((filep = fopen(fileName, "rb")) == NULL)
printf("%s: %s: %s\n", __progname, fileName,
@ -662,15 +699,23 @@ streamFile(shout_t *shout, const char *fileName)
if (ret == STREAM_UPDMDATA || queryMetadata) {
queryMetadata = 0;
if (metadataFromProgram) {
char *mdataStr;
char *mdataStr = NULL;
metadata_t *mdata;
if (vFlag > 1)
printf("%s: Querying '%s' for fresh metadata\n",
__progname, pezConfig->metadataProgram);
if ((mdataStr = processMetadata(shout, pezConfig->metadataProgram)) == NULL) {
if ((mdata = getMetadata(pezConfig->metadataProgram)) == NULL) {
retval = 0;
ret = STREAM_DONE;
continue;
}
if (setMetadata(shout, mdata, &mdataStr) != SHOUTERR_SUCCESS) {
retval = 0;
ret = STREAM_DONE;
continue;
}
metadata_free(&mdata);
printf("%s: New metadata: ``%s''\n",
__progname, mdataStr);
xfree(mdataStr);

View File

@ -44,6 +44,7 @@
#include "util.h"
extern char *__progname;
extern int vFlag;
struct metadata {
char *filename;
@ -298,34 +299,14 @@ metadata_get_name(const char *file)
void
metadata_process_md(metadata_t *md)
{
size_t siz = 0;
if (md == NULL) {
printf("%s: metadata_process_md(): Internal error: Bad arguments\n",
__progname);
abort();
}
if (md->string != NULL)
return;
if (md->artist != NULL)
siz += strlen(md->artist);
if (md->title != NULL) {
if (siz > 0)
siz += strlen(" - ");
siz += strlen(md->title);
}
siz++;
md->string = xcalloc(1, siz);
if (md->artist != NULL)
strlcpy(md->string, md->artist, siz);
if (md->title != NULL) {
if (md->artist != NULL)
strlcat(md->string, " - ", siz);
strlcat(md->string, md->title, siz);
}
if (md->string == NULL)
md->string = metadata_assemble_string(md);
}
metadata_t *
@ -467,6 +448,8 @@ metadata_program_update(metadata_t *md, enum metadata_request md_req)
!metadata_program_update(md, METADATA_ARTIST) ||
!metadata_program_update(md, METADATA_TITLE))
return (0);
else
return (1);
break;
case METADATA_STRING:
strlcpy(command, md->filename, sizeof(command));
@ -491,6 +474,9 @@ metadata_program_update(metadata_t *md, enum metadata_request md_req)
fflush(NULL);
errno = 0;
if (vFlag > 1)
printf("%s: Running command `%s`\n", __progname,
command);
if ((filep = popen(command, "r")) == NULL) {
printf("%s: playlist_run_program(): Error while executing '%s'",
__progname, command);
@ -591,3 +577,40 @@ metadata_get_title(metadata_t *md)
return (md->title);
}
char *
metadata_assemble_string(metadata_t *md)
{
size_t siz;
char *str;
if (md == NULL) {
printf("%s: metadata_assemble_string(): Internal error: Bad arguments\n",
__progname);
abort();
}
if (md->artist == NULL && md->title == NULL && md->program == 0)
return (metadata_get_name(md->filename));
siz = 0;
if (md->artist != NULL)
siz += strlen(md->artist);
if (md->title != NULL) {
if (siz > 0)
siz += strlen(" - ");
siz += strlen(md->title);
}
siz++;
str = xcalloc(1, siz);
if (md->artist != NULL)
strlcpy(str, md->artist, siz);
if (md->title != NULL) {
if (md->artist != NULL)
strlcat(str, " - ", siz);
strlcat(str, md->title, siz);
}
return (str);
}

View File

@ -92,4 +92,11 @@ const char * metadata_get_artist(metadata_t *);
*/
const char * metadata_get_title(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.
*/
char * metadata_assemble_string(metadata_t *);
#endif /* __METADATA_H__ */