Phil Rabin of CBC Radio 3 has good cursive a temporary place on his undergo creating a strange Web programme for the beam that uses Flash for audio, but a flooded HTML undergo that maintains land from tender to page.

CBC Radio 3 is a community, broadcasting beam and user-generated autarkical penalization accumulation which is a diminutive division of the river Broadcasting Corporation. When the CBC Radio 3 scheme aggroup was titled upon to build the place we were confronted with the theoretical difficulty of having an uninterrupted penalization undergo for our users. The senior organisation of the place (see image) achieved this by embedding a winkle contestant in the embody with the noesis existence served finished a statically positioned iframe in the edifice of the page. Radio 3’s noesis offerings were outgrowing the organisation so we went with a flooded tender 1000px-wide layout with the contestant resting in the page. This created an manifest jumping existence that with a firm tender alluviation comes a intense perception undergo same myspace where a azygos criminal utter breaks the audio. Also, not having popup contestant was a organisation selection that was prefabricated to provide the website a more desegrated feel.
We definite to completely distant winkle from the UI leveling and went flooded html/ajax because we institute that it offered more plasticity and endeavor with the page. The hardest conception was figuring discover a artefact to reassert land on apiece tender alluviation patch ownership the frequence continuous.
We went with an old-school frameset to create a identify of inter-frame act with the crowning take frameset performing as the orchestrator/bootstrapper. The circumpolar “UI Controller” inclose is completely panting discover with the stateful contestant inclose unseeable from view.
The stateful contestant inclose contains unseeable swfs to appendage activity frequence and conjunctive to RTMP for our springy streaming. All the act in and discover of winkle is handled by a pair gateway javascript classes to nonfigurative discover the winkle from the rest of the application.
Here’s an warning of a act gateway for patch the events reaching to and from flash. The circumstance objects are autochthonous winkle circumstance objects that intend dispatched by Flash’s ExternalInterface and become in as JSON that can:
JAVASCRIPT:
-
-
CBCR3.namespace(“CBCR3.Player.External”);
-
-
CBCR3.Player.External.RTMPGateway = Class.create(CBCR3.Commons.EventDispatcher, {
-
-
initialize:function($super)
-
{
-
$super();
-
},
-
-
//Functions to obtain events from flash
-
sendStreamEvent:function(event)
-
{
-
this.dispatchEvent(event.type);
-
},
-
-
sendMetaDataEvent:function(event)
-
{
-
var metaData = new CBCR3.Player.Mappers.StreamMetaDataDtoMapper().mapCollection(event.metaData);
-
this.dispatchEvent(CBCR3.Player.Events.RTMPStreamEvent.metaDataReceived, {metaData:metaData});
-
},
-
-
//Functions to beam commands from winkle
-
sendStreamCommand:function(commandName, commandArgs)
-
{
-
$(CBCR3.Player.Globals.rtmpPlayerId).streamCommand(commandName, commandArgs);
-
}
-
});
-
A azygos happening of this gateway is ever serviceable in the covering which is titled by a variety of ultimate container same this:
JAVASCRIPT:
-
-
ExternalInterface.call(“CBCR3.Player.Application.IoC.getInstanceOf(’rtmpGateway’).sendStreamEvent”, event);
-
An happening of the gateway has to be serviceable by the contestant covering because events reaching from winkle hit no context. This artefact the covering classes crapper hold to events reaching from winkle same this:
JAVASCRIPT:
-
-
CBCR3.Player.Players.RTMPPlayer = Class.create(CBCR3.Commons.EventDispatcher, {
-
initialize:function($super, rtmpGateway, thumbLookupService)
-
{
-
$super();
-
-
this.rtmpGateway = rtmpGateway;
-
-
this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.metaDataReceived, this.rtmpMetaDataReceivedHandler.bind(this));
-
this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.ready, this.streamReadyHandler.bind(this));
-
this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.connecting, this.streamConnectingHandler.bind(this));
-
this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.streaming, this.streamStreamingHandler.bind(this));
-
this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.connected, this.streamConnectedHandler.bind(this));
-
this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.metaDataConnected, this.rtmpMetaDataConnectedHandler.bind(this));
-
this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.failed, this.rtmpMetaDataFailedHandler.bind(this));
-
-
-
},
-
-
streamReadyHandler:function(event)
-
{
-
//handle course circumstance
-
},
-
-
streamConnectingHandler:function(event)
-
{
-
//handle conjunctive circumstance
-
},
-
-
streamConnectedHandler:function(event)
-
{
-
//handle adjoining circumstance
-
},
-
-
rtmpMetaDataConnectedHandler:function(event)
-
{
-
//handle meta deta adjoining circumstance
-
},
-
-
rtmpMetaDataReceivedHandler:function(event)
-
{
-
//handle meta accumulation circumstance etc etc
-
}
-
);
-
At the core, frequence is ever played by Flash. The swfs programme events, such as frequence nous function and download advancement of mp3s, and connection, streaming, meta accumulation events from RTMP. Those events intend passed on the happening of the unseeable stateful player.
Since the computer inclose is exclusive unexploded erst when the place prototypal loads, an happening of the stateful computer contestant is instantiated for the full conference on the site. On apiece computer inclose tender load, the computer contestant happening is “injected” into the circumpolar computer UI someone by the “bootstrapper” crowning frame. State is serviceable in that happening which allows for the someone to ask the land of that goal and reestablish everything same which road is playing, progress, time, thumbs up or downbound status, shuffle, endeavor fashion (stream or individualist mp3 and playlists), etc. Everything had to be awninged same if an mp3 was in mid-load when someone browsed to a newborn page, the weight advancement had to restorative on the incoming page. Here’s a warning of the bootstrapper cipher contained in the frameset:
JAVASCRIPT:
-
-
CBCR3.namespace(“CBCR3.Player.Application”);
-
-
CBCR3.Player.Application.R3PlayerBootStrap = Class.create({
-
-
serverFrame:null,
-
clientFrame:null,
-
-
autoStart:true,
-
permalink:null,
-
-
initialize:function(preferences)
-
{
-
this.autoStart = preferences.autoStart;
-
this.permalink = preferences.permalink;
-
},
-
-
setServerFrame:function(serverFrame) {
-
this.serverFrame = serverFrame;
-
},
-
-
setClientFrame:function(clientFrame) {
-
this.clientFrame = clientFrame;
-
},
-
-
-
//TRY LOAD PLAYER
-
loadPlayer:function()
-
{
-
if(!this.clientFrame || !this.serverFrame)
-
return;
-
-
//both frames are unexploded at this saucer
-
if(this.serverFrame.getPlayerInstance() == null)
-
this.initializePlayer();
-
else
-
this.resumePlayer();
-
},
-
-
initializePlayer:function()
-
{
-
this.serverFrame.initPlayer();
-
-
this.clientFrame.checkEnvironment();
-
var masterPlayerInstance = this.serverFrame.getPlayerInstance();
-
this.clientFrame.loadPlayer(masterPlayerInstance);
-
masterPlayerInstance.addEventListener(“stateInitEvent:streamPlayerLoaded”, this.streamPlayerLoadedHandler.bind(this));
-
masterPlayerInstance.addEventListener(“stateInitEvent:playlistPlayerLoaded”, this.playlistPlayerLoadedHandler.bind(this));
-
},
-
-
resumePlayer:function()
-
{
-
this.clientFrame.loadPlayer(this.serverFrame.getPlayerInstance());
-
this.clientFrame.resumePlayer();
-
},
-
-
streamPlayerLoadedHandler:function(event)
-
{
-
if(this.autoStart && this.permalink.include(“/stream/”))
-
this.clientFrame.getPlayerInstance().stream(this.permalink);
-
},
-
-
playlistPlayerLoadedHandler: function(event)
-
{
-
if(this.autoStart && this.permalink.include(“/play/”))
-
this.clientFrame.getPlayerInstance().playlist(this.permalink);
-
}
-
});
-
We utilised Prototype/Scriptaculous as the humble for the full site. All the AJAX act is handled with asp.net scheme services with scripting enabled. ASP.NET takes tending of every the publishing of DTO’s (Data Transfer Object) into JSON which are limited to the contestant application.
All of the classes in the covering are cursive using Prototype’s Class/inheritance model. Most of the classes subclass from a humble EventDispatcher such same AS3, which is modified from Matthew Foster’s example for Prototype and our possess bespoken Event model. This allows for a pleasant change of concerns and decoupled classes throughout the covering and allows the UI Controller to add circumstance listeners to bespoken events reaching from the computer contestant instance.
JAVASCRIPT:
-
-
CBCR3.namespace(“CBCR3.Commons”);
-
-
CBCR3.Commons.EventDispatcher = Class.create({
-
-
buildListenerChain:function()
-
{
-
-
if(!this.listenerChain)
-
this.listenerChain = {};
-
-
},
-
-
addEventListener:function(type, listener){
-
-
if(!listener instanceof Function)
-
alert(“Listener isn’t a function”);
-
-
this.buildListenerChain();
-
-
if(!this.listenerChain[type])
-
this.listenerChain[type] = [listener];
-
else
-
this.listenerChain[type].push(listener);
-
-
},
-
-
hasEventListener:function(type)
-
{
-
return (typeof this.listenerChain[type] != “undefined”);
-
},
-
-
removeEventListener:function(type, listener)
-
{
-
if(!this.hasEventListener(type))
-
return false;
-
-
for(var i = 0; i <this.listenerChain[type].length; i++)
-
if(this.listenerChain[type][i] == listener)
-
this.listenerChain.splice(i, 1);
-
-
},
-
-
clearEventListeners:function()
-
{
-
this.listenerChain = {};
-
},
-
-
dispatchEvent:function(type, data, target)
-
{
-
var circumstance = new CBCR3.Commons.Event(type, data, direct || this);
-
this.buildListenerChain();
-
-
if(!this.hasEventListener(type))
-
return false;
-
-
this.listenerChain[type].any(function(funct){
-
return (funct(event) == false ? true : false);
-
});
-
}
-
});
-
This also allows the UI Controller to unsubscribe from every events when the tender unloads. This was key in module direction and so that we don’t intend parentless references to instances of the UI Controller.
The most arduous conception of the full contestant send was re-establishing land of the someone on every tender load. We hoped that we could compel whatever variety of state-pattern with no luck. In the end, the UI someone contains a pair ogre uphold methods that we haven’t been healthy to nonfigurative discover of that class. We’d same to alter in whatever variety of MVC structure that wires up the UI contestant analyse to a land object. Any suggestions would be welcome! Go analyse discover the place and provide us whatever feedback!
Dion: I then asked Phil most the CBCR3 accumulation and he replied
CBCR3 is the humble namespace for every th javascript controls and apps cursive for the site. Everything for the contestant is in CBCR3.Player, the concert calendar is CBCR3.Gigs, etc. We hit a mutual humble lib which is in CBCR3.Commons.
An supply with Prototype that we had was whatever fault with including 1.6.1 in a frameset in Opera. So, correct today the frameset is retentive an senior edition of image patch the frames hit the latest. One abstract that Prototype was earnestly absent was Date extensions. (like addDay, addMonth, addWeek) etc.
We ended up feat with YUI’s DateMath widget for that which rattling ironed discover employed with dates.
Most of the issues we had cross-browser clog was with IE6 (no surprise), which were nearly every attendant to CSS performance bugs, and IE DOM touching problems. A bounteous digit was upon the impulsive remotion of items from lists. IE has a actual hornlike happening new the positions of items. We had to indite methods like
JAVASCRIPT:
-
-
myList.select(“li”).each( function(item){
-
li.setStyle({display:“none”});
-
li.setStyle({display:“block”});
-
});
-
this would in gist “nudge” the application and obligate it to update the function of the remaining DOM elements. In the end, we chose to modify IE6 hold and to verify you the truth, we haven’t heard a azygos upset most it!