<div dir="ltr">Here is a patch for icecast 2.3.2 that adds support for listening to mp3 and aac+ streams on the iphone.<br><br>A quick background on the technical aspects of the patch and why it is needed :<br><br>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. <br>
<br>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.<br>
<br>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.<br>
<br>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.<br>
<br>Enjoy!<br><br>Begin Patch<br>--------------------<br>Index: src/format_mp3.c<br>===================================================================<br>--- src/format_mp3.c (revision 15198)<br>+++ src/format_mp3.c (working copy)<br>
@@ -639,6 +639,9 @@<br> char *ptr = client->refbuf->data + client->refbuf->len - 2;<br> int bytes;<br> const char *useragent;<br>+ char *range;<br>+ int rangenumber;<br>+ int rangenumber2;<br>
<br> if (client_mp3 == NULL)<br> return -1;<br>@@ -657,7 +660,44 @@<br> remaining -= bytes;<br> ptr += bytes;<br> }<br>+ range = httpp_getvar (client->parser, "range");<br><br>
+ if (range != NULL) {<br>+ int ret = 0;<br>+ int rangeproblem = 0;<br>+ ret = sscanf(range, "bytes=%d-%d", &rangenumber, &rangenumber2);<br>+ if (ret != 2) {<br>+ rangeproblem = 1;<br>
+ }<br>+ if (rangenumber < 0) {<br>+ rangeproblem = 1;<br>+ }<br>+ if (!rangeproblem) {<br>+ char currenttime[50];<br>+ time_t now;<br>+ int strflen;<br>
+ struct tm result;<br>+ time(&now);<br>+ strflen = strftime(currenttime, 50, "%a, %d-%b-%Y %X GMT",<br>+ gmtime_r(&now, &result));<br>+ client->respcode = 206;<br>
+<br>+ bytes = snprintf (ptr, remaining, "Date: %s\r\n", currenttime);<br>+ if (bytes > 0)<br>+ {<br>+ remaining -= bytes;<br>+ ptr += bytes;<br>
+ }<br>+ bytes = snprintf (ptr, remaining, "Content-Range: bytes %d-%d/221183499\r\n",<br>+ rangenumber, rangenumber2);<br>+ if (bytes > 0)<br>
+ {<br>+ remaining -= bytes;<br>+ ptr += bytes;<br>+ }<br>+ }<br>+ }<br>+<br> client->format_data = client_mp3;<br> client->free_client_data = free_mp3_client_data;<br>
metadata = httpp_getvar(client->parser, "icy-metadata");<br>Index: src/format.c<br>===================================================================<br>--- src/format.c (revision 15198)<br>+++ src/format.c (working copy)<br>
@@ -279,13 +279,22 @@<br> int bitrate_filtered = 0;<br> avl_node *node;<br> ice_config_t *config;<br>+ char *range;<br><br> remaining = client->refbuf->len;<br> ptr = client->refbuf->data;<br>
client->respcode = 200;<br><br>- bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n"<br>+ range = httpp_getvar (client->parser, "range");<br>+<br>+ if (range) {<br>+ bytes = snprintf (ptr, remaining, "HTTP/1.1 206 Partial Content\r\n"<br>
+ "Content-Type: %s\r\n", source->format->contenttype);<br>+ }<br>+ else {<br>+ bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n"<br> "Content-Type: %s\r\n", source->format->contenttype);<br>
+ }<br><br> remaining -= bytes;<br> ptr += bytes;<br>-----------------------<br>End Patch<br>Ed<br></div>