More Books
Flash Communication Server
Flash Communication Server
Table of Contents
Copyright
About the Authors
Brian Lesser
Giacomo
Joey Lott
Robert Reinhardt
Justin Watkins
Foreword
Preface
What Does FlashCom Offer?
What's in This Book?
How to Use This Book
Audience
ActionScript 1.0 Versus ActionScript 2.0
Server-Side ActionScript
The flash-communications.net Site
Director, Breeze, and Other Options
Flash Video Options
Licensing and Hosting Options
Conventions Used in This Book
Voice
Using Code Examples
Safari Enabled
Comments and Questions
Acknowledgments
Part I:  FlashCom Foundation
Chapter 1.  Introducing the Flash Communication Server
Section 1.1.  Clients and Servers
Section 1.2.  Creating an Application
Section 1.3.  Real-Time Messaging Protocol
Section 1.4.  The Communication Classes
Section 1.5.  Communicating with Application Servers, Databases, and Directory Servers
Section 1.6.  Firewalls and Security
Section 1.7.  Getting Started
Section 1.8.  Hello Video!
Section 1.9.  Conclusion
Chapter 2.  Communication Components
Section 2.1.  Overview of Communication Components
Section 2.2.  Summary of Communication Components
Section 2.3.  Creating an Application that Monitorsa Connection
Section 2.4.  Building a Simple Chat Room
Section 2.5.  Adding Audio and Video to the Chat Room
Section 2.6.  Forgoing the SimpleConnect Component
Section 2.7.  Conclusion
Chapter 3.  Managing Connections
Section 3.1.  Making a Connection
Section 3.2.  Managing a Connection
Section 3.3.  Reusing a NetConnection Object
Section 3.4.  Multiple Simultaneous NetConnection Objects
Section 3.5.  Testing and Debugging Network Connections
Section 3.6.  Subclassing the NetConnection Class
Section 3.7.  Communication Components Without SimpleConnect
Section 3.8.  Conclusion
Chapter 4.  Applications, Instances, and Server-Side ActionScript
Section 4.1.  Scripting Application Instances
Section 4.2.  Differences Between Flash ActionScript and Server-Side ActionScript
Section 4.3.  The Life of an Application Instance
Section 4.4.  Running a Simple Hello World Test Script
Section 4.5.  A More Realistic Example
Section 4.6.  Instance-to-Instance Communications
Section 4.7.  Script Filenames and Locations in Detail
Section 4.8.  Testing and Debugging Server-SideScript Files
Section 4.9.  Designing Communication Applications
Section 4.10.  Conclusion
Part II:  Audio, Video, and Data Streams
Chapter 5.  Managing Streams
Section 5.1.  A Simple Publisher/Subscriber Example
Section 5.2.  Stream Names
Section 5.3.  Publishing Streams in Detail
Section 5.4.  Playing Streams in Detail
Section 5.5.  The Stream Class
Section 5.6.  Publishing and Playing ActionScript Data
Section 5.7.  Creating Synchronized Presentations
Section 5.8.  The NetStream and Stream Information Objects
Section 5.9.  Stream Enhancements and Limitations
Section 5.10.  Conclusion
Chapter 6.  Microphone and Camera
Section 6.1.  Working with Microphone/Audio Input
Section 6.2.  Working with Camera Input
Section 6.3.  Building a Message-Taking Application
Section 6.4.  Building a Surveillance Application
Section 6.5.  Conclusion
Chapter 7.  Media Preparation and Delivery
Section 7.1.  Audio and Video Compression
Section 7.2.  Converting Prerecorded Materialto FLV Format
Section 7.3.  Using Flash Pro's Media Components
Section 7.4.  Enabling Multiple Bit Rate FLVsWithin an Application
Section 7.5.  Streaming MP3 Audio
Section 7.6.  Conclusion
Part III:  Remote Connectivity and Communication
Chapter 8.  Shared Objects
Section 8.1.  Objects and Shared Objects
Section 8.2.  Getting a Shared Object in Flash
Section 8.3.  Updates and Frame Rates
Section 8.4.  Scripting Shared Objects on the Server
Section 8.5.  Temporary and Persistent Shared Objects
Section 8.6.  Proxied Shared Objects
Section 8.7.  Shared Objects and Custom Classes
Section 8.8.  Avoiding Collisions
Section 8.9.  Optimizing Shared Object Performance
Section 8.10.  Broadcasting Remote Method Callswith send( )
Section 8.11.  A Simple Video and Text Chat Application
Section 8.12.  Conclusion
Chapter 9.  Remote Methods
Section 9.1.  Why Use Calls?
Section 9.2.  The send( ) and call( ) Methods
Section 9.3.  Client-to-Server Calls
Section 9.4.  Server-to-Client Calls
Section 9.5.  Server-to-Server Calls
Section 9.6.  A Simple Lobby/Rooms Application
Section 9.7.  Debugging Calls
Section 9.8.  Advanced Topics
Section 9.9.  Conclusion
Chapter 10.  Server Management API
Section 10.1.  Connecting to the Admin Service
Section 10.2.  Using the Server Management API
Section 10.3.  Server Management API Uses
Section 10.4.  Conclusion
Chapter 11.  Flash Remoting
Section 11.1.  The Remoting Gateway
Section 11.2.  Remoting Basics
Section 11.3.  Role of Remoting in FlashCom Applications
Section 11.4.  Securing Access
Section 11.5.  Conclusion
Chapter 12.  ColdFusion MX and FlashCom
Section 12.1.  Understanding ColdFusion MXand Flash Remoting
Section 12.2.  Using Flash Remoting to Log Events
Section 12.3.  Getting a List of Streams
Section 12.4.  Using ColdFusion and FTP to Mirror Streams
Section 12.5.  Conclusion
Part IV:  Design and Deployment
Chapter 13.  Building Communication Components
Section 13.1.  Source Files
Section 13.2.  People Lists
Section 13.3.  A Simple People List
Section 13.4.  Listenable Shared Objects
Section 13.5.  Status and People List
Section 13.6.  Text Chat
Section 13.7.  Shared Text
Section 13.8.  Video Conference and Video Window
Section 13.9.  PeopleGrid
Section 13.10.  Summary
Section 13.11.  Conclusion
Chapter 14.  Understanding the Macromedia Component Framework
Section 14.1.  The Component Framework
Section 14.2.  Under the Hood of the Chat Component
Section 14.3.  Creating a Simple Component from Scratch: SharedTextInput
Section 14.4.  Creating a Container Component: SharedAddressForm
Section 14.5.  Creating an Authenticating Component
Section 14.6.  Integrating Components with Your Existing Applications
Section 14.7.  Understanding the Framework
Section 14.8.  Conclusion
Chapter 15.  Application Design Patterns and Best Practices
Section 15.1.  Shared Object Management
Section 15.2.  Moving Code to the Server
Section 15.3.  Building Façades on the Server
Section 15.4.  Server-Side Client Queues
Section 15.5.  A Framework for Recording and Playing Back Componentized Applications
Section 15.6.  Components and Component Frameworks
Section 15.7.  Conclusion
Chapter 16.  Building Scalable Applications
Section 16.1.  Coordinating Instances
Section 16.2.  Scalability and Load Balancing
Section 16.3.  Conclusion
Chapter 17.  Network Performance, Latency,and Concurrency
Section 17.1.  Latency
Section 17.2.  Bandwidth
Section 17.3.  Concurrency
Section 17.4.  Conclusion
Chapter 18.  Securing Applications
Section 18.1.  The Three A's: Authentication, Authorization, and Accounting
Section 18.2.  Authentication
Section 18.3.  Authorization
Section 18.4.  Accounting
Section 18.5.  Suggestions and References
Section 18.6.  Conclusion
Index
SYMBOL
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
R
S
T
U
V
W

3.7. Communication Components Without SimpleConnect

Chapter 2 showed how applications can be created using Macromedia's communication components. Macromedia supplies the SimpleConnect component to manage a network connection and connect all the other components to it. SimpleConnect allows users to log in using any name when they connecteven the same name someone else is using. If you need to develop an application that manages user identities differently but want to use Macromedia's communication components, there are two options. One is to write your own connection component. Chapter 13 through Chapter 15 describe how to build custom components. The other option is not to use a connection component at all, as illustrated in the final example in Chapter 2. The following example uses a little server-side scripting, a NetConnection subclass, and the communication components to demonstrate creating a basic chat room application with separate login and chat screens. The application enforces unique usernames, doesn't allow name changes while connected, and does not permit lurking. It is not designed to provide a lobby and multiple chat rooms. These and other enhancements are added in later chapters.

3.7.1. Creating the Application on the Server

To use the communication components without SimpleConnect, an application's main.asc file must load the component framework and store a username for every client that connects within the framework. A minimal main.asc file is shown in Example 3-12.

Example 3-12. Minimal main.asc file when SimpleConnect is not used
load("components.asc");

application.onConnect = function (client, userName) {
  gFrameworkFC.getClientGlobals(client).username = userName;
  application.acceptConnection(client);
};

Example 3-12 allows anyone to connect with any username. To reject connections in which the username is blank or already in use requires a little more work. Example 3-13 shows a listing of another main.asc file. The script uses an object named users to keep track of the userName associated with each Flash movie. (An object such as users, in which the item name is used to access array elements, is known as an associative array, hash table, or simply hash.) The trim( ) function is used to preprocess each userName before checking whether it is null, an empty string, or already in the users object.

