Dynamic Bandwidth Detection (BWCheck)

Hi CHarlie,

I have been trying to make the bandwidth test work before we go ahead and purchase the lincense but no luck. I work for a university and we have many extension workers with dial up connection and I have been working with Richard by email to test the bandwidth check but it seems impossible to get it done. I have the plug-in in lib folder and have appropriate video files for each bandwidth here is the code:

var bandwidthVer = “_100”;

if (detected_bw >= 800)

bandwidthVer = “_750”;

else if (detected_bw >= 550)

bandwidthVer = “_500”;

else if (detected_bw >= 300)

bandwidthVer = “_250”;

But on dial up modem still gets the the one with _750, I am soo frustrated here and want to know what am I doing wrong?

thanks ina dvance for your help.

Richard,

how do I know if bandwidthVer have default of “_750”?

thanks

The default is _100

Here is the code:

import flash.geom.*;

var nc:NetConnection;

var nsPlay:NetStream = null;

var serverName:String = “rtmp://server/video”;

var movieName:String = “Extremists”;

var duration:Number = 0;

var progressTimer:Number = 0;

var isPlaying:Boolean = true;

var isProgressUpdate:Boolean = false;

var fastSettings:Array = new Array();

var currFastDir:Number = 0;

var currFastIndex:Number = 0;

var scrubTimer:Number = 0;

var isScrubbing:Boolean = false;

var scrubTime:Number = 0;

var scrubIsPlaying:Boolean;

var stageListener:Object = new Object();

var saveVideoObjX:Number;

var saveVideoObjY:Number;

var saveVideoObjW:Number;

var saveVideoObjH:Number;

var adjVideoObjW:Number;

var adjVideoObjH:Number;

var videoSizeTimer:Number = 0;

var videoLastW:Number = 0;

var videoLastH:Number = 0;

var fullscreenCapable:Boolean = false;

var hardwareScaleCapable:Boolean = false;

function mainInit()

{

// get movie name from parameter is defined

if (_root.zmovieName != undefined)

movieName = _root.zmovieName;

// initialize player control events

_root.controls.doPlay.onPress = _root.doPlayToggle;

_root.controls.doRewind.onPress = _root.doRewind;

_root.slider.onPress = _root.startScrub;

_root.slider.onRelease = _root.stopScrub;

_root.slider.onReleaseOutside = _root.stopScrub;

// uncomment this to monitor frame rate and buffer length

//setInterval(_root, “updateStreamValues”, 500);

_root.connect.connectStr.text = serverName;

_root.connect.streamStr.text = movieName;

_root.connect.connectButton.onPress = _root.doConnect;

_root.doFullscreen.onPress = _root.enterFullscreen;

enablePlayControls(false);

stageListener.onFullScreen = enterLeaveFullscreen;

Stage.addListener( stageListener );

saveVideoObjX = videoObj._x;

saveVideoObjY = videoObj._y;

adjVideoObjW = (saveVideoObjW = videoObj._width);

adjVideoObjH = (saveVideoObjH = videoObj._height);

videoObj._visible = false;

fullscreenCapable = testVersion(9, 0, 28, 0);

hardwareScaleCapable = testVersion(9, 0, 60, 0);

}

function doConnect()

