• How to check bandwidth from client to server to test uplink to be used by a live stream encoder (ModuleClientBWCheck)

    This module is used along with a Flash client to test the bandwidth available from the Flash client to the server (client-to-server bandwidth). This is useful for a client that will publish high-bitrate streams to the server, for example, when checking to see if the uplink bandwidth is adequate.

    Note: The standard BWCheck module measures server-to-client bandwidth.
    A compiled version of this module is included in the Wowza Module Collection.

    Configuration



    To enable this module, add the following module definition to your application. See Configure modules for details.

    Name
    Description
    Fully Qualified Class Name
    ClientBWCheck Checks client-to-server bandwidth. com.wowza.wms.plugin.collection.module.ModuleClientBWCheck

    Flash Clients



    Flex 4 AS3 version

    A pre-built version of this client is included in clientBWCheck.zip.

    ClientBWCheck.mxml
    <?xml version="1.0" encoding="utf-8"?>
    <local:cbwc xmlns:fx="http://ns.adobe.com/mxml/2009" 
    			   xmlns:local="*"
    			   xmlns:s="library://ns.adobe.com/flex/spark" 
    			   xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%">
    	
    	<mx:Image source="http://www.wowza.com/img/header.gif" x="0" y="0"/>
    	
    	<s:VGroup x="10" y="70" horizontalAlign="left">
    		<s:HGroup>
    			<s:Button label="Connect: " click="mainInit()"/>
    			<mx:TextInput id="wowzaAddress" text="rtmp://laketk.com:1935/upbwcheck" width="380"/>
    		</s:HGroup>
    		<mx:Button label="Run" id="runButton" click="start()" enabled="{isConnected}"/>
    
    		<mx:TextArea id="output" width="400" height="400"  editable="false" contentBackgroundColor="#E7E2E2"/>
    	</s:VGroup>
    	
    	<mx:TabNavigator x="540" y="120" >
    		<mx:VBox label="Graph" horizontalAlign="center">
    			<mx:ColumnChart  id="chart" dataProvider="{chartData}">
    				<mx:horizontalAxis>
    					<mx:CategoryAxis 
    						dataProvider="{chartData}" 
    						categoryField="testNumber"/>
    				</mx:horizontalAxis>
    				
    				<mx:series>
    					<mx:ColumnSeries 
    						yField="kbitUp"
    						displayName="kbitUp"
    						labelField="kbitUp"
    						labelPosition = "inside"
    						/>
    				</mx:series>
    			</mx:ColumnChart>	
    			<mx:Legend direction="horizontal" dataProvider="{chart}"/>
    		</mx:VBox>
    		<mx:Box label="Data">
    			<mx:DataGrid dataProvider="{chartData}" width="600" height="400">
    				<mx:columns>
    					<mx:DataGridColumn dataField="testNumber"/>					
    					<mx:DataGridColumn dataField="kbitUp"/>
    					<mx:DataGridColumn dataField="KBytes"/>
    					<mx:DataGridColumn dataField="latency"/>
    					<mx:DataGridColumn dataField="deltaUp"/>
    					<mx:DataGridColumn dataField="deltaTime"/>
    				</mx:columns>
    			</mx:DataGrid>
    		</mx:Box>	
    	</mx:TabNavigator>
    	
    </local:cbwc>
    cbwc.as
    package
    {
    	import flash.events.MouseEvent;
    	import flash.events.NetStatusEvent;
    	import flash.net.NetConnection;
    	import flash.net.Responder;
    	import flash.system.Security;
    	
    	import mx.charts.ColumnChart;
    	import mx.collections.ArrayCollection;
    	import mx.controls.Button;
    	import mx.controls.DataGrid;
    	import mx.controls.Text;
    	import mx.controls.TextArea;
    	import mx.controls.TextInput;
    	import mx.events.FlexEvent;
    	
    	import spark.components.Application;
    	
    	public class cbwc extends Application
    	{
    		Security.LOCAL_TRUSTED;
    		
    		public var nc:NetConnection;
    		private var data:Object = new Object();
    		
    		private var testNumber:int = 0;
    		
    		public var output:TextArea;
    		public var wowzaAddress:TextInput;
    		public var runButton:Button;
    		
    		private var run:Boolean = false;
    		
    		[Bindable]
    		public var isConnected:Boolean = false;
    		
    		public var chart:ColumnChart = new ColumnChart();
    		
    		[Bindable]
    		public var chartData:ArrayCollection = new ArrayCollection();
    			
    		public function mainInit():void
    		{
    			nc = new NetConnection();
    			
    			nc.addEventListener(NetStatusEvent.NET_STATUS,function(infoObject:NetStatusEvent):void
    			{
    				output.text = infoObject.info.code;
    				
    				if (infoObject.info.code == "NetConnection.Connect.Success")
    				{
    					isConnected = true;
    					testNumber = 0;
    					chartData = new ArrayCollection()
    				}
    			});
    			
    			var clientObj:Object = new Object();
    			
    			
    			nc.addEventListener(NetStatusEvent.NET_STATUS, function(infoObject:NetStatusEvent):void 
    			{
    				trace (infoObject.info.code);
    				if (infoObject.info.code == "NetConnection.Connect.Success") {
    					isConnected = true;
    				}	
    			});
    			nc.connect(wowzaAddress.text);
    		}
    		
    		public function start():void
    		{
    			if (run)
    			{
    				run = false;
    				runButton.label = "Run";
    			}
    			else
    			{	
    				runButton.label = "Stop";
    				run = true;
    				doClientBWCheck();		
    			}
    		}
    		private function doClientBWCheck():void
    		{
    			output.text = "";
    			
    			data.latency = 0;
    			data.cumLatency = 1;
    			data.bwTime = 0;
    			data.count = 0;
    			data.sent = 0;
    			data.kbitUp = 0;
    			data.deltaUp = 0;
    			data.deltaTime = 0;
    			data.pakSent = new Array();
    			data.pakRecv = new Array();
    			data.beginningValues = {};
    			
    			nc.call("onClientBWCheck", new Responder(bwResponse));
    		}
    		
    		private function bwResponse(p_res:Object):void
    		{
    			var deltaTime:Number;
    			var deltaUp:Number;
    			var kbitUp:Number;
    			var payload:Array = new Array();
    			for (var i:int=0; i<1200; i++){
    				payload[i] = Math.random();	//16K approx
    			}
    			
    			var now:Number = (new Date()).getTime()/1;
    			if(data.sent == 0) {
    				data.beginningValues = p_res;
    				data.beginningValues.time = now;
    				data.pakSent[data.sent++] = now;
    				nc.call("onClientBWCheck", new Responder(bwResponse), now);
    			} else {
    				data.pakRecv[data.count] = now;
    				trace( "Packet interval = " + (data.pakRecv[data.count] - data.pakSent[data.count])*1  );
    				output.text += "Packet interval = " + (data.pakRecv[data.count] - data.pakSent[data.count])*1  ;
    				data.count++;
    				var timePassed:Number = (now - data.beginningValues.time);
    				
    				if (data.count == 1) {
    					data.latency = Math.min(timePassed, 800);
    					data.latency = Math.max(data.latency, 10);
    					data.overhead = p_res.cOutBytes - data.beginningValues.cOutBytes;
    					trace("overhead: "+data.overhead);
    					data.pakSent[data.sent++] = now;
    					nc.call("onClientBWCheck", new Responder(bwResponse), now, payload);
    				}
    				trace("count: "+data.count+ " sent: "+data.sent+" timePassed: "+timePassed+" latency: "+data.latency);
    				
    				output.text += "count: "+data.count+ " sent: "+data.sent+" timePassed: "+timePassed+" latency: "+data.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 ( (data.count >= 1) && (timePassed<1000))
    				{
    					data.pakSent[data.sent++] = now;
    					data.cumLatency++;
    					nc.call("onClientBWCheck", new Responder(bwResponse), now, payload);
    				} else if ( data.sent == data.count ) {	
    					// See if we need to normalize latency
    					if ( data.latency >= 100 )
    					{ // make sure we detect sattelite and modem correctly
    						if (  data.pakRecv[1] - data.pakRecv[0] > 1000 )
    						{
    							data.latency = 100;
    						}
    					}
    					payload = new Array();
    					// Got back responses for all the packets compute the bandwidth.
    					var stats:Object = p_res;
    					deltaUp = (stats.cOutBytes - data.beginningValues.cOutBytes)*8/1000;
    					deltaTime = ((now - data.beginningValues.time) - (data.latency * data.cumLatency) )/1000;
    					if ( deltaTime <= 0 )
    						deltaTime = (now - data.beginningValues.time)/1000;
    					
    					kbitUp = Math.round(deltaUp/deltaTime);
    					trace("onBWDone: kbitUp = " + kbitUp + ", deltaUp= " + deltaUp + ", deltaTime = " + deltaTime + ", latency = " + data.latency + " KBytes " + (stats.cOutBytes - data.beginningValues.cOutBytes)/1024) ;
    					output.text = "kbitUp = " + kbitUp + ", deltaUp= " + deltaUp + ", deltaTime = " + deltaTime + ", latency = " + data.latency + " KBytes " + (stats.cOutBytes - data.beginningValues.cOutBytes)/1024  + "/n/n" + output.text;	
    					
    					var obj:Object = new Object();
    					obj.kbitUp = kbitUp;
    					obj.deltaUp = deltaUp;
    					obj.deltaTime = deltaTime;
    					obj.latency = data.latency;
    					obj.KBytes = (stats.cOutBytes - data.beginningValues.cOutBytes)/1024;
    					obj.testNumber = "Test # " + ++testNumber;
    					chartData.addItemAt(obj,0);
    					
    					if (run)
    						doClientBWCheck();
    					
    				}
    			}
    		}
    	}
    }

    Flash AS2 version
    function doClientBWCheck() {
    	nc.call("onClientBWCheck", res, null);
    	trace("testing CtoS performance...");
    	
    }
    
    var nc:NetConnection = new NetConnection();
    nc.onStatus = function(info) {
    	trace (info.code);
    	if (info.code == "NetConnection.Connect.Success") {
    		doClientBWCheck();		
    	}
    }
    nc.connect("rtmp://localhost/bwcheck");
    
    var payload = new Array();
    for (var i=0; i<1200; i++){
    	payload[i] = Math.random();	//16K approx
    }
    
    var 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 = {};
    
    res.onResult = function(p_res) {
    	trace ("ClientBWResult: ");
    	var now = (new Date()).getTime()/1;
    	if(this.sent == 0) {
    		this.beginningValues = p_res;
    		this.beginningValues.time = now;
    		this.pakSent[res.sent++] = now;
    		nc.call("onClientBWCheck", this, now);
    	} else {
    		this.pakRecv[this.count] = now;
    		trace( "Packet interval = " + (this.pakRecv[this.count] - this.pakSent[this.count])*1  );
    		this.count++;
    		var timePassed = (now - this.beginningValues.time);
    
    		if (this.count == 1) {
    			this.latency = Math.min(timePassed, 800);
    			this.latency = Math.max(this.latency, 10);
    			this.overhead = p_res.cOutBytes - this.beginningValues.cOutBytes;
    			trace("overhead: "+this.overhead);
    			this.pakSent[res.sent++] = now;
    			nc.call("onClientBWCheck", res, now, payload);
    		}
    		trace("count: "+this.count+ " sent: "+this.sent+" timePassed: "+timePassed+" latency: "+this.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 ( (this.count >= 1) && (timePassed<1000))
    		{
    			this.pakSent[res.sent++] = now;
    			this.cumLatency++;
    			nc.call("onClientBWCheck", res, now, payload);
    		} else if ( this.sent == this.count ) {	
    			// See if we need to normalize latency
    			if ( this.latency >= 100 )
    			{ // make sure we detect sattelite and modem correctly
    				if (  this.pakRecv[1] - this.pakRecv[0] > 1000 )
    				{
    					this.latency = 100;
    				}
    			}
    			delete payload;
    			// Got back responses for all the packets compute the bandwidth.
    			var stats = p_res;
    			deltaUp = (stats.cOutBytes - this.beginningValues.cOutBytes)*8/1000;
    			deltaTime = ((now - this.beginningValues.time) - (this.latency * this.cumLatency) )/1000;
    			if ( deltaTime <= 0 )
    				deltaTime = (now - this.beginningValues.time)/1000;
    			
    			kbitUp = Math.round(deltaUp/deltaTime);
    	
    			trace("onBWDone: kbitUp = " + kbitUp + ", deltaUp= " + deltaUp + ", deltaTime = " + deltaTime + ", latency = " + this.latency + " KBytes " + (stats.cOutBytes - this.beginningValues.cOutBytes)/1024) ;
    		}
    	}
    }

    Wowza media server software and all components, including modules, source code, and other related items offered on this page, are copyrighted (c) 2006-2014 by Wowza Media Systems, LLC, all rights reserved, and are licensed pursuant to the Wowza Media Software End User License Agreement.
    Updated: For Wowza Streaming Engine 4.0.6 on 08-11-2014

    If you're having problems or want to discuss this article, post in our forum.