Publishers of technology books, eBooks, and videos for creative people

Home > Articles > Web Design & Development > Adobe Flash

  • Print
  • + Share This

Server-Side Objects

SSAS has many of the same communication object models that you have become familiar with in Flash—NetConnection, Stream (also known as NetStream), and SharedObject—with two additional objects—Application and Client. Flash ActionScript uses these objects to connect, stream, and share data with the server. The server can also use the objects to connect, stream, and share data with other Flash Communication Servers or application servers connected to databases. Flash Communication Server ships with two additional libraries—Components (components.asc) and NetServices (netservices.asc)—that add a number of other objects to SSAS. When loaded, these extra objects become available to handle the Flash UI components and Flash Remoting MX. Let's review each object individually.

NetConnection (SSAS) Object

There exists no relationship between the server-side NetConnection object and the client-side NetConnection object. A client connection with a Communication Server accesses the Application object to handle connection events. NetConnection (on the server) is used to connect to servers. These servers can include other Application instances on a local server or an Application instance on a remote server.

Much like the client-side NetConnection, this object has all the same methods, properties, and events. These features allow you to connect and call methods on other communication or application servers and handle any status changes just like a Flash client would. In essence, when you use the NetConnection on the server, your server becomes a client.

Connecting with other Application instances on the same Flash Communication Server or servers that are remote is just as simple as connecting the Flash player with the server. When you use NetConnection, the receiving server (or Application instance) handles the server as another client, using the events in the Application object on the called server.

Exercise 11.1: Calling an Application Instance from SSAS

This exercise will have your Flash movie call the instance myInstanceName from the SSASTests application. A value will be passed invoking the server to call another instance of the same application using the NetConnection object in SSAS.

The exercise will show how you can connect to another Application instance from SSAS, but the same technique can also be used to connect with a remote Flash Communication Server:

  1. Create a new folder called SSASTests in the FlashCom applications folder.

  2. Open a new file in Flash MX.

  3. Open the ActionScript panel (F9).

  4. Enter the following script on Layer 1, Frame 1:

    nc = new NetConnection();
    nc.onStatus = function(info) {
       trace("LEVEL: "+info.level+" CODE: "+info.code);};
    nc.connect("rtmp:/SSASTests/myInstance", "kevin", "bird");
  5. Save your Flash movie.

When the username "kevin" is passed through the .connect method, it triggers the server to connect again to a different instance name, myServerInstance. This time, a different username is used so the server won't enter into an infinite loop. If you pass the same username, the server will continue to connect to itself and you will probably bring down the server. (This is said out of experience.)

Follow these steps to create the SSAS connection when the username, "kevin," is received:

  1. Create the main.asc file in the SSASTests folder.

  2. Add the following script to main.asc:

    application.onConnect = function(clientObject, username) {
       // ** ACCEPT THE CONNECTION **
       application.acceptConnection(clientObject);
       // ** CONNECT TO A NEW INSTANCE IF USERNAME == "kevin"
       if (username == "kevin") {
          trace("the Server is connecting");
          nc = new NetConnection();
          nc.onStatus = function(info) {
             trace("LEVEL: "+info.level+" CODE: "+info.code);
             if (info.code == "NetConnection.Connect.Success") {
                -trace("you Connected - Great! Go get your self _something nice");
             }
          };
          nc.connect("rtmp:/SSASTests/myServerInstance", "notKevin");
       } else {
          trace("the Server is NOT connecting");
       }
    };
  3. Save the main.asc file.

As you can see, there is an IF statement embedded within the .onConnect event that monitors the username value for "kevin." If the value matches, a new NetConnection is invoked with a trace informing you that it is connecting. Follow these steps to test your application:

  1. In Flash MX, open the Communication App Inspector (in the Window menu).

  2. Test your movie (Ctrl+Enter).

When these scripts are tested with Flash MX, a review of the App Inspector will show two instances of the same application running (see Figure 11.2).

Figure 11.2Figure 11.2 The App Inspector displays the Application instances that are active on the server.

Now, monitor the trace activity as it happens in the Live Log:

  1. Close your test movie in Flash MX. (Leave the FLA file open; you will be testing it again.)

  2. Select the myInstance instance in the App Inspector and click View Detail. Because myInstance is acting as a client, trace actions are output to its Live Log.

  3. Test your Flash movie (Ctrl+Enter) again while monitoring the Live Log window.

You will see the trace information including the onStatus trace in the Live Log window. Figure 11.3 demonstrates the output created by this application's instance. If you do the same with the other instance, you will not see the onStatus output, because a NetConnection is not being established from that instance.

Figure 11.3Figure 11.3 Watch your application's trace activity in the Live Log window. You must first have an instance running before you can access this window. Use the Reload App button to watch traces when the application loads.

Although this may seem an impractical exercise, it demonstrates the ease of connecting with another server. Where the IP address (192.168.0.1) is mentioned, replace that with a proper URI of a remote Flash Communication Server.

Application Object

The Application object contains methods, properties, and events that give you control over a connection invoked by a Flash client and also provides information about the Application instance. Application instances, as you read earlier in this chapter, are loaded when called by a client or through the App Inspector. Each method, property, and event is specific only to the instance, and has no relationship to other instances running on the server.

The Application class is one that you will use most often. Application events handle NetConnection commands from a Flash client or another connected Flash Communication Server. The Application methods offer control over the maintenance of your application, such as cleaning up SharedObjects or streams that weren't closed properly. There are also methods to manage class registration or proxy a remote NetConnection.

When the NetConnection.connect method is called by a Flash client or another server, there are two events that could be triggered. If the Application instance hasn't been loaded, the event Application.onAppStart is called before any other function. After the instance is loaded, every client connecting triggers the Application.onConnect method. This is a function primarily used to assemble any authentication scripts or prepare unique objects, such as streams or SharedObjects. The most important aspect of the onConnect is to accept or reject a connection request. Like all ActionScript events, you are required to overwrite both the onAppStart and onConnect events.

You can create any additional properties or methods within the application scope. These methods and properties are available to each client that connects to manage the details of the Application instance.

Exercise 11.2: Authenticating a User

A common use of the onConnect method is accepting or rejecting a connection. You have seen this event at work in earlier chapters when you scripted a connection to the Communication Server. This exercise will manually populate an array of usernames and passwords when the application starts. Flash Communication Server uses this array to challenge a login and password sent from the Flash player and decides to accept or reject the connection. To authenticate a user, follow these steps:

  1. Create a new folder in the Flashcom Applications folder called mySecureApp.

  2. Create an empty main.asc file within the mySecureApp folder.

  3. Add the following script to the main.asc file:

    application.onAppStart = function() {
       -// define the array of users that will be authenticated to use _this application
       user_array = [];
       user_array.push({uname:"kevin", password:"bird"});
       user_array.push({uname:"colin", password:"tank"});
       user_array.push({uname:"sharon", password:"craft"});
       user_array.push({uname:"sandy", password:"car"});
    };

You have just overwritten the onAppStart method for this application. This script runs only once when the application is instantiated. For those of you who might be wondering, "This is a strange way to declare an array," this array is known as an associative array or an array of objects. You might also notice that instead of using new Array when declaring the array, a double square bracket is used to declare an empty array ([]). The array of objects operates very similar to a database record set, which is a little foreshadowing to Chapter 13. This associative array is used as a data store by the onConnect method to ensure each person accessing the application has a valid login and password.

For a Flash client to connect to the application, the connection must be "accepted." You can accept connections using the methods Application.acceptConnection or Application.rejectConnection. Combining these methods with the onConnect event is the most common use.

The NetConnection call from a Flash client sends the login and password as custom parameters of the .connect method. They are handled by the onConnect method. You use those values to match against the data in the array. These next steps will construct the authentication script inside the onConnect handler:

  1. Below the onAppStart function, add the following script to overwrite the onConnect method:

    application.onConnect= function(clientObject, username, password) {
       -// Loop through the array to challenge the username and _password passed
       through the connect
  2. Declare a variable called isAuthenticated to false. You use this to store a successful match in the array loop:

       var isAuthenticated = false;
  3. Create an array loop that steps through the array trying to match the username and password combination. If the challenge is true, isAuthenticated will be true, and the loop will break out:

       for (uname in user_array) {
          trace("testing" + uname);
          var thisUSR = user_array[uname].uname;
          var thisPWD = user_array[uname].password;		
          var challenge = (username == thisUSR) && (password == thisPWD);
          if (challenge) {
             var isAuthenticated = true;
             break;
          }
       }
  4. When the loop has finished, a second challenge of the isAuthenticated variable accepts or rejects the connection. This is the end of the onConnect function, so make sure the closing bracket is included:

       // Accept/Reject the Connection
       if (isAuthenticated) {
          application.acceptConnection(clientObject);
       } else {
          application.rejectConnection(clientObject);
       }
    };

This may look a little complicated, but it really isn't. You can immediately see that this method is set up to receive three parameters:

  • clientObject

  • username

  • password

You can have as many parameters in this method as you need; however, you must always pass the clientObject to assign this client to the application. The bulk of the work is done by the looping through the array of objects. The username and password are transferred into temporary variables on each loop. A challenge looks for a matching username/password combination. Each loop sets the challenge variable to false until a correct match is found. The loop breaks out with a correct match, setting the isAuthenticated variable to true. After the loop, the isAuthenticated variable is challenged, and if it is true, the application accepts the connection. This changes the status of the connection and triggers the NetConnection.onStatus function on the Flash client (not shown here).

The Flash player does not have an interface for this exercise. Instead, you hardcode the username and password values. The values are passed to the .connect method as extra parameters. Let's script the call that the Flash player will make:

  1. Open a new Flash movie within Flash MX.

  2. Add the following script to Layer 1, Frame 1:

    nc = new NetConnection();
    nc.onStatus = function(info) {trace("LEVEL: "+info.level+" CODE: _"+info.code);};
    nc.connect("rtmp:/mySecureApp/myInstance", "kevin", "bird");
  3. Save the Flash movie.