{

// connect to the Wowza Media Server

if (nc == null)

{

enablePlayControls(true);

nc = new NetConnection();

nc.onStatus = function(infoObject)

{

trace(“nc.onStatus: “+infoObject.code+” (”+infoObject.description+")");

for (var prop in infoObject)

{

trace("\t"+prop+":\t"+infoObject[prop]);

}

// once we are connected to the server create the nsPlay NetStream object

if (infoObject.code == “NetConnection.Connect.Success”)

{

enablePlayControls(true);

createPlayStream();

videoLastW = 0;

videoLastH = 0;

videoSizeTimer = setInterval(_root, “updateVideoSize”, 500);

}

else if (infoObject.code == “NetConnection.Connect.Failed”)

_root.prompt.text = “Connection failed: Try rtmp://[server-ip-address]/simplevideostreaming”;

else if (infoObject.code == “NetConnection.Connect.Rejected”)

_root.prompt.text = infoObject.description;

}

nc.connect(_root.connect.connectStr.text);

// uncomment this to monitor frame rate and buffer length

//debugInterval = setInterval(_root, “updateStreamValues”, 500);

_root.connect.connectButton.label = “Stop”;

}

else

{

videoObj.attachVideo(null);

videoObj.attachAudio(null);

videoObj.clear();

videoObj._visible = false;

if (videoSizeTimer)

clearInterval(videoSizeTimer);

videoSizeTimer = 0;

videoLastW = 0;

videoLastH = 0;

nc.close();

nc = null;

if (debugInterval > 0)

clearInterval(debugInterval);

debugInterval = 0;

enablePlayControls(false);

setProgress(0);

_root.connect.connectButton.label = “Play”;

_root.prompt.text = “”;

}

}

function enablePlayControls(isEnable:Boolean)

{

_root.controls.doPlay.enabled = isEnable;

_root.controls.doRewind.enabled = isEnable;

_root.doFullscreen._visible = isEnable & fullscreenCapable;

}

// function to monitor the frame rate and buffer length

function updateStreamValues()

{

var newVal:String = “”;

if (nsPlay != null)

newVal = (Math.round(nsPlay.currentFps1000)/1000)+" fps/"+(Math.round(nsPlay.bufferLength1000)/1000)+" secs";

fpsText.text = newVal;

}

// create the nsPlay NetStream object

function createPlayStream()

{

nsPlay = new NetStream(nc);

nsPlay.onStatus = function(infoObject)

{

trace("onStatus: ");

for (var propName:String in infoObject)

{

trace(" "+propName + " = " + infoObject[propName]);

}

if (infoObject.code == “NetStream.Play.Start”)

_root.isProgressUpdate = true;

else if (infoObject.code == “NetStream.Play.StreamNotFound” || infoObject.code == “NetStream.Play.Failed”)

_root.prompt.text = infoObject.description;

};

nsPlay.onMetaData = function(infoObject:Object)

{

trace(“onMetaData”);

// print debug information about the metaData

for (var propName:String in infoObject)

{

trace(" "+propName + " = " + infoObject[propName]);

}

// grab the movies duration from the metadata

if (_root.duration == 0)

{

_root.duration = infoObject.duration;

progressTimer = setInterval(_root, “updateProgress”, 250);

}

};

// print debug information when we encounter a cuePoint

nsPlay.onCuePoint = function(infoObject)

{

trace(“onCuePoint: “+infoObject.name+” (”+infoObject.type+")");

for(param in infoObject.parameters)

{

trace(" param: “+param+”="+infoObject.parameters[param]);

}

};

// print debug information when we play status changes

nsPlay.onPlayStatus = function(infoObject:Object)

{

trace(“onPlayStatus”);

for (var prop in infoObject)

{

trace("\t"+prop+":\t"+infoObject[prop]);

}

};

// set the buffer time and attach the video and audio

nsPlay.setBufferTime(3);

_root.videoObj.attachVideo(nsPlay);

_root.videoObj.attachAudio(nsPlay);

// start playback

_root.isProgressUpdate = false;

_root.isPlaying = true;

var bandwidthVer = “_100”;

if (detected_bw >= 800)

bandwidthVer = “_750”;

else if (detected_bw >= 550)

bandwidthVer = “_500”;

else if (detected_bw >= 300)

bandwidthVer = “_250”;

_root.connect.streamStr.text = _root.connect.streamStr.text+bandwidthVer;

nsPlay.play(_root.connect.streamStr.text);

}

the rest:

// play video (no fast play)

function doPlay()

{

currFastDir = 0;

currFastIndex = 0;

trace(“doPlay”);

var timecode:Number = nsPlay.time;

_root.isProgressUpdate = false;

if (!_root.isPlaying)

nsPlay.pause(false);

nsPlay.seek(timecode);

_root.isPlaying = true;

}

// event for clicking the play button

// if we are paused or in fast play mode just play the video

// else pause the video

function doPlayToggle()

{

if (!isPlaying)

doPlay();

else

{

_root.isProgressUpdate = false;

_root.isPlaying = false;

nsPlay.pause(true);

}

}

// rewind to the beginning of the movie and start playing

function doRewind()

{

_root.isProgressUpdate = false;

nsPlay.seek(0);

}

// update the progress bar

function setProgress(timecode:Number)

{

var totalWidth:Number = slider.sliderBack._width;

var newTimecode:Number = timecode;

var newWidth = (totalWidth*newTimecode)/duration;

if (newWidth > totalWidth)

newWidth = totalWidth;

if (!_root.isScrubbing && _root.isProgressUpdate)

slider.sliderSlide._width = newWidth;

}

function updateProgress()

{

setProgress(nsPlay.time);

}

// calculate the movie scrub location based on current mouse position

function calcScrub()

{

var xpos:Number = _root.slider._xmouse;

var xmax:Number = _root.slider._width;

if (xpos < 0)

xpos = 0;

else if (xpos > xmax)

xpos = xmax;

scrubTime = (duration*xpos)/xmax;

slider.sliderSlide._width = xpos;

}

// update the scrub location as we are scrubbing

function updateScrub()

{

calcScrub();

}

// start scrubbing

function startScrub()

{

scrubTimer = setInterval(_root, “updateScrub”, 250);

isScrubbing = true;

scrubTime = -1;

calcScrub();

scrubIsPlaying = _root.isPlaying;

if (_root.isPlaying)

nsPlay.pause(true);

}

// stop scrubbing and setup new play position

function stopScrub()

{

if (scrubTimer)

clearInterval(scrubTimer);

scrubTimer = 0;

if (scrubTime != -1)

{

_root.isProgressUpdate = false;

if (scrubIsPlaying)

{

_root.isPlaying = true;

nsPlay.pause(false);

nsPlay.seek(scrubTime);

}

else

{

_root.isPlaying = false;

nsPlay.seek(scrubTime);

}

}

isScrubbing = false;

}

function updateVideoSize()

{

// when we finally get a valid video width/height resize the video frame to make it proportional

if (videoObj.width != videoLastW || videoObj.height != videoLastH)

{

videoLastW = videoObj.width;

videoLastH = videoObj.height;

var videoAspectRatio:Number = videoLastW/videoLastH;

var frameAspectRatio:Number = saveVideoObjW/saveVideoObjH;

adjVideoObjW = saveVideoObjW;

adjVideoObjH = saveVideoObjH;

if (videoAspectRatio > frameAspectRatio)

adjVideoObjH = saveVideoObjW/videoAspectRatio;

else

adjVideoObjW = saveVideoObjH*videoAspectRatio;

videoObj._width = adjVideoObjW;

videoObj._height = adjVideoObjH;

videoObj._y = saveVideoObjY + saveVideoObjH - adjVideoObjH;

videoObj._x = (Stage.width - adjVideoObjW)/2;

videoObj._visible = true;

}

}

// show/hide the controls when we enter/leave fullscreen

function hideAllControls(doHide:Boolean)

{

_root.fpsText._visible = !doHide;

_root.bufferLenText._visible = !doHide;

_root.logo._visible = !doHide;

_root.connect._visible = !doHide;

_root.controls._visible = !doHide;

_root.doFullscreen._visible = !doHide;

_root.slider._visible = !doHide;

_root.backdrop._visible = !doHide;

_root.playerVersion._visible = !doHide;

}

function enterLeaveFullscreen(isFullscreen:Boolean)

{

trace("enterLeaveFullscreen: "+enterLeaveFullscreen);

hideAllControls(isFullscreen);

if (!isFullscreen)

{

// reset back to original state

Stage.scaleMode = “noScale”;

videoObj._width = adjVideoObjW;

videoObj._height = adjVideoObjH;

videoObj._y = saveVideoObjY + saveVideoObjH - adjVideoObjH;

videoObj._x = (Stage.width - adjVideoObjW)/2;

}

}

function enterFullscreen()

{

if (hardwareScaleCapable)

{

// best settings for hardware scaling

videoObj.smoothing = false;

videoObj.deblocking = 0;

// set the video frame size to the actual video size

videoObj._width = videoObj.width;

videoObj._height = videoObj.height;

// grab the portion of the stage that is just the video frame

Stage[“fullScreenSourceRect”] = new Rectangle(

videoObj._x, videoObj._y,

videoObj.width, videoObj.height);

}

else

{

Stage.scaleMode = “noBorder”;

var videoAspectRatio:Number = videoObj.width/videoObj.height;

var stageAspectRatio:Number = Stage.width/Stage.height;

var screenAspectRatio:Number = System.capabilities.screenResolutionX/System.capabilities.screenResolutionY;

// calculate the width and height of the scaled stage

var stageObjW:Number = Stage.width;

var stageObjH:Number = Stage.height;

if (stageAspectRatio > screenAspectRatio)

stageObjW = Stage.height*screenAspectRatio;

else

stageObjH = Stage.width/screenAspectRatio;

// calculate the width and height of the video frame scaled against the new stage size

var fsVideoObjW:Number = stageObjW;

var fsVideoObjH:Number = stageObjH;

if (videoAspectRatio > screenAspectRatio)

fsVideoObjH = stageObjW/videoAspectRatio;

else

fsVideoObjW = stageObjH*videoAspectRatio;

// scale the video object

videoObj._width = fsVideoObjW;

videoObj._height = fsVideoObjH;

videoObj._x = (stageObjW-fsVideoObjW)/2.0;

videoObj._y = (stageObjH-fsVideoObjH)/2.0;

}

Stage[“displayState”] = “fullScreen”;

}

function testVersion(v0:Number, v1:Number, v2:Number, v3:Number):Boolean

{

var version:String = System.capabilities.version;

var index:Number = version.indexOf(" ");

version = version.substr(index+1);

var verParts:Array = version.split(",");

var i:Number;

var ret:Boolean = true;

while(true)

{

if (Number(verParts[0]) < v0)

{

ret = false;

break;

}

else if (Number(verParts[0]) > v0)

break;

if (Number(verParts[1]) < v1)

{

ret = false;

break;

}

else if (Number(verParts[1]) > v1)

break;

if (Number(verParts[2]) < v2)

{

ret = false;

break;

}

else if (Number(verParts[2]) > v2)

break;

if (Number(verParts[3]) < v3)

{

ret = false;

break;

}

break;

}

trace(“testVersion: “+System.capabilities.version+”>=”+v0+","+v1+","+v2+","+v3+": "+ret);

return ret;

}

var h264Capable:Boolean = testVersion(9, 0, 115, 0);

playerVersion.text = (h264Capable?“H.264 Ready (”:“No H.264 (”)+System.capabilities.version+")";

if (!h264Capable)

playerVersion.textColor = 0xee0000;

Stage.align = “TL”;

Stage.scaleMode = “noScale”;

nc.onBWDone = function(kbitDown, deltaDown, deltaTime, latency) {

trace(“onBWDone: kbitDown:”+kbitDown+" deltaDown:"+deltaDown+" deltaTime:"+deltaTime+" latency:"+latency);

// app logic based on the bandwidth detected follows here

detected_bw = kbitDown;

// close the Netconnection to bwcheck

this.close();

}

nc.onBWCheck = function() {

trace(“onBWCheck”);

return ++counter; // Serverside, just ignore any return value, For now return the call count

}

mainInit();

setProgress(0);

Level: status Code: NetConnection.Connect.Success

— connected to: rtmp://server/bwcheck

onBWCheck

onBWCheck

onBWCheck

onBWCheck

onBWCheck

onBWCheck

onBWCheck

onBWDone: kbitDown:4998 deltaDown:779.616 deltaTime:0.156 latency:0

Level: status Code: NetConnection.Connect.Closed

here is the xml:

true

default

${com.wowza.wms.AppHome}/content

-1

*

*

*

*

*

*

digest

senderreport

12000

base

Base

com.wowza.wms.module.ModuleCore

properties

Properties

com.wowza.wms.module.ModuleProperties

logging

Client Logging

com.wowza.wms.module.ModuleClientLogging

bwcheck

Bandwidth Checker

com.wowza.wms.plugin.bwcheck.ModuleBWCheck

NO, it is not. I try with different internet speed and only play _750 nothing else and I am doing this test from a different server so is not even on the same server. what is the solution? do you want me to email you the link to the server so you can test it?

when I make the changes nothing happens and trace gives this:

testVersion: MAC 10,0,2,54>=9,0,115,0: true

testVersion: MAC 10,0,2,54>=9,0,28,0: true

testVersion: MAC 10,0,2,54>=9,0,60,0: true

nc.onStatus: NetConnection.Connect.Success (Connection succeeded.)

objectEncoding: 0

clientid: 1292074402

description: Connection succeeded.

code: NetConnection.Connect.Success

level: status

Basically it doesn’t load any videos.

Cheers for the reply. It seems a little strange that it should get it that wrong though, excuse my ignorance but does anyone know how bandwidth detection sites calculate more accurate results? As they seem to do it in a similar amount of time and seem to be much more consitent? Or am I just imagining this?

Any suggestions would be great. I could get it to check on every video but it seems so sporadic to me that I’m not sure how much of an improvement that would make?

Thanks,

Joe

Ok cool cheers for that. I am using the one at the start of the post, I think this is the right one as it is measuring the clients download bandwidth, which is what I need. It is based on an adobe bandwidth tutorial I think, which is used for the exact use I am using it for, just a little baffled by the odd results coming through.

Has anyone experimented with the settings within the jar file?

I have noticed the same situation. Maybe we need a little bit larger chunks of data to test with? The reason I think the test is over too quick with current settings is that when I start a stream my bandwidth @ home comes back around 1400 on average. However If I fire up two movies closely together the first call comes back around 1400kb as expected by the 2nd will usually come back higher closer to 2000kb. I have a 15Mbit connection that I am testing from which I can fill when using HTTP protocol from the same server. (Server is Gigbit @ a data center)

Hi,

Is there a limit on the rate at which the server sends the packets to the client during bw detection?

The reason I ask this:

With Flash media server, I used to get detected at around 8mbps for downlink, with wowza on the same data center, I am now just getting 2mbps.

Thanks,

Rohan

Charlie,

Thanks for the reply.

I too looked at the code, there was no limit. But let us wait for Roger anyway.

Still thinking why there is a huge difference in the bw detected.

Thanks,

Rohan

Hi!

I’ve played a bit with BWCheck module and found probable bug here:

line #128 (ModuleBWCheck2.java):

deltaTime = (double) ((now - start) - (latency * cumLatency)) / 1000;

look at (latency * cumLatency). cumLatency is (bluntly speaking) count of packets sent to client(not including playing packets, how we could forget about them?). This multiplication could be almost as 1 sec, so we could get:

deltaTime = 1 sec - (near 1 sec)

and then we make: deltaBytes/deltaTime = big_number

In practice, I was “reaching” 20000 kbit/sec from Europe to USA for my office PC.

what do you think to change this line to?:

deltaTime = (double) ((now - start) - (latency)) / 1000;

I’ve got much more realistic bandwidth detection after this change.

What do you think about this?

Thank you.

Thank you for response, Roger! It makes everything much clearer.

As for wisdom, that’s not me, but JW Player :slight_smile:

However, I see that BWCheck uses the whole traffic per period to calculate bandwidth. So, together with my solution (without multiplication) it actually needs 1 packet to be sent to calculate the bandwidth(if second, for example, elapsed).

I understood your thoughts, but you actually didn’t say if it is better for player-in-browser users to migrate to my modification or to leave with initial BWCheck.

By the way, I was a bit confused that nobody in this thread was not confused with speed like “20000 kbit/sec” (I’m sure they’ve got it).

m…

Hi, Roger!

Sorry for late response… Yes, I checked this with checker that comes with Wowza. So… problem exists. But such spikes are not permament, but happen for example in 1 from 10 measures. or in 1 from 5. I guess, particular browser, server, and client side configuration influence on this.

One more…

line #110 in ModuleBWCheck2.java

	// Time elapsed now do the calcs
		else if (sent == count)
		{ ...

What happens if sent != count ? :slight_smile:

In my modification I removed this check.

Thank you

Hi Richard/Charlie,

Do you have a ready built mdoule for me to use for upload bandwidth checker? I seem to have only the download check in the examples folder. In one of the threads above, there was a discussion of the upload test code, but the link gave me a 404. I am using 1.7.2 Wowza EC2. Thanks, Ramesh

Richard, I will send you a DM on this, if you don’t mind. Thanks, Ramesh

Hi Richard/Charlie, based on yours and Roger’s code, I attempted to write a small flex app to detect upload BW check code and i run into an error. When I ask the debugger to continue, it seems to run and provide the result. However, I would very much like to solve the error. Do you have an idea as to why this might be happening? The code is below…

The error I get is :

SWF] Users:admin:Documents:Flex Builder 3:flexTestApps:bin-debug:FlexUploadBWCheck.swf - 633,710 bytes after decompression

ArgumentError: Error #1063: Argument count mismatch on FlexUploadBWCheck/onBWDone(). Expected 4, got 0.

asyncErrorEvtHanlder: [AsyncErrorEvent type=“asyncError” bubbles=false cancelable=false eventPhase=2 text=“Error #2095: flash.net.NetConnection was unable to invoke callback onBWDone.” error=ArgumentError: Error #1063: Argument count mismatch on FlexUploadBWCheck/onBWDone(). Expected 4, got 0.]

testing CtoS performance…

Thanks, Ramesh

------------------ code ------

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init()">
	<mx:Script>
		<![CDATA[
			import flash.net.NetConnection;
			import flash.net.NetStream;
			import mx.managers.SystemManager;
			
			private var nc:NetConnection;
			private	var thumb:NetStream; 
			private var connectionObj:Object; 	
			private var res:Object;	
			private	var payload:Array = new Array();
            private function init():void {
				res = new Object();
				res.latency = 0;
				res.cumLatency = 1;
				res.bwTime = 0;
				res.count = 0;
				res.sent = 0;
				res.kbitUp = 0;
				res.deltaUp = 0;
				res.deltaTime = 0;
				//res.client = p_client;
				//var stats = p_client.getStats();
				res.pakSent = new Array();
				res.pakRecv = new Array();
				res.beginningValues = {};
				
				for (var i:int=0; i<1200; i++){
					payload[i] = Math.random();	//16K approx
				}
				samplePlay();
            }
			private function samplePlay():void{
				nc=new NetConnection() ;
				nc.client = this;
				nc.addEventListener (NetStatusEvent.NET_STATUS,checkConnect);
				nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorEvtHandler);
				var rtmpNow:String = "rtmp://localhost/bwcheck";
				nc.connect (rtmpNow);
			}
			private function checkConnect(e:NetStatusEvent):void{
				if(e.info.code == "NetConnection.Connect.Success"){
					doClientBWCheck();
				}
			}
			private function doClientBWCheck():void {
				nc.call("onClientBWCheck", new Responder(getBWCheckData, noBWData), null);
				trace("testing CtoS performance...");
				
			}
			public function getBWCheckData(p_res:Object):void {
				trace ("ClientBWResult: ");
				var now:Number = (new Date()).getTime()/1;
				if(res.sent == 0) {
					res.beginningValues = p_res;
					res.beginningValues.time = now;
					res.pakSent[res.sent++] = now;
					nc.call("onClientBWCheck", new Responder(getBWCheckData, noBWData), now);
				} else {
					res.pakRecv[res.count] = now;
					trace( "Packet interval = " + (res.pakRecv[res.count] - res.pakSent[res.count])*1  );
					res.count++;
					var timePassed:Number = (now - res.beginningValues.time);
			
					if (res.count == 1) {
						res.latency = Math.min(timePassed, 800);
						res.latency = Math.max(res.latency, 10);
						res.overhead = p_res.cOutBytes - res.beginningValues.cOutBytes;
						trace("overhead: "+res.overhead);
						res.pakSent[res.sent++] = now;
						nc.call("onClientBWCheck", new Responder(getBWCheckData, noBWData), now, payload);
					}
					trace("count: "+res.count+ " sent: "+res.sent+" timePassed: "+timePassed+" latency: "+res.latency);
				
					// If we have a hi-speed network with low latency send more to determine
					// better bandwidth numbers, send no more than 6 packets
					if ( (res.count >= 1) && (timePassed<1000))
					{
						res.pakSent[res.sent++] = now;
						res.cumLatency++;
						nc.call("onClientBWCheck", new Responder(getBWCheckData, noBWData), now, payload);
					} else if ( res.sent == res.count ) {	
						// See if we need to normalize latency
						if ( res.latency >= 100 )
						{ // make sure we detect sattelite and modem correctly
							if (  res.pakRecv[1] - res.pakRecv[0] > 1000 )
							{
								res.latency = 100;
							}
						}
						payload = null;
						System.gc();
						//delete payload;
						// Got back responses for all the packets compute the bandwidth.
						var stats:Object = p_res;
						var deltaUp:Number = (stats.cOutBytes - res.beginningValues.cOutBytes)*8/1000;
						var deltaTime:Number = ((now - res.beginningValues.time) - (res.latency * res.cumLatency) )/1000;
						if ( deltaTime <= 0 )
							deltaTime = (now - res.beginningValues.time)/1000;
						
						var kbitUp:Number = Math.round(deltaUp/deltaTime);
				
						trace("getBWCheckData: kbitUp = " + kbitUp + ", deltaUp= " + deltaUp + ", deltaTime = " + deltaTime + ", latency = " + res.latency + " KBytes " + (stats.cOutBytes - res.beginningValues.cOutBytes)/1024) ;
					}
				}
				
			}
			public function onBWDone(kbitDown:Number, deltaDown:Number, deltaTime:Number, latency:Number):void
			{
				trace("onBWDone: kbitDown:"+kbitDown+" deltaDown:"+deltaDown+" deltaTime:"+deltaTime+" latency:"+latency);
				// app logic based on the bandwidth detected follows here
				var detected_bw:Number = kbitDown;
				// close the Netconnection to bwcheck
			}
			private function noBWData(result:Object):void{
				trace("No BandWidth data: ", result);
			}	
			public function asyncErrorEvtHandler(result:Object):void {
				trace("asyncErrorEvtHanlder: ", result);
			}
			private function onMetaData(o:Object):void{	}
			private function onPlayStatus(o:Object):void{}
		]]>
	</mx:Script>
</mx:Application>

Sorry, what a dreadfully silly mistake. In my mind, I was sure that that onBWDone should be having parameters because the download test had a lot of parameters in teh code. Embarrassing!! Thanks