Example 3-13. The main.asc file for the netConnectChat application
load("components.asc");

// Trim any whitespace from before or after the userName.
// SSAS supports regular expressions, but client-side ActionScript does not.
function trim (str) {
  if (typeof str != "string") return "";  // Make sure str is a string.
  str = str.replace(/^\s*/, "");          // Trim leading spaces.
  str = str.replace(/\s*$/, "");          // Trim trailing spaces.
  str = str.replace(/\n/g,  "");          // Remove new lines.
  str = str.replace(/\r/g,  "");          // Remove carriage returns.
  str = str.replace(/\t/g,  "");          // Remove tabs.
  return str;
}

// Hash of client objects using the userName as a property name.
users = {};

// The onConnect( ) method rejects connection attempts
// where userName is invalid text or is already in use.
application.onConnect = function (client, userName) {
  userName = trim(userName);   // Remove leading and trailing whitespace.
  if (userName.length == 0) {  // If it is empty, reject it.
    application.rejectConnection(client, {msg: "Empty username."});
    return;
  }
  if (users[userName]) {    // If it is in use already, reject it.
    application.rejectConnection(client,
            {msg: 'The username "' + userName + '" is already in use.'});
    return;
  }
  // Store a reference to the client in the users hash.
  users[userName] = client;
  gFrameworkFC.getClientGlobals(client).username = userName;
  application.acceptConnection(client);
};

// When a client disconnects, remove the username from the
// users hash so someone can use it again.
application.onDisconnect = function (client) {
  var userName = gFrameworkFC.getClientGlobals(client).username;
  delete users[userName];
};

Placing the main.asc file from Example 3-13 into an applications subdirectory named netConnectChat allows this server-side main.asc script to control the netConnectChat application. If you were developing the main.asc script, you could always test it with a test client but let's push on to create the client-side part of the netConnectChat application in the next section.

3.7.2. Building the Client

Let's build a Flash movie to connect to our brand new netConnectChat application. For now, we'll stick with ActionScript 1.0 and the v1 UI components on which Macromedia's communication components rely. In Chapter 13, when we develop our own custom communication components, we'll switch to ActionScript 2.0 and the v2 UI components.

Using Macromedia's communication components without SimpleConnect is a two-step process: establish a network connection to the application instance and then pass the NetConnection object to each component's connect( ) method. The netConnectChat application uses the PeopleList, Chat, and UserColor components to create a simple text chat interface. The interface can be created with everything on a single frame, as is popular when using the SimpleConnect component, or the different states of the movie can be spread over the timeline. The book's web site includes an example of a single-frame movie. In this example, we'll build the client-side movie for this application using the timeline. Figure 3-4 shows the timeline and Stage when the movie is on the Chat frame.

Figure 3-4. The timeline and Stage with the playhead on the Chat frame


The Chat frame includes the following movie clips (components) and text field:


chat_mc

A Chat component instance


peopleList_mc

A PeopleList component instance


userColor_mc

A UserColor component instance


userName_txt

The text field at the bottom of the Stage


connect_btn

The Connect button at the bottom of the Stage

The Login frame contains only the userName_txt field and connect_btn button. If we were using the SimpleConnect component to log in the user, any other communication component would have to exist throughout the same timeline frames as SimpleConnect. In this example, the communication components do not need to be on the same frames as the username field or the Connect button. The components need only a NetConnection to function, so the username field and Connect button don't have to be included in the Chat frame either. However, in the Chat state, we change the Connect button label to Disconnect; the button logs out the user when clicked. The username text field is kept on the Stage to show the current user's name, but it is disabled during the chat.

