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);
}