diff --git a/doc/icecast2_config_file.html b/doc/icecast2_config_file.html index f289bffb..bdcbff36 100644 --- a/doc/icecast2_config_file.html +++ b/doc/icecast2_config_file.html @@ -335,6 +335,7 @@ If you are relaying a Shoutcast stream, you need to specify this indicator to al <no-yp>1</no-yp> <hidden>1</hidden> <burst-size>65536</burst-size> + <mp3-metadata-interval>4096</mp3-metadata-interval> <authentication type="htpasswd"> <option name="filename" value="myauth"/> <option name="allow_duplicate_users" value="0"/> @@ -392,6 +393,13 @@ to a local relay instead This optional setting allows for providing a burst size which overrides the default burst size as defined in limits. The value is in bytes. +

mp3-metadata-interval

+
+This optional setting specifies what interval, in bytes, there is between metadata updates within +shoutcast compatible streams. This only applies to new listeners connecting on this mountpoint, +not existing listeners falling back to this mountpoint. The default is either the hardcoded +server default or the value passed from a relay. +

hidden

Enable this to prevent this mount from being shown on the xsl pages. This is mainly diff --git a/src/admin.c b/src/admin.c index 2ad36691..4305a860 100644 --- a/src/admin.c +++ b/src/admin.c @@ -34,7 +34,6 @@ #include "xslt.h" #include "format.h" -#include "format_mp3.h" #include "logging.h" #include "auth.h" @@ -920,33 +919,30 @@ static void command_shoutcast_metadata(client_t *client, source_t *source) { char *action; char *value; - mp3_state *state; DEBUG0("Got shoutcast metadata update request"); COMMAND_REQUIRE(client, "mode", action); COMMAND_REQUIRE(client, "song", value); - if (source->format->type == FORMAT_TYPE_OGG) { - client_send_400 (client, "Cannot update metadata on vorbis streams"); - return; - } - if (strcmp (action, "updinfo") != 0) { client_send_400 (client, "No such action"); return; } - state = source->format->_state; + if (source->format && source->format->set_tag) + { + source->format->set_tag (source->format, "title", value); - mp3_set_tag (source->format, "title", value); - - DEBUG2("Metadata on mountpoint %s changed to \"%s\"", - source->mount, value); - - - html_success(client, "Metadata update successful"); + DEBUG2("Metadata on mountpoint %s changed to \"%s\"", + source->mount, value); + html_success(client, "Metadata update successful"); + } + else + { + client_send_400 (client, "mountpoint will not accept URL updates"); + } } static void command_stats(client_t *client, int response) { diff --git a/src/cfgfile.c b/src/cfgfile.c index 8cf7dddc..5cfb9e4d 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -521,6 +521,7 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, /* default settings */ mount->max_listeners = -1; mount->burst_size = -1; + mount->mp3_meta_interval = -1; mount->next = NULL; do { @@ -552,6 +553,11 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, mount->max_listeners = atoi(tmp); if(tmp) xmlFree(tmp); } + else if (strcmp(node->name, "mp3-metadata-interval") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + mount->mp3_meta_interval = atoi(tmp); + if(tmp) xmlFree(tmp); + } else if (strcmp(node->name, "fallback-override") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->fallback_override = atoi(tmp); diff --git a/src/cfgfile.h b/src/cfgfile.h index 3617fba1..e87dee04 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -60,6 +60,7 @@ typedef struct _mount_proxy { int no_yp; /* Do we prevent YP on this mount */ int hidden; /* Do we list this on the xsl pages */ unsigned int source_timeout; /* source timeout in seconds */ + int mp3_meta_interval; /* outgoing per-stream metadata interval */ char *auth_type; /* Authentication type */ char *cluster_password; diff --git a/src/format.h b/src/format.h index f3bf3602..f34b91a4 100644 --- a/src/format.h +++ b/src/format.h @@ -23,6 +23,7 @@ #include "httpp/httpp.h" struct source_tag; +struct _mount_proxy; typedef enum _format_type_tag { @@ -48,6 +49,7 @@ typedef struct _format_plugin_tag struct source_tag *source, client_t *client); void (*set_tag)(struct _format_plugin_tag *plugin, char *tag, char *value); void (*free_plugin)(struct _format_plugin_tag *self); + void (*apply_settings)(client_t *client, struct _format_plugin_tag *format, struct _mount_proxy *mount); /* for internal state management */ void *_state; diff --git a/src/format_mp3.c b/src/format_mp3.c index 53082992..96a5bdf1 100644 --- a/src/format_mp3.c +++ b/src/format_mp3.c @@ -63,6 +63,8 @@ static int format_mp3_write_buf_to_client(format_plugin_t *self, client_t *clien static void format_mp3_send_headers(format_plugin_t *self, source_t *source, client_t *client); static void write_mp3_to_file (struct source_tag *source, refbuf_t *refbuf); +static void mp3_set_tag (format_plugin_t *plugin, char *tag, char *value); +static void format_mp3_apply_settings(client_t *client, format_plugin_t *format, mount_proxy *mount); typedef struct { @@ -90,6 +92,7 @@ int format_mp3_get_plugin (source_t *source) plugin->client_send_headers = format_mp3_send_headers; plugin->free_plugin = format_mp3_free_plugin; plugin->set_tag = mp3_set_tag; + plugin->apply_settings = format_mp3_apply_settings; plugin->contenttype = httpp_getvar (source->parser, "content-type"); if (plugin->contenttype == NULL) { @@ -115,6 +118,7 @@ int format_mp3_get_plugin (source_t *source) { state->offset = 0; plugin->get_buffer = mp3_get_filter_meta; + state->interval = state->inline_metadata_interval; } } source->format = plugin; @@ -124,7 +128,7 @@ int format_mp3_get_plugin (source_t *source) } -void mp3_set_tag (format_plugin_t *plugin, char *tag, char *value) +static void mp3_set_tag (format_plugin_t *plugin, char *tag, char *value) { mp3_state *source_mp3 = plugin->_state; unsigned int len; @@ -193,10 +197,31 @@ static void filter_shoutcast_metadata (source_t *source, char *metadata, unsigne } +static void format_mp3_apply_settings (client_t *client, format_plugin_t *format, mount_proxy *mount) +{ + mp3_state *source_mp3 = format->_state; + + if (mount->mp3_meta_interval <= 0) + { + char *metadata = httpp_getvar (client->parser, "icy-metaint"); + source_mp3->interval = -1; + if (metadata) + { + int interval = atoi (metadata); + if (interval > 0) + source_mp3->interval = interval; + } + } + else + source_mp3->interval = mount->mp3_meta_interval; + DEBUG2 ("mp3 interval %d, %d", mount->mp3_meta_interval, source_mp3->interval); +} + + /* called from the source thread when the metadata has been updated. * The artist title are checked and made ready for clients to send */ -void mp3_set_title (source_t *source) +static void mp3_set_title (source_t *source) { const char meta[] = "StreamTitle='"; int size; diff --git a/src/format_mp3.h b/src/format_mp3.h index cb028f9c..7f6d73d3 100644 --- a/src/format_mp3.h +++ b/src/format_mp3.h @@ -36,6 +36,5 @@ typedef struct { } mp3_state; int format_mp3_get_plugin(struct source_tag *src); -void mp3_set_tag (format_plugin_t *plugin, char *tag, char *value); #endif /* __FORMAT_MP3_H__ */ diff --git a/src/source.c b/src/source.c index 61b00fbc..6ce65516 100644 --- a/src/source.c +++ b/src/source.c @@ -912,6 +912,8 @@ void source_apply_mount (source_t *source, mount_proxy *mountinfo) if (mountinfo->burst_size > -1) source->burst_size = mountinfo->burst_size; DEBUG1 ("amount to burst on client connect set to %u", source->burst_size); + if (source->format && source->format->apply_settings) + source->format->apply_settings (source->client, source->format, mountinfo); }