.heading{fontFamily:Arial;fontWeight:bold;color:#C73105;fontSize:12pt;}
.logo{fontFamily:Arial;fontWeight:bold;color:navy;fontSize:10pt;}
.mainTitle{fontFamily:Arial;fontWeight:normal;color:grey;fontSize:9pt;}
.mainTitleBold{fontFamily:Arial;fontWeight:bold;color:navy;fontSize:11pt;}
Ready...');
}
private function PageLoaded():void {
/* This starts the timers that drive the VU meter and the auto-reconnect process */
var myTimer:Timer = new Timer(10, 0);
myTimer.addEventListener("timer", onTimer);
myTimer.start();
var myTicker:Timer = new Timer(3000, 0);
myTicker.addEventListener("timer", onTicker);
myTicker.start();
if(Application.application.parameters.autoStart) {
// if the script is invoked with ?autoStart=1, it will start playback automatically
var myStarter:Timer = new Timer(750, 1);
myStarter.addEventListener("timer", onStarter);
myStarter.start();
}
metadataLoader = new URLLoader;
metadataLoader.addEventListener(Event.COMPLETE, onCompleteMetadata);
}
private function onStarter(event:TimerEvent):void {
onPlayEvent("playback");
}
private function onTimer(event:TimerEvent):void {
if(sc) {
vuMeter.setProgress(sc.leftPeak * 100, 100);
bufferMeter.setProgress(bufferAvg, 2000);
if(s.isBuffering) {
buffering = true;
debugOut('Buffering...');
} else if(buffering) {
buffering = false;
debugOut('Playing...');
}
/* if(sc.leftPeak > 0.75)
vuMeter.barColor = 0xFF0000;
else
vuMeter.barColor = 0x00FF00; */
}
}
private function onTicker(event:TimerEvent):void {
// if we are still playing and our link is dead
// instruct it to rise again
if(playing && retrying) {
retries++;
debugOut('Retrying... (' + retries + ')');
// doPlay();
}
// this fetches metadata from a php script on the server that parses out the current
// song from the icecast status page
metadataLoader.load(new URLRequest("http://www.wshr.org/metadata.php"));
}
public function onCompleteMetadata(e:Event):void
{
var x:XML = new XML(metadataLoader.data);
id3Display.htmlText = '' + x.song + '';
}
public function doPlay():void
{
// this function actually starts playback - hopefully
var url:URLRequest = new URLRequest("http://icecast.sheer.us:8000/wshr");
// debugOut('doplay');
if(sc)
sc.stop(); // stop any playback that might have already been happening
if(s) // close any previous sound channel that might have been open
try {
s.close();
} catch (e:Object) {
Alert(e);
}
s = new Sound(null,new SoundLoaderContext(7500,true)); // create a new sound, encourage buffering
s.addEventListener(Event.OPEN,onOpen);
s.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
s.addEventListener(Event.COMPLETE,onComplete);
s.addEventListener(Event.ID3, onID3); // this will never fire ;-(
s.addEventListener(ProgressEvent.PROGRESS, onProgress);
s.load(url); // load the stream
sc = s.play(); // start playback
}
public function doSkip():void
{
// this calls a php script that then calls *another* php script on the encoder machine
// which sends SIGUSR2 to ices. It's a total hack.
var u:URLLoader = new URLLoader(new URLRequest('http://www.wshr.org/skip.php'));
}
public function onID3(e:Event):void
{
// this never happens because IceCast apparently strips out ID3 information
// so we have a hackish metadata system, see above
debugOut('onID3');
id3Display.htmlText = '' + s.id3.TIT2 + '';
}
public function onProgress(e:ProgressEvent):void
{
// this keeps a moving average filter of the amount of buffer data we have
var bc:int = e.bytesTotal - e.bytesLoaded;
bufferAvg = ((bufferAvg * 100) + bc) / 101;
/* todo: there's a bug where sometimes the player starts at half the correct
sample rate. We should be able to detect this because the buffer will grow to a unreasonable
size very quickly. We should detect this and restart the stream */
}
public function onPlayEvent(sAction:String):void {
debugOut('Playback requested');
playing = true;
retrying = false;
retries = 0;
doPlay();
btnPlay.enabled = false;
btnStop.enabled = true;
}
private function onOpen(event:Event):void
{
// this gets called when the mp3 stream has been successfully opened
if(retrying)
retrying = false;
retries = 0;
debugOut('Playing...');
// This timer invokes the stream switch when it fires
var t:Timer = new Timer(switchTime,1);
t.addEventListener("timer",onSwitch);
t.start();
}
private function onSwitch(event:Event):void
{
// open new sound channel
var url:URLRequest = new URLRequest("http://icecast.sheer.us:8000/wshr?" + Math.random());
s2 = new Sound(null,new SoundLoaderContext(7500,true));
s2.addEventListener(Event.OPEN,onSwitchOpen);
s2.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
s2.addEventListener(Event.COMPLETE,onComplete);
s2.addEventListener(Event.ID3, onID3);
s2.addEventListener(ProgressEvent.PROGRESS, onProgress);
s2.load(url);
debugOut('Switching...');
sc2 = s2.play();
}
private function onSwitchOpen(event:Event):void
{
// set timer to shut down old sound channel
var t:Timer = new Timer(250,1);
t.addEventListener("timer",onSwitchClose);
t.start();
// set timer for next switch
var t2:Timer = new Timer(switchTime,1);
t2.addEventListener("timer",onSwitch);
t2.start();
}
private function onSwitchClose(event:Event):void
{
// close and stop the old channel, then give the primary over to the new channel
// there's a potential bug here if the user presses stop in the window between, but
// statistically rather unlikely
sc.stop();
s.close();
sc = sc2;
s = s2;
// clear the 'switch' message from the status display
debugOut('Playing...');
}
private function stopSound():void {
if (btnPlay.enabled==false) {
sc.stop();
s.close();
sc = null;
s = null;
debugOut('Stopped...');
playing = false;
retrying = false;
btnStop.enabled = false;
//btnPause.enabled = false;
btnPlay.enabled = true;
//vis.visible = false;
}
}
/* private function pauseSound():void {
if (btnPause.label=="Pause") {
btnPause.label = "Resume"
} else {
btnPause.label = "Pause"
}
//mp3Stream.togglePause();
} */
private function catchAll(event:Object):void {
if (event.type == "netStatus") {
debugOut("catchAll:code:" + event.info.code);
} else {
debugOut("catchAll:event:" + event);
}
}
public function debugOut(str:String):void {
// several different output modes
// this has turned into a inapprorpaitely-named status window
// but the other code is still here so it can be uncommented for debugging
//debugOutDisplay.text = debugOutDisplay.text + str + "\n";
//debugOutDisplay.text = str;
//debugOutDisplay.htmlText = str;
debugOutDisplay.htmlText = str + "
" + debugOutDisplay.htmlText;
}
public function onComplete(event:Object):void
{
// the stream is never supposed to go away, so if it does, we restart
retrying = true;
sc = null;
// debugOut("onComplete");
doPlay();
}
public function onIOError(event:Object):void
{
// the stream is never supposed to go away, so if it does, we restart
retrying = true;
sc = null;
// debugOut("onIOError");
doPlay();
}
]]>