Scenario 2: MP3 Online Radio Station
To embark on a slightly more challenging project using Flash Communication Server 1.5 server-side ActionScript, you'll build an MP3 web radio station, "AB web FM" (see Figure 5). The online radio station will play continuous music to all connected users. You will integrate a number of technologies within this application.
Figure 5. AB web FM interface
You will store the names of the MP3 files and artists in a simple Microsoft Access database. You will query the database from Flash Communication Server server-side ActionScript (using Flash Remoting), using ColdFusion MX for the server functionality. The database results will provide the information required to play the MP3 files. A NetStream object on the client will let Macromedia Flash Player play the MP3 files.
Note: This example assumes that you have ColdFusion MX and Microsoft Access installed on your system.
Requirements for the MP3 Online Radio Station
-
Macromedia Flash Communication Server 1.5
-
ColdFusion MX
- Macromedia Flash Remoting
-
Macromedia Flash MX (This will be your authoring environment.)
- Microsoft Access database
- MP3 files
- Background graphics or animation (optional)
Downloads
Download the source files to use as a guide:
Building the MP3 Online Radio Station
-
Create the database.
- Open Microsoft Access.
- Create a new database. Select the Database icon. Name it mp3_db and save it in the folder C:\CfusionMX\db.
- When the wizard comes up, select the "Create table by entering data" option. The design view table now appears before you. Double-click the top of the first column "Field1"and rename it "ARTIST."
- Do the same for the second column and rename it "SONG."
- Type the names of the MP3 files (without the .mp3 extension) in the SONG column.
- Match the MP3 files to the artists in the ARTIST column. (See Figure 6.)
- When you've finished, close the table. A prompt asks you to name the table; name it "mp3_music". Click OK. Access asks you to create a primary key; click "YES". You have created the mp3_db.
- Quit Microsoft Access.
Figure 6. Database table
- Set up an ODBC connection. Set up the Open Database
Connectivity Driver (ODBC) to let the ColdFusion MX server gain access
to the data. Begin by clicking
- Start on your Windows Task Bar and navigate to the following path:
Start > Control Panel > Administrative tools/Data Sources (ODBC)
Figure 7. Navigating to the Data Sources settings
-
In the ODBC Data Source Administrator, select the System DSN tab and click Add.
-
In the Create New Data Source window, select the Microsoft Access driver and click Finish.
-
In the ODBC Microsoft Access Setup window, type the Data Source Name (DSN), in this case "mp3_db".
-
Click Select and find the path to the folder where the database file is located.
-
Select it and click "OK".
-
Leave every thing else and click the OK buttons till all the dialog boxes close. You have now set up your ODBC connection.
- Start on your Windows Task Bar and navigate to the following path:
- Add the data source to ColdFusion MX.
- Open the ColdFusion MX administrator and select Data Sources from the side bar.
- Type the data source name "mp3_db".
- Select ODBC socket as the driver type, and click Add.
- Find and select mp3_db in the pop-up menu. Click Submit.
This brings you back to the Data Sources page, where the database should now be listed. At the right hand cell of the table you should see an ok.
- Create a virtual directory for the MP3 files. The
virtual directory lets the web radio application access any MP3 files
within the directory. This way the MP3 files do not need to be hard
coded into the server-side ActionScript. Now you must list the files
you want to stream into the database and "Voila"—you
have play. Note: For this section, an understanding
of XML is helpful but not essential.
- Navigate to your Program files and in the Macromedia folder find Flash Communication Server.
- Open the Flash Communication Server folder.
- Double-click the conf folder, and continue opening the folders until you get to the _defaultVHost_.
- Open the _defaultVHost_ folder and open the Vhost.xml file.
- Using Dreamweaver MX or HomeSite 5, scroll down to the <Virtual directory> tag.
- Find the <Streams> tag; it is inside the <Virtual directory> tag.
- Type the path to the folder containing the MP3 files you want
to use. Use a prefix to identify the virtual directory; I used mpGroove.
For example, on my workstation the path is as follows:
< Streams>mpGroove;d:/Nu_Music/tuff_music</Streams>
Note: It is imperative that the slashes are forward slashes.
-
Save the file. You have now created the virtual directory.
- Create the server-side ActionScript logic. Now comes
the core of the application. You will use Flash Remoting to query the
server and retrieve the details for the MP3 files to be published. While
you can use Notepad to write your Flash Communication Server 1.5 server-side
ActionScript, I strongly recommend Dreamweaver MX. I describe the following
processes as they are performed in Dreamweaver MX.
Almost all the server-side logic happens within the application.onAppStart tags. This prevents the application from triggering again when new client makes a NetConnection.
Open a new ActionScript Communications document (ASC). Call it main.asc and save it in the webstation folder inside your Flash Communication Server applications directory. Add the following code, step by step:
- Remoting NetServices: At the top of the document
type:
load("NetServices.asc");This loads up the framework required to enable Flash Remoting.
- application.onAppStart: Next, enable the application
object.
application.onAppStart = function(){ trace(";mp3********";);In the Communications Application Inspector the trace confirms that the application is active.
- application.mp3_so: Create a nonpersistent Remote
shared object. Call it mp3_so. Initialize it in the following manner:
application.mp3_so = SharedObject.get(";song_list";, false); application.mp3_so.onStatus= function(info){trace(info.code)} -
Default gateway: To use Flash Remoting, set up a NetConnection default gateway. Call this gateway mp3Gate. For development purposes, set it up on the localhost as follows:
NetServices.setDefaultGatewayUrl(";http://localhost:8500/flashservices/gateway";); // Connect to the gateway mp3Gate = NetServices.createGatewayConnection();When deployed live, localhost resolves to the site URL (www.whatever.com) or the site IP address (217.23.23.23).
-
Mp3_obj: Create an object called mp3_obj to hold all the data requested from the database
mp3_obj = {};Create a property of the mp3_obj; name it
mp3_obj.service. This mp3_obj.service property is assigned thegetService()method of the mp3Gate Remoting gateway. ThegetService()method creates a Remoting service object. This lets information flow between the server, database, and the Macromedia Flash client. Flash Remoting lets developers write Remoting ActionScript functions (*.asr) which do the same job as a ColdFusion template in querying the database. You will write a Flash Remoting function which will be saved in the webstation folder, located at the root of the ColdFusion server wwwroot. This is the folder from which you will be serving your web documents to the web. This Remoting ActionScript document needs to be below the ColdFusion wwwroot for ColdFusion to process it.mp3_obj.service= mp3Gate.getService("applications.webstation.myMP3query";, mp3_obj);After setting up the
NetService.getService()method, use the service to call the function within the document it is mapped to. The function within myMP3query.asr ismp3Question().mp3_obj.service.mp3question();
To receive the data returned from the database, create a Result object for the mp3Question function:
mp3_obj.mp3question_Result = function (result){ var cols= result.getColumnNames(); trace("Columns: "+ cols);From the result, you get the number of rows in the database table:
// reclen is the length of the recordset reclen =application.reclen= result.getLength() trace ("reclen: "+reclen);Using the length as a control, assign the Shared Object slots based on the values of the results retrieved from the database. As shown below, the app retrieves results from the ARTIST and SONG columns of our database and assigned accordingly.
for (var i = 0; i<reclen; i++){ application.mp3_so.setProperty("artist"+i, result.getItemAt(i)["ARTIST"]); application.mp3_so.setProperty("song"+i, result.getItemAt(i)["SONG"]); }Call the application
.playSelected()function to start webcasting to connected clients.application.playSelected(); }
-
application.playSelected callback function: This function controls MP3 file play on the client. When the right conditions occur, the function executes. It allocates the right MP3 file to the Stream object and triggers play of the file. It also sends the name of the file being played to the client to display on the user's radio interface. As a control, it sets a variable j to zero .
application.playSelected = function(){ j=0;Declare a variable mp3_title. Once the application starts, assign the value of the first
mp3_sosong slot,song0, to the variablemp3_title. Concatenate its value to themp3:mpGrooveprefix. Remember that the mp3: prefix is required to play MP3 files, mpGroove is the name of our virtual directory.mp3_title = application.mp3_so.getProperty("song"+j); mp3Sound = "mp3:mpGroove/"+mp3_title, trace(mp3Sound); application.mpStream.play(mp3Sound); application.mpStream.send("mp3_caption", mp3_title)Next create a Stream object to publish the MP3 file and trace the info.code of its onStatus information object.
//
application.mpStream= Stream.get("mp3_music"); application.mpStream.onStatus=function(info){ trace("mp_strmCode:"+" "+info.code);The info object code property "NetStream.Play.Stop" indicates that the current MP3 file has finished playing, so add 1 to the variable j, retrieve the information for the next MP3 file, and play it. As it does this, it sends the name of the file to play to the client.
(info.code=="NetStream.Play.Stop" ){ j++, trace(j); //assign the value of the MP3file name to the variable mp3_title mp3_title = application.mp3_so.getProperty("song"+j); //assign the value of mp3_title concatenated to the mp3: prefix and // the virtual directory mpGroove to the variable mp3Sound mp3Sound = "mp3:mpGroove/"+mp3_title; application.mpStream.play(mp3Sound); application.mpStream.send("mp3_caption", mp3_title)If, however, j equals
application.reclenor is greater than the length of the recordset (application.reclen), reset the value of j to zero and begin play again from the top.} else if (j>=application.reclen) { j=0; mp3_title = application.mp3_so.getProperty("song"+j); mp3Sound = "mp3:mpGroove/"+mp3_title; trace(mp3Sound); application.mpStream.play(mp3Sound); application.mpStream.send("mp3_caption", mp3_title) } }For the user to connect to the application, we declare the application onConnect method.
application.onConnect = function(music_lover){The acceptConnection method accepts the client connection.
application.acceptConnection(music_lover); }
- Remoting NetServices: At the top of the document
type:
- Create the Flash Remoting function. To query the
database, create a new ActionScript Remote document and call it myMP3query.asr.
Declare the function mp3Question. Assign the ColdFusion.query to the
variable mp3data.
// ActionScript Remote Document function mp3question (){ mp3data = CF.query({datasource:"mp3_db", sql:"SELECT * FROM mp3_music"});return mp3data; }Save the file to the folder with your web document below the ColdFusion MX wwwroot.
- Create the client-side ActionScript logic. The logic is quite elementary. In this next step, you merely create a conduit for the MP3 files being streamed from the server to be played. You also define a few controls to let the user play the stream or mute the sound. You also create two movie clips as buttons, start_mc and mute_mc. All the code lies in the first frame of the Logic layer.
- NetService and NetDebug files: Start by including
the NetService and NetDebug files; they are crucial to debugging and
tracing application behavior.
//CF version #include "NetDebug.as" #include "NetServices.as"
You will create and initialize two variables: radio_bool and mute_bool. They will pass Boolean values of true or false to two functions: init and doMuteSound. The function
init()initializes the application by making a NetConnection to Flash Communication Server when passed a value of true and closes the NetConnection when passed a value of false. The methoddoMuteSound()on the other hand, will close the NetStream when passed a value of true and open the NetStream when passed false.radio_bool = false; mute_bool = false;
-
Init(): Write the init function.
init = function (radio_bool) { if (radio_bool == true) { _level0.createEffect(); -
NetConnection: Create a new NetConnection. Call it mp3_nc. Trace its status by declaring the NetConnection.
onStatus()method. Connect your new NetConnection to the rtmp protocol.mp3_nc = new NetConnection(); mp3_nc.onStatus = function(info) { trace(info.code); }; mp3_nc.connect("rtmp:/webstation/station1"); -
NetStream: Create a new NetStream object. Call it mp3_ns. This NetStream object is the key element required to play the MP3 streams.
mp3_ns = new NetStream(mp3_nc); mp3_ns.onStatus = function(info) { trace(info.description); };To play back the mp3 files, you will assign the audio stream to a movie clip object. Attaching the audio stream to a movie clip object gives you greater control over the playback sound through the Sound object methods and properties. You could also attach the audio stream to a Video object.
Use the
movieclip.attachAudio(source)method to assign the playback audio stream to the movie clip object. In this cast, the movieclip object is the Macromedia Flash movie. Assign the attachAudio method to level0 (the default root of your Macromedia Flash movie). Then declare its source as the default NetStream object mp3ns. Next, point the source of the NetStream “mp3”_ns at “mp3_music”, which is the name of the Stream source on the server side. This creates the connection between the server Stream object and the client NetStream object._level0.attachAudio(mp3_ns); mp3_ns.play("mp3_music"); // -
NetStream function: To receive the MP3 file string from the server, create a callback function of the NetStream object mp3_ns.
mp3_ns.mp3_caption = function(song_caption) { trace(song_caption); song_details_txt.text=song_caption, start_txt.text="stop"; }; } else if (radio_bool == false) { mp3_nc.close(); start_txt.text = "start"; } }; -
doMuteSound: The function
doMuteSound()lets users who do not want to close the NetConnection mute the sound played from the radio. It is a toggle conditional based on the value of the variable mute_bool.doMuteSound = function (mute_bool) { if (mute_bool == true) { _level0.attachAudio(false), _level0.mp3_ns.close(); mute_txt.text = "unmute"; } else if (mute_bool == false) { _level0.attachAudio(mp3_ns), _level0.mp3_ns.play("mp3_music"); mute_txt.text = "mute"; } }; -
Define the actions for the movie clip buttons. Define the various event states for the two movie clips start_mc and mute_mc.
//
start_mc.onRollOver = mute_mc.onRollOver=function () { this.gotoAndStop(2); }; start_mc.onRollOut = mute_mc.onRollOut=start_mc.onReleaseOutside=mute_mc.onReleaseOutside=function () { this.gotoAndStop(1); }; start_mc.onRelease = function() { if (radio_bool == true) { radio_bool = false; } else if (radio_bool == false) { radio_bool = true; } init(radio_bool); }; mute_mc.onRelease = function() { if (mute_bool == true) { mute_bool = false; } else if (mute_bool == false) { mute_bool = true; } trace(mute_bool) doMuteSound(mute_bool); };
Voila! You have a web radio station powered by Flash Communication Server 1.5.
The complete code for the application follows. I hope these two examples give you an idea of the possibilities of Flash Communication Server 1.5.
MP3 Online Radio Station: Complete Code
Server Code
// ActionScript Communications Document
//K version
load("NetServices.asc");
application.onAppStart = function(){
trace("mp3********");
application.mp3_so = SharedObject.get("song_list", false);
application.mp3_so.onStatus= function(info){trace(info.code)}
NetServices.setDefaultGatewayUrl("http://localhost:8500/flashservices/gateway");
// Connect to the gateway
mp3Gate = NetServices.createGatewayConnection();
mp3_obj = {};
mp3_obj.service= mp3Gate.getService("applications.webstation.myMP3query", mp3_obj);
mp3_obj.service.mp3question();
mp3_obj.mp3question_Result = function (result){
var cols= result.getColumnNames();
trace("Columns: "+ cols);
reclen =application.reclen= result.getLength()
trace ("reclen: "+reclen);
for (var i = 0; i<reclen; i++){
application.mp3_so.setProperty("artist"+i, result.getItemAt(i)["ARTIST"]);
application.mp3_so.setProperty("song"+i, result.getItemAt(i)["SONG"]);
}
application.playSelected();
}
//
// application callback function to activate the radio station
//application.playSelected begins
//
application.playSelected = function(){
j=0;
//
//create two Stream objects, one to publish the MP3 file and
// the other to publish its ID3tag data
//
application.mpStream= Stream.get("mp3_music");
application.mpStream.onStatus=function(info){
trace("mp_strmCode:"+" "+info.code);
if (info.code=="NetStream.Play.Stop" ){
j++, trace(j);
//assign the value of the MP3file name to the variable mp3_title
mp3_title = application.mp3_so.getProperty("song"+j);
//assign the value of mp3_title concatenated to the mp3: prefix and
// the virtual directory mpGroove to the variable mp3Sound
mp3Sound = "mp3:mpGroove/"+mp3_title;
application.mpStream.play(mp3Sound);
application.mpStream.send("mp3_caption", mp3_title)
} else if (j>=application.reclen) {
j=0;
mp3_title = application.mp3_so.getProperty("song"+j);
mp3Sound = "mp3:mpGroove/"+mp3_title;
trace(mp3Sound);
application.mpStream.play(mp3Sound);
application.mpStream.send("mp3_caption", mp3_title)
}
}
mp3_title = application.mp3_so.getProperty("song"+j);
mp3Sound = "mp3:mpGroove/"+mp3_title, trace(mp3Sound);
application.mpStream.play(mp3Sound);
application.mpStream.send("mp3_caption", mp3_title)
}
//
//application.playSelected ends
//
}
application.onConnect = function(music_lover){
application.acceptConnection(music_lover);
}
Client Code
//CF version
#include "NetDebug.as"
#include "NetServices.as"
radio_bool = false;
mute_bool = false;
init = function (radio_bool) {
if (radio_bool == true) {
_level0.createEffect();
mp3_nc = new NetConnection();
mp3_nc.onStatus = function(info) {
trace(info.code);
};
mp3_nc.connect("rtmp:/webstation/webstation");
mp3_ns = new NetStream(mp3_nc);
mp3_ns.onStatus = function(info) {
trace(info.description);
};
_level0.attachAudio(mp3_ns);
mp3_ns.play("mp3_music");
//
mp3_ns.mp3_caption = function(song_caption) {
trace(song_caption);
song_details_txt.text=song_caption, start_txt.text="stop";
};
} else if (radio_bool == false) {
mp3_nc.close();
start_txt.text = "start";
}
};
doMuteSound = function (mute_bool) {
if (mute_bool == true) {
_level0.attachAudio(false), _level0.mp3_ns.close();
mute_txt.text = "unmute";
} else if (mute_bool == false) {
_level0.attachAudio(mp3_ns), _level0.mp3_ns.play("mp3_music");
mute_txt.text = "mute";
}
};
//
start_mc.onRollOver = mute_mc.onRollOver=function () {
this.gotoAndStop(2);
};
start_mc.onRollOut = mute_mc.onRollOut=start_mc.onReleaseOutside=mute_mc.onReleaseOutside=function () {
this.gotoAndStop(1);
};
start_mc.onRelease = function() {
if (radio_bool == true) {
radio_bool = false;
} else if (radio_bool == false) {
radio_bool = true;
}
init(radio_bool);
};
mute_mc.onRelease = function() {
if (mute_bool == true) {
mute_bool = false;
} else if (mute_bool == false) {
mute_bool = true;
}
trace(mute_bool)
doMuteSound(mute_bool);
};
Flash Remoting Code
// ActionScript Remote Document
function mp3question (){
mp3data = CF.query({datasource:"mp3_db", sql:"SELECT * FROM mp3_music"});
//result= CF.query("dbX", "SELECT partname from rXTable");
return mp3data;
}