by aYo Binitie II

aYo Binitie II
 

Created

23 June 2008

 

- Requirements

Prerequisite knowledge

This article assumes that you have a moderate knowledge of ActionScript 2.0 or 3.0 and some experience using Flash Media Interactive Server 3. A rudimentary knowledge of XML would also be helpful.
 

User level

Intermediate

 

 

Required products

Flex Builder (Download trial)

 

 

Sample files

 

Flash Media Interactive Server 3 (FMIS) extends and improves on the technology and application programming interface (API) provided by its older siblings, Flash Communication Server 1.5 and Flash Media Server 2. Among the many improvements that this new iteration of the server offers is support for AAC-encoded audio formats. You can use a variety of techniques to stream MP3 and AAC encoded audio files using FMIS. This article examines an application that uses a one-to-one streaming technique. Such a deployment creates a unique instance of the application for each user, allowing each user to have a unique music listening experience.

The application demonstrating this technique is a music playlist (MP3 player) powered by FMIS. You will be able to share your music with your friends, certain in the knowledge that while they do not have physical access to your MP3 files, they can fully enjoy your excellent music library. To achieve this, each user creates a unique signature (instance) of the application. Each user can then access their own choice of songs even though they share the same music library.

 

Flash Media Server 3 streaming media capabilities

Wikipedia defines the Advanced Audio Coding (AAC) as "a standardized, lossy compression and encoding scheme for digital audio. AAC generally achieves better sound quality than MP3 at the same bitrate, particularly below 192 kbps." Flash Media Interactive Server now streams AAC formats in addition to its prior support for MP3 formats. Popular AAC extensions include .m4a, .m4b, .m4p, .m4v, .m4r, .3gp, .mp4, and .aac.

Another new feature is the Real Time Messaging Protocol Encrypted (RTMPE), a secure, encrypted option for creating encrypted network connections between the client and server. This persistent transfer protocol provides security without the hassle of SSL certification and server setups. RTMPE is enabled by default when you install Flash Media Interactive Server 3. It is a real boon in the area of content security and digital rights management (DRM). The FMIS stream provides content on demand, giving users immediate access to the required data without the need to download the music for playback.

The client API brings a brand new dimension to Flash Media Interactive Server development: ActionScript 3.0 and MXML. ActionScript 3.0 is an object-oriented language with an expanded and improved API (from ActionScript 2.0), allowing for a granular low-level control of objects. This API provides developers with a powerful, controllable, and elegant medium for developing sophisticated applications that deploy rich media. This has resulted in some changes to development techniques with regards to ActionScript for FMIS client applications. (The client is the part deployed in Adobe Flash Player or as an Adobe AIR application.)

Flash Media Interactive Server 3 applications can also be developed in Adobe Flex Builder 3, the Flex 3 SDK (Eclipse or FlashDevelop development environments), and Flash CS3 Professional. Flex Builder 3 and the Flex 3 SDK offer support for MXML and ActionScript 3.0. MXML is an XML language used to create layouts for user interfaces. You can also use MXML declaratively to define nonvisual aspects of an application. Such nonvisuals may provide access to server-side data sources or create data bindings between user interface components and server-side data sources. If you use Flash CS3 Professional, do not feel shortchanged by the fact that you do not have MXML. Flash CS3 Professional provides the same interface and data components that you can drag on, or instantiate to the Stage. Flash also gives you a much better control over design and layered animation.

 

Defining the music application

Before you start, review the logic flow of the system as a user experiences it:

  1. The user connects successfully to the audio playlist application.
  2. The Flash Media Interactive Server application extracts the required data to populate the song list from an external source—in this case, an XML document.
  3. The playlist receives the list of available songs from Flash Media Interactive Server.
  4. The audio playlist application displays the list of available songs for a user to play back (see Figure 1).
  5. To play a song, the user makes a selection by clicking the song in the list. The audio playlist application responds by activating playback of the selected song.
  6. The audio playback is streamed to the user.