This script makes a connection call to the myInstance instance of the mySecureApp application. Because there is no Flash interface used in this exercise, you must monitor the trace activity of both the Flash movie and the server. You need the App Inspector window and the Flash MX output window. Follow these steps to manually load the application in the App Inspector:

  1. Open the App Inspector window in Flash MX.

  2. Load the instance manually using the App/Inst text input box on the main screen of the App Inspector. Enter mySecureApp/myInstance in the field, and click Load.

  3. Click the new active instance and select View Detail.

  4. Click the Reload App button to monitor the trace actions while the Application instance reloads.

  5. Test your Flash movie (Ctrl+Enter).

If everything is correct, your Flash MX output window should display a connect.success status message. Now, try a wrong username and password and test again to receive the connect.rejected status message.

The Application object also has application.onDisconnect and application.onAppStop events. When a user closes the browser, or disconnects the application, the onDisconnect method is triggered. When the server shuts down, or the instance is reloaded, the onAppStop method triggers. Try these out by placing the following functions at the bottom of your main.asc file, and then reload your application:

application.onDisconnect = function() { trace("Was it something I said?"); }
application.onAppStop = function() { trace("Thanks for all the Fish!"); }

If you know you will have multiple instances running within a single application, you could use the application.name property as a challenge to grant additional privileges to the user. The best place for this test is within the onConnect event:

application.onConnect = function(myClientObj) {
  -if (application.name == "SSASTests/underwear"){ trace("welcome to the _underworld!"); }
}

To get the most out of what the Application object can offer, review the Quick Reference guides in the appendices.

Client Object

By now, you have a good understanding of object-oriented programming (OOP) concepts. A key to understanding OOP is realizing that objects can be instanced (or instantiated). The concept of a prototype can be daunting at first; however, it is very straightforward. Each of the objects you have reviewed so far are prototypes. A prototype is like a stencil. In OOP, you prototype methods, properties, and events. Each object used is actually a prototype.

How does this relate to the Client object? Macromedia has taken the concept of OOP and related it to everything, as you saw with the Application object. When a client (Flash player) successfully connects to an Application instance, that client becomes an instance of the Client object on the server. The properties, methods, and events that are built into the Client class are instanced and now only relate to that Client instance. There is no connection to other instances. A quick example of this is the property Client.ip. This property exposes the IP address of the connected client to the server. This IP address is unique for each client that is connected to the Flash Communication Server. Similar properties are available to return the Flash player version and operating system for each client.

The Client prototype (or class or object) can be used to set permissions to access streams or SharedObjects, or set the limits on bandwidth.

Creating Custom Client Methods and Properties

You can create custom methods and properties within the Client instance. When you do this, the Flash client can access server-side methods and properties. Using the NetConnection.call method in Flash MX, you can invoke methods that have been defined in that Client's instance. There are some tricks to this, however. First, you can only create Client methods and properties after the client's connection has been accepted, using the Application.acceptConnection. This is because there has been no instance of the client until it has connected. After the connection has been accepted, you can then set new functions that can be called by the Flash client. The following example shows a custom function, called hello, that can be accessed by the client after the connection has been accepted:

ClientObj.hello = function(name){
return "hello from the server, "+ name;
}

This function must be declared after the connection has been accepted. To access this function in Flash, use the NetConnection.call method. This function takes one parameter.

nc.call("hello", new eventHandler, "Kevin Towes");

Remember that this function is not available until the server has accepted the connection and created the Client object. To test this, place the client-side code within a nc.onStatus handler.

Exercise 11.3: First Contact

This exercise will step you through Flash ActionScript that will call and handle a function defined on the server. To make things more interesting, the server will also call and handle a function defined in Flash ActionScript. So, there will be a function on the server called sayHelloServer and a function on the client called sayHelloClient. Each of these functions will have a trace function that will show up in the respective trace output windows.

This is a brain teaser, so let's walk through it. When the Flash client calls the server function, the App Inspector's Live Log will display a message that was set on the server. When the server calls the Client function, the Flash MX output window will display a trace in its output window. Let's go one level deeper and send an object from the server to the client. We'll start on the server in SSAS, and then move to Flash MX to script the client:

  1. Create a new folder in the Flashcom/Application folder called myHello.

  2. Create a new main.asc file.

  3. Add the following onConnect handler to the main.asc file. This script automatically accepts all incoming connection requests and instantiates the Client instance:

    application.onConnect = function(clientObject, username) {
       application.acceptConnection(clientObject);

    After the Client object has been instanced by the Application.acceptConnection, you can now start declaring new functions the client can access.

  4. Create a new function called sayHelloServer in the Client instance clientObject. Place a trace action and a return object (in this case, just a string):

       // Define a function for the Client to Call - send him an object 
       clientObject.sayHelloServer = function() {
          -trace("The client says How Ya Doin, Bucko.. Got Somthin' _for ya!");
          return ("FlashCom Server Rocks!");
       };
  5. Call the function sayHelloClient that you will script in Flash MX:

       // invoke the function on the Client 
       clientObject.call("sayHelloClient");
    };