The Scripts layer contains all but two lines of the script for the movie. The three important frames are the Init frame, which contains most of the script, and the Login and Chat frames. When the script on the Init frame has completed executing, the playhead moves to the Login frame. There is only one line of code on the Login frame of the Scripts layers:

startLoginState(  );

This statement calls the startLoginState( ) function declared in the first frame of the timeline to initialize the elements on the Stage:

function startLoginState (  ) {
  connect_btn.setLabel("Connect");
  userName_txt.selectable = true;
}

Similarly, there is only a single function call on the Chat frame:

startChatState(  );

The startChatState( ) function, also declared on the first frame, initializes the elements in the Chat frame:

function startChatState (  ) {
  connect_btn.setLabel("Disconnect");
  userName_txt.selectable = false;
  peopleList_mc.connect(nc);
  chat_mc.connect(nc);
  userColor_mc.connect(nc);
}

The label on the Connect button is reset as necessary by both functions, and the selectable property of the username field is used to disable and enable the userName_txt field.

When the playhead moves to the Chat frame, the communication components are created because that is the first frame in which they exist. But they also need to be connected to a NetConnection object or a NetConnection subclass to operate. The startChatState( ) function passes the global nc object to the connect( ) method of each component for this purpose.

The remaining scripts on the timeline (frames 4, 14, and 24) contain only a stop( ) function call. In addition to the components and movie clips placed directly on the Stage, the Library also contains an AlertBox movie clip symbol. It contains a MessageBox component named alert_mc from the Flash UI components set 2 and provides a way to display pop-up messages. The AlertBox movie clip's timeline contains code to set the title of the MessageBox and set its message text:

alert_mc.setTitle("Alert");
alert_mc.setMessage(message);

Example 3-14 shows the script from the main timeline (see timelineComponentConnect.as on the book's web site):.

Example 3-14. Main timeline script
// A simple alert function and variables to pop a message dialog box on stage.
alertLevel = 10;  // Level on which to display the alert dialog box.
upperLeft  = 10;  // _x and _y position of the alert dialog box.

// alert( ) displays msg in a pop-up alert dialog box.
function alert (msg) {
  attachMovie("AlertBox", "abox" + alertLevel, alertLevel,
               {_x: upperLeft, _y: upperLeft, message: msg} );
  // Increment the alertLevel and upperLeft position.
  alertLevel += 1;
  upperLeft += 10;
  if (upperLeft > 150) upperLeft = 10;
}

/* ChatConnection is a subclass of NetConnection designed to move the playhead
 * to the Chat frame when a connection is made and move it back to the Login
 * frame when it is lost.
 */
function ChatConnection ( ) {
  super( );
}

ChatConnection.prototype = new NetConnection( );      // Subclass NetConnection.
ChatConnection.prototype.handleCloseEvents = true;   // Initial value.

// connect( ) turns on the handleCloseEvents flag before calling super.connect( ).
ChatConnection.prototype.connect = function ( ) {
  this.handleCloseEvents = true;
  var result = super.connect.apply(super, arguments);
  if (!result) {
    alert("Invalid target URI: " + this.uri);
  }
  return result;
};

// close( ) turns off the handleCloseEvents flag before closing the connection.
ChatConnection.prototype.close = function ( ) {
  this.handleCloseEvents = false;
  super.close( );
};

/* onStatus( ) reports closed connections and errors except when closed
 * connections are expected. When a connection is closed, the playhead is
 * sent to the Login frame. When it is opened, it is sent to the Chat frame.
 */
ChatConnection.prototype.onStatus = function (info) {
  if (info.code == "NetConnection.Connect.Success") {
    gotoAndPlay("Chat");
  }
  else if (!this.isConnected) {
    if (this.handleCloseEvents) {
      var msg;
      if (info.code == "NetConnection.Connect.Rejected") {
         msg = 'Connection Rejected!';
         if (info.application) {
           msg += '\n' + info.application.msg;
        }
      }
      else {
        msg = 'Error: Connection ' + info.code.split(".").pop( );
      }
      alert(msg);
      this.handleCloseEvents = false;
      gotoAndPlay("Login");
    }
  }
};

// Main timeline button handler functions.

/* doConnect( ) is called whenever connect_btn is clicked. If the button label
 * is Connect, the NetConnection.connect( ) method is called. If the label
 * is Disconnect, the close( ) method is called.
 */
function doConnect (btn) {
  if (btn.getLabel( ) == "Connect") {
    if (!nc.isConnected) {
      nc.connect("rtmp:/netConnectChat", userName_txt.text);
      btn.setLabel("Waiting...");
    }
  }
  else if (btn.getLabel( ) == "Disconnect") {
    if (nc.isConnected) {
      userColor_mc.close( );
      peopleList_mc.close( );
      chat_mc.close( );
      nc.close( );
      gotoAndPlay("Login");
    }
  }
}
// Main timeline state change functions.

// Called after the Chat frame is entered to connect communication components
// and change the appearance or behavior of other Flash components.
function startChatState ( ) {
  connect_btn.setLabel("Disconnect");
  userName_txt.selectable = false;
  peopleList_mc.connect(nc);
  chat_mc.connect(nc);
  userColor_mc.connect(nc);
}

// Called after the Login frame is entered to reset login components.
function startLoginState ( ) {
  connect_btn.setLabel("Connect");
  userName_txt.selectable = true;
}

// Create the chat connection object.
_global.nc = new ChatConnection( );

gotoAndPlay("Login");

If you test the movie in multiple browser windows, you'll see that you can log in only if the specified username is unique.

Other than that the fact the alert( ) method has replaced writeln( ) and that state change functions have been added, there should be little here that isn't familiar from the previous examples in this chapter. One difference is in the onStatus( ) handler, which reports some errors a little differently:

msg = 'Error: Connection ' + info.code.split(".").pop(  );

The info.code property always contains a dot-delimited string. The preceding statement uses the split( ) method to split the string into an array and then the array pop( ) method to return the last part of the array. If info.code returns a message such as "NetConnection.Connect.Failed", the preceding statement appends the string "Failed" to "Error: Connection". When a code property is provided, the first term in the string is always the class of object with which the event is associated. The second term is usually the name of the action attempted, and the third is the result. Table 3-2 shows all the NetConnection information object code and level values as of FlashCom 1.5.

Table 3-2. NetConnection code and level values

Code

Level

Meaning

NetConnection.Call.Failed

Error

A remote method call was attempted on this connection and failed. The info.description property contains more details including the name of the method. Remote method calls are discussed in Chapter 9.

NetConnection.Connect.AppShutdown

Error

This message is supposed to be returned when an application instance is forced to shut downfor example when it is out of memory. However, as of FlashCom 1.5, this message is never received; "NetConnection.Connect.Closed" is received instead.

NetConnection.Connect.Closed

Status

Connection was closed by the server or the client. As of FlashCom 1.5, despite the level value of "status", it may indicate an error such as an application instance shutting down because it is using too much memory.

NetConnection.Connect.Failed

Error

The connection attempt failed. The server may not have been reachable or may be down.

NetConnection.Connect.InvalidApp

Error

This message is supposed to be returned when an application name is not registered on the server. However, as of FlashCom 1.5, this message is never received; "NetConnection.Connect.Closed" is received instead.

NetConnection.Connect.Rejected

Error

The attempt to connect was rejected by the server or by the application on the server. The reason the client was rejected depends on several factors. For example, the application may reject the connection because the user's credentials are invalid. The application may return an application object as a property of the information object. The info.description property will contain useful information if the application name was not found, if the resource limits of the application were exceeded, or if the server license does not allow more connections or the usage of more bandwidth. See Table 3-3.

NetConnection.Connect.Success

Status

A connection has been established.


The info.description property is often empty but for some messages contains important additional information. When the server returns a "NetConnection.Connect.Rejected" message, either the server or the application has rejected the connection. When an application rejects a connection, the server-side script writer has the option to return an application object to explain why. When the server rejects a connection, it returns information in the description property that explains why. A rejected description message looks like this:

[ Server.Reject ] : (_defaultRoot_, _defaultVHost_) : Application (appName)
 is not defined.

Table 3-3 lists the three types of server rejection messages included in the description property.

Table 3-3. Description values for NetConnection.Connect.Rejected messages

Message

Meaning

Server.Reject

The server rejected the connection because the application did not exist, because of a configuration error, or because of some other problem such as bad network data.

Resource.Limit.Exceeded

The resource limits for the server, virtual host, or application have been exceeded. For example, the maximum allowed number of instances or shared objects has been exceeded.

License.Limit.Exceeded

The number of simultaneous client connections or bandwidth limit has been exceeded. See the Preface for FlashCom licensing information.