Audio playlist user interface (modified with Papervision3D)

The actions of this application are executed across two separate APIs: Flash Media Interactive Server 3.0 (the server) and the Flash Player or AIR application (the client). It is important to understand the flow of logic and the relationships between both.

Server-side processes

First study the operations that occur on the server:

  1. The client attempts to make a network connection to the application on the server.
  2. If the connection is successful, the server requests the list of available MP3/AAC files. This audio file list of audio files is stored in an XML document.
  3. The server checks to see if such an XML document exists.
  4. If the playlist XML document exists, the application accesses it, extracts the required data from it, and places that data into an array.
  5. The array is sent back to the client.
  6. The client uses this array information to populate the user interface list with the available songs.

Client-side functionality

Next study the process on the client:

  1. The user attempts to make a network connection to the application on the server.
  2. If the connection is successful, a list of songs is sent from the server to the playlist application.
  3. The user selects a song to play by clicking an item in the list.
  4. The selected song is played.

It's that simple. Now that you have an overview of this application, you are ready to start building it. Begin with the client user interface. This tutorial uses Flex Builder 3 for client development.

 

Client-side development

At its simplest, all this application really needs for its user interface are a couple of features: one to display the list of songs and the other to allow the user select, play, pause, and stop the songs.

Creating the MXML

Create a new MXML project in Flex Builder 3, or in your IDE and the Flex SDK. When the Flex Project wizard appears, select the Basic option and name the project Flexplaylist.

If Flex Builder is your development tool, you can either select your own project location (my preferred option) or create the application in the default Flex Builder location. How you set this up is entirely up to you; however, I recommend choosing the option to specify a unique file location. This enables you to set up the project in a manner that conforms to your personalized structure of files and folders on your computer.

Once you have selected the project's location, click Finish. Flex Builder 3 automatically creates a main application MXML document called flexplaylist.mxml. A similar process with your IDE and the Flex SDK will probably give the same result.

Select flexplaylist.mxml from the Outline module and select the Source view. By default, Flex Builder generates code in the Source window. This auto-generated code provides the basic scaffolding for the application about to be developed:

 

<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" > //All your code will go here </mx:Application>

 

If you're developing with Flex Builder 3, switch to Design view and select the Components tab. In the Components view, open the layout folder and drag a Canvas container to the Stage. Set the width and height properties to 100%. Drag a Panel control into the canvas. Arrange the panel in the canvas to suit your requirements. You can also specify a name for the title of the Panel, such as "Flex Play List" or a different title of your choosing.

You'll need to add buttons that will play, pause, and stop the playback of the selected song . The ButtonBar control is perfect for the job. It arranges a set of push buttons (simple widgets that do not remember their state, if and when that state changes), horizontally or vertically. This component is perfect for grouping sets of related buttons together, which is just what our audio controls are.

The ButtonBar control centralizes the handling of the click event in a single place but also standardizes the way the buttons look. The ButtonBar control is in the Component view module in a folder named "Navigation." Drag the control onto the canvas and position it where you wish. The following code allows use of the ButtonBar control. Switch back to the source code and look for the <mx:ButtonBar> tag. It looks like this:

 

<mx:ButtonBar horizontalGap="5" y="42" x="32"> </mx:ButtonBar>

 

Insert the following code within the <mx:ButtonBar> tags:

<mx:dataProvider> <mx:Array> <mx:String>Stop</mx:String> <mx:String>Pause</mx:String> <mx:String>Play</mx:String> </mx:Array> </mx:dataProvider>

After making these changes, your code should look like this:

<mx:ButtonBar horizontalGap="5" y="42" x="32"> <mx:dataProvider> <mx:Array> <mx:String>Stop</mx:String> <mx:String>Pause</mx:String> <mx:String>Play</mx:String> </mx:Array> </mx:dataProvider> </mx:ButtonBar>

 

Now switch back to Design view to see what you've accomplished. You'll see that the ButtonBar component is now comprised of three buttons, separated from one another with a horizontal gap of five pixels. By adding the code shown above, you've specified that the DataProvider displays three buttons in the ButtonBar using labels defined by the strings that are indexed in the array.

Switch back to the Source view. Update the <mx:ButtonBar> tag by adding the highlighted code shown below:

<mx:ButtonBar horizontalGap="5" itemClick="clickHandler(event);" y="42" x="32">

You've just added itemClick , which is one of the available event handlers provided for this component. Now when the event occurs (when the item is clicked), the ButtonBar will dispatch an event object to the event listener method, clickHandler(e:ItemClickEvent). The event object possesses all of the information needed for the method to execute the correct instructions. For instance, if a user clicks the Pause button, all the information to allow the event handler function (clickHandler) to respond appropriately—and thus pause the playing song—is sent to it in the event object. Later you'll return to this bit of code to write the method for clickHandler(event).

Finish the application layout by dragging a List control and a TextArea control on the Stage. The List control displays the list of songs received from the server. When the user clicks a song in the list, the song is streamed back. The TextArea control serves as a visual cue, so the user gets feedback from each process as he or she interacts with the various features of the player. This is optional. Position both components on the Stage. Assign the List id property the value "play_list" and the TextArea id property the value"feedback".

Setting up the connections

The next step is to write the ActionScript logic that defines the relationship between the client side and the server side of the application. This is the time to step back and take an overview of the entire scope of the application before you write any more code. Review the outline for the application and the desired functionality for the client side:

  1. The end user logs unto the application.
  2. The application connects to server.
  3. The server sends the application the playlist information.
  4. The application receives the data and displays the song titles.
  5. The end user selects a song to play by clicking an item in the playlist.

It is a best practice to write out the logic for an application in plain language and focus on how the application should function before writing the code. A friend of mine likened these steps to a series of stories, each one creating a better understanding and flow for the next. With this in mind, the story begins with a task: The first task is for the user/client side of the application to make a successful connection to the server.

It is time to start writing the code to make this happen.

Connecting to the server

For the purposes of this article, the playlist will auto-connect to the server once the application loads. In order to avoid null object errors, it is a good idea make sure that the attempt at a server network connection occurs only when requisite application assets are initialized. Flex provides you with the perfect method to ensure that. All Flex UIComponents have a creationComplete event. This event is fired when the component has finished its construction, property processing, measuring, layout, and drawing. After you assign a build() method as an event listener to this event, and it is dispatched, the listener will begin the procedures to initiate a network connection.

Add the creationComplete attribute to the <mx:Application> tag and assign the method build() as its value:

 

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="build()" backgroundAlpha="0">

 

The build() method initializes a NetConnection class instance. This class provides the means by which the client side of the application attempts to make a connection to the server.

To set up the build() method, you'll need to add some inline ActionScript code to your MXML document. The <mx:Script> tag allows you write inline ActionScript code within an MXML document. Within the <mx:Script> tag is the XML character data tag:

<![CDATA[ "all code here" ]]>

 

This CDATA tag ensures that the MXML XML parser does not interpret the ActionScript code as XML. All the code you write goes within the character data tags:

<mx:Script> <![CDATA[ //All the code goes here ]]> </mx:Script>

 

Within the CDATA tag, add the following code:

private var connection:NetConnection; private var musicstream:NetStream; private var _cs:String;

 

Note: Prior versions of Flash Media Server required that, at this point, the defaultObjectEncoding be set to AMF0 for the NetConnection and SharedObject classes. This is no longer necessary because Flash Media Interactive Server provides native support for AMF3 object encoding.

public function build():void { trace("::::make network connection::::"); connection = new NetConnection(); connection.client = new NetConCalls(); }

 

Take a look at the build() method. First, an instance of the NetConnection class is initialized and assigned to the application variable,connection.

The next line of code requires some explanation. The nature of the interaction between the server and Flash Player requires that custom methods reside on the client to deal with unique requests and calls from the server, and vice versa. On the other hand, ActionScript 3.0 no longer has dynamic native classes, so it is not possible to create custom methods on the NetConnection class. To solve this, the NetConnection class provides a client property to which you can assign an object or a class. This custom class can then carry all the custom methods needed to deal with calls from the server.

ActionScript 3.0 provides a variety of ways to set up this server/client correlation. For this tutorial, the custom class NetConCalls will be created, and an instance of this class will be assigned as a value of the NetConnection client property.

Create the class NetConCalls. This class will be examined in detail shortly. To avoid compiler errors, however, create NetConCalls as an empty class.

Set up a getter method for the NetConnection instance. This getter will be called getNetCon():

public function getNetCon():NetConnection { // returns the NetConnection instance return connection; }

 

It would be helpful to have a utility provide you with some visual cues for your playlist processes. You can use the Flex Builder 3 debugger at development time, but you want the end user of the application to receive feedback upon making successful connections, audio buffering, and so on. To create this feedback mechanism, use a little method called writeln() that sends strings to the TextArea feedback window. The trace() method can be used as well; it's the developer's prerogative.

The NetConnection class

The NetConnection and NetStream class instances dispatch events in the course of their various processes. The status of these processes are reported by the NetStatusEvent class. Complete the build() method by adding event listeners to the instance of the NetConnection class. This enables you to get feedback from the NetStatusEvent object. The event listener method is netStatusHandler:

connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);

Now you are ready to attempt a connection to the server using the NetConnection connect(URI) method. Add the following code:

connection.connect("rtmp:/flexplaylist/music");

 

Your finished build() method should look like this:

public function build():void { trace("::::make network connection::::"); connection = new NetConnection(); connection.client = new NetConCalls(); connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); connection.connect("rtmp:/flexplaylist/music"); }

 

As the NetConnection object has been set to listen to the NetStatusEvent object, the next step is to set up the listening method netStatusHandler(). Add the code below:

 

public function netStatusHandler(event:NetStatusEvent):void { switch (event.info.code) { case"NetConnection.Connect.Success": trace(event.info.code); trace(":::musicstream created:::::") musicstream = new NetStream(getNetCon()); getNetStream().addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); getNetStream().client = new NetConStreams(); break; case"NetStream.Play.StreamNotFound": trace("Stream not found: "); break; default: trace(event.info.code); break; } }

 

In the code above, you are using the information passed from the NET_STATUS object to confirm if there has been a successful connection. This information is contained in the NetStatusEvent information object's code property. A successful connection will return the string, "NetConnection.Connect.Success".

The NetStream class

To retrieve and play the music served from the server, you need the NetStream class. Within the switch statement that confirms a successful NetConnection, create an instance of the NetStream class and call it musicstream. Create a getter method for the new NetStream class instance, as shown below:

public function getNetStream():NetStream { return musicstream; }

 

Now you can ask your NetStream instance to listen for its NetStatusEvent by adding this line of code:

getNetStream().addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);

 

You may notice that your NetStream instance is listening to the same method that initialized it. It makes sense to write it this way for the purposes of this exercise because our requirements are nominal.

The NetStream class also has a client property to provide access to custom methods. You may need it so you will create a custom class called NetConStreams. This class allows you to process server/client callbacks over the NetStream or Stream class when they are needed.

The NetConCalls class

It is now time to finish the custom classes beginning with the NetConCalls class, referenced by the NetConnection client property.

First, import the classes that the class properties reference. You will need access to the Application class, the classes in the flash.net package, and the flash.events package. Importing the Application class enables you to reference the root component instantiated by the <mx:Application> tag. The flash.net package provides you access to the classes it contains. Of interest here are the NetConnection and NetStream classes. The flash.events package provides access to the EventsDispatcher base class. In order to import these classes, you can place import statements in the space between the package declaration and the class declaration, as shown below:

package { import mx.core.Application; import flash.net.*; import flash.events.*; public class NetConCalls {

 

The NetConCalls class has a single property: an array called arr. Declare the instance before the class constructor and initialize it in the class constructor. The array arr
is assigned the array of songs that is sent from the server, after a successful NetConnection has been made and a request for the list of songs is successful. The code below shows how this is accomplished:

 

public class NetConCalls { private var _arr:Array = new Array(); public function NetConCalls() { }

 

To access the arr array, create the following getter/setter methods: getArray()setArray(), and getPlaylist():

public function getArray():Array { return arr; } public function setArray(a:Array):void { arr = a; } public function getPlaylist():Array { return getArray(); }

 

In addition to these three getter/setter methods, the NetConCalls class has a number of methods to help set up the audio listing and then allow the user to play the selected item. Each of these methods is allocated its duties, as follows:

  • makePlaylist(a:Array) sets up the playlist from information pushed by the server
  • changeEventHandler() sets up the event listener method for the List component

The first method,makePlaylist(a:Array) , is a server callback method. This means that it is called from the server when the request for the list of songs is made. Through makePlaylist(a:Array), the server sends the requested list of songs back to the application with the argument a (an array). The following code sets out the method:

public function makePlaylist(a:Array):void { trace(":::makePlaylist:::"); var father:* = Application.application; setArray( a) ; father.play_list.dataProvider = getArray(); father.play_list.addEventListener(Event.CHANGE, changeEventHandler) }

 

Examine the statements in the method above. The first thing you'll see is a reference variable for the Application.application property, father. The reason for this is that the play_list control is a child of the application display stack, and having a reference to the Application.application property gives you a route to pass information to play_list. This is your List component (with the ID set to play_list). Having obtained access to the play_list control, the array received from the server is passed to its dataProvider property in order to populate the playlist. Please note that the wildcard (*) data type on father allows you assign any object you may wish to reference, as your own version may not have the playlist as a child of the Application display stack.

The play_list requires an associate designed to listen to the user selecting a song for play. The Event.CHANGE object is provided to respond to this sort of interaction with play_list. The Event.CHANGE event is dispatched when a user interacts with the list (by selecting a song). The listener method, changeEventHandler(), takes the Event.CHANGE object as an argument and responds to the requirements of the user. The event listener method, changeEventHandler(), is provided with a series of arguments to manage the choice of song to be played. Simply put, this part extracts the name of the selected song from the event object, which passes the value when the method is fired. The extracted name is assigned to a local variable, selectedSongs, which in turn is passed to the Application component method, playSong. The method changeEventHandler() is defined below:

 

public function changeEventHandler(event:flash.events.Event):void { var selectedSong:String = event.currentTarget.selectedItem.label; var selectedSongType:String = event.currentTarget.selectedItem.type; try { trace("Selected: " + selectedSongType) father.playSong(selectedSong, selectedSongType) } catch (e:Error) { father.writeln("ERROR!!"); } }

 

The NetConCalls class is now complete. It is shown in its entirety below:

package { import mx.core.Application; import flash.net.*; import flash.events.*; public class NetConCalls { private var _arr:Array; public function NetConCalls() { arr = new Array(); } public function setPlaylist(a:Array):void { var father:* =Application.application; trace(":::setPlaylist:::"); for(var i:int =0; i < a.length; i++) { getPlaylist().push({label:a[i].fileid}) } father.play_list.dataProvider = getPlaylist(); father.play_list.addEventListener(Event.CHANGE,changeEvent) } public function getPlaylist():Array { return getArray();; } public function getArray():Array { return _arr; } public function setArray(a:Array):void { return _arr; } public function changeEventHandler(event:flash.events.Event):void { var selectedSong:String = event.currentTarget.selectedItem["fileid"]; var songtype:String = event.currentTarget.selectedItem["type"]; currentSong = selectedSong; try { playSong(selectedSong, songtype) } catch (e:Error) { trace("ERROR!!") } } } }

Check your application code to make sure it looks like the example above.

The NetConStreams class

The main function of this tiny class is to give you some information from the MP3 being played. It accesses the metadata of the MP3 file and prints the information on the screen by passing the metadata to a utility method called trace(). The method writeIn() is declared inline within Application. You set this class up in the same way you set up NetConCalls.

The NetConStreams class is defined below:

package { public class NetConStreams { import mx.core.Application; import flash.net.*; import flash.events.*; public function NetConStreams() { trace("::::NetConStreams:::") } public function onMetaData(info:Object):void { trace("metadata: duration=" + info.duration + " width=" + info.width + " height=" + info.height + " framerate=" + info.framerate); } } }

Take a moment now to reflect on the work you've done so far. You've set up the classes required to connect to and interact with Flash Media Interactive Server from the client side of your audio playlist application. You're well on your way, so turn your attention now to playing the MP3 or AAC files.

Controlling audio playback

This section of the tutorial discusses the processes needed to control the playback of your songs in the audio playlist application. If you step back a few lines in the code, you will remember that the NetConCalls method setPlaylist() has the following statement:

father.play_list.addEventListener(Event.CHANGE,changeEventHandler);

 

This particular code assigns the changeEventHandler() method as the event listener for the Event.CHANGE broadcast by the play_list control when a list Item is selected. The method changeEventHandler() allows us to play the song selected by firing the playSong() method:

 

father.playSong(selectedSong, songtype);

 

Now it's time to create this method. Write the code for the playSong() method underneath the netStatusHandler() method. Before you do that, set up getter/setter methods to help you retrieve the name of the song and the format of the song you want to play:

 

public function set currentSong(s:String):void { _cs = s; } public function get currentSong():String { return _cs; } public function set songtype(s:String):void { _type = s; } public function get songtype():String { return _type; }

Next add the statements for the playSong() method, as shown below:

public function playSong(song:String, type:String):void { trace(":::play song:::::"); currentSong = song; songtype = type if (songtype != "mp3") { getNetStream().play("mp4:"+currentSong+"."+ songtype); } else { getNetStream().play("mp3:"+currentSong); } getNetStream().bufferTime = 10; }

Whenever the playSong() method is called, it takes the arguments passed though its song and type parameters to the currentSong setter method. Your instance of the NetStream class is passed the currentSong as the argument for its play() method. NetStream deals with playback of MP3 formats and AAC formats differently.

To play MP3 formats, the string "mp3:" must be concatenated as a prefix to the song name without the file extension, as shown below:

getNetStream().play("mp3:"+currentSong);

 

To play AAC-encoded files, the string "mp4:" must be concatenated as a prefix to the song name with the file extension as shown below:

 

getNetStream().play("mp4:"+currentSong+"."+ type);

 

The NetStream buffertime property is then set to 10seconds. NetStream.buffertime sets up a buffer with some of the selected MP3 file's data before playback.Setting up a buffer is important due to the size of the files requested forplayback. By default, a buffer (which you can think of as a little store ofdata) is set up before playback of any data by the server. If a buffer is notset, there is a high probability that the default buffer will empty while thesong is playing. This will cause the playback of the audio to stutter becausethe server needs to replenish its buffer in order to continue. In the meantime, getNetCon() calls the method accessStr() on the server and sends it the argument currentSong.Once the buffer is loaded, the song plays.

Controlling playback with the ButtonBar component

Now that you can play the audio, it's time to add a little functionality to the playlist. You will use the ButtonBar control to give the playlist "Play," "Pause," and "Stop" functions. To do this, you need to write an event listener to respond to clicks from ButtonBar:

 

private function clickHandler(event:ItemClickEvent):void { trace(":::click handler::::"); trace("Selected button label: " + event.label); var btnlabel:String = event.label; switch(btnlabel) { case"Stop": getNetStream().close(); break; case"Pause": getNetStream().togglePause(); break; case"Play": if (songtype !="mp3") { getNetStream().play("mp4:"+currentSong+"."+ songtype); } else { getNetStream().play("mp3:"+currentSong); } break; } }

The development of the client side of the audio playlist application is now complete. In the next section, you'll take a look at the server side and see how it runs and interacts with your Playlist client.

Server-side development

The server-side logic acts like a croupier in a card game, dealing out song list cards to the client card players. The client connects to the server, the server accepts the client and allows the connected client to communicate with the server. The client sends a request to the server for the list of songs. The server then checks to see if there is a list. This data is stored in an XML document accessible to the server. If the XML document exists, the data is retrieved and the list is sent back to the client. The client can then create NetStream objects to play back its audio streams.

It's time to register the application on the server. Every Flash Media Interactive Server application begins as a unique folder created in a designated directory for locating applications on the server. The application has to be registered on the server in order for the server to recognize it as a legitimate server application. After the required application folder is created in the designated applications folder, it is considered registered.

The registration procedure makes an application a legitimate Flash Media Interactive Server structure capable of interacting with clients requiring its service. By default, Flash Media Interactive Server has a generic designated folder where all legitimate applications are listed: "applications." The applications folder is analogous to the web root folder of a web application server, where files and folders for HTTP access are placed. In the case of Flash Media Interactive Server 3, all folders accessible to RTMP (Real Time Messaging Protocol, used by the server to communicate) are placed in this folder.

To create an application, a folder named after the proposed application is created in the applications root folder of Flash Media Interactive Server. If an application requires server-side scripting, scripts are placed within the named application folder. Server-side scripts are written in Server-side ActionScript (SSAS), a language based on the ECMA-262 specification.

Navigate to the default application folder of your Flash Media Interactive Server installation to find the folder called "applications." Open this folder and create a new folder called flexplaylist. If you run the client of your client application now, you will be able to make a successful network connection to the server. However, you will not be able to play back any songs yet because you have not yet added the code to manage the data flow and control. This is the next step.

Server-side ActionScript files in Flash Media Interactive Server are called ActionScript Communications (ASC) documents. They can be recognized by their .asc file extension. (Such ASC documents can also be written as JavaScript files with the .js extension.) Every scripted Flash Media Interactive Server application has a main application logic document that manages the execution of application instructions from the server environment. This script is always named either main.asc or application_name.asc.

Although you can create your ASC files in Flex Builder 3, they are not natively recognized by Flex Builder. So you will need to do a custom setup (by installing plug-ins for the Flex Builder 3 Eclipse framework) to support JavaScript. Alternatively, you can write ASC files with Dreamweaver CS3 or Flash CS3 Professional, as both of these IDEs natively handle the ASC format. Dreamweaver CS3 has built-in color coding and code hints. (FlashDevelop and Notepad provide alternative options for creating ASC files.)

Whatever you choose to use, create a new file and call it either main.asc or flexplaylist.asc. Save this file in the flexplaylist folder you created within the Flash Media Interactive Server applications folder.

The Flash Media Interactive Server scripting API has an Application class, which is the base class for every Flash Media Interactive Server application created. This class allows or refuses connections from the client. It deals with connected clients and orchestrates events and communication for the application. Begin the server script by accepting a NetConnection from a client:

 

application.onConnect = function(newClient) { this.acceptConnection(newClient); trace("client accepted");

 

Now you need to get the playlist. Within your application.onConnect() method, assign the list of songs to a variable plist:

 

var plist = newClient.getPlaylist();

 

This next line sends the information back to the setPlaylist() method in the connected client application:

 

newClient.call("setPlaylist", null, plist); }

 

Going back to the first instruction, var plist = newClient.getPlaylist(), create the code for the getPlaylist() method. This is a method of the Client object:

 

Client.prototype.getPlaylist = function() { var cpath = "playlists/myplaylist.xml"; var cList = new File(cpath); switch (cList.isFile) { casefalse: trace ("We do not have a playlist") //music_lover.call ("pleaseRegister"); break; casetrue: trace ("We have a playlist") cList.open( "text","read") var mStr = cList.read(cList.length) var mXML = new XML(mStr); mXML.ignoreWhite = true; mXML.parseXML(mStr); var mPodclientArr = []; for (var i =0; i<mXML.firstChild.firstChild.childNodes.length; i++) { trace (i+"[::::::>"+mXML.firstChild.firstChild.childNodes[i].attributes.fileid); mPodclientArr.push({fileid:mXML.firstChild.firstChild.childNodes[i].attributes.fileid,type:mXML.firstChild.firstChild.childNodes[i].attributes.type}); } return mPodclientArr; break; default: // if the default Radio Playlist information is created get it break; } }

The Client class of the server API represents each unique client connected to the server. This instance of an individual client facilitates the processing of unique requests to and from the server. The Client class is dynamic, making it possible to create custom methods on the Client class to fire unique instructions. This is accomplished by using the Client prototype property as the framework for developing these custom methods.

Review the code you just wrote. First you create a method getPlaylist on the prototype object of the Client class.

Note: The File class in Flash Media Interactive Server 3 makes it possible for applications to write to the server's file system. This is useful for storing information without using a database server, creating log files for debugging, or tracking usage.

In this case, you will use the File class to check if there is an XML file with the data you need. This class can also write to the system disk, so you can even create the needed XML file if so desired.

Assign the path of the XML file that will hold your data to a local variable named cpath. You have not created this variable yet, so don't worry if you looked at your code and noticed it was missing. You'll create the variable in a little bit.

For the moment, assume you have created an XML file and that it is located in the folder called "playlists". The XML file will be called playlist.xml. The next step is to create a new instance of the File class and pass it to the XML document path as its argument. The File class instance uses this argument to check for the existence of the XML file, using the Boolean property, File.isFile. If the file exists, the instance of the File class reads the file and returns the length of the file.

Unlike Array.length, the File.length property returns all the bytes in the file. To say it a different way, the File.length property contains everything written to the file (your XML document in the string). After it retrieves your XML document in a string, simply pass it to an XML class instance. Then you can use a for statement to loop through your instance of the XML class. The XML object, mXML, processes the nodes in the XML document and pushes the attributes field and fileName to an object that is assigned to an index in the array, mPodClientArr. This array is what is assigned to the variable plist in line 2 of your server code. The server immediately sends the array plist, which has all the information about the songs on the playlist, back to the client using the third line of your code, like this:

 

newClient.call("setPlaylist", null, plist);

 

This line provides the callback on the client, setPlaylist, which is a method of your class NetConCalls. This is the argument that populates your List component named play_list.

You are really close now. All that remains is to create the XML document. Open Notepad and type the following:

 

<playlist> <listheader id="aYo's Groove"> <music fileid="Snoop_Doggy_Dogg_-_Tha_Dogg_-_11_.2_Of_Amerikaz_Most_Wanted" type="mp3" /> <music fileid="Fort_Minor_-_The_Rising_Tied_-_07_.In_Stereo" type="mp3" /> <music fileid="Fort_Minor_-_The_Rising_Tied_-_09_.Cigarettes" type="m4a" /> <music fileid="Fort_Minor_-_The_Rising_Tied_-_13_.Kenji" type="mp4" /> </listheader> </playlist>

You can use this XML file as a template. Replace the music with any songs you'd prefer, as long as they are MP3 files. Simply replace the strings in the fileid attributes with your own MP3/AAC filenames to populate the playlist in your audio playlist application. Put the file extension in the type attributes in place of the .mp3 suffix when referencing the audio files.

That's it! Run your playlist application and enjoy. You can find a modified version of the application at ayobinitie.com/streamer/.

 

Where to go from here

I recommend you check out the following articles and resources to get a better understanding of building streaming media applications.

 


 

More Like This