That's it! As you can see by this example, you must declare custom Client functions after the client has connected. As your functions get more complex, you may find it easier to move them outside the onConnect event and into another function. Now, on to Flash:

  1. Open a new Flash movie in Flash MX.

  2. Open the Actions panel on Label 1, Frame 1.

  3. Create a new NetConnection object:

    nc = new NetConnection();
  4. Create the onStatus function for the NetConnection, and place a challenge on the returned status .code. If the connection is successful, call the server function sayHelloServer. Remember, server functions are casE SensItivE:

    nc.onStatus = function(info) {
       trace("LEVEL: "+info.level+" CODE: "+info.code);
       if (info.code == "NetConnection.Connect.Success") {
          // Call the Server
          nc.call("sayHelloServer", new server_ret());
       }
    };

In the nc.call, there is a new object instantiated called server_ret. A function that is called over a NetConnection may not return its results immediately. To compensate for this, an object to receive and handle the result or error must be created for each server function you call. This is called the result object, and it can contain two functions. The onStatus function is invoked if there was an error with the function. The onResult function handles successful function calls. Here is the script to handle a successfully returned function; add this code below the nc.OnStatus function:

// handle any objects returned from Flash's call to the server
server_ret = function () {
   this.onResult = function(value_ret) {
      trace("Message From the Server: "+value_ret);
   };
};

The server returns an object that contains a string value. The returned value is captured in our variable value_ret. This can be any variable name you want. We are only going to use the value to trace it to the output window.

Declaring a function that the server can invoke is simple. You define it as a NetConnection method. The server cannot call a function that is not declared in the NetConnection instance. The following traces output to the Flash MX output panel when it is invoked:

  1. Add this line of code to the bottom of your ActionScript panel to define the function sayHelloClient within the context of the NetConnection:

    // define a function on the NetConnection that will be called by the server
    nc.sayHelloClient = function() {
       trace("The Server says.. Yo, Dude!");
    };
  2. Connect the NetConnection to the Communication Server to start the show:

    nc.connect("rtmp://192.168.0.1/myHello/myInstance");
  3. Save the Flash file.

Now, you are ready to play. To watch the action, you must have the output window in Flash MX open (F2) and the App Inspector ready. If you want, manually load the Application instance in the App Inspector, or you can wait until your Flash test movie creates the instance. Test your movie using Ctrl+Enter. Your output windows should look something like Figure 11.4.

Figure 11.4Figure 11.4 The App Inspector displays the Application instances that are active on the server.

Extending the Client Class

What if you want to create a function on the server that all clients can have access to? You can do this by adding a method or property to the Client object prototype. This is called extending the class.

This example will extend the Client class with a new method called setConnectTime. It will first check to see if the property connectTime is defined, which it won't be, and then it will set it to the current date and time. You try this code using the previous exercise. Place it at the bottom of your SSAS in main.asc:

Client.prototype.setConnectTime = function() {
   if(this.connectTime == undefined) {
    this.connectTime = new Date();
}
return this.connectTime
}

This is now a global method to the entire Client class, just like the Client methods. To use this method, place the call in the onConnect event. This example uses the instance name clientObject, so you could place it in the previous example:

clientObject.setConnectTime();

A new property called connectTime is set. When accessed, it returns the date and time the client connected. As you have already seen, all Client methods within the Client class can be accessed by the Flash client, including this new prototype. You can try it by adding the following line to the onStatus function in the previous exercise:

nc.call("setConnectTimes", new server_ret());

This traces the server time you connected in your Flash MX output window.

Client Object Security and Permissions

One last technique to note is the capability to assign read and write permission to streams and SharedObjects. There are two properties used for this: Client.writeAccess and Client.readAccess. These properties both work on the principle of file access. By default, when a client connects, it is given read and write access to the entire instance. This means it can publish and subscribe to streams, or read and write any SharedObject accessible to the Application instance. You can handle security by setting up different access levels to your SharedObjects and streams. This will be covered in the next two sections; however, this is a good introduction. Let's say you create a SharedObject that you only want the server to write to, but everyone can access it and "listen" to changes made to it. You would set up the SharedObject on the server like this:

server_so = SharedObject.get("mySecureFolder/mySharedObject",true);

Notice the use of a folder here. This actually translates on the server as a folder name, but more importantly, it is an access level. Streams are the same; for example:

myStream = Stream.get("mySecureStreams/myStream");

Now you have two access levels you must lock out: mySharedObject and myStream. To achieve this, you simply set the Client properties when they connect. The following script would allow all clients to read and listen to all resources available; however, the client could only create resources (SharedObjects and streams) in the /pub folder:

application.onConnect = function(clientObject, username){
   clientObject.writeAccess = "/pub";
   clientObject.readAccess = "/";
   application.acceptConnection(clientObject);
}

