24.4 Creating the Administrator Client
The administrator client should
include the following functionality:
The administrator should be able to view a list of available messages
that have been left. The administrator should be able to play and/or delete messages. The administrator should be alerted when there is an incoming call
and should be able to accept or ignore the call. If the administrator accepts a call, she should be able to end the
call by clicking on a button.
Complete the following steps to make the administrator client movie:
Create a new Flash document named
adminClient.fla and open it. Add the PushButton and ListBox component symbols to the Library by
creating an instance of each on the Stage and then deleting them. Add a new video symbol by choosing New Video from the Library
panel's pop-up Options menu. Create a new movie clip symbol named videoMc. Edit videoMc and create an instance of the video
symbol within it so that the video symbol instance is placed at
(0,0). Name the video symbol instance vid. Open the linkage properties for videoMc. Select the Export for ActionScript and Export on First Frame options
and set the linkage identifier to VideoMcSymbol. Add the following code to the first frame of the main timeline: // NetDebug.as is part of Flash Remoting.
#include "NetDebug.as"
// Include MovieClip.as from Chapter 7 and Date.as from Chapter 10.
#include "MovieClip.as"
#include "Date.as"
// Include Table.as and Forms.as from Chapter 11.
#include "Table.as"
#include "Forms.as"
// Include DrawingMethods.as from Chapter 4.
#include "DrawingMethods.as"
function init ( ) {
// Create a net connection and connect to the FlashCom application as the
// administrator (username = "admin", password = "adminPass").
myConnection = new NetConnection( );
myConnection.connect("rtmp:/communicationCenterApp/", "admin", "adminPass");
// Once the connection has been made successfully, invoke initMessagesList( ).
myConnection.onStatus = function (infoObject) {
if (infoObject.code == "NetConnection.Connect.Success") {
_root.initMessagesList(this);
}
};
// The onIncomingCall( ) method is invoked from the server when a calling
// client places a call to the administrator.
myConnection.onIncomingCall = function (username) {
_root.incomingCallUser = username;
// Make the incoming call button visible.
_root.incomingCallBtn._visible = true;
// Create an interval on which the notifyIncomingCall( ) function is called.
_root.incomingCallInterval = setInterval(_root, "notifyIncomingCall",
1000, getTimer( ));
}
// This method is invoked when a call is ended.
myConnection.incomingCallEnd = function ( ) {
// Delete the incoming caller name and clear the videos and net streams.
delete _root.incomingCallUser;
_root.livePublishNs.publish(false);
_root.livePublishNs.close( );
_root.liveSubscribeNs.close( );
_root.incomingVideoMc.vid.attachVideo(null);
_root.localVideoMc.vid.attachVideo(null);
_root.imcomingVideoMc.vid.clear( );
_root.localVideoMc.vid.clear( );
};
createForm( );
}
// The createForm( ) function creates all the movie clip/component/symbol
// instances and positions them.
function createForm ( ) {
// Add the list box to display the list of available messages.
_root.attachMovie("FListBoxSymbol", "messageList", _root.getNewDepth( ));
// Create the video instance for the incoming calls.
_root.attachMovie("videoMcSymbol", "incomingVideoMc", _root.getNewDepth( ));
// Add a push button instance that enables the administrator to accept an
// incoming call.
_root.attachMovie("FPushButtonSymbol", "incomingCallBtn",
_root.getNewDepth( ));
// Create a movie clip containing a small, green circle used to alert the
// administrator of an incoming call.
_root.createEmptyMovieClip("callLight", _root.getNewDepth( ));
with (callLight) {
lineStyle(0, 0, 0);
beginFill(0x00FF00, 100);
drawCircle(5);
endFill( );
}
callLight._visible = false;
incomingCallBtn.setLabel("incoming call");
incomingCallBtn._visible = false;
incomingCallBtn.setClickHandler("acceptCall");
// Create the videos for displaying the messages
// and for monitoring the local camera stream during calls.
_root.attachMovie("videoMcSymbol", "messageVideoMc", _root.getNewDepth( ));
_root.attachMovie("videoMcSymbol", "localVideoMc", _root.getNewDepth( ));
// Create buttons for playing and removing messages.
_root.attachMovie("FPushButtonSymbol", "playBtn", _root.getNewDepth( ));
_root.attachMovie("FPushButtonSymbol", "removeBtn", _root.getNewDepth( ));
playBtn.setClickHandler("viewMessage");
playBtn.setLabel("play message");
removeBtn.setClickHandler("removeMessage");
removeBtn.setLabel("remove message");
// Use a table to position all the elements.
tr0 = new TableRow(5, new TableColumn(5, messagelist, playBtn, removeBtn),
new TableColumn(5, messageVideoMc));
tr1 = new TableRow(5, new TableColumn(5, incomingVideoMc),
new TableColumn(5, localVideoMc));
tr2 = new TableRow(5, new TableColumn(0, callLight, incomingCallBtn));
t = new Table(5, 0, 0, tr0, tr1, tr2);
}
// The startLiveCall( ) function is invoked when the administrator accepts an
// incoming call.
function startLiveCall ( ) {
// Create a net stream for subscribing to the calling client's audio and video.
liveSubscribeNs = new NetStream(myConnection);
liveSubscribeNs.play(incomingCallUser + "live");
// Attach the local and remote video streams to the respective video instances.
localVideoMc.vid.attachVideo(Camera.get( ));
incomingVideoMc.vid.attachVideo(liveSubscribeNs);
// Create a net stream for publishing the administrator's audio and video.
livePublishNs = new NetStream(myConnection);
livePublishNs.attachVideo(Camera.get( ));
livePublishNs.attachAudio(Microphone.get( ));
livePublishNs.publish("adminLive", "live");
}
// The notifyIncomingCall( ) function is invoked at
// one-second intervals when an incoming call is being placed.
function notifyIncomingCall(startTime) {
// Toggle the visibility of the call light. This creates a blinking effect.
callLight._visible = !callLight._visible;
// If the user has been trying to place the call for more than ten seconds,
// clear the interval, make the call button and call light invisible, and send
// the incoming caller to record a message instead.
if (getTimer( ) - startTime > 10000) {
clearInterval(incomingCallInterval);
callLight._visible = false;
incomingCallBtn._visible = false;
myConnection.call("sendToLeaveMessage", null, incomingUser);
delete incomingCallUser;
}
}
// The acceptCall( ) function is invoked when the administrator accepts an
// incoming call.
function acceptCall( ) {
// Once the call is accepted, turn off the call light.
callLight._visible = false;
// Modify the button so that it allows the administrator to end the call.
incomingCallBtn.setLabel("end call");
incomingCallBtn.setClickHandler("endCall");
// If there is an incoming caller, clear the interval that blinks the call
// light and call the server-side acceptIncomingCall( ) method.
if (incomingCallUser != undefined) {
clearInterval(incomingCallInterval);
myConnection.call("acceptIncomingCall", null);
startLiveCall( );
}
}
// The endCall( ) function is invoked when
// the administrator clicks the End Call button.
function endCall ( ) {
// Reset the button behavior so that when another call comes in, the
// administrator can accept it.
incomingCallBtn.setLabel("incoming call");
incomingCallBtn._visible = false;
incomingCallBtn.setClickHandler("acceptCall");
// Invoke the endCall( ) method on the server
// to take care of all the loose ends.
myConnection.call("endCall", null);
}
// The viewMessage( ) function is invoked when the
// administrator clicks on the button to play a message.
function viewMessage ( ) {
subscribeNs.play("message" + messageList.getSelectedItem( ).data);
_root.messageVideoMc.vid.attachVideo(subscribeNs);
}
// The initMessagesList( ) function is invoked when the administrator has
// connected to the FlashCom application. It retrieves the list of messages from
// the server and populates the list box.
function initMessagesList ( ) {
// Create a remote shared object to retrieve the message data from the server.
messagesSO = SharedObject.getRemote("messages", myConnection.uri, true);
messagesSO.connect(myConnection);
// When there is an update to the messages
// information, repopulate the list box.
messagesSO.onSync = function ( ) {
// First, remove all existing items from the list box.
_root.messageList.removeAll( );
var mssg, un, dt;
// Loop through all the items in the messages list from the server and add an
// item to the list box for each.
for (var i = 0; i < this.data.messages.length; i++) {
mssg = this.data.messages[i];
un = mssg.username;
dt = mssg.dateTime;
_root.messageList.addItem(un + " " + dt.format("MM-dd-yyyy") + " " +
dt.format("hh:mm a"), mssg.id);
_root.messageList.adjustWidth( );
_root.t.render(true);
}
};
// Create the net stream over which each video message can be retrieved.
subscribeNs = new NetStream(myConnection);
}
// The removeMessage( ) function is invoked when the administrator clicks the
// Remove Message button. It invokes the removeMessage( ) method on the server.
function removeMessage( ) {
var messageName = "message" + messageList.getSelectedItem( ).data;
myConnection.call("removeMessage", null, messageName);
}
init( );
Now that you have completed the administrator client, save the file,
and let's take a closer look at some elements of the
code.
The init( ) function
creates the net connection and connects the administrator to the
FlashCom application. Notice that the username and password are
hardcoded into the connect( ) method invocation.
This is not a secure approach, although for this example application
it should not pose a problem. If you need to ensure security, the
username and password should be entered by the administrator via a
login screen.
myConnection = new NetConnection( );
myConnection.connect("rtmp:/communicationCenterApp/", "admin", "adminPass");
You want to invoke the initMessagesList(
) function once the connection is
completed. Do this by invoking it from within the connection
object's onStatus(
) method:
myConnection.onStatus = function (infoObject) {
if (infoObject.code == "NetConnection.Connect.Success") {
_root.initMessagesList(this);
}
};
When the administrator accepts an incoming call, you want to start a
live call. To do this, follow these steps:
Create a net stream, subscribe to the stream that the calling client
is publishing, and display that video. Display the video that the administrator is publishing so that she
can monitor what the calling client is seeing. Publish the camera and microphone data so that the calling client can
subscribe to it.
For example:
function startLiveCall ( ) {
liveSubscribeNs = new NetStream(myConnection);
liveSubscribeNs.play(incomingCallUser + "live");
localVideoMc.vid.attachVideo(Camera.get( ));
incomingVideoMc.vid.attachVideo(liveSubscribeNs);
livePublishNs = new NetStream(myConnection);
livePublishNs.attachVideo(Camera.get( ));
livePublishNs.attachAudio(Microphone.get( ));
livePublishNs.publish("adminLive", "live");
}
When a calling client places a call to the administrator, blink the
call light by creating an interval that invokes
notifyIncomingCall(
) once per second. Each time the
function is invoked, the visibility of the call light is toggled.
Additionally, you want the call to time out after 10 seconds. To do
this, compare the current timer value with the timer value from when
the interval began (which is passed to the function as the
startTime parameter). Once the call request has
timed out, clear the interval and reset the rest of the values that
changed when the call request came in.
function notifyIncomingCall(startTime) {
callLight._visible = !callLight._visible;
if (getTimer( ) - startTime > 10000) {
clearInterval(incomingCallInterval);
callLight._visible = false;
incomingCallBtn._visible = false;
myConnection.call("sendToLeaveMessage", null, incomingUser);
delete incomingCallUser;
}
}
The initMessagesList(
) function is invoked when the
connection to the FlashCom application is made successfully. This
function creates a remote shared object and uses it to populate the
list box with the available messages. By placing the code to populate
the list box within the onSync(
) method, the list box is updated every
time a new message is left.
function initMessagesList ( ) {
messagesSO = SharedObject.getRemote("messages", myConnection.uri, true);
messagesSO.connect(myConnection);
messagesSO.onSync = function ( ) {
_root.messageList.removeAll( );
var mssg, un, dt;
for (var i = 0; i < this.data.messages.length; i++) {
mssg = this.data.messages[i];
un = mssg.username;
dt = mssg.dateTime;
_root.messageList.addItem(un + " " + dt.format("MM-dd-yyyy") + " " +
dt.format("hh:mm a"), mssg.id);
_root.messageList.adjustWidth( );
_root.t.render(true);
}
};
subscribeNs = new NetStream(myConnection);
}
|