Wowza Community

Dynamic Bandwidth Detection (BWCheck)

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

I am running a flash client based in AS3. Do you have a client side script that can be written in AS3?

Hi

i was trying the code:

public void getStreamStats(IClient client, RequestFunction function, AMFDataList params)

{

String streamName = params.getString(PARAM1);

/* List streamList = null;*/

AMFDataObj streamStatObj = new AMFDataObj();

IApplicationInstance appInstance = client.getAppInstance();

MediaStreamMap streams = appInstance.getStreams();

IMediaStream stream = streams.getStream(streamName);

IOPerformanceCounter streamStats = stream.getMediaIOPerformance();

streamStatObj.put(“droppedBytes”, new AMFDataItem(streamStats.getMessagesLossBytes()));

streamStatObj.put(“outBytes”, new AMFDataItem(streamStats.getMessagesInBytes()));

String outputString="";

outputString = “getStreamStats for “+streamName+”, BytesIn: “+streamStats.getMessagesInBytes()+”, BytesIn Rates: “+streamStats.getMessagesInBytesRate()+ “, BytesOut:”+streamStats.getMessagesOutBytes()+”, BytesLoss:”+streamStats.getMessagesLossBytes();

//getLogger().debug(“getStreamStats for “+streamName+”, BytesIn: “+streamStats.getMessagesInBytes()+”, BytesIn Rates: “+streamStats.getMessagesInBytesRate()+ “, BytesOut:”+streamStats.getMessagesOutBytes()+”, BytesLoss:”+streamStats.getMessagesLossBytes());

sendResult(client, params, outputString);

}

and i got into a error. The error is: java.lang.nullpointerexception which is at this line: IOPerformanceCounter streamStats = stream.getMediaIOPerformance(); What could be the problem?

thanks for the help!

Hi

Oh thanks. Btw that property only apply to Play is it? it cannot apply to publish? Unable to get the stats of the publishing stream? Maybe i misunderstand that.

Thanks for the reply.

Hi

i am using actionscript 3.0 and the codes for CtoSBWCheck are in actionscript 2.0. I tried converting but the returned results were very inconsistent as compared to the original ctoSBWCheck, so i think there are problems in my conversion.

Can anyone please help me convert to actionscript 3.0? I am totally new in actionscript, so can anyone please help me?

thanks in advance. :slight_smile:

Hi

there is no cToSBWCheck.fla in [install dir]\examples\BWChecker. I only see client, clientAS2, conf, lib and src folders, readme and a install bat file, perhaps u can send mi the file please? my email: alex_rongfu@hotmail.com

I tried using the codes in both the client and clientAS2 folder, and both have errors. Type Coercion failed: cannot convert Object@13aa5ce1 to flash.net.Responder.

I do understand sometimes the bandwidth can varies, but version i converted myself can varies by thousands or even more as compared to the original codes. I can be sure that my conversion went wrong somewhere.

thanks :slight_smile:

Hi

thanks alot… i made a small mistake thats why not working. Anyway really thanks for your help.

Hi All

I’m a newbee to Wowza server and please somebody help to meet this requirement.

I have Wowza installed and JW Player 4.3+ streaming videos from the server.

I know there is a bandwidth checker with Wowza and will automatically set the quality of the video to stream. But there is no setup to set the buffer length according to the bandwidth. JW Player have a Flashvar to set this, but This cannot be dynamically set before the player is loaded. If there is a mechanism for this, Please give me some reference to study it.

Or else, Is there any method/script to check the client side bandwidth before loading the player and set the buffer length according to the speed? I want to start the video as soon as possible and play it without giving a pause, ie; without letting the buffer to zero on runtime.

Please do give me some steps on how to apply he code to Wowza/JW Player.

Thnx in advance

Hi rrlanham

Thanks for the quick reply and correction.

The bwchecker is already installed and selecting high/low quality video according to the bandwidth also. The problem is Can we adjust the settings for the dynamic bandwidth checking for Wowza (current version 1.7.2)? How any change in that can improve streaming quality?

Your valuable comments are really helpful.

Thank you

Below is a link to a simple Flash movie for testing the connection speed to the Wowza Pro server from a client machine. If you configure your server as prescribed in the previous post, this tool will just work out of the box. It calls the server side bandwidth detection code every 5 seconds and returns the results. Its very useful for debugging client bandwidth issue like stuttering movies or poor video chat performance.

BWChecker.zip

To install, unzip. To run, double click bwchecker.html and change the connection string if needed.

The results are returned in kilobits per seconds which is the same units used to determine the bit rate of your media content. So if you are consistently seeing values of 600Kbps or greater, then this connection should be able to support content encoded at combine rate of ~500Kbps (400Kbps video, 96Kbps audio).

Enjoy,

Charlie

Hi.

I made the settings detailed on the first post and I downloaded this bwchecker, but I haven’t been able to make it work.

The default connection string is “rmtp://localhost/bwchecker”. I’ve tried this, “rmtp://my_servers_ip”, “rmtp://my_servers_url”, with and without “/bwchecker” at the end, with no results. I’ve even tried http://my_servers_url and http://my_servers_ip.

Does it matter when you located the “client” folder?

Thanks in advance,

Danilo

:o

I forgot to restart the Wowza service.

Thanks!

Roger,

I didn’t have to change much to get your actionscript to work correctly. Adobe has done away with the onResponse callback on its own, it now has to become a Responder object with a specific callback, onResponse or onFault or both.

This following actionscript file can be used as is and works great. I have a reference to the Object res, but the responder calls itself, and references the res Object from within its code.

To anyone else who had issues getting the actionscript part of this to work, I hope this saves some headache.

Roger thanks for the Java class and for the logic to get this to work.

Cheers,

Scott Haines


var nc:NetConnection;

var res;

var payload;

var ro;

function doClientBWCheck() {

trace(“testing CtoS performance…”);

nc.call(“onClientBWCheck”, ro, null);

}

function netConnectionStatusHandler(e:NetStatusEvent):void

{

if (e.info.code == “NetConnection.Connect.Success”) {

doClientBWCheck();

}

}

function ncOnBWDone()

{

trace(“BW Done”);

}

function ncOnBWCheck()

{

trace(“BW Check”);

}

function onClientResponse()

{

trace(“got info”);

}

var totalCount = 10;

function onResult(arg){

trace(“Got some Args Bytes Out”+arg[“cOutBytes”]+" Bytes In: “+arg[“cInBytes”]+” Time: "+arg[“time”]);

var now = (new Date()).getTime()/1;

if(res.sent == 0)

{

res.beginningValues = arg;

res.beginningValues.time = now;

res.pakSent[res.sent++] = now;

nc.call(“onClientBWCheck”, ro, now);

}

else

{

res.pakRecv[res.count] = now;

trace( "Packet interval = " + (res.pakRecv[res.count] - res.pakSent[res.count])*1 );

res.count++;

var timePassed = ( now - res.beginningValues.time );

if (res.count == 1)

{

res.latency = Math.min(timePassed, 800);

res.latency = Math.max(res.latency, 10);

res.overhead = arg.cOutBytes - res.beginningValues.cOutBytes;

trace("overhead: "+res.overhead);

res.pakSent[res.sent++] = now;

nc.call(“onClientBWCheck”, ro, 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”, ro, now, payload);

}

else if (res.sent == res.count)

{

// See if we need to normalize latency

if ( this.latency >= 100 )

{

if ( res.pakRecv[1] - res.pakRecv[0] > 1000 )

{

res.latency = 100;

}

}

payload.length = 0;

// Got back responses for all packets, compute bandwidth upspeed

var stats = arg;

var deltaUp = (stats.cOutBytes - res.beginningValues.cOutBytes)*8/1000;

var deltaTime = ((now - res.beginningValues.time) - (res.latency * res.cumLatency) )/1000;

if ( deltaTime <= 0 )

deltaTime = ( now - res.beginningValues.time) / 1000;

var kbitUp = Math.round(deltaUp/deltaTime);

trace("onBWDone: kbitUp = " + kbitUp + ", deltaUp= "+ deltaUp + " , deltaTime = " + deltaTime + ", latency = " + res.latency + " KBytes " + (stats.cOutBytes - res.beginningValues.cOutBytes)/1024) ;

}

}

};

function init()

{

nc = new NetConnection();

nc.addEventListener(NetStatusEvent.NET_STATUS,netConnectionStatusHandler);

ro = new Responder(onResult);

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 = {};

nc.objectEncoding = ObjectEncoding.AMF0;

var ncClientObj:Object = new Object();

nc.client = ncClientObj;

ncClientObj.onBWDone = ncOnBWDone;

ncClientObj.onBWCheck = ncOnBWCheck;

payload = new Array();

for (var i=0; i<1200; i++){

payload = Math.random(); //16K approx

}

nc.connect(“rtmp://localhost/bwcheck”);

}

init();

-----------------------------------------------------------------------------

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

Im sorry my ignorance about this but…

What should I put on

var rtmpNow:String = “rtmp://localhost/”;

I which address should I use for rtmp? I always get … connection failed… Do i have to export a release version of this, and put the address of the application as : localhost/TestingBandwidth/TestBandwith.html ??

thank you Id appreciate it

I’m using the upload version of this for a video chat. It sets a bandwidth limit in camera.setQuality, so users with bad upload have their webcams videos pixellated instead of freezed or not working. It works well but only BEFORE the stream is published.

Of course this can’t be used when the stream is published.

I’ve came accross a post from rrlanham (can’t find it again) who said that from flash player 10 there where built-in tools to detect the bandwidth of a running stream.

I don’t find those tools, all i’ve come accross is netstream.bytesLoaded that could help me but it’s for buffering non-live videos.

If you come accross this post rrlanham, could you remember what you meant (it’s was a 3years old post i think), or does anyone know how to detect the bandwidth of an upload running stream without sending additional data.

Indeed currentBytesPerSecond on the netstreaminfo object seems promising.

Thanks, i’ll look into that.

I think that camera.setQuality() will have an affect on a stream after you do netstream.publish()

It will. Changing the resolution on the fly while the stream is published makes the camera stop/start wich results in some frozen videos on low-end cpus. Changing the quality on the fly works well. Up to this point i had a slider wich users could use to lower their broadcast quality, i’m now trying to adapt automatically to their upload capability.

(I’m using a very “personal” form of english, so sorry if the grammar/syntax is a bit weird :slight_smile: