[PATCH 01/31] Hack to support IPhone streaming

Niv Sardi <[email protected]>
Newsgroups gmane.comp.audio.icecast.devel
Message-ID <[email protected]>
Iphone (CoreMedia) requires that we insert a Range header,
create a fake one on the fly !

Signed-off-by: Niv Sardi <[email protected]>
---
 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 <[email protected], 
+ * Copyright 2000-2004, Jack Moffitt <[email protected],
  *                      Michael Smith <[email protected]>,
  *                      oddsock <[email protected]>,
  *                      Karl Heyes <[email protected]>
@@ -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 <[email protected], 
+ * Copyright 2000-2004, Jack Moffitt <[email protected],
  *                      Michael Smith <[email protected]>,
  *                      oddsock <[email protected]>,
  *                      Karl Heyes <[email protected]>
@@ -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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.