[Icecast-dev] [PATCH 01/31] Hack to support IPhone streaming
Niv Sardi
nsardi at smartjog.com
Fri Jul 30 07:54:23 PDT 2010
Iphone (CoreMedia) requires that we insert a Range header,
create a fake one on the fly !
Signed-off-by: Niv Sardi <nsardi at smartjog.com>
---
src/format.c | 26 ++++++++++++++++++------
src/format_mp3.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 70 insertions(+), 12 deletions(-)
diff --git a/src/format.c b/src/format.c
index 415391c..369dfbd 100644
--- a/src/format.c
+++ b/src/format.c
@@ -3,7 +3,7 @@
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
- * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
* Michael Smith <msmith at xiph.org>,
* oddsock <oddsock at xiph.org>,
* Karl Heyes <karl at xiph.org>
@@ -85,7 +85,7 @@ int format_get_plugin(format_type_t type, source_t *source)
break;
}
if (ret < 0)
- stats_event (source->mount, "content-type",
+ stats_event (source->mount, "content-type",
source->format->contenttype);
return ret;
@@ -93,7 +93,7 @@ int format_get_plugin(format_type_t type, source_t *source)
/* clients need to be start from somewhere in the queue so we will look for
- * a refbuf which has been previously marked as a sync point.
+ * a refbuf which has been previously marked as a sync point.
*/
static void find_client_start (source_t *source, client_t *client)
{
@@ -248,7 +248,7 @@ int format_generic_write_to_client (client_t *client)
/* This is the commonly used for source streams, here we just progress to
- * the next buffer in the queue if there is no more left to be written from
+ * the next buffer in the queue if there is no more left to be written from
* the existing buffer.
*/
int format_advance_queue (source_t *source, client_t *client)
@@ -280,12 +280,24 @@ static int format_prepare_headers (source_t *source, client_t *client)
avl_node *node;
ice_config_t *config;
+ /* Partial hack, check for range and user agent in this function */
+ const char *useragent;
+ const char *range;
+ useragent = httpp_getvar (client->parser, "user-agent");
+ range = httpp_getvar (client->parser, "range");
+
remaining = client->refbuf->len;
ptr = client->refbuf->data;
client->respcode = 200;
- bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n"
- "Content-Type: %s\r\n", source->format->contenttype);
+
+ if (range && useragent && strstr(useragent, "CoreMedia")) {
+ bytes = snprintf (ptr, remaining, "HTTP/1.1 206 Partial Content\r\n"
+ "Content-Type: %s\r\n", source->format->contenttype);
+ } else {
+ bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n"
+ "Content-Type: %s\r\n", source->format->contenttype);
+ }
remaining -= bytes;
ptr += bytes;
@@ -307,7 +319,7 @@ static int format_prepare_headers (source_t *source, client_t *client)
if (bitrate_filtered == 0)
brfield = strstr(var->value, "bitrate=");
if (brfield && sscanf (brfield, "bitrate=%u", &bitrate))
- {
+ {
bytes = snprintf (ptr, remaining, "icy-br:%u\r\n", bitrate);
next = 0;
bitrate_filtered = 1;
diff --git a/src/format_mp3.c b/src/format_mp3.c
index 7f08e15..2d62314 100644
--- a/src/format_mp3.c
+++ b/src/format_mp3.c
@@ -4,7 +4,7 @@
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
- * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
* Michael Smith <msmith at xiph.org>,
* oddsock <oddsock at xiph.org>,
* Karl Heyes <karl at xiph.org>
@@ -461,7 +461,7 @@ static void format_mp3_free_plugin(format_plugin_t *self)
/* This does the actual reading, making sure the read data is packaged in
* blocks of 1400 bytes (near the common MTU size). This is because many
- * incoming streams come in small packets which could waste a lot of
+ * incoming streams come in small packets which could waste a lot of
* bandwidth with many listeners due to headers and such like.
*/
static int complete_read (source_t *source)
@@ -476,7 +476,7 @@ static int complete_read (source_t *source)
if (source_mp3->read_data == NULL)
{
- source_mp3->read_data = refbuf_new (REFBUF_SIZE);
+ source_mp3->read_data = refbuf_new (REFBUF_SIZE);
source_mp3->read_count = 0;
}
buf = source_mp3->read_data->data + source_mp3->read_count;
@@ -603,7 +603,7 @@ static refbuf_t *mp3_get_filter_meta (source_t *source)
source_mp3->build_metadata_offset += bytes;
break;
}
- /* copy all bytes except the last one, that way we
+ /* copy all bytes except the last one, that way we
* know a null byte terminates the message */
memcpy (source_mp3->build_metadata + source_mp3->build_metadata_offset,
src, metadata_remaining-1);
@@ -654,6 +654,42 @@ static refbuf_t *mp3_get_filter_meta (source_t *source)
return refbuf;
}
+inline int format_mp3_insert_coremedia_header(client_t *client, char *ptr, int remaining) {
+ int range[2];
+ char *rangestr;
+ int read = 0;
+ int bytes;
+ rangestr = httpp_getvar(client->parser, "range");
+
+ if (rangestr != NULL) {
+ if (sscanf(rangestr, "bytes=%d-%d", &range[0], &range[1]) != 2)
+ return 0;
+ if (range[0] < 0)
+ return 0;
+
+ char currenttime[50];
+ time_t now;
+ int strflen;
+ struct tm result;
+ time(&now);
+ strflen = strftime(currenttime, 50, "%a, %d-%b-%Y %X GMT",
+ gmtime_r(&now, &result));
+ client->respcode = 206;
+ bytes = snprintf(ptr, remaining, "Date: %s\r\n", currenttime);
+ if (bytes > 0){
+ remaining -= bytes;
+ read += bytes;
+ }
+ bytes = snprintf(ptr + read, remaining, "Content-Range: bytes %d-%d/221183499\r\n",
+ range[0], range[1]);
+ if (bytes > 0) {
+ remaining -= bytes;
+ read += bytes;
+ }
+ }
+
+ return read;
+}
static int format_mp3_create_client_data(source_t *source, client_t *client)
{
@@ -681,7 +717,17 @@ static int format_mp3_create_client_data(source_t *source, client_t *client)
/* avoid browser caching, reported via forum */
bytes = snprintf (ptr, remaining, "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n");
remaining -= bytes;
- ptr += bytes;
+ ptr += bytes;
+ }
+
+ /* hack for iPhone OS or Simulator with CoreMedia. checks user agent then adds iPhone-specific headers */
+ if (useragent && strstr(useragent, "CoreMedia"))
+ {
+ bytes = format_mp3_insert_coremedia_header(client, ptr, remaining);
+ if (bytes) {
+ ptr += bytes;
+ remaining -= bytes;
+ }
}
client->format_data = client_mp3;
--
1.7.1
More information about the Icecast-dev
mailing list