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.2. Managing a Connection

After a successful connection is made, it can be broken by various occurrences. A well-scripted Flash movie monitors the network status and takes appropriate action as changes occur. This is easily done inside your NetConnection.onStatus( ) handler, which is notified whenever the connection status changes. When a connection is first established, the objects and components that rely on it can begin using it. When a connection is closed, these objects may have to be disabled or disposed of. It is especially important that the user doesn't experience a sudden and unexplained loss of functionality when a network connection is dropped by the server or lost because of a network problem.

Avoiding Timing Problems

A commonand sometimes difficult to debugproblem occurs when scripts define the onStatus( ) handler after calling the connect( ) method:

nc = new NetConnection(  );
nc.connect(  ); // WRONG: do this after onStatus is defined!
nc.onStatus = function (info) {
  trace("info.code: " + info.code);
};

If connect( ) is called prematurely, the network connection may be established or the connection rejected before the onStatus( ) handler has been defined. The result is that the messages representing those events are never returned to the handler. The onStatus( ) method must always be defined before the connect( ) call is made. The preceding example should be rewritten as:

nc = new NetConnection(  );
nc.onStatus = function (info) {
  trace("info.code: " + info.code);
};
nc.connect( );


For the most part, when a connection is closed, the info object passed to the onStatus( ) method will have a level value of "status" and a code value of "NetConnection.Connect.Closed". This will happen if the network goes down, the server disconnects the client, the server stops, or the connection is closed using NetConnection.close( ). It is also possible that the level value will be "error" and the code value "NetConnection.Connect.AppShutdown". The following sections discuss how to deal with various connection status changes.

3.2.1. Dealing with Success

When Flash establishes a connection, any streams and shared objects that rely on the connection can be set up. Testing for the "NetConnection.Connect.Success" code in the onStatus( ) handler is the easiest way to do this:

if (info.code = "NetConnection.Connect.Success") {
  // Initialize and connect dependent objects and components (not shown).
}

3.2.2. Dealing with Problems

When a connection cannot be established or is lost, a number of possible message sequences can be sent to an onStatus( ) handler:

  • A single error code

  • An error code followed by a closed status

  • A single closed status

The isConnected property of the NetConnection object is false when any of these events occurs. Whenever a problem occurs, you may want your script to take action, such as informing the user. The simplest way to deal with problems is to look at the isConnected property in the onStatus( ) handler:

if (!this.isConnected) {
  if (info.code = "NetConnection.Connect.Rejected") {
    // Tell the user the connection was rejected by the application.
  }
  else {
    // Give the user more info based on info.code and/or info.level.
  }
  // Clean up any objects and components that need them.
  // Change state by going to another frame on the main timeline.
}

Displaying a message whenever isConnected is false may lead to the user seeing two messagesa reject message followed by a closed message. To avoid displaying two messages, the onStatus( ) handler must be stopped from acting on the second message. One way to do this is to remove the onStatus( ) handler completely by setting the onStatus property to null after the first message arrives. This can be done inside the onStatus( ) method:

this.onStatus = null;

Removing the onStatus( ) handler so that no further message processing can take place may seem like a drastic solution. However, the onStatus property can be reset later to a method that can handle messages. Alternatively, another NetConnection object, with a working onStatus( ) handler, can be created and used to connect again. Another approach is to create an extra property of the NetConnection object that toggles the handling of certain messages. When messages are expected after a connect( ) call is made or after a "success" status message, the property is set to true. When a connection has been closed, the property can be set to false. Example 3-2 shows one way to do this.

3.2.3. Closing the Connection from the Client

Another potential problem is that when you let the user close the connection via NetConnection.close( ), the onStatus( ) handler still receives a "closed" status message. There is often little point in showing this message to the user since she was responsible for closing the connection in the first place. It may be simpler to just change the state of the application by, for example, moving the playhead of the main timeline. Again, a property can be stored in a NetConnection object or the onStatus( ) method can be set to null, to avoid displaying a close message.

Example 3-2 uses a property named handleCloseEvents to indicate if error and close messages should be processed. This is just one way to write an onStatus( ) handler using this type of flag, and it can be altered as requirements dictate. An example that assigns values dynamically to the onStatus property is included in the online version of Example 3-2 (at http://flash-communications.net). Figure 3-1 shows the timeline for the movie used in Example 3-2. The movie can be in one of three states, each represented by a label at the beginning of a series of frames. Init starts on the first frame and is played only when the movie first loads; the Login frame is shown when the movie is in a disconnected state and the user can try to connect; the Connected frame is shown when the movie is in the connected state.

Figure 3-1. The timeline from Example 3-2


The script in Example 3-2, located on frame 1 of the Scripts layer of the main timeline, displays user messages in a text field. The ActionScript sends the playhead to either the Login or Connected frame depending on the state of the network connection.

Example 3-2. A script that handles connection-related events
// writeln(  ) writes messages into a text field named trace_txt
// and is a runtime alternative to trace( ) and the Output panel.
function writeln (msg) {
  trace_txt.text += msg + "\n";
  trace_txt.scroll = trace_txt.maxscroll;
}

/* A simple onStatus( ) handler that moves the playhead to Login if a
 * connection is closed and to Connected when a connection is established.
 * User messages are written via writeln( ) into a text window.
 * The this.handleCloseEvents flag is used to make sure the user never
 * sees redundant messages.
 */
NetConnection.prototype.onStatus = function (info) {
  // Always deal with successful connections.
  if (info.code == "NetConnection.Connect.Success") {
    this.handleCloseEvents = true;
    writeln("Success, you are connected!");
    gotoAndPlay("Connected");
  }
  // Handle messages when the connection is closed.
  if (!this.isConnected && this.handleCloseEvents) {
    if (info.code == "NetConnection.Connect.Rejected") {
      writeln(info.application.message);
      writeln('Did you use the username "Guest" and password "Guest"?');
    }
    else {
      writeln("Error: Connection Closed.");
    }
    this.handleCloseEvents = false;
    gotoAndPlay("Login");
  }
  // Handle remote method call errors here if you need to.
};

// Create a NetConnection object.
lobby_nc = new NetConnection( );

// Called when the Connect button in the Login frames is clicked.
function doConnect ( ) {
  lobby_nc.handleCloseEvents = true;
  if (lobby_nc.connect("rtmp:/testLobby/",
                       userName_txt.text, password_txt.text)) {
    writeln("Please wait. Attempting connection...");
  }
  else {
    writeln("Can't attempt connection. Is the URI correct?");
  }
}

// Called when the Disconnect button in the Connected frames is clicked.
function doDisconnect ( ) {
  // User is requesting a close so we don't handle it in onStatus( ).
  lobby_nc.handleCloseEvents = false;
  lobby_nc.close( );
  gotoAndPlay("Login");
}

gotoAndPlay("Login");

The script listed in Example 3-2 needs an application to which to connect. Therefore, we need a testLobby subdirectory in the applications directory on the server from which the movie is downloaded. Once the directory is created, the main.asc file shown in Example 3-3 can be placed in the testLobby subdirectory to provide the application with its logic. This server-side script accepts connections only from users who log in using the username "Guest" and the password "Guest". Rejected clients are passed a message to display to the user.

Example 3-3. Server-side script (main.asc) to accept or reject connections based on username and password
/* The application.onConnect(  ) method handles each client
 * connection request. In this case, users who log in
 * with userName "Guest" and password "Guest" are
 * allowed to connect. Other connection requests are rejected.
 */
application.onConnect = function (client, userName, password) {
  if (userName == "Guest" && password == "Guest") {
    client.writeAccess = "";   // Don't give write access.
    application.acceptConnection(client);
  }
  else {
    application.rejectConnection(client,
      {message: "This application has refused your connection."});
  }
};

Whenever a Flash movie connects to an application instance, the onConnect( ) method of the instance's application object is called. The first parameter passed to onConnect( ) is always a Client object that represents the client-side Flash movie. The remaining parameters are the parameters passed into the connect( ) method in the movie.

Therefore, when a client attempts to connect to the testLobby FlashCom application, the main.asc file shown in Example 3-3 checks the username and password passed in. A full-fledged version could validate the username and password against a database of valid users.

3.2.4. Using a Connection

A NetConnection object represents a network connection within a Flash movie. Any object that communicates over a network connection must have access to a NetConnection object. For example, the NetStream class requires a NetConnection object be passed into its constructor function:

myStream_ns = new NetStream(myNetConnection);

Working with the NetStream class is covered in Chapter 5.

Similarly, a remote shared object's connect( ) method must be passed a NetConnection object:

myRemote_so = SharedObject.getRemote("SOName", myNetConnection.uri, true);
myRemote_so.onStatus = onStatusFunction;
if (myRemote_so.connect(myNetConnection)) {
  trace("Connection ok so far...");
}

Macromedia designed both the NetStream and SharedObject classes so that, with some exceptions, they could be used as soon as a NetConnection object was passed to them. In both cases, the NetConnection object should be one that has attempted to make a connection even if the connection is not yet established. For example the process of sending data can be started via a NetStream.send( ) or SharedObject.send( ) method call before a connection is established. The data is held in a queue until the connection is made. Similarly, a NetStream object can start the process of publishing or playing audio or video before a connection is made. In this case, when the connection is made, the stream will begin to publish or play.

The important exception to this is shared object data and the shared object onSync( ) handler described in Chapter 8. As an added convenience, if onStatus( ) handlers are not created for SharedObject and NetStream objects, the onStatus( ) handler of the NetConnection with which they are associated will be called and passed the SharedObject and NetStream information objects. In some cases, especially when data is sent, these conveniences are useful, but for the most part should be avoided. It is often easier to manage an application and provide better information to the user if objects that depend on a network connection define their own onStatus( ) event handlers and do nothing until a connection is successfully made.