diff --git a/src/format.c b/src/format.c index c507daab..9ffc044e 100644 --- a/src/format.c +++ b/src/format.c @@ -15,13 +15,14 @@ #include "format_vorbis.h" -format_plugin_t *format_get_plugin(format_type_t type) +format_plugin_t *format_get_plugin(format_type_t type, char *mount) { format_plugin_t *plugin; switch (type) { case FORMAT_TYPE_VORBIS: plugin = format_vorbis_get_plugin(); + if (plugin) plugin->mount = mount; break; default: plugin = NULL; diff --git a/src/format.h b/src/format.h index 24f81158..d7963d63 100644 --- a/src/format.h +++ b/src/format.h @@ -16,6 +16,9 @@ typedef struct _format_plugin_tag { format_type_t type; + /* we need to know the mount to report statistics */ + char *mount; + /* set this is the data format has a header that ** we must send before regular data */ @@ -29,7 +32,7 @@ typedef struct _format_plugin_tag void *_state; } format_plugin_t; -format_plugin_t *format_get_plugin(format_type_t type); +format_plugin_t *format_get_plugin(format_type_t type, char *mount); #endif /* __FORMAT_H__ */ diff --git a/src/format_vorbis.c b/src/format_vorbis.c index 29006f56..7e27b236 100644 --- a/src/format_vorbis.c +++ b/src/format_vorbis.c @@ -18,10 +18,15 @@ typedef struct _vstate_tag { ogg_sync_state oy; + ogg_stream_state os; + vorbis_info vi; + vorbis_comment vc; + ogg_page og; unsigned long serialno; int header; refbuf_t *headbuf[10]; + int packets; } vstate_t; void format_vorbis_free_plugin(format_plugin_t *self); @@ -58,6 +63,9 @@ void format_vorbis_free_plugin(format_plugin_t *self) /* free state memory */ ogg_sync_clear(&state->oy); + ogg_stream_clear(&state->os); + vorbis_comment_clear(&state->vc); + vorbis_info_clear(&state->vi); for (i = 0; i < 10; i++) { if (state->headbuf[i]) { @@ -76,7 +84,9 @@ refbuf_t *format_vorbis_get_buffer(format_plugin_t *self, char *data, unsigned l { char *buffer; refbuf_t *refbuf; - int i; + int i, result; + ogg_packet op; + char *tag; vstate_t *state = (vstate_t *)self->_state; if (data) { @@ -95,28 +105,67 @@ refbuf_t *format_vorbis_get_buffer(format_plugin_t *self, char *data, unsigned l if (state->serialno != ogg_page_serialno(&state->og)) { /* this is a new logical bitstream */ state->header = 0; + state->packets = 0; + + /* release old headers, stream state, vorbis data */ for (i = 0; i < 10; i++) { if (state->headbuf[i]) { refbuf_release(state->headbuf[i]); state->headbuf[i] = NULL; } } - + state->serialno = ogg_page_serialno(&state->og); + ogg_stream_init(&state->os, state->serialno); + vorbis_info_init(&state->vi); + vorbis_comment_init(&state->vc); } if (state->header >= 0) { if (ogg_page_granulepos(&state->og) == 0) { state->header++; } else { - state->header = 0; + /* we're done caching headers */ + state->header = -1; + + /* put known comments in the stats */ + tag = vorbis_comment_query(&state->vc, "TITLE", 0); + if (tag) stats_event_args(self->mount, "title", tag); + else stats_event_args(self->mount, "title", "unknown"); + tag = vorbis_comment_query(&state->vc, "ARTIST", 0); + if (tag) stats_event_args(self->mount, "artist", tag); + else stats_event_args(self->mount, "artist", "unknown"); + + /* don't need these now */ + ogg_stream_clear(&state->os); + vorbis_comment_clear(&state->vc); + vorbis_info_clear(&state->vi); } } - /* cache first three pages */ - if (state->header) { + /* cache header pages */ + if (state->header > 0) { refbuf_addref(refbuf); state->headbuf[state->header - 1] = refbuf; + + if (state->packets >= 0 && state->packets < 2) { + ogg_stream_pagein(&state->os, &state->og); + while (state->packets < 2) { + result = ogg_stream_packetout(&state->os, &op); + if (result == 0) break; /* need more data */ + if (result < 0) { + state->packets = -1; + break; + } + + state->packets++; + + if (vorbis_synthesis_headerin(&state->vi, &state->vc, &op) < 0) { + state->packets = -1; + break; + } + } + } } } diff --git a/src/source.c b/src/source.c index 87420af7..42f185da 100644 --- a/src/source.c +++ b/src/source.c @@ -41,10 +41,10 @@ source_t *source_create(connection_t *con, http_parser_t *parser, const char *mo source_t *src; src = (source_t *)malloc(sizeof(source_t)); - src->format = format_get_plugin(type); + src->mount = (char *)strdup(mount); + src->format = format_get_plugin(type, src->mount); src->con = con; src->parser = parser; - src->mount = (char *)strdup(mount); src->client_tree = avl_tree_new(_compare_clients, NULL); src->pending_tree = avl_tree_new(_compare_clients, NULL); @@ -110,6 +110,7 @@ void *source_main(void *arg) int ret, timeout; client_t *client; avl_node *client_node; + char *s; refbuf_t *refbuf, *abuf; int data_done; @@ -134,6 +135,14 @@ void *source_main(void *arg) /* start off the statistics */ stats_event(source->mount, "listeners", "0"); + if ((s = httpp_getvar(source->parser, "ice-name"))) + stats_event(source->mount, "name", s); + if ((s = httpp_getvar(source->parser, "ice-url"))) + stats_event(source->mount, "url", s); + if ((s = httpp_getvar(source->parser, "ice-bitrate"))) + stats_event(source->mount, "bitrate", s); + if ((s = httpp_getvar(source->parser, "ice-description"))) + stats_event(source->mount, "description", s); while (global.running == ICE_RUNNING) { refbuf = source->format->get_buffer(source->format, NULL, 0); diff --git a/src/stats.c b/src/stats.c index 5b33c33e..a7bc8eab 100644 --- a/src/stats.c +++ b/src/stats.c @@ -286,7 +286,10 @@ static stats_event_t *_copy_event(stats_event_t *event) else copy->source = NULL; copy->name = (char *)strdup(event->name); - copy->value = (char *)strdup(event->value); + if (event->value) + copy->value = (char *)strdup(event->value); + else + copy->value = NULL; copy->next = NULL; return copy; @@ -480,7 +483,7 @@ static int _send_event_to_client(stats_event_t *event, connection_t *con) int ret; /* send data to the client!!!! */ - ret = sock_write(con->sock, "EVENT %s %s %s\n", (event->source != NULL) ? event->source : "global", event->name, event->value); + ret = sock_write(con->sock, "EVENT %s %s %s\n", (event->source != NULL) ? event->source : "global", event->name, event->value ? event->value : "null"); return (ret == -1) ? 0 : 1; }