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

5.6. Publishing and Playing ActionScript Data

ActionScript data can be added to a published stream at any time. The data is always added as part of a method invocation request. For example, we can't just add the text string "Hi Robert, how are you?" to a stream. Instead, we have to name a method that will receive our text. In Example 5-1, we chose to have each client publishing an out_ns stream specify the method name "showMessage" and the text to pass to it:

out_ns.send("showMessage", input_txt.text);

The NetStream.send( ) method sends a method name, parameters, and timestamp to the server along with the published stream.

The out_ns.send( ) method invocation adds the name of the method ("showMessage"), the data to be passed into the method (the text from the input_txt.text field), and a stream timestamp to the published stream.

In the case of a live stream, the method name, parameters, and timestamp will be sent to the server along with any audio and video. The server forwards the ActionScript data on to any clients subscribed to the stream. When each client receives the ActionScript data from the server, nothing will happen unless the NetStream object playing the stream has a showMessage( ) method defined on it. From Example 5-1:

in_ns.showMessage = function (msg) {
  writeln(msg);
};

Since the showMessage( ) method is usually invoked on a client other than the sender, it is referred to as a remote method.

Not only does the server send on ActionScript data to live subscribers of a stream, but it also stores the ActionScript data in the stream's FLV file if the stream is being recorded. Clients that subscribe to a recorded stream will also receive the recorded ActionScript data in sync with stream time and any audio or video that was recorded.

Sending ActionScript data in a stream can be tremendously useful. The data can be used to record all sorts of events, such as someone adding text to a chat, showing a slide during a presentation, or starting to publish a different stream.


Chapter 15 includes an entire session recording and playback framework based on recording and playing back ActionScript data in a stream. However, there are other ways to send a remote method request to other clients that are often more practical than sending data in a stream. Chapter 9 covers all the options for invoking remote methods in detail.

The client-side NetStream.send( ) method and the server-side Stream.send( ) method both allow you to send ActionScript data in a stream. There are two essential steps to making remote method invocation work: defining a method on the subscribing NetStream object and sending the request to the method within a published stream.

5.6.1. Defining a Remote Method

Defining a remote method to be executed on a NetStream object is no different than defining a method on any ActionScript object. The method can be defined on NetStream.prototype, which makes it available to every NetStream object, or as an individual method of a particular NetStream instance. The following code snippet shows two simple method definitions. Both methods rely on a function or object (not shown) to do the real work:

// Defining a method on the prototype object for all instances.
NetStream.prototype.showMessage = function (msg) {
  writeln(msg);
};

ns = new NetStream(nc);

// Defining a method for a single instance.
ns.doCommand = function (command) {
  commandHandler.doCommand(command);
};

Both methods can be invoked only if the NetStream object ns is playing a stream. Publishing streams cannot invoke their own methods using send( ). When a NetStream method such as showMessage( ) or doCommand( ) is invoked, it cannot return a value the way a normal ActionScript function can. If a remote method does attempt to use a return statement to return a value, the value is discarded.

5.6.2. Sending a Request

A request to invoke a remote method can be sent by a publishing NetStream object or by a subscribed server-side Stream object. Both objects use the send( ) method to make a request. The first parameter of the send( ) method is always the name of the remote method (handler name) to invoke. Any optional parameters passed after the method name are passed as parameters into the remote method when it is invoked:

// Passing a single string parameter.
out_ns.send("showMessage", input_txt.text);

// Passing a complex object.
cObj = {command: "rewriteField", text: "Sample Text.", scroll: 1};
out_ns.send("doCommand", cObj);

On the server, method invocation requests can also be made by a Stream object:

s = Stream.get("monitorStream");
s.send("showMessage", "New client logged in from " + client.ip);

5.6.2.1 Stream logs

The send( ) method can be used to write log data into a recorded stream file. In fact, this is the way FlashCom stores all its log files.

The advantage to using streams to store log data is that streams, unlike shared objects, can store very large amounts of data with little impact on client or server memory.


The data can be read back by defining a method on a NetStream object and then playing the stream.

In the simple homegrown Example 5-15, a server-side Stream object is used to record events as they occur.

Example 5-15. Simple application logging
log_s = Stream.get("log");
log_s.record("append");

application.onAppStart = function ( ) {
  log_s.send("onLog", {event: "onAppStart",
                       time: new Date( ),
                       appInstance: application.name});
};

application.onConnect = function (client, userName, password) {
  log_s.send("onLog", {event: "onConnect",
                       time:  new Date( ),
                       ip:    client.ip,
                       userName: userName});
  return true;
};

application.onDisconnect = function (client) {
  log_s.send("onLog", {event: "onDisconnect",
                       time:  new Date( ),
                       ip:    client.ip,
                       userName: userName});
  return true;
};

Playing the log file back from a remote client is done by connecting to the instance and then playing the log stream. However, since this is a log file that may have taken many hours to record, we don't want to wait for hours to get back all the ActionScript data. To play all the ActionScript data immediately, we can set the flushPlaylists parameter to a value of 2 or 3:

ns = new NetStream(nc);
ns.onLog = function (info) {
  for (var p in info) {
    trace(p + ": " + info[p]);
  }
};
ns.play("log", 0, -1, 3);

In this example, the value 3 is specified as the NetStream.play( ) method's flushPlaylists parameter. If a value of 2 or 3 is passed in, all remote method call requests are retrieved immediately before any stream audio or video begins to play. A value of 3 resets the playlist while a value of 2 maintains the current playlist.

Here is some sample output:

time: Sat May 24 22:42:51 GMT-0400 2003
event: onAppStart
appInstance: customLog/_definst_
userName: Guest
time: Sat May 24 22:42:51 GMT-0400 2003
ip: 127.0.0.1
event: onConnect
userName: blesser
time: Sat May 24 22:43:04 GMT-0400 2003
ip: 127.0.0.1
event: onDisconnect

In fact, you don't have to go to all this work to log events. FlashCom can write out trace( ) messages to an application log for you if you ask it to. The messages are saved in a stream file as onLogMsg( ) requests and can be read back with a utility such as the one cited shortly. To turn on application logging, use the <RecordAppLog> tag in any Application.xml file. Replace the default false value with true:

<RecordAppLog>true</RecordAppLog>

Logging can use a great deal of disk space, so you may want to place individual Application.xml files with the <RecordAppLog> tag set to true in the home directory of the applications you want to log. The log file will be saved to the .../admin/streams/logs/application/appName directory and will be named after the application instance name, for example, _definst_.flv. FlashCom can also create a server access log that records information about when users logged in and out of the system.

A utility to read log files and more information on FlashCom logs are available at:

http://www.macromedia.com/support/flashcom/ts/documents/flashcom_logging.htm

See Chapter 12 for another approach to application-level logging and Chapter 18 for a discussion of logging options.

5.6.2.2 Sending and recording events

The send( ) method can be used to send and record information to be acted on in sync with audio and video. For example, during an online lecture, a professor may wish to bold a section of text in a text field in order to focus attention on it. When the professor clicks a Send button, each student will see the section of text bolded in the Flash movie she is watching. Later, when the recorded version of the stream is played back, the bolding of text will again occur, synchronized to the audio stream of the professor's voice.

Making a system like this work requires building a Flash movie or movies that capture audio and events from the professor, translate the events into some form of data, such as an object, and send them in the stream. When the data in the stream arrives at the subscribing movie, it must be acted on to produce the required effect.

When an object is used to send an instructionfor example to tell another movie to bold text in a text fieldit is often called a command object. See the Command design pattern in the book Design Patterns by Erich Gamma et al. (Addison Wesley).

Example 5-16 shows a partial listing of code that creates an object containing information about the formatting of text in a text field. (The complete example is available on the book's web site.) The formatTextCommand object is an instance of the FormatTextCommandClass class and contains the starting and ending positions of the text to select and bold. It is created after the user highlights some text and clicks a Send button.

Example 5-16. Sending a command to set selected text in bold
function FormatTextCommandClass (start, end) {
  this.startIndex = start;       // Beginning of selection
  this.endIndex = end;           // End of selection
}

FormatTextCommandClass.prototype.destination = "code_mc";
FormatTextCommandClass.prototype.command = "formatText";
FormatTextCommandClass.prototype.repaint = false;

// Called when the Send button is clicked.
function doSend ( ) {
  if (lastTextobj.focusedField == code_txt) {
    // Show the professor the text set in bold.
    code_txt.setTextFormat(normalFormat);
    code_txt.setTextFormat(lastTextObj.startIndex,
                           lastTextObj.endIndex,
                           highlightFormat);
    // Create a command object and queue it up.
    var formatTextCommand = new FormatTextCommandClass(lastTextObj.startIndex,
                                                       lastTextObj.endIndex);
    sender.queueCommand(formatTextCommand);
  }
  sender.send( );
}

The lastTextObj and sender objects are not shown. The sender object contains a queue of events and sends them in a stream using the following statement (where obj is a command already in the sender's queue):

ns.send("doCommand", obj);

When the stream is playing (live or recorded), command objects are passed into the doCommand( ) method of subscribing streams:

ns.doCommand = function (command) {
  command.time = this.time;
  commandHandler.doCommand(command);
};

In this case, the commandHandler object passes the command on to an object that finds the destination movie clip (in this case named code_mc) and calls its formatText( ) method. The formatText( ) method, shown in Example 5-17, sets the formatting of the code_txt field and then uses the information in the command to bold a section of the text.

Example 5-17. Processing the command to bold a text selection
highlightFormat = new TextFormat(  );
highlightFormat.bold = true;
highlightFormat.color = 0x004433;

normalFormat = new TextFormat( );
normalFormat.bold = false;
normalFormat.color = 0x006655;

function formatText (command) {
  code_txt.setTextFormat(normalFormat);
  code_txt.setTextFormat(command.startIndex, command.endIndex, highlightFormat);
}