How the download bandwidth check works
Flash Media Server has a native method to check download bandwitdh of the client, a feature that becomes very useful when you are going to stream multi bitrate content.
In a fresh installation of a Flash Media Server you can find a couple of default applications: live and vod, both come with a main.far containing the server side Actionscript code. To get a readable version you can grab the files from your FMS_ROOT/samples/applications/. Unless you have a Flash Media Interactive Server you are not authorized to substitute the original main.far with your own version, your server would throw an error; anyway you have a complete freedom in modifying and/or adding new applications if you use a developer edition (with its inbound connection limit).
Going back to the main.asc file, we can check the last lines of application.onConnect
function( p_client, p_autoSenseBW )
{
...
if (p_autoSenseBW)
p_client.checkBandwidth();
else
p_client.call("onBWDone");
}
application.onConnect is unsurprisingly a function called when a client connects to a FMS, the last if-block checks for the p_autoSenseBW flag; if it's present and true, a routine that checks the client bandwidth is called and does a callback on onBWDone when finished, otherwise onBWDone is called directly.
The bandwidth check can be called programmatically as well:
nc.call("checkBandwidth", null);
where nc is our NetConnection after a successful connection to the server.
Why you can need to check the upload
Sometimes you can need a bandwidth check from client to server, i.e. the upload bandwidth a client has toward the server. The most common scenario is a streaming from a client webcam. Via Actionscript we are able to adjust the camera quality affecting directly the amount of data transferred from the client, the best we can do is to get the best stream quality using all the bandwidth at our disposal; this will result in a smooth and good quality flv.
We can use the same approach used in Flash Media Server for the download bandwidth check. Basically the server starts sending chunks of data bigger and bigger until a size limit specified in the configuration or a timeout is reached. More info here http://www.adobe.com/livedocs/flashmediaserver/3.0/docs/help.html?content=08_xmlref_057.html#216930
Server side code
We can just do thinks the other way round, so the first thing we need server side is a function that accepts data from the client and subsequently calls a callback:
Client.prototype.recData = function(data)
{
trace('recData('+data.size+')')
var s = this.getStats();
this.call("ack", 0, s.ping_rtt);
};
This server side code makes available to all clients a method called "recData" that takes as input generic data and calls a client side method "ack" passing the round trip time between client and server.
Client side code
The client will call the "recData" function on the server until a certain condition is met
startUploadTime=new Date().time;
_netConn.call("recData", new Responder(onRecDataResult, onRecDataFault), data);
we are calling the server side function passing a responder (not used) and the data. The data can be a simple string filled with a cycle (es. 4096 chars for 4KB). The "ack" method can be something like this:
public function ack(result:*):void
{
finishUploadTime=new Date().time;
var rtt:Number=new Number(result);
// calculate time considering round trip time
var totalTime:Number=(finishUploadTime - startUploadTime - rtt) / 1000;
// calculate current bandwidth, current data size is base size * attempt number
var bw:Number=UPLOAD_DATA_SIZE*(current_try+1) / totalTime;
// check the attempts limit
if (current_try < UPLOAD_BANDWIDTH_REPEATS)
{
// use a sum to make a final average
bw_sum+=bw;
// check the timeout limit
if(totalTime>MAX_WAIT) {
// set the bandwidth calculated so far
if (Camera.getCamera())
Camera.getCamera().setQuality(int(bw_sum / (current_try)), 0);
uploadTestFinished = true;
return;
}
// increase data size
current_data += data;
current_try++;
startUploadTime=new Date().time;
// recall the server side method
_netConn.call("recData", new Responder(onRecDataResult, onRecDataFault), current_data);
return ;
}
// Attempts limit reached, calculated the bw
if (Camera.getCamera())
Camera.getCamera().setQuality(int(bw_sum / (current_try)), 0);
}
Use the result to set up camera quality
ActionScript gives us a useful method to set up the camera quality: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/Camera.html#setQuality()
In our case we will set the bandwidth limit as found with our routine and set the quality to 0, i.e. the best quality supported by the current bandwidth.