Wowza Community

Dynamic Bandwidth Detection (BWCheck)

Yes, the source code for bandwidth checker is in first post of this thread. You can compile your own version in the Wowza IDE to make adjustments.

Richard

Did you add the jar file to wowza/lib folder then restart Wowza, and did you add the module to Application.xml. You want to connect to the Wowza server that you added that jar to, and to the application that you added the Module to.

Richard

There is a Actionscript 3 version of ctosbwcheck in [wowza-install-dir]/examples/BWCheck/CtoSBWCheck.fla

The results of the bwcheck do vary from moment to moment, which is normal result of varying network conditions.

Richard

It should be here:

[install dir]\examples\BWChecker\client\CtoSBWCheck.fla

I’ll send it to that email too.

Richard

There is a working AS3 example here:

[wowza-install-dir]/examples/BWChecker/client/bwchecker.fla

Richard

It’s on page 2 of this thread. You have to build it in the Wowza IDE

It tests from client to server. The default one at the top tests from server to client.

Richard

I don’t understand the question. Can you explain?

Richard

I think you are talking about using Netstream.play2() and netstreaminfo object. This what is used to implement Flash Dynamic Streaming, for example JW Player’s implementation

You can search around but here is one article that looks useful

http://help.adobe.com/en_US/flashmediaserver/devguide/WSae44d1d92c7021ff-1f5381712889cd7b56-8000.html

Here is how the simple, before connect method to check bandwidth

https://www.wowza.com/docs/how-to-test-server-to-client-bandwidth-for-rtmp-clients

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

Richard

You’re English is great. Thanks for the update.

Richard

i’m having some problems with converting the BWChecker to AS3.

this is what i’ve got :

var constring="rtmp://localhost/bwcheck";
var detected_bw:String;
var counter:Number=0;
var nc:NetConnection=new NetConnection;
nc.client=this;
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler );
function netStatusHandler (e:NetStatusEvent):void{
	trace("Level: "+e.info.level+" Code: "+e.info.code);
	if (e.info.code == "NetConnection.Connect.Success") {
		trace("--- connected to: " + nc.uri);	//this.uri
	}
}
function onBWCheck(latency:String):Number{
	trace("in onBWCheck");
	return ++counter; // Serverside, just ignore any return value, For now return the call count
}
function onBWDone(kbitDown, deltaDown, deltaTime, latency):void{
	trace("==>in onBW_DONE");
	trace("onBWDone: kbitDown:"+kbitDown+" deltaDown:"+deltaDown+" deltaTime:"+deltaTime+" latency:"+latency);
	//detected_bw = kbitDown;
	nc.close();
}
nc.connect(constring, true);
stop();

and i get this as a result (haven’t changed anything to serverside code, or is it necessary that i do that?):

in onBWCheck

Level: status Code: NetConnection.Connect.Success

— connected to: rtmp://localhost/bwcheck

ok , works like a charm now. Thanks a lot !

Hi Craigweb,

You may find netlimiter useful:

http://www.netlimiter.com

Regards,

Dean

Hi Charlie,

like balint.pelhos , I need to calculate the actual bandwidth after the stream has started without start another connection and generating an extra traffic.

I read your reply about it, but I’m not able to use IOPerformanceCounter interface like you suggested…

Is it possible have some indication or some reference how to implement it (server side and client side).

Thanks!

For using the bandwidth checker module, the instruction (posted below) asks for the FLVPlayback module to be removed. I would like to know why this needs to be done?

thanks

maple01

Configuration:

Create a folder named [install-dir]/applications/bwcheck

Create a folder named [install-dir]/conf/bwcheck

Copy [install-dir]/conf/Application.xml into new bwcheck config folder

Edit copied Application.xml file and remove the module reference to ModuleFLVPlayback and add the module reference below as the last entry in the section (it is important that it is the last entry):

A complete built version can be downloaded from here. Follow Charlie’s instructions at the top of the page to install.

Please let me know if there are any problems.

Roger.

This link is dead, can anyone help? Ive tried to compile it myself but im ignorant when it comes java. Thanks.

-jason

thanks! you guys are top notch support - jason

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);