« Axis2, Spring and Annotations | Main | Filtering nested elements of a Tree data provider »

How to test upload bandwidth to a FMS

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.

TrackBack

TrackBack URL for this entry:
http://blog.comtaste.com/mt-tb.cgi/102

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

About

This page contains a single entry from the blog posted on February 11, 2010 11:37 AM.

The previous post in this blog was Axis2, Spring and Annotations.

The next post in this blog is Filtering nested elements of a Tree data provider.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33