UPDATE 11/5/07 After inserting that first line of code
set_time_limit(10 * 60);
I seem to have less choppy music. It turns out my server only allowed any PHP script to run for only 60 seconds. This disconnected Safari, and initiated another request from it…causing the overlapping music problem I explained below. I haven’t had time to fully test it, but in theory setting a longer time limit would tone this problem down quite a bit. Ideally, you’d give Safari every byte it asked for, and not bail out because the script is taking too long.
The first post in a brand new blog!
I frequently listen to a certain online radio station, Cerritos All Stars. Since I’m always around the house listening to music on my iPhone, I wanted a way to listen to the station instead of just my music library. Of course I started Google searching ASAP. I found several things:
- There is no Shoutcast client for the iPhone yet
- iPhone’s Safari can play mp3 files which are located online, but not Shoutcast streams
On a Macrumors forum, some people were talking about tricking Safari into thinking that a Shoutcast stream is just a plain mp3 file on a web server. The method they tried was using PHP to fake some HTTP headers: Content-type, Content-Length. After that, just read bytes from the Shoutcast server and pass them on to Safari. This almost works. Safari brings starts up the built-in Quicktime player and seems ready to play, but instead the “play” symbol with a strikeout line through it shows up.
Further on in the forum thread, someone mentioned that Safari downloads the mp3 in chunks. This is to enable simultaneous playing and buffering. This is why the aforementioned method did not work.
- Safari first requests the script
- The script sends mp3 type headers, Safari likes them and starts up its Quicktime player
- Safari asks for bytes 0 and 1 of the mp3, to test for file-resuming capabilities
- The script sends out the same headers
- Safari thinks, “impostor!”
So after doing a little reading about HTTP responses and all that good stuff, I realized that the PHP script needed to be a little more flexible. It needed to pretend to be resuming a file transfer when Safari asked it to. So a little modifying, and bingo.
- Safari first requests the script
- The script sends mp3 type headers, Safari likes them and starts up its Quicktime player
- Safari asks for bytes 0 and 1 of the mp3, to test for file-resuming capabilities
- The script sends HTTP 206 and related headers
- The script sends two bytes of the Shoutcast stream
- Safari thinks, “sweet, gimme more!”
- Safari asks for bytes 0 - x
- The script sends more bytes of the stream
- Quicktime plays bytes of the stream
The quick and dirty code:
set_time_limit(10 * 60); //this could take a while, allowing 10 minutes. just added recently see UPDATE at the top of post
$bytes_to_send = 480000 * 130; //stream about about 2 hours of music
$headers = http_get_request_headers(); //get the HTTP request headers safari has sent
//if safari is only asking for a portion of the "mp3"
if (isset($headers['Range'])) {
$exploded_range = explode('=', $headers['Range']);
$limits = explode('-', $exploded_range[1]);
$length = ($limits[1] - $limits[0]) + 1; //the content length
$content_range = 'bytes ' . $limits[0] . '-' . $limits[1]; //the content range
//send fake HTTP headers to safari, telling it that we're sending only the portion of the "mp3" it asked for
header('HTTP/1.1 206 Partial Content');
header('Accept-Ranges: bytes');
header('Content-Length: ' . $length);
header('Content-Range: ' . $content_range . '/' . $bytes_to_send);
header('Content-type: audio/mpeg');
//open the stream to the shoutcast server, set as resource $fp
$fp = fsockopen("stream.cerritosallstars.com", "80", $errno, $errstr, 30) or die("Unable to connect to server!");
//HTTP commands that will initiate the shoutcast server sending stream data
$buf = "GET / HTTP/1.0\r\nIcy-MetaData:0\r\n\r\n";
//send HTTP commands in string $buf to stream $fp
fwrite($fp, $buf);
//get next line from stream
$buf = fgets($fp, 1024);
//get next few lines and discard them, this is only
//shoutcast data that would sound like noise if iphone played them
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
//break if EOF
if ($buf == "\r\n") {
break;
}
$bytes_sent = 0;
//while pointer is not at EOF, and not too many bytes are sent...
while (!feof($fp) AND ($bytes_sent < $length)) {
//read 1 byte of stream
$buf = fread($fp, 1);
//output byte to iphone;
echo $buf;
$bytes_sent++;
}
fclose($fp);
exit();
}
//else, it is the initial request. safari is asking for the whole "mp3", and seeing how big it is ($bytes_to_send)
else {
header('Accept-Ranges: bytes');
header('Content-Length: ' . $bytes_to_send);
header('Content-type: audio/mpeg');
echo 'blah';
exit();
}
exit();
So in the end, music played. However, this is a pretty sketchy way of doing things. Because of the way Quicktime buffers, seconds of music are not heard, and seconds of music are repeated. Know what I mean? Every request that happens at the same time will be filled with the same byte. The script can definitely get bytes from the present fine but when Safari requests bytes from the future, it still gets bytes from the present. Here is another way to view the issue.
- Safari asks for bytes 1 - 3
- Script serves bytes 1, 2, 3 and Safari plays them
- While playing byte 2, Safari asks for bytes 4 - 6
- CRAP, byte 3 will be the same as byte 4
A few seconds of repeated music are heard. I can live with this, but theres no way any final solution could have this problem.
I would also like to point out that PHP and Apache have been ported to the iPhone. There might be a way to run the script locally on the iPhone, eliminating the need for another server and extra bandwidth. And another reminder, this would only be ideal on WiFi…iPhone can’t make or receive calls while using EDGE.
If anyone has an elegant way of listening to Shoutcast on iPhone, please leave a comment!
{ 35 } Comments
this helped me out immensely! THANKS!
Conceited Software has concocted a Shoutcast client called iRadio (EDGE/WIFI; mpeg-only so far)
Yes, iRadio is fantastic. However, I still can’t choose to listen to any stream I want.
Im having trouble with this.
i get the player to start, but i dont get more then a play arrow that has a circle and a line over it
What extension do you have loaded to your php when u run this?
You need the HTTP extension to run this code
Hello, you are fantastic. I found your script an love it. Everything is fine with mp3streaming.
I try to use the script for streaming a aac stream. I’t doesn’t work.
Everyone have an idea?
Greets
Daniel
need help i get this error
Parse error: syntax error, unexpected T_IF in /home/queer/public_html/iphone.php on line 7
<?php
set_time_limit(10 * 60); //this could take a while, allowing 10 minutes. just added recently see UPDATE at the top of post
$bytes_to_send = 480000 * 130; //stream about about 2 hours of music
$headers = http_get_request_headers(); //get the HTTP request headers safari has sent
//if safari is only asking for a portion of the “mp3″
if (isset($headers['Range'])) {
$exploded_range = explode(’=', $headers['Range']);
$limits = explode(’-', $exploded_range[1]);
$length = ($limits[1] - $limits[0]) + 1; //the content length
$content_range = ‘bytes ‘ . $limits[0] . ‘-’ . $limits[1]; //the content range
//send fake HTTP headers to safari, telling it that we’re sending only the portion of the “mp3″ it asked for
header(’HTTP/1.1 206 Partial Content’);
header(’Accept-Ranges: bytes’);
header(’Content-Length: ‘ . $length);
header(’Content-Range: ‘ . $content_range . ‘/’ . $bytes_to_send);
header(’Content-type: audio/mpeg’);
//open the stream to the shoutcast server, set as resource $fp
$fp = fsockopen(”stream.cerritosallstars.com”, “80″, $errno, $errstr, 30) or die(”Unable to connect to server!”);
//HTTP commands that will initiate the shoutcast server sending stream data
$buf = “GET / HTTP/1.0\r\nIcy-MetaData:0\r\n\r\n”;
//send HTTP commands in string $buf to stream $fp
fwrite($fp, $buf);
//get next line from stream
$buf = fgets($fp, 1024);
//get next few lines and discard them, this is only
//shoutcast data that would sound like noise if iphone played them
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
$buf = fgets($fp, 1024);
//break if EOF
if ($buf == “\r\n”) {
break;
}
$bytes_sent = 0;
//while pointer is not at EOF, and not too many bytes are sent…
while (!feof($fp) AND ($bytes_sent
@Russell: Try erasing the comments in the code. If that doesn’t work, let me think about it more
@Trent, i tryed everything, am website is hosted on a linux server… I tryed the script in all my web browsers and iphone and ipod touch.
PLZ HELP
@Trent, do you have any idea? why it not working?
@Russel: I’ve been extremely busy with work and school lately… I will find time to work this out asap. My apologies
@Trent: thx
first off, I love concept of this code. However, I can’t get it to work.
are you running this on PHP4 or php5?
all of my servers are php4 and I think that may have something to do with it. with a little tweaking I was able to get it to load quicktime on my phone, but it keeps saying “error playing movie”
I got it to work!!!
I works fine with my shoutcast stream from Spacial, but my other streams through limelight won’t load. Is there some problem opening a long url with slashes in it? Other than that I can’t seem to find any reasons why it would not load.
Any ideas?
@Bill: Can you post what you did to get the code to work.
Russell, it took some hair pulling, but I believe that this is the course of events that lead to it working.
first, I built a dedicated test server, because I couldn’t get my netsol, or godaddy hosting to work.
The server is running Fedora Core 2, has XAMPP installed, and I made sure that the PECL_HTTP extensions were installed.
Next, none of my systems would recognize the function http_get_request_headers() so I changed that to apache_request_headers()
and then it worked. I also got my limelight streams to work by contacting limelight and getting the exact port, not the proxy that they gave me to stream over port 80, (in this case port 80 didn’t work)
So now all my streams are working great. I did have to tweek it a bit to get it to play for more than 10 minutes. My latest version of it will play for 14 hours.
I have had a 96k and 128k stream play great over EDGE with no buffering even while driving around.
I am not in my office right now, I will try to post a link to my tweeked code next week.
If you would like to see it in action you can hear one of my streams at …
http://www.allpetsradio.com/iphone
just click on “listen live”
I love this code!!!!
Bill, if you could, it would be great to share the source of what you’ve done.
It would help me a lot!
Thanks. :)
@Bill: Like what you have done, seem that changing http_get_request_headers() to apache_request_headers()
works fine however have some problems
1. My Ipod Touch is saying “Server is not responding”
However i know my stream is working fine, as i am listening to it at home. (Stream is in a office in the City i live north of the city)
Iam using Shoutcast
Any idea
Russel, may I ask what host you’re using?
Thanks, Tom.
I am using Cyberspace - cyberspace.net.au
General server information:
Operating system Linux
Service Status Click to View
Kernel version 2.6.23.12-ts.grh.mh.i386
Machine Type i686
Apache version 1.3.37 (Unix)
PERL version 5.8.8
Path to PERL /usr/bin/perl
Path to sendmail /usr/sbin/sendmail
Installed Perl Modules Click to View
PHP version 5.2.3
MySQL version 4.1.22-standard
cPanel Build 11.18.2-RELEASE 21594
Theme cPanel X v2.6.0
Documentation Click to View
cPanel Pro 1.0 (RC1)
Hmmmm….. I seem to be having a problem with this http://joystickradio.com/stream.php?server=joystickradio.com&port=8000
any ideas?
You have to install the pecl_http extension to your php :
for php5 :
apt-get install php5-dev (to enable pecl command)
apt-get install libcurl3 (to get curl support)
apt-get install libmagic
(perhaps some differences for different distributions)
pecl install pecl_http
cp /usr/lib/php5/20060613+lfs/http.so /usr/lib/apache2/modules
then add to your php.ini “extension=http.so”
and restart apache
This script is great. It works. I use it to stream shoutcast teluguone radio to iphone. Still not able to resolve the 1-2 second repetitions. Any ideas on how to resolve this??
I don’t have PECL_HTTP extensions so modified the script to use basic server variables
foreach($_SERVER as $key_name => $key_value)
$headers[$key_name] = $key_value ;
Once you have all the keys just use $headers['HTTP_RANGE'] and it works
thanks for the great script nakasaki and bill your allpetsradio is an inspiration for writing my radio page.
It works great! I use a Mac OS X 10.3.9 as Server (Apache/1.3.33 (Darwin) PHP/4.3.10) and the
$headers = apache_request_headers();
http://212.201.36.171/stream3000.php
Good concept, but how do you deal with the metadata embedded in the shoutcast stream? The script looks like it will just pass that to iphone and im not sure the players can handle that. What this means is every 32768 bytes of data, your stream will sound like it clicks, pops or stutters (as the metadata, raw text, is buried in the mp3 stream. Thats not so in regular files or other streaming methods). Maybe people here have noticed it and just figured it was an artifact of wireless or something. Some info on it here http://www.smackfu.com/stuff/programming/shoutcast.html
Hello guys i am realy not very good on php and i need some help to make this work, if you think you can help me please send me an email. indefixx@gmail.com
Thanks in advance.
for the script php , where you need to insert your url , try to withdraw the “http://”
just insert the dns or ip adress
thanks for the script… works beautifully. i just wish safari on iphone would let you switch tabs while running quicktime, so i could control my MPD stream thru a web UI…
I’ve implemented this code and works great! Thanks.
Only I’ve noticed about one issue:
- When you press pause, and turn off your iphone, the streaming, seems, that are storing a “buffer” under the server… later, when you turn on your iphone, the streaming continues on the same point where you have been paused.
Can some one test these issue?
Only I’ve made tests on 3G not Wi-Fi.
Thanks.
Awesome code… works like a charm… awesome job. I just had to use Bill’s fix, since I am running Apache too, and it worked!!!! :D
Thanks a ton….
Awesome stuff… Thanks for the info.
hi i try but i have this error
Fatal error: Call to undefined function http_get_request_headers() in /home/afterco/public_html/stream.php on line 4
any can help me
thanks.
Great job. Thanks your. :)
I should email u about it.
{ 25 } Trackbacks
[...] -> Streaming Shoutcast on the iPhone [...]
[...] a traditional broadcast station. However, for those who have more time to configure their service, there are ways to stream live music using QuickTime. Apparently the Tuner application in the app store will [...]
quality casino online…
t845t…
Gay Atlanta…
t1000t…
Free Online Personals China Friends…
t136t…
Gay Ballbusting…
t662t…
Free Personals Online Dating Services…
t300t…
Gay Bangkok Hotel…
t633t…
Free Personals Trial Yahoo…
t274t…
Gay Bar Directory…
t568t…
Free Phone Dating Services…
t994t…
Gay Barcelona…
t870t…
Free Porn Of Gay Guys In Jockstraps Having Sex…
t922t…
Gay Bareback Anal Sex…
t483t…
Free Single Parent Dating Personals…
t532t…
Free Singles Dating…
t872t…
Gay Bars Charleston Sc…
t916t…
Free Swingers Personals Uk…
t36t…
Free Teen Dating Chat…
t573t…
Gay Locker Room Stories Gay Stories…
t809t…
Michigan Swingers…
t336t…
Gay London Massage…
t3t…
Military Dating…
t793t…
Gay Male Naturists…
t977t…
Miss Gay…
t800t…
Post a Comment