[Icecast] patch for native iphone support

oddsock
Mon, 25 Aug 2008 01:48:40 -0000

Here is a patch for icecast 2.3.2 that adds support for listening to mp3 and
aac+ streams on the iphone.

A quick background on the technical aspects of the patch and why it is
needed :

With the advent of 3g on the iphone, lots of people have been jumping on the
bandwagon of providing internet radio streams that work on the iPhone.  The
biggest problem is that (without having to install an dedicated app) in
order to listen to streams on an iphone you need to use the embedded
quicktime player.  Now quicktime supports both mp3 and aac+, however it only
supports the streaming of them insomuch as if you are doing on-demand
streaming (i.e. from an apache server).  I don't know WHY they don't
support
standard HTTP-based mp3 or aac+ streams from Icecast or Shoutcast, but they
don't... At least not reliably.

So, when a quicktime embedded object is configured with an icecast stream on
the iphone, the first thing the quicktime object does is to check to see if
the stream supports the "Range" semantics.  Files served from a
webserver
will support this, however icecast (and I'm pretty sure Shoutcast as well)
do not.  The quicktime object expects RTSP (I believe) and not HTTP for live
internet streams.  Anyway, so in order to "fake out" the quicktime
object,
I've added basic support for the "Range" http request header.
This does NOT
mean that seeking within a stream will be supported, it's just a hack
honestly (and why it's not probably going to be committed) just to get the
embedded quicktime player to work.

So, essentially, the quicktime player will connect and ask for bytes 1-2 of
the stream (just a test to see if it's seekable), and as long as it gets the
proper response code (HTTP 206 Partial Content), it will happily start
streaming on a second connection.

Anyway, here is the patch, it's pretty simple, and should work with aac+
although I've not tested it with that.  It will NOT work with ogg vorbis,
but then again, ogg vorbis isn't supported on the quicktime embedable object
on the iPhone.

Enjoy!

Begin Patch
--------------------
Index: src/format_mp3.c
==================================================================---
src/format_mp3.c    (revision 15198)
+++ src/format_mp3.c    (working copy)
@@ -639,6 +639,9 @@
     char *ptr = client->refbuf->data + client->refbuf->len - 2;
     int bytes;
     const char *useragent;
+    char *range;
+    int rangenumber;
+    int rangenumber2;

     if (client_mp3 == NULL)
         return -1;
@@ -657,7 +660,44 @@
         remaining -= bytes;
         ptr += bytes;
     }
+    range = httpp_getvar (client->parser, "range");

+    if (range != NULL) {
+        int ret = 0;
+        int rangeproblem = 0;
+        ret = sscanf(range, "bytes=%d-%d", &rangenumber,
&rangenumber2);
+        if (ret != 2) {
+            rangeproblem = 1;
+        }
+        if (rangenumber < 0) {
+            rangeproblem = 1;
+        }
+        if (!rangeproblem) {
+            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;
+                ptr += bytes;
+            }
+            bytes = snprintf (ptr, remaining, "Content-Range: bytes
%d-%d/221183499\r\n",
+                                               rangenumber, rangenumber2);
+            if (bytes > 0)
+            {
+                remaining -= bytes;
+                ptr += bytes;
+            }
+        }
+    }
+
     client->format_data = client_mp3;
     client->free_client_data = free_mp3_client_data;
     metadata = httpp_getvar(client->parser, "icy-metadata");
Index: src/format.c
==================================================================---
src/format.c    (revision 15198)
+++ src/format.c    (working copy)
@@ -279,13 +279,22 @@
     int bitrate_filtered = 0;
     avl_node *node;
     ice_config_t *config;
+    char *range;

     remaining = client->refbuf->len;
     ptr = client->refbuf->data;
     client->respcode = 200;

-    bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n"
+    range = httpp_getvar (client->parser, "range");
+
+    if (range) {
+        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;
-----------------------
End Patch
Ed
-------------- next part --------------
An HTML attachment was scrubbed...