You can create a list of folders by separating them with a semicolon (;). In the preceding script, a client can only publish a SharedObject in the /pub folder (or access level). The ActionScript on the client would like this:

flash_so = SharedObject.get("pub/mySharedObject",true);

As you can see, the Client object is a great tool to communicate between client and server. Understanding the concept of the instance is the key to the entire Flash Communication Server. Next, you will review the Stream object. Keep in mind that you will instance the Stream class each time you want to use it.

Stream Object

The Stream object is a powerful object that can be used to manage streams coming in and going out from the server. As you have already seen with the client-side NetStream object, a Flash Communication Server stream is a one-way feed of video, audio, or a combination. Communication Server clients can connect multiple streams to a single connection; however, each stream must either publish content to the server or subscribe to content from the server. Streams are collected on the server within an Application instance. They can be prerecorded or live.

Obviously, you cannot watch or listen to a stream on a server, because there is no interface! So what can you do with SSAS and streams? The server can do a number of unique operations that cannot be done on the client. Because of its position in the network, the server maintains priority control over all streams. This means that it can cancel or overwrite any stream. Some roles that SSAS can take with the Stream object include chaining servers together, acting as a video switcher between live and/or recorded video sources, streaming a play list, or recording a play list or live stream that wasn't set to be recorded by the publisher.

A key difference between the server-side Stream object and the client-side NetStream object is the play() function. The play() method on the server is similar to the publish() method on the client. The play() function publishes content to a stream. You might ask, "If the server does not have a video or sound device, how can it publish?" The play() function takes its video sources from one of two places: prerecorded Flash video (FLV) or live streams being published by a client.

Consider the play() function as a play list that can control what a stream is sending. Let's say you have three prerecorded Flash videos that you want to sequence together. video1.flv would play for 10 seconds, then video2.flv would play for 10 seconds, and then video3.flv for 10 seconds. Using multiple play() functions in SSAS makes it easy to build this sequence. Here is some sample script that would achieve that:

startStream = function(){
  // Create the stream 
  var my_stream = Stream.get("serverStream");
  // Start the playList
  my_stream.play("video1",0,10);
  my_stream.play("video2",0,10);
  my_stream.play("video3",0,10);
}

When the function startStream is called, the stream serverStream is created, and the play list begins. This play list starts immediately, even if no client is connected. The stream is running in real time. If a client subscribes to the stream 15 seconds after the function was called, the client would start in the middle of video2.flv.

You could also do this with a live stream. Let's say you want to play video1, then video2, and then switch to a live stream. The script would look very similar, except video3 would be replaced with the name of the live stream being published to the server by a client. Take a look:

startStream = function(){
  // Create the stream 
  var my_stream = Stream.get("serverStream");
  // Start the playList
  my_stream.play("video1",0,10);
  my_stream.play("video2",0,10);
  my_stream.play("someClientStream",0,-2);
}

The play() function has similar parameters to the client side. The first parameter is the stream name. This can be the name of a live stream being published by a remote client or server. startTime is the next parameter. With a recorded stream (FLV file), this references the start time in seconds to begin the stream. If you are referencing a stream that is being published by a client, there are two values you can use. If startTime is set to a value of -1, Flash Communication Server tries to connect to a live stream published remotely. If the stream does not exist, it waits until the stream is created by the publisher. If you set the value to -2, Communication Server attempts to look for a prerecorded FLV video on the server with the same name. If there is no live stream and no recorded file, Communication Server creates a stream and waits for someone to publish to it.

The –2 option is great if you are preparing a live broadcast and need to have some filler while the stream is being set up. The reset parameter follows the startTime and expects a Boolean value. It clears the stream if it is set to true. The last option allows the play function to source a stream from a NetConnection to another server. This is a key element for chaining servers together. Let's look at some scenarios of how you can use the Stream object, including chaining servers to increase user and bandwidth capacity.

Live Video Switcher

As you saw, the Flash Communication Server can switch between live and recorded streams using a preset play list. This is a great technique, but you may find you want some additional control over what subscribers are seeing. At this point, you will have to create some sort of Switching interface in Flash MX.

Figure 11.5 represents a scenario of four live streams being published to Flash Communication Server by four separate Flash clients. The Flash clients that are on the receiving end are only receiving one stream. Using SSAS, you could automatically cycle the source of the outbound stream from any of the four inbound streams similar to the previous example. This would be great with a security-camera application that required you to cycle between a number of video sources. However, you want more control over when the streams are switched.

Figure 11.5Figure 11.5 In this situation, each subscriber would require only one stream to be connected to the server, not four. As interesting as this is, it wouldn't have much practicality in a real-world communication situation.

A better solution would be to build a Flash application that could control the SSAS and allow you to manually "switch" between video sources. Figure 11.6 isn't real, but it demonstrates how you could build a Flash-based video switcher to control what the live stream is.

Figure 11.6Figure 11.6 A fictitious Flash video switcher application that will control the play list on the server.

In this example, there are four live streams and one prerecorded advertising stream. The operator of this interface can control what is being sent to the server stream.

Chaining Servers

Chaining servers is a great technique for distributing the load on your server. If your Flash Communication Server license only allows 10 users and you need 15, you can use this redistribution technique. The Flash Communication Server is a point-to-point network. This translates into the server reserving enough bandwidth for each user subscribing to a stream. This is different from a satellite TV approach, which uses a point-to-multipoint connection. With satellite TV, the broadcaster sends out its signal and, it doesn't matter how many people are watching it, there is no additional load on the satellite if one person is watching or one million people are watching.

When you chain servers together, you can increase the number of users that can watch your stream, and you increase the bandwidth available. In Figure 11.7 there are three servers chained together. Each server has a 10-user license. This would allow a total of 24 Flash players to connect to the live stream. Each server would reserve one publish stream (outbound) for another server. Each server would use another stream as its subscription (or inbound) stream.

Figure 11.7Figure 11.7 The Flash Communication Server can be chained with other servers to increase bandwidth and user capacity.

A fictitious Flash video switcher application will control the play list on the server.

You can achieve this very easily. First, you need to connect the server to another server, and then you simply connect the play function to a remote server stream. Let's use the same script from the earlier example, but this time, video 3 will be sourced from another Flash Communication Server stream:

startStream = function(){
  // establish a NetConnection to a remote application instance that
  // is streaming.
  nc = new NetConnection();
  nc.connect("rtmp://[remote server]/[remote app]/[remote instance]");
  // Create the stream 
  var my_stream = Stream.get("serverStream");
  // Start the playList
  my_stream.play("video1",0,10);
  my_stream.play("video2",0,10);
  // receive the 3rd video from a remote server
  my_stream.play("someOtherServerStream",0,-1, false, nc);
}

As you can see, the syntax is not that complex. Sourcing streams is another great feature of Flash Communication Server.

Video Recorder

There is one more thing you can do with the Stream object: record. You can assemble a series of streams into a single recorded stream that can be played back without a play list. The record() method records the play list into a single FLV file, named with the stream name. In the following code sample, a file called serverStream will be created in the folder /myApp/streams/myInstance/ serverStream.flv:

startStream = function(){
  // Create the stream 
  var my_stream = Stream.get("serverStream");
  // Start the playList
  my_stream.record();
  my_stream.play("video1",0,10);
  my_stream.play("video2",0,10);
  // receive the 3rd video from a live source
  my_stream.play("someClientStream",0,-1);
}

Other Methods of Stream

Like the client-side NetStream, you can also invoke functions through the stream using the .send method. You can monitor buffer time and set the buffer time, just like on the client. Buffer time is the amount of memory allocated to preload a stream before it is played. You can also use the length function to determine the length of a prerecorded FLV file.

Stream is an integral part of the Flash Communication Server. It is very powerful and extremely scalable. Security is achieved as with SharedObjects through access levels, or folders. For more details on security, review SharedObject security in the next section.

SharedObject (SSAS)

The SharedObject programming model is clearly the most exciting and most powerful feature of the Communication Server. Some might consider the capability to stream video as the best part, but after you understand the power of SharedObjects, your imagination will work overtime with the possibilities. The server-side SharedObject is like the client-side SharedObject, with a few additional features.

A SharedObject stores two things: objects and methods. They can be accessed by any connected Flash or server client. These clients are completely synchronized with each other. Any client or server with appropriate permissions can change, add, or remove data. These activities invoke Flash Communication Server to announce the change to all connected clients. These clients respond to the announcement appropriately by refreshing their local memory cache of the SharedObject. Client-side functions can be invoked through broadcast messages over the SharedObject.

SharedObjects can be persistent or temporary. They can be created by the server or by a client connected to the server. SharedObjects can be locally owned or owned by another instance. This means that you can share data across instances and applications. If that isn't enough, you can also access SharedObjects owned by an instance on a different server somewhere else in the world! This is a technique called proxied SharedObjects.

These next few sections will introduce you to some advanced concepts of the SharedObject as it is accessed using server-side ActionScript.

SharedObject Slots

Data is stored in a concept called slots. Slots are name and value properties contained as attributes of the SharedObject.data property. This may be a little confusing at first, but when you get used to the idea, it makes a lot of sense. Consider the data property of a SharedObject like the _root of a directory. Within the root, you can create folders that contain files. Folders can also contain subfolders, and so on. Visualizing this tree will help you understand the concept. A slot can be any valid ActionScript object. This includes arrays, objects, recordsets, or even simple variables. The exercise in Chapter 8, "STEP 8: Collaboration with SharedObject()," clearly demonstrated simple name and value variables as independent slots of the data property. The user access array you created earlier in this chapter could be completely stored in a persistent SharedObject, if you wanted. Let's take a look at how you would do that.

This was the array you created earlier:

user_array = [];
   user_array.push({uname:"kevin", password:"bird"});
   user_array.push({uname:"colin", password:"tank"});
   user_array.push({uname:"sharon", password:"craft"});
   user_array.push({uname:"sandy", password:"car"});

