Displaying FLV video previews in a listbox

Download Source

This video tutorial will explain how you can create an XML-driven listbox component which displays thumbnail previews of a series of flv files. The download of each flv file is stopped as soon as the preview is displayed, allowing for a large amount of flv files to be previewed, scrolled through and played.

Requirements: You need Player 8 and tolerance for a heavy german accent :-P


Credits
Lisa Larson for the original article
Srinivas Manapragada of Macromedia for the cellrenderer
Craig Goodman of Macromedia
Akamai for hosting the video


Clearing the Chat History (Part 2)

As promised here is the second part of our tutorial. We will now take a closer look at how we can clear the chat history by clearing the server-side shared object that holds it and broadcasting this change to all connected users.

This tutorial presumes that you are using the pre-build communication components from Macromedia.

A fortunate fact is that all functionality to do what we are trying to achieve is already built into the components, all we need to take care of is how to call upon these functions.

Step one: Make sure clients are allowed to clear the history.
Take a look at the chat.asc file, it includes all the server-side code that works alongside your chat component (and after all that's where the chat history is displayed).

Line 35 of chat.asc should look like this
FCChat.prototype.allowClear = true; // Allow clients to clear history

If allowClear is set to false then make sure you change it to true.

Step two: Making sure you know what you are doing ;-)
The function that you will be calling in a minute is located from line 90 of chat.asc, it starts like this:
FCChat.prototype.clearHistory = function( client ) {
...
}

If you (somehow, anyhow) call this function it will first check if allowClear is set to true (which it is now), then it will clear the chat history by running these four lines of code
this.history_so.setProperty( "history", null );
this.history_so.flush();
delete this.history;
this.history = new Array;

and finally it will broadcast this change to all connected clients.
// Broadcast a clearHistory command to all clients
this.message_so.send( "clearHistory" );
return true;


So far that's very easy, you don't even have to write any code at all.

Step three: call the clearHistory() method
Easier said than done... but then again it's not that hard. I will show you one way of doing this very easily and it will allow you to clear the chat history by typing a 'secret' string into the input field of your application's chat window.

Line 73 of chat.asc contains the method sendMessage() and here it takes two parameters, one of which is mesg - the message string that has just been received and will now be sent to all clients. However before it gets sent we will intercept mesg, parse it and if the string matches our secret command then we will call the clearHistory() method.

This is easily done by simply adding the following piece of code on line 74 (and inside the sendMesage() method:
if (mesg.toLowerCase() == "secretstring"){
   this.clearHistory();
   }
else {
...
}


Basically all the original code will now be inside the else statement and will only be executed if the string does not match our secret command. However if you were to type "secretstring" (or whatever you have hard coded on line 74) then only this.clearHistory(); would run, resulting in the deletion of the chat history and a broadcast of this change to all connected users.

Moreover, none of the connected clients will ever see the secret string because it will not be broadcasted.

Remember that you must restart your application from the application inspector, this will reload the modified chat.asc file.

Hopefully this little tutorial will get you started. There are loads of other ways of calling clearHistory(), for example you could call it every time a user connects (but then again that's a bit silly) or every time the last user disconnects (makes more sense).

I leave that part up to you but the most obvious option is probably writing your own server-side function which you can call by pressing a pushbutton inside your client movie - for example you could have some kind of admin movie that is different to all the 'public' ones. For more information take a closer look at the call() method of the client-side communication actionscript dictionary.

Good luck and keep those suggestions coming in.

Check the first part of this tutorial
.


Clearing the Chat History (Part 1)

This is one of those subjects that keep coming up again and again: How to clear the chat history.

Most commonly known chat systems do not show you the conversations that have gone on before the user logs in. Developers therefore often like to emulate this behaviour in their FlashCom applications.

There are several ways of clearing a chat. The chat history is held in a server side persistent shared object (SSPSO) by default. If you clear the contents of this object then all clients will reflect this change immediately through their onSync event.

The following tutorial presumes that you are using Macromedia's Communication Components.


Option 1: Clearing the history on the client side only - the lazy way
Lazy way meaning you are not actually clearing the shared object which holds the history on the server but you are simply resetting the chat text field inside one client's movie to an empty string, effectively clearing it.

All you need to do is for example to add the following code to frame one of your movie (in this case your chat component instance must be called chat_mc):
chat_mc.history_txt = "";

To make it more robust you can also put this line of code into an onLoad() event of the chat_mc movie or provide a function that can be called by the user, for example when clicking a button.
Your function on frame 1 of the main timeline could be:
function clearHistory() {
    this.chat_mc.clearHistory();
};


and all you then need is a pushbutton, it will call the function clearHistory() when clicked by a user:


Hopefully this will point you in the right direction for integrating it with your own application. Next week we will look at how to clear the server side shared object on the server and broadcasting this change to all connected users, clearing the chat on each client.

Make sure to also check the second part of this tutorial
.


Live Screen capture with Camtasia and Flashcom (by Brajeshwar)

All the way long, I had been thinking that Camtasia Studio Recorder can output only a max of 320 x 240 res. But I am wrong, now you can broadcast whatever dimension you wish. As there is no easy way to do an app sharing or a desktop sharing directly with Macromedia Flash Communication Server MX 1.0 (or indeed 1.5 - ed.), Camtasia Studio comes to the rescue with its live record output feature.

First you may download the file (I was playing with) so that you can skip everything and start playing.

Steps :
(a) create a video object on your stage and size it to 640 x 480, give an instance name of say "camtasia_mc".
(b) add the following frame script

//let us get the Camtasia Studio Video Capture Driver
//you may throw up an array of camera source available and
//let the user choose from them
//for this, we know what we are doing, so let us get it
for (i = 0; i < camera.names.length; i++) {
   if (camera.names[i] == "Camtasia Studio Video Capture Driver") {
   break;
   }
}
// Get the camera
mycamera = camera.get(i);
mycamera.setMode(640, 480, 5, true);
mycamera.setQuality(0, 50);
//show the live output
camtasia_mc.attachVideo(mycamera);


(c) start live recorder and remember to set the video format to 640 x 480
(d) run your Flash document.

There you see your live feed coming out in the Flash document.
This same technique cam be used for any camera source, like a TV Tuner card which can in turn broadcast a TV channel live using Flashcom Server.

External link: Camtasia Studio


Flash Communication Server-Side framework (by Fernando Florez)

This subject sounds really advanced but it is not. There isn’t much info about the Flash Communication Server Server-Side framework but along this tutorial I’ll try to document some interesting parts of it that hopefully will help you with some common tasks you could have on your daily development.

I think this framework was created not as a utility but as a manager for flashcom server-side components (something like the UIComponent class for Client-Side components) but it also has some nice utilities we can take advantage of.

The normal .asc structure
Normally an .asc (ActionScript Communication) file will have this structure:


This is the basic structure, we have more server-side events but they are used in specific occasions and are not really common as these ones are.

Server-side event declaration
We can only specify one server-side event declaration, if we specify more than one then only the last one will remain. So is it possible to have more than one server-side event declaration and make them all work?
Not really but this is when the server-side framework is useful.
This feature is not supported and I sincerely haven’t tested it much so it may have some wrong behaviors.

First of all we need to load the framework into our .asc file.
load("framework.asc");
The framework.asc file is on our scriptlib folder so we can load it this way without specifying any path (I extremely recommend not modifying or moving this file if we don’t have an idea of what we are doing exactly).

Then just create your server-side events like you normally do but instead of making them inside your application object create them inside other objects created by you. For example:


You can have as many objects as you want/need and each one of these objects can have any of the server-side methods. We have the “onConnectAccept” and “onConnectReject” events too if you have already used them with components.

Now we only need to subscribe our objects into the gFrameworkFC object which is the base instance of the framework.

gFrameworkFC.addListener(this.myFirstObject);
gFrameworkFC.addListener(this.mySecondObject);


Run the code and Voila!

The framework was intended to work with components, it’s our base class for server-side components but there are so many nice things in there so why not use it with non-component application?
We use it a lot here at funciton communications.

Why have a Server-side framwork
The first question that came to my mind was the purpose of the server-side framework, in flash remoting we don’t have a server-side framework and we still have components for it so what’s the real purpose of this framework?

The reason for this is that flashcom is pure event callbacks, we have the onConnect, the onDisconnect, the onStatus, etc, etc. but we only have one “application” object and the possibility for only one main.asc file. I bet the flashcom team asked themselves this question: “How can we execute these events for different objects?” and the answer is with an event manager that should be able to broadcast the events to all subscribed objects.

The first part of this tutorial explains on how to use it (see above). This is done by the framework each time we subscribe our component class via the FCComponent constructor.
Now the problem is that each component should have it’s own room in where it can rest, this room depends on the component type (the type can be a simpleconnect, peoplelist, etc.).

The object gFrameworkFC object has another object named “components” and this is the *hotel* for all the components.
Inside this object new objects are created for each component type (what we call rooms before, remember?)

For example, if we use the FCChat component then it will be placed like this in the framework: gFrameworkFC.components.FCChat.componentInstance

“componentInstance” is the instance of our client-side component on stage. Any symbol on stage has a unique instance name even if we didn’t give it one Flash will give one for us to it.
Each “room” can have any amount of components subscribed to it, each of those properties point to our server-side component class instance. Now everything is getting clear, huh?

Anyway, let’s continue by reviewing one framework method that appeared in one of the dot releases for flashcom 1.5 (it was for flashcom 1.5.1 if I remember right).

We all know that “arguments” in flashcom is not really an array but an object. “What a great bug!” you may say but not really, it’s not Macromedia’s fault or even decision it’s something specified on the ECMA in which the flashcom engine is based. To avoid this uncomfortable thing the framework has this method that will convert any object into an array. It can convert any object into an array but it’s used only for arguments conversion (this does not mean that you can’t use it for other things).

The method is named “__toarray__” and is placed in the gFrameworkFC object.

An example of it could be:

var obj = new Object();
trace (obj.length); //Error! I don’t have that property, that is an array property
obj = gFrameworkFC.__toarray__(obj);
trace (obj.length); // Look Ma’! It’s working


Now we can do whatever we want with “obj”, this means we can apply an splice, pop, shift, etc. to it.

Ok, last thing in this tutorial before I get too boring. How many times you had the need to give each client instance a unique id or how many times have you seen people doing it? Lots, right?

Normally a developer will do something like: (Editor: yes, I do it all the time...)

application.onAppStart = function(){
this.uniqueID = 0;
}
application.onConnect = function(newClient){
newClient.id = this.uniqueID++;
}


So every client instance will have a unique identifier. “uniqueID” will return to 0 when the application is restarted.

We can avoid these steps and just include the framework.asc file on our main.asc file (if we haven’t done it yet). The framework creates a unique identifier that you can access with the “__ID__” property. For example:

load("framework.asc");
  application.onConnect = function(newClient){
  trace (newClient.__ID__);
}


That’s all for this tutorial, I hope you like it.
Don’t forget to visit our blog at: http://blog.funciton.com/en/

Take care, have fun and keep flashing.


Letting Users Log Out of an FCS/FMS App

If you are reading this article you will probably have had some experience with Flash Communication Server already. Maybe you have even had a go at building some nice apps and maybe you have come across an issue which I have encountered recently:
I wanted to 'pause' my application, let a user log out and terminate all broadcasting from that user without forcing her to close her browser. Instead I wanted to provide a 'log out' button.

My FlashCom application was being loaded via loadMovie() into another movie I though that simply unloading it on releasing a button would work. It didn't.

on (release) {
   unloadMovie(this);
}
DID NOT WORK!

Ok, it unloaded the movie alright but the netconnection appeared to be still open as I didn't explicitly disconnect it. The weird thing was that even when opening Google in one browser window and then closing my Flash window down completely I could still hear other user's broadcast and was clearly still connected to the application!

I must add at this stage that I was using Macromedia's pre-built components (although they were slightly modified). If you have had a look inside these components you will know that their internals are quite complex.

In the end it turned out that adding a new function (courtesy of Sam Wan) to the simpleconnect component did the trick.

It was necessary to
modify the code on frame 1 inside the SimpleConnect component by adding the following new method to the FCSimpleConnect Class, I slotted it in on line 182 of the actions layer.

FCSimpleConnectClass.prototype.shutdownApplication = function() {
   for (var i = 0; i<this.fcComponents.length; i++) {
   this._parent[this.fcComponents[i]].close();
   trace("closing:"+this._parent[this.fcComponents[i]]);
   }
   this.close();
   this.main_nc.close();
};

I won't go into too much detail as to how this new method works but what it achieves is to disconnect all connected components (such as AVPresence, Chat, ConnectionLight etc.).

My SimpleConnect component instance was named 'simple_conn' and was sitting on the same timeline as my button which contained the disconnect action. Therefore all that was needed for the button action was:

on (release) {
   simple_conn.shutdownApplication();
   // add more actions here if needed
   // ie gotoAndStop("disconnected")
}
WORKED FINE!

Now if a user clicks this button it will call shutdownApplication() inside the SimpleConnect component which in turn will disconnect the user. Excellent.


Secure Your FCS/FMS Applications From Abuse

If you run your own server or even just use a shared hosting account for your Flashcom applications then you should be aware of the fact that anyone who can guess or indeed spy on your connection string can connect and abuse your bandwidth and connections. In this tutorial I show you one way of making live a little bit harder for these hijackers.
Please note that ideally you would be using the <Allow>mydomain.com</Allow> tag in vhost.xml but this can sometimes be a bit awkward especially on a development server.

Whenever a client (Flash movie) connects to your application it will invoke the application.onConnect method on the server. We will use this method to authenticate the movie, basically making sure that it is allowed to connect.

Let's have a look at the following serverside script which is located inside main.asc. This script can authenticate multiple domains.




The first line loads your components, you can omit this line if you are not using any pre-built communication components in your movie.

This is followed by the onConnect method which receives one parameter: client_obj
The client_obj parameter must always be passed in order to assign the client to the application. You can extend this function to receive as many parameters as you like but for our needs the client_obj is sufficient.

We then declare our allowed domain, once with www prefixed and once without. It is set up to accept connections fromvarious variations of flashcomguru.com but you must change this domain to the one of your own website - doh! Also make sure you write it in lowercase.

We then read the referrer and converts it to lower case (just to be safe).
var theReferrer = client_obj.referrer.toLowerCase();

What follows is the actual comparison between our allowedDomain and the domain of the swf that is trying to connect. We do this by looping over the domainList array and check if our allowed domain is a substring of the referrer. We also make sure that the match is in position 1 and not further along.
if (challenge == 0) {...
Thanks to Brian Lesser for spotting this one.

The rest is fairly self explanatory. If we find a match we set a variable acceptit to 1. In the if statement that follows we decide - based on the value of acceptit - if we accept or reject the connection.

Please note that this method does not require any scripting on the client side (inside your swf file) but it is not as secure as using the <Allow> tag in vhost.xml.

If you are looking for a few more advanced ways of authenticaing a user I can highly recommend Kevin Towes' book 'Flash Communication Server MX'.
He provides code listings on his side including this one which authenticates a user through FlashCom via Remoting to an Access database.
Another great read is Bill Sanders' book out of the Reality Series - one of my favourites on Flashcom.

A slightly easier way is to use a serverside array of valid passwords as described in chapter 11 of his book. You can find the code for it here. However this might be easily hacked with an Actionscript decompiler.


Have fun.


Generating Thumbnail Previews Using Progressive FLVs

We probably all know by now how to play a progressive flv without Flashcom:

nc = new NetConnection();
nc.connect(null);
ns = new NetStream(my_nc);
ns.setBufferTime(0.1); // small buffer to limit motion in preview
my_video.attachVideo(ns); // my_video is a video object on stage
ns.play(thefile);


To turn this example into a thumbnail preview of the actual flv you could do this:

ns.onStatus = function (info) {
     if(info.code == "NetStream.Buffer.Full"){
          ns.pause();
     }
};


There's even a way of surpressing the sound resulting in a silent preview:

// soundholder is a simple movieclip on stage
soundholder.attachAudio(ns);
audio = new Sound(soundholder);
audio.setVolume(0);

You don't have to be a rocket scientist to take this example further using a 'play' button and kicking the video plus sound into life upon click.
But what's not so obvious is the fact that even if you pause the video, the flv file will load in its entirety in the background, potentially clogging up a user's connection. This is even more of an issue if you want to display many previews at once.

I found out about this behaviour using a neat little program called Netlimiter. It allows you to see which applications are using what kind of bandwidth and it also enables you to throttle a fast connection on a per application basis, emulating dialup users for example.

I thought it would be easy enough to stop the flv downloading by killing the NetConnection or close the NetStream similar to how this would work using Flashcom. Unfortunately I had no success with that approach, the flv would continue downloading come what may.

Furtunately the workaround was suprisingly easy: try loading a non-existing flv. Here's the code I used:
ns.onStatus = function (info) {
     if(info.code == "NetStream.Buffer.Full"){
          my_video.attachVideo(null);
          ns.pause();
          ns.play("nonexist.flv");
     }
};


This seems to do the trick quite nicely, showing one frame of the previously loaded flv without clearing the video object. A typical preview only consumed about 5kB to 10 kB of data - a big saving over a whole flv file which is potentially several MB in size.

Download source

The sourcecode is a bit messy but I couldn't be bothered to clean it up :-P

Let me emphasize again: if you only have a single flv file on your page then the background download can be a great feature and even improve the user experience. But if you want to preview many different flv files on one page then I recommend you use my approach above.

Hope this helps someone.


Security of Flash Communication Server MX reviewed

UPDATE:
There was previously an error in this tutorial. It was claimed that a code such as

if ((_root._url.indexOf("http://www.flashcomguru.com") == 0) || (_root._url.indexOf("http://flashcomguru.com") == 0) ){
gotoAndStop("niceone");
} else {
gotoAndStop("feckoff");
}

inside your swf would solve the problem of succeeded connections when someone linked directly to the swf. Unfortunately this does not seem to be the case. It is however a workable solution if the swf has been 'stolen' is being served from another domain. However the server side method already takes care of this...
This leaves quite a big hole in the security of FCS!


The following tips should be read in conjuction with my tutorial on securing your application with the help of a server side script. It uses the client.referrer property to authenticate the connecting domain (the domain the swf is originating from).

More than one way to Rome
So far we have seen different ways by which (in particular some italian) sites have tried to hijack flashcom applications, stealing bandwidth and connections. One way was to spy on the connection string by hacking the swf file and using this to connect straight to the FCS Server. This approach only works if the server is completey unsecured meaning the owner hasn't made use of the security features in vhost.xml nor has the owner used any sort of client.referrer check. Here is an image of how your server.xml should not look:

Instead you should use <Allow>yourdomain.com</Allow>. This will offer a bit of protection.

Still not enough
However I think we all were surprised to find out that by simply embedding a swf from another domain into an HTML page we could steal the application, even with all the above measure in place. Not good.

If a hijacker was to put the swf on his own server an run it then it wouldn't connect. However if the thief would simply embed the swf like so
value="http://www.yourdomain.com/yourfile.swf" into his own page then the client.referrer would resolve to 'yourdomain.com' and the connection would succeed. Obviously the server.xml method also relies on the referrer that the swf file sends, not the HTML file in which it is embedded...

You will find that if you try and run it locally or on another domain then the (pretended) connection will fail.
We are working on a method that will stop people from linking to the swf on your server.

Taking things a step further
If your webserver is Apache then why not use .htaccess, courtesy of Fernando:


That's pretty much bullet proof. Check out the complete article by Fernando. It also features some steps you can take against people trying to frame your site.

Further info on the topic can be found here http://www.macromedia.com/devnet/mx/flashcom/articles/firewalls_proxy06.html

Then there is the option of banning IP addresses. I personally do not like this approach because a lot of the time IP addresses are dynamically assigned and you might lock out innocent users.
Stay safe.


Using client.call to invoke a method on all connected clients (by Steve)

To sit along with Ultimate's tutorial on ringing a sound as people are added to the people list in this tutorial were going to solve the same problem but by using a function call on the server side that will play a sound on all the clients side browsers.
You can adapt this to call any function you see fit, however for simplicity were going to use the situation where a client logs onto an app.

To use this tutorial you should already have built a few apps and understand how to make a connection to the server and some basic AS.

Firstly create an app called ringbell (or better still alter one of your existing apps).

In our main.asc file (this is the file on the comms server that loads the components, you will find it in the server installation directory inside the folder with your apps name, ie C:\Program Files\Macromedia\Flash Communication Server\MX\applications\my_apps_name\main.asc, for Windows users.)
we need to place the following code:

// this line is induced whenever a new connection is added to the app
application.onConnectAccept = function(){

trace("Connection accepted");

// then lets establish all the users, and loop through them calling the function
for (i = 0; i < application.clients.length; i++){
   trace ("call ring on client "+i)
   // this is the line that calls each client in turn from the application object
   application.clients[i].call("ring_my_bell");
   }
}

Now on the client side we have to create our sound, link it and then build a function for the server side script to call.
First you need to import a sound, then set it's linkage to be "my_bell_sound".
Once you have done that place the following code in the frist frame:

// connect to the server
my_nc = new NetConnection();
my_nc.connect("rtmp:/ringbell/room1");

// attach the sound
bell_sound = new Sound();
bell_sound.attachSound("my_bell_sound");

// then add the function to be called
my_nc.function= ring_my_bell(){
  //play the sound
  trace("ring bell");
  bell_sound.start();
}



The structure of this code is very simple, yet as a tool to be able to call functions across all clients on an event is a very strong peice of coding to understand. You can replace the connection accept event with any event you wish. In this next peice of code I use the above bell ring sound , but this time the trigger for it is on one of the clients browsers.

Pushbutton action
In the second part of this tutorial we are building the functionality to allow one user to push a button that rings the bell sound notifying all connected users of something.

Firstly create a button on your stage, then add the following code to it

on (release) {
   trace("send call");
   _root.my_nc.call("foo");
}

Again import a sound and set its linkage to be my_bell_sound

Then in the first frame of your movie place the following

//firstly connect to the server
my_nc = new NetConnection();
my_nc.connect("rtmp:/ringbell/01");
my_nc.onStatus = function(info) {
   trace("Level: " + info.level + " Code: " + info.code);
}

// attach the sound
bell_sound = new Sound();
bell_sound.attachSound("my_bell_sound");

// then add the function to be called
my_nc.ring_my_bell=function(){
   trace("bell ring")
   //play the sound
   bell_sound.start();
}


The important point when creating objects to be called from the server is that thie are associated with the connection object, for eaxample the above code my_nc.funcname=function(){ works however function funcname(){ wont be found from the comms server call, its to do with scope i belive.

Once again we need to crack open the main.asc file and place the following code

trace("load app")
// this gets triggered when a client connects
application.onConnect = function (clientObj) {

   // then we need to accept this connection
   
application.acceptConnection(clientObj);
   trace("connect accepted"+clientObj)

   // now we want to create the function that we call from the button being pushed
clientObj.foo=function(){
   trace("foo start")
   // loop over all clients and call ring_my_bell
   for (i = 0; i < application.clients.length; i++){
      trace("call ring "+i);
      application.clients[i].call("ring_my_bell");
      }
   }
}


And that's it. You now know how to invoke a method on all clients and you can do it from the server or from any connected client. Many Flashcom apps center around these very methods and they are one of the key features to get you started with multi user applications.


Previous Entries / More Entries