Placing this array into a SharedObject slot is simple.

NOTE

Unlike the client-side method, in server-side ActionScript, you must use a setProperty method to add or edit slots. Here is some sample SSAS to add/edit a slot called user_array in the SharedObject secureData/systemObject:

MySystemObject_so = SharedObject.get("secureData/mySystemObject", true);
MySystemObject_so.setProperty("userData", user_array);

Reading SharedObject data also requires a unique method, getProperty. Here is an example of transferring the entire array from the SharedObject to a local server variable:

var myServerVar = MySystemObject_so.getProperty("userData");

SharedObject Synchronization

This all happens in real time through a powerful process of synchronization messaging. The Flash Communication Server sends messaging "objects" to each connected client and server. This object is an ActionScript array of objects called information objects. This is a similar concept you see with NetConnection or Stream. When data changes in the SharedObject, everything that is connected is informed of the data change by the Flash Communication Server. Data can be simultaneously changed, added, or removed by the server with SSAS, or by any number of connected clients using ActionScript or SSAS.

At first glance, it might seem very complicated, primarily because of the array of objects. The information object is handled on each client and the server by the onSync event. The process was demonstrated in Chapter 8 where there were multiple clients changing data at the same time.

The array can contain a batch of change events. It does not contain data. You are responsible for building a handler on the client and the server for the data change notifications. This might include transferring a SharedObject slot value to a local variable, or affecting an object appropriately. The array is useful (on the client) if it becomes disconnected and has to reconnect. Upon reconnect, the array may have a number of messages inside that it must handle.

The following onSync handler script template demonstrates how you can handle the information object both on the client and on the server. You must loop through the array and challenge and handle the code property on each loop. This template will handle the four possible cases of the code property:

this.so.onSync = function(info) {
  trace("Synchronizing Data");
  // 
  // Use this structure as a prototype for your onSync Handlers.
  // Loop through the Array of Objects using the IN operator
  // 
  for (name in info) {
      trace("[sync] Reading Array Object #"+name+"
      code("+info[name].code+","+info[name].name+")");
      // 
      -// ::: The following switch handles code values returned by the _object
      // Place Code Here
      //
      switch (info[name].code) {
      case "change" :
         trace("::Handle a change of data by another client");
         // Place Code Here
         break;
      case "success" :
         trace("::Handle successful change of data from this 
         server");
         // Place Code Here
         break;
      case "reject" :
         trace("::Handle a rejected SharedObject write operation");
         // Place Code Here
         break;
      case "clear" :
         trace("::Handle an initialization of the SharedObject");
         // Place Code Here
         break;
      case "delete" :
         trace("::Handle deleted Attributes");
         // Place Code Here
      }
      // ::: End the Switch, continue Looping through the Information 
      Object
   }
   // ::: Complete the onSync Handler
};

The whole synchronization process is explained in detail in Chapter 8.

SharedObject Security

You can control the security of SharedObjects using the Client properties Client.writeAccess and Client.readAccess. Review the Client object section earlier in this chapter for some example script. SharedObjects, like the Stream object, can be filed into access levels, or folders. This can only be done when they are first created.

For maximum security, creating a SharedObject on the server is the best practice. If you can, create the SharedObject on the application.onAppStart. Create a strategy for storing SharedObjects. For example, use a common folder for all sensitive SharedObjects and a public folder for all non-sensitive objects. Remember, you can have as many SharedObjects as you need. Don't try to place sensitive data in slots of one big general SharedObject. It just cannot be secured that way.

Proxied SharedObjects

SharedObjects can also exist within other Application instances, or even on different servers altogether. Connecting to a remote SharedObject from the server is a process called proxied SharedObject. The concept isn't that difficult to grasp. When an Application instance connects to a SharedObject within another instance or application local or remote, it makes that SharedObject available to all of its connected clients.

The process is similar to an Internet service provider, or your network router. When you dial up your computer to your provider, you have access to everything your provider is sharing. If you then have a router in your home or office, you redistribute that feed to workstations in your network. This can be called a proxy server. To connect, you must route your request through the proxy server. The Flash Communication Server Application instance is no different. When the SharedObject is connected, it is available to all of its connected clients, unless you have placed it within an access level (or folder). Connecting is simple.

First, you make a connection to a remote server, or Application instance, using the SSAS NetConnection object. This can be done in the application.onAppStart function. It is not recommended to have it within the onConnect, because each time a client connects, the server will reconnect. You could write some script that challenges the NetConnection.isConnect property. The following script uses this technique:

application.onAppStart = function() {
   nc = new NetConnection();
};
application.onConnect = function() {
   if (not nc.isConnected) {
      nc.connect("rtmp://[remote server]/[remote app]/[remote instance]");
      // - or - 
      nc.connect("rtmp:/[local app]/local instance]");
   }
};

When your server is connected, you then attach the SharedObject to the NetConnection instance. The following script is the exact script you saw in the preceding; however, it is not stored within its Application instance:

mySystemObject_pso = SharedObject.get("secureData/mySystemObject", true, nc);
mySystemObject_pso.setProperty("userData", user_array);

The suffix _pso was added to the SharedObject to signify proxy SharedObject. It is not required, but it helps you keep things straight.

SharedObject Methods

If you weren't impressed enough already by the SharedObject model, this might just add the cherry to the top. You can create ActionScript functions and assign them to a SharedObject. Think about that for a moment. If you can create a function and assign it to a SharedObject, that means a Flash player can invoke a function on another Flash player! SharedObject functions are primarily used for messaging. You cannot "call" a SharedObject function like you can a remote Flash function. You use the SharedObject's send method to invoke the function. You cannot create a SharedObject function using server-side ActionScript. It can only be created by the client, and the server doesn't receive any response from the client on success or failure of the send method; therefore, it is asynchronous.

To execute a SharedObject method on the Flash client using the send method, use the following code:

var my_so = SharedObject.get("SharedObjectFileName", true);
my_so.send("client-so-method");

Creating SharedObject functions will be covered in the next chapter; however, here's a sneak peak to create a SharedObject function on the Flash client:

   so=SharedObject.getRemote("myObject", nc.uri, true);
   so.connect(nc);
   so.data.myMethod = function() {
      trace("Hi There from your Friendly SharedObject.");
   };

SharedObject Locking

SharedObjects can be temporarily "locked" only by the server. Locking a SharedObject allows the server to perform operations on the SharedObject without triggering the onSync events for each player. Locking also allows you to ensure that there are no SharedObject write actions while the server does what you want it to do. During the lock, each change that is made is batched. Unlocking the SharedObject engages the batch to announce the changes to the connected clients.

There are two methods associated with locking: so.lock() and so.unlock(). Wrap your SSAS operations in these functions and you will execute a lock and release.

Other SSAS Methods Unique to the Server Side

Because the server-side version has direct access to the SharedObject, you can perform a few additional methods to the data such as some clean up methods like .clear, .purge, and .flush.

.clear deletes all properties (slots) of any a object. It doesn't take any arguments. This method is useful if you create a temporary SharedObject and want to clear all traces of it from the server. Here is the .clear method:

var my_so = SharedObject.get("SharedObjectFileName", true);
my_so.clear();

.purge is useful to clean up any empty properties or properties that are older than the current version (more on versions shortly). The flush function transfers the memory-version of the object to a file. You can only do this with persistent SharedObjects. The file is located in a SharedObjects folder within the Application folder. Like the Streams folder, this folder contains subfolders referencing any instance names of the application.

.flush forces Flash Communication Server to dump the memory version of a persistent SharedObject to the file version. It's like hitting the Save button when you are writing a book. This is a good habit to get into if the synchronized data you are storing is extremely important and a sudden server halt (such as a power failure or someone clicking that Halt button in the Administration Console) would kill the data. You can do it using the setInterval tag,or after a major operation such as a database query.

Flash Communication Server installs with two additional objects that are used with Flash Remoting MX. These two objects are NetServices and RecordSet. They are discussed in detail in Chapter 13, but we will make a brief mention of them here to keep everything together.

NetServices Object

Using the Communication Server, you can expose databases and other services to the Flash player. This is achieved through technology called Flash Remoting MX. Flash Remoting MX operates on the standard HTTP or secure HTTPS protocols using a binary format called Action Message Format (AMF).

The NetServices class contains the methods required to call services on remote application servers. Remote application servers can provide database access and access to other server-level resources such as email or LDAP.

Making a Flash Remoting MX call requires a server that is compatible with Flash Remoting MX. These servers are discussed in Chapter 13. NetServices gives you the tools to connect and call remote service methods that can return any ActionScript object including the new RecordSet object.

RecordSet Object

The RecordSet object is a series of 17 unique methods that give you familiar tools to interact with a database query result set. Using the concept of columns and rows, you can sort, get column names, and even search through the RecordSet easily.

RecordSet objects can be transferred into SharedObjects for distribution to connected clients. A complete breakdown of the RecordSet methods are included in the Quick Reference appendixes. Example applications using the RecordSet object can be seen in Chapter 13 and Appendix E, "Useful ActionScript Templates Quick Reference."

Timed Events Using Intervals

ActionScript intervals were introduced in Flash MX to allow Flash developers to schedule the call of functions at specific timed intervals. The functionality is also available within SSAS. Intervals on the server can be used fully to let you call functions that may clean up the SharedObjects with a purge() method, or flush() them periodically to the hard disk. You could also develop an interval to capture a still image of an incoming stream to create a time-lapse photography effect. Intervals are easy to set up. This example calls the captureMyCamera function every two seconds:

intervalID_itv = setInterval("captureMyCamera", 2000);

It is important to use a variable to run this setInterval function because setInterval will return an ID value that you need if you want to shut it off. When you are finished with the interval, you can clear it using the clearInterval function, referencing the intervalID used in the previous example:

clearInterval(intervalID_itv);
  • + Share This
  • 🔖 Save To Your Account

Related Resources

There are currently no related titles. Please check back later.