<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Derek J Entringer &#124; Interactive Media, Web Application, and Mobile App Developer &#187; flash media server</title>
	<atom:link href="http://www.derekentringer.com/blog/tag/flash-media-server/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.derekentringer.com/blog</link>
	<description>Interactive Media Development, Web Application Development, Mobile App Development, Flash, Flash Media Server, Flex, Flash Component Creation, Game Programming &#38; Design, Blog, CMS, eCommerce Setup &#38; Styling, Search Engine Optimization, Social Networking Strategies, Website Interface &#38; Template Creation, Windows Vista Gadget Development, Apple Widget Development, Email Marketing, Code Samples, Tutorials</description>
	<lastBuildDate>Tue, 13 Jul 2010 19:25:15 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Flash Media Server Streaming Speed Testing [Part 3] &#8211; Compare Multiple Server Resources, Port Connections, Detect Upload, Download, and Latency Speed</title>
		<link>http://www.derekentringer.com/blog/flash-media-server-streaming-speed-testing-part-3-compare-multiple-server-resources-port-connections-detect-upload-download-and-latency-speed/</link>
		<comments>http://www.derekentringer.com/blog/flash-media-server-streaming-speed-testing-part-3-compare-multiple-server-resources-port-connections-detect-upload-download-and-latency-speed/#comments</comments>
		<pubDate>Tue, 12 May 2009 20:21:58 +0000</pubDate>
		<dc:creator>Derek J Entringer</dc:creator>
				<category><![CDATA[Code Samples]]></category>
		<category><![CDATA[FMS]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[bandwidth]]></category>
		<category><![CDATA[detection]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[flash media server]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[multiple]]></category>
		<category><![CDATA[port]]></category>
		<category><![CDATA[servers]]></category>
		<category><![CDATA[speed]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[upload]]></category>

		<guid isPermaLink="false">http://www.derekentringer.com/blog/?p=218</guid>
		<description><![CDATA[
			
				
			
		

This tutorial is the final in a series of three. Part one of this tutorial outlined what is needed to detect a users upload, download, and latency between a Flash client and the Flash Media Server. Part two adds on the ability to detect which ports are available while connecting. In part three, we will be adding an external xml file that will allow you to compare connections to different Flash Media Servers in order to find which of them is the best connection for serving media. If you haven&#8217;t ...]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="clear:left; float:left; margin-top:10px; margin-bottom: 10px; margin-right:12px; margin-left:2px;">
			<a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2FwaS50d2VldG1lbWUuY29tL3NoYXJlP3VybD1odHRwJTNBJTJGJTJGd3d3LmRlcmVrZW50cmluZ2VyLmNvbSUyRmJsb2clMkZmbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0zLWNvbXBhcmUtbXVsdGlwbGUtc2VydmVyLXJlc291cmNlcy1wb3J0LWNvbm5lY3Rpb25zLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWQlMkY="><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.derekentringer.com%2Fblog%2Fflash-media-server-streaming-speed-testing-part-3-compare-multiple-server-resources-port-connections-detect-upload-download-and-latency-speed%2F&amp;source=derekentringer&amp;style=normal&amp;service=TinyURL.com" height="61" width="50" /><br />
			</a>
		</div>
<p><!--PLAIN_TEXT--><br />
This tutorial is the final in a series of three. Part one of this tutorial outlined what is needed to detect a users upload, download, and latency between a Flash client and the Flash Media Server. Part two adds on the ability to detect which ports are available while connecting. In part three, we will be adding an external xml file that will allow you to compare connections to different Flash Media Servers in order to find which of them is the best connection for serving media. If you haven&#8217;t already read part one, you can find it <a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0xLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLw==">here</a>, and part two is available <a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0yLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLWFuZC1wb3J0LWNvbm5lY3Rpb24v">here</a>.</p>
<p>Again, Bandwidth detection is most important when connecting your users to the correctly compressed media to be streamed, recorded, or delivered via a Flash Media Server. This third example will walk you through the process of being able to detect a users download bandwidth, upload bandwidth, latency speeds, and the connected port between the client computer and the host server, along with iterating through multiple Flash Media Servers in an attempt to connect to the fastest and most available server. All of the code is Actionscript 2.0, and I&#8217;ve setup a Flash Media Server 3.5 to host the server side scripting. I use Influxis as my Flash Media Server host for all of these tutorials and smaller examples.</p>
<p>First, lets put together our Flash Actionscript. Here our goal is to setup our connection manager, and create a BandwidthInfo object that will call to our main.asc file (this is explained next) for sending packets to the Flash Media server to the client, and vice versa. We also will be creating an instance of our NetConnManager.as (also explained further down) which will allow the flash client to detect which port is best to connect to the Flash Server.</p>
<pre class="brush: as3;">
import NetConnManager;

var bestConn:Number;
var bestBandwidth:Number;
var connectBestConn:Number;
var whichServer:String;
var hasConnected:Boolean;
var currentlyChecking:Boolean;
var nextCheck:Number;
var upstreamsAvailable:Array = new Array();
var downstreamsAvailable:Array = new Array();
var theServers:Array;
var startTime:Number = getTimer();
var ncm:NetConnManager = new NetConnManager();
var ncmListener:Object = new Object();
var theServersXML:XML = new XML();
theServersXML.ignoreWhite = true;

ncmListener.ncConnected = function(evt:Object) {
	trace(&quot;[&quot;+Math.round(getTimer()-startTime)+&quot;ms] successfully connected using &quot;+evt.protocol+&quot;:&quot;+evt.port);
	conn_stat.text += &quot;[&quot;+Math.round(getTimer()-startTime)+&quot;ms] successfully connected using &quot;+evt.protocol+&quot;:&quot;+evt.port+newline;
};
ncmListener.ncFailedToConnect = function(evt:Object) {
	trace(&quot;failed to connect after &quot;+evt.timeout+&quot; ms&quot;);
	conn_stat.text += &quot;failed to connect after &quot;+evt.timeout+&quot; ms&quot;+newline;
};
ncm.addEventListener(&quot;ncConnected&quot;, ncmListener);
ncm.addEventListener(&quot;ncFailedToConnect&quot;, ncmListener);
ncm.connect(&quot;your.rtmphost.com&quot;, &quot;application_name&quot;);

theServersXML.load(&quot;xml/server_config.xml&quot;);
theServersXML.onLoad = function(success) {
	var index:Number = 0;
	theServers = new Array(this.firstChild.firstChild.childNodes.length);
	for (var aNode:XMLNode = this.firstChild.firstChild.firstChild; aNode != null; aNode=aNode.nextSibling) {
		theServers[index] = new Array(aNode.firstChild.childNodes.length);
		for (var subNode:XMLNode = aNode.firstChild; subNode != null; subNode=subNode.nextSibling) {
			theServers[index][subNode.nodeName] = subNode.firstChild.nodeValue;
		}
		index++;
	}
	//setup first connection
	checkConnection(theServers[0][&quot;host&quot;], theServers[0][&quot;app&quot;], 0);
};

function checkConnection(host, app, which) {

	currentlyChecking = true;

	rec_nc = new NetConnection();
	rec_nc.onStatus = function(info) {
		trace(&quot;Level: &quot;+info.level+&quot; Code: &quot;+info.code);
		if (info.code == &quot;NetConnection.Connect.Success&quot;) {
			trace(&quot;connected to: &quot;+this.uri);
			conn_stat.text += &quot;connected to: &quot;+this.uri+newline;
			startTest(rec_nc);
		} else if (info.code == &quot;NetConnection.Connect.Failed&quot; || info.code == &quot;NetConnection.Connect.Closed&quot;) {
			trace(&quot;no connection to app&quot;);
			conn_stat.text += &quot;error connection failed&quot;+newline;
		}
	};
	rec_nc.connect(&quot;rtmp://&quot;+host+&quot;/&quot;+app+&quot;/&quot;);

	function startTest(nc) {
		_global.bwInfo = new BandwidthInfo(nc);
		_global.bwInfo.start();
	}
	for (i=0; i&lt;1000; i++) {
		data += &quot;C-&gt;S&quot;;
	}
	function BandwidthInfo(nc) {
		this.nc = nc;
		this.maxLength = 10;
		this.bwInHistory = new Array(this.maxLength);
		this.bwInCtr = 0;
		this.bwOutHistory = new Array(this.maxLength);
		this.bwOutCtr = 0;
		this.pingHistory = new Array(this.maxLength);
		this.headIn = 0;
		this.headOut = 0;
		this.headPing = 0;
		this.bBWOutStop = false;
		this.bBWInStop = false;
		this.onBWInTimeout = function() {
			clearInterval(this.bwInfoTimeout);
			this.bwInfoTimeout = null;
			delete this.bwInfoTimeout;
			this.bBWInStop = true;

			if (this.bwInCtr == 0) {
				conn_stat.text += &quot;unable to receive data from server.&quot;+newline;
				this.abort(&quot;unable to receive data from server.&quot;);
				return;
			}
			this.stop();
		};
		this.onBWOutTimeout = function() {
			clearInterval(this.bwInfoTimeout);
			this.bwInfoTimeout = null;
			delete this.bwInfoTimeout;
			this.bBWOutStop = true;

			if (this.bwOutCtr == 0) {
				conn_stat.text += &quot;unable to receive data from server\n&quot;;
				this.abort(&quot;unable to send data to server\n----------\n&quot;);
				return;
			}
			trace(&quot;testing bandwidth from server&quot;);
			conn_stat.text += &quot;testing bandwidth from server&quot;+newline;
			this.bwInfoTimeout = setInterval(this, &quot;onBWInTimeout&quot;, 5*1000);
			this.serverToClient();
		};
		this.clientToServer = function() {
			this.time = getTimer();
			size = 0;
			bwinfo = this;
			this.nc.ack = function(pingVal) {
				if (!bwinfo.bBWOutStop) {
					bwinfo.bwOutHistory[bwinfo.headOut++%bwinfo.maxLength] = Math.floor(size/(getTimer()-bwinfo.time)*1000);
					bwinfo.pingHistory[bwinfo.headPing++%bwinfo.maxLength] = pingVal;
					bwinfo.nc.call(&quot;recData&quot;,0,data);
					size += 4000;
					bwinfo.bwOutCtr++;
				}
			};
			this.nc.call(&quot;recData&quot;,0,data);
			this.nc.call(&quot;recData&quot;,0,data);
		};
		this.serverToClient = function() {
			this.time = getTimer();
			size = 0;
			bwinfo = this;
			nc.onEcho = function() {
				if (!bwinfo.bBWInStop) {
					bwinfo.bwInHistory[bwinfo.headIn++%bwinfo.maxLength] = Math.floor(size/(getTimer()-bwinfo.time)*1000);
					this.call(&quot;echoData&quot;,0,0);
					size += 4000;
					bwinfo.bwInCtr++;
				}
			};
			nc.call(&quot;echoData&quot;,0,0);
			nc.call(&quot;echoData&quot;,0,0);
		};
		this.start = function() {
			conn_stat.text += &quot;testing upload speed&quot;+newline;
			trace(&quot;testing upload speed&quot;);
			clearInterval(this.bwInfoTimeout);
			this.bwInfoTimeout = null;
			delete this.bwInfoTimeout;
			this.bwInfoTimeout = setInterval(this, &quot;onBWOutTimeout&quot;, 5*1000);
			this.clientToServer();
		};
		this.stop = function() {
			this.nc = null;
			var ping_rtt = 0;
			var bw_out = 0;
			var bw_in = 0;
			for (var i = 0; i&lt;this.maxLength &amp;&amp; i&lt;this.bwOutCtr; i++) {
				ping_rtt = Math.max(ping_rtt, this.pingHistory[i]);
			}
			for (var i = 0; i&lt;this.maxLength &amp;&amp; i&lt;this.bwOutCtr; i++) {
				bw_out += this.bwOutHistory[i];
			}
			bw_out /= Math.min(this.maxLength, this.bwOutCtr);
			bw_out = Math.round((bw_out/1024)*8);
			for (var i = 0; i&lt;this.maxLength &amp;&amp; i&lt;this.bwInCtr; i++) {
				bw_in += this.bwInHistory[i];
			}
			bw_in /= Math.min(this.maxLength, this.bwInCtr);
			bw_in = Math.round((bw_in/1024)*8);

			//record
			upstreamsAvailable.push(bw_out);
			downstreamsAvailable.push(bw_in);

			var s;
			s = &quot;bandwidth results:\n&quot;;
			s += &quot;   upstream: &quot;+bw_out+&quot; kbps\n&quot;;
			s += &quot;   downstream: &quot;+bw_in+&quot; kbps\n&quot;;
			s += &quot;   latency: &quot;+ping_rtt+&quot; ms\n&quot;;
			if (ping_rtt&gt;1000) {
				s += &quot;network appears to have a very high delay\n&quot;;
			}
			if ((bw_in&gt;500) &amp;&amp; (bw_out&gt;200)) {
				s += &quot;connection supports high quality speed\n----------\n&quot;;
			} else if ((bw_in&gt;=200) &amp;&amp; (bw_out&gt;=100)) {
				s += &quot;connection supports good quality speed\n----------\n&quot;;
			} else if ((bw_in&gt;100) &amp;&amp; (bw_out&gt;80)) {
				s += &quot;connection supports mid quality speed\n----------\n&quot;;
			} else if ((bw_in&gt;20) &amp;&amp; (bw_out&gt;15)) {
				s += &quot;connection supports slow quality speed\n----------\n&quot;;
			} else {
				s += &quot;connection supports very slow quality speed\n----------\n&quot;;
			}
			trace(s);
			conn_stat.text += s+newline;
			currentlyChecking = false;
			nextCheck = which+1;
		};
		this.abort = function(reason) {
			conn_stat.text += &quot;failed &quot;+reason+newline;
			trace(&quot;failed &quot;+reason);
			currentlyChecking = false;
			nextCheck = which+1;
		};
	}

}

checkIfRunning = setInterval(this, &quot;checkConnBusy&quot;, 1000);

function checkConnBusy() {
	if (currentlyChecking == false) {
		if (nextCheck&lt;theServers.length) {
			checkConnection(theServers[nextCheck][&quot;host&quot;], theServers[nextCheck][&quot;app&quot;], nextCheck);
		} else {
			clearInterval(checkIfRunning);
			conn_stat.text += &quot;comparing connection&quot;+newline;
			compareConnections();
		}
	}
}

maxValueIndex = function (array) {
	mxm = array[0];
	for (i=0; i&lt;array.length; i++) {
		if (array[i]&gt;mxm) {
			mxm = array.index;
		}
	}
	return mxm;
};

Array.prototype.indexOf = function(value) {
	var i = 0;
	var l = this.length;
	var res = -1;
	for (i; i&lt;l; i++) {
		if (this[i] == value) {
			res = i;
			break;
		}
	}
	return res;
};

function compareConnections() {
	bestConn = maxValueIndex(upstreamsAvailable);
	bestBandwidth = maxValueIndex(upstreamsAvailable);
	connectBestConn = upstreamsAvailable.indexOf(bestConn);
	setConnectionsInterval = setInterval(this, &quot;setConnections&quot;, 500);
}
function setConnections(){
	if(theServers[connectBestConn][&quot;host&quot;] != undefined &amp;&amp; theServers[connectBestConn][&quot;app&quot;] != undefined){
		clearInterval(setConnectionsInterval);
		conn_stat.text += &quot;choosing server: rtmp://&quot;+theServers[connectBestConn][&quot;host&quot;]+&quot;/&quot;+theServers[connectBestConn][&quot;app&quot;]+newline;
	}else{
		clearInterval(setConnectionsInterval);
		conn_stat.text += &quot;connection to the server(s) has failed&quot;+newline;
	}
}
</pre>
<p>
In order to get the above to work correctly with your own Flash Media Server, you simply need to edit the following line. </p>
<pre class="brush: as3;">
ncm.connect(&quot;your.rtmphost.com&quot;, &quot;application_name&quot;);
</pre>
<p>
This is the path to the application which will hold our Main.asc file. You will also need to edit the xml/server_config.xml file in order to test against several different Flash Media Servers. This file serves as the que by which the flash client will verify and test each of the different connections, and finally pick the fastest one.</p>
<pre class="brush: xml;">
&lt;servers version=&quot;1&quot; xmlns=&quot;http://xspf.org/ns/0/&quot;&gt;
  &lt;serverList&gt;
    &lt;server&gt;
      &lt;host&gt;first_host&lt;/host&gt;
      &lt;app&gt;first_app&lt;/app&gt;
    &lt;/server&gt;
	&lt;server&gt;
      &lt;host&gt;second_host&lt;/host&gt;
      &lt;app&gt;second_app&lt;/app&gt;
    &lt;/server&gt;
  &lt;/serverList&gt;
&lt;/servers&gt;
</pre>
<p>
We now have our Flash file ready, and our servers setup within the server_config.xml.</p>
<p>Next, we want to create the server side code that will allow our final swf to call server side functions in order to return the correct upload, download, and latency values.</p>
<pre class="brush: as3;">
application.onAppStart = function (info){
	for ( i = 0; i &lt; 500; i++ ) {
		data += &quot;S-&gt;C&quot;;
	}
	Client.prototype.recData = function(data) {
		this.ping();
		var v = this.getStats();
		this.call(&quot;ack&quot;, 0, v.ping_rtt);
	}
	Client.prototype.echoData = function() {
		this.call(&quot;onEcho&quot;, 0, data);
	};
	Client.prototype.getBWInfo = function() {
		return this.getStats();
	};
	Client.prototype.onConnTimeout = function(){
		clearInterval( this.connTimeout );
		this.connTimeout = null;
		application.disconnect(this);
	}
}
application.onConnect = function(client_obj, id) {
	application.acceptConnection(client_obj);
}
</pre>
<p>
We also need our NetConnManager.as file which allows for multiple port detections.</p>
<pre class="brush: as3;">
import mx.events.EventDispatcher;
class NetConnManager extends Object {
	//EventDispatcher needs these
	var addEventListener:Function;
	var removeEventListener:Function;
	var dispatchEvent:Function;
	var dispatchQueue:Function;
	//Constants
	private var k_DEFAULTCONNLIST = [{protocol:&quot;rtmp&quot;, port:1935}, {protocol:&quot;rtmp&quot;, port:443}, {protocol:&quot;rtmpt&quot;, port:80}, {protocol:&quot;rtmps&quot;, port:443}];
	private var k_TIMEOUT:Number = 60000;
	//Variables
	private var m_connList:Array;
	private var m_serverName:String;
	private var m_appName:String;
	private var m_streamName:String;
	private var m_connListCounter:Number;
	private var m_flashComConnectTimeOut:Number;
	private var m_validNetConnection:NetConnection;
	//Constructor
	function NetConnManager() {
		EventDispatcher.initialize(this);
	}
	//Public
	//Initiates all the connection attempts.
	//Note: If no connection list is passed, the default list is used
	function connect(p_serverName:String, p_appName:String, p_connList:Array) {
		m_serverName = p_serverName;
		m_appName = p_appName;
		m_connList = (p_connList != undefined) ? p_connList : k_DEFAULTCONNLIST;
		//Set a timeout function, just in case we never connect successfully
		clearInterval(m_flashComConnectTimeOut);
		m_flashComConnectTimeOut = setInterval(this, &quot;onFlashComConnectTimeOut&quot;, k_TIMEOUT, k_TIMEOUT);
		//Creates a NetConnection for each of the protocols/ports listed in the m_connList list.
		//Connection attempts occur at intervals of 1.5 seconds. The first connection to succeed
		//will be used, all the others will be closed.
		for (var i = 0; i&lt;m_connList.length; i++) {
			this[&quot;nc&quot;+i] = new NetConnection();
			this[&quot;nc&quot;+i].owner = this;
			this[&quot;nc&quot;+i].connIndex = i;
			this[&quot;nc&quot;+i].onStatus = function(info) {
				this.pending = false;
				this.owner.m_validNetConnection = this.owner[&quot;nc&quot;+this.connIndex];
				if (info.code == &quot;NetConnection.Connect.Success&quot;) {
					clearInterval(this.owner.m_flashComConnectTimeOut);
					this.owner.dispatchEvent({type:&quot;ncConnected&quot;, nc:this.owner.m_validNetConnection, protocol:this.owner.m_connList[this.connIndex].protocol, port:this.owner.m_connList[this.connIndex].port});
					for (var i = 0; i&lt;this.owner.m_connList.length; i++) {
						if (i == this.connIndex) {
							continue;
						}
						if (this.owner[&quot;nc&quot;+i].pending) {
							clearInterval(this.owner[&quot;ncInt&quot;+i]);
							this.owner[&quot;nc&quot;+i].onStatus = null;
							this.owner[&quot;nc&quot;+i].close();
							this.owner[&quot;nc&quot;+i] = null;
							delete this.owner[&quot;nc&quot;+i];
						}
					}
				} else {
					trace(this.owner.m_connList[this.connIndex].protocol+&quot;: &quot;+this.owner.m_connList[this.connIndex].port+&quot;, onStatus: &quot;+info.code+&quot; : &quot;+info.description);
				}
			};
			this[&quot;nc&quot;+i].pending = true;
		}
		m_connListCounter = 0;
		nextConnect();
	}
	//Public
	//Returns the active connection or null if it does not exist.
	function getActiveConnection(Void):NetConnection {
		return m_validNetConnection == undefined ? null : m_validNetConnection;
	}
	function closeConnections() {
		m_validNetConnection.close();
	}
	//Private
	//Walks through the connection list to try every protocol.
	private function nextConnect(Void):Void {
		clearInterval(this[&quot;ncInt&quot;+m_connListCounter]);
		this[&quot;nc&quot;+m_connListCounter].connect(m_connList[m_connListCounter].protocol+&quot;://&quot;+m_serverName+&quot;:&quot;+m_connList[m_connListCounter].port+&quot;/&quot;+m_appName);
		if (m_connListCounter&lt;(m_connList.length-1)) {
			m_connListCounter++;
			this[&quot;ncInt&quot;+m_connListCounter] = setInterval(this, &quot;nextConnect&quot;, 1500);
		}
	}
	//Private
	//Cleans up all conenctions if none have succeeded by the timeout interval
	private function onFlashComConnectTimeOut(timeout:Number):Void {
		clearInterval(m_flashComConnectTimeOut);
		this.dispatchEvent({type:&quot;ncFailedToConnect&quot;, timeout:timeout});
		for (var i = 0; i&lt;m_connList.length; i++) {
			if (this[&quot;nc&quot;+i].pending) {
				clearInterval(this[&quot;ncInt&quot;+i]);
				this[&quot;nc&quot;+i].onStatus = null;
				this[&quot;nc&quot;+i].close();
				this[&quot;nc&quot;+i] = null;
				delete this[&quot;nc&quot;+i];
			}
		}
	}
}
</pre>
<p>
<a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmFuZHdpZHRoX2V4YW1wbGVfdGhyZWUv" target=\"_blank\">Click here to see your bandwidth results</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vZG93bmxvYWRzL2JhbmR3aWR0aF9wYXJ0X3RocmVlLnppcA==">Download the source</a></p>
<p>This completes the tutorial series of the various methods to detect and stream media to flash clients. All three of these tutorials have built upon each other in order to provide solid methods for dynamically streaming any type of media via Flash Media Server.</p>
<p>Here are the links for this tutorial in its entirety:</p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0xLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLw==">Flash Media Server Streaming Speed Testing [Part 1] &#8211; Detect Upload, Download, and Latency Speeds</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0yLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLWFuZC1wb3J0LWNvbm5lY3Rpb24v">Flash Media Server Streaming Speed Testing [Part 2] &#8211; Detect Upload, Download, and Latency Speeds, and Port Connection</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0zLWNvbXBhcmUtbXVsdGlwbGUtc2VydmVyLXJlc291cmNlcy1wb3J0LWNvbm5lY3Rpb25zLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWQv">Flash Media Server Streaming Speed Testing [Part 3] &#8211; Compare Multiple Server Resources, Port Connections, Detect Upload, Download, and Latency Speed</a></p>
 <img src="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=218" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.derekentringer.com/blog/flash-media-server-streaming-speed-testing-part-3-compare-multiple-server-resources-port-connections-detect-upload-download-and-latency-speed/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Flash Media Server Streaming Speed Testing [Part 2] &#8211; Detect Upload, Download, and Latency Speeds, and Port Connection</title>
		<link>http://www.derekentringer.com/blog/flash-media-server-streaming-speed-testing-part-2-detect-upload-download-and-latency-speeds-and-port-connection/</link>
		<comments>http://www.derekentringer.com/blog/flash-media-server-streaming-speed-testing-part-2-detect-upload-download-and-latency-speeds-and-port-connection/#comments</comments>
		<pubDate>Tue, 12 May 2009 20:20:18 +0000</pubDate>
		<dc:creator>Derek J Entringer</dc:creator>
				<category><![CDATA[Code Samples]]></category>
		<category><![CDATA[FMS]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[bandwidth]]></category>
		<category><![CDATA[detection]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[flash media server]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[port]]></category>
		<category><![CDATA[speed]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[upload]]></category>

		<guid isPermaLink="false">http://www.derekentringer.com/blog/?p=216</guid>
		<description><![CDATA[
			
				
			
		

This tutorial is the second in a series of three. Part one of this tutorial outlined what is needed to detect a users upload, download, and latency between a Flash client and the Flash Media Server. Part 2 adds on the ability to detect which ports are available while connecting.
Again, Bandwidth detection is most important when connecting your users to the correctly compressed media to be streamed, recorded, or delivered via a Flash Media Server. This second example will walk you through the process of being able to detect a ...]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="clear:left; float:left; margin-top:10px; margin-bottom: 10px; margin-right:12px; margin-left:2px;">
			<a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2FwaS50d2VldG1lbWUuY29tL3NoYXJlP3VybD1odHRwJTNBJTJGJTJGd3d3LmRlcmVrZW50cmluZ2VyLmNvbSUyRmJsb2clMkZmbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0yLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLWFuZC1wb3J0LWNvbm5lY3Rpb24lMkY="><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.derekentringer.com%2Fblog%2Fflash-media-server-streaming-speed-testing-part-2-detect-upload-download-and-latency-speeds-and-port-connection%2F&amp;source=derekentringer&amp;style=normal&amp;service=TinyURL.com" height="61" width="50" /><br />
			</a>
		</div>
<p><!--PLAIN_TEXT--><br />
This tutorial is the second in a series of three. Part one of this tutorial outlined what is needed to detect a users upload, download, and latency between a Flash client and the Flash Media Server. Part 2 adds on the ability to detect which ports are available while connecting.</p>
<p>Again, Bandwidth detection is most important when connecting your users to the correctly compressed media to be streamed, recorded, or delivered via a Flash Media Server. This second example will walk you through the process of being able to detect a users download bandwidth, upload bandwidth, and the latency between the client computer and the host server, along with iterating through all of the available ports that allow you to connect to the Flash Media Server. All of the code is Actionscript 2.0, and I&#8217;ve setup a Flash Media Server 3.5 to host the server side scripting. I use Influxis as my Flash Media Server host for all of these tutorials and smaller examples.</p>
<p>First, we will add our NetConnManager object which will use the NetConnManager.as exteranal Actionscript file. This is the first part of our Flash Actionscript code.</p>
<pre class="brush: as3;">
import NetConnManager;

var startTime:Number = getTimer();
var ncm:NetConnManager = new NetConnManager();
var ncmListener:Object = new Object();

ncmListener.ncConnected = function(evt:Object) {
	trace(&quot;[&quot;+Math.round(getTimer()-startTime)+&quot;ms] successfully connected using &quot;+evt.protocol+&quot;:&quot;+evt.port);
	conn_stat.text += &quot;[&quot;+Math.round(getTimer()-startTime)+&quot;ms] successfully connected using &quot;+evt.protocol+&quot;:&quot;+evt.port+newline;
};
ncmListener.ncFailedToConnect = function(evt:Object) {
	trace(&quot;failed to connect after &quot;+evt.timeout+&quot; ms&quot;);
	conn_stat.text += &quot;failed to connect after &quot;+evt.timeout+&quot; ms&quot;+newline;
};
ncm.addEventListener(&quot;ncConnected&quot;, ncmListener);
ncm.addEventListener(&quot;ncFailedToConnect&quot;, ncmListener);

ncm.connect(&quot;your.rtmphost.com&quot;, &quot;your_application_name&quot;);
</pre>
<p>In order to get the above to work correctly with your own Flash Media Server, you simply need to edit the following line.</p>
<pre class="brush: as3;">
ncm.connect(&quot;your.rtmphost.com&quot;, &quot;your_application_name&quot;);
</pre>
<p>The following code is the same as part one of this series of tutorials. If you have not read part one, you can find it <a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0xLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLw==">here</a>.</p>
<pre class="brush: as3;">
function connectMe() {
	rec_nc = new NetConnection();
	rec_nc.onStatus = function(info) {
		trace(&quot;Level: &quot; + info.level + &quot; Code: &quot; + info.code);
		if (info.code == &quot;NetConnection.Connect.Success&quot;) {
			trace(&quot;connected to: &quot;+this.uri);
			conn_stat.text += &quot;connected to: &quot;+this.uri+newline;
			startTest(rec_nc);
		} else if (info.code == &quot;NetConnection.Connect.Failed&quot; || info.code == &quot;NetConnection.Connect.Closed&quot;) {
			trace(&quot;no connection to app&quot;);
			conn_stat.text += &quot;error connection failed&quot;+newline;
		}
	};
	rec_nc.connect(&quot;rtmp://y9cq49zks4.rtmphost.com/bwcheck/&quot;);
}

function startTest(nc) {
	_global.bwInfo = new BandwidthInfo(nc);
	_global.bwInfo.start();
}

for (i=0; i&lt;1000; i++) {
	data += &quot;C-&gt;S&quot;;
}
function BandwidthInfo(nc) {
	this.nc = nc;
	this.maxLength = 10;
	this.bwInHistory = new Array(this.maxLength);
	this.bwInCtr = 0;
	this.bwOutHistory = new Array(this.maxLength);
	this.bwOutCtr = 0;
	this.pingHistory = new Array(this.maxLength);
	this.headIn = 0;
	this.headOut = 0;
	this.headPing = 0;
	this.bBWOutStop = false;
	this.bBWInStop = false;
	this.onBWInTimeout = function() {
		clearInterval(this.bwInfoTimeout);
		this.bwInfoTimeout = null;
		delete this.bwInfoTimeout;
		this.bBWInStop = true;

		if (this.bwInCtr == 0) {
			conn_stat.text += &quot;unable to receive data from server.&quot;+newline;
			this.abort(&quot;unable to receive data from server.&quot;);
			return;
		}

		this.stop();
	};
	this.onBWOutTimeout = function() {
		clearInterval(this.bwInfoTimeout);
		this.bwInfoTimeout = null;
		delete this.bwInfoTimeout;
		this.bBWOutStop = true;

		if (this.bwOutCtr == 0) {
			conn_stat.text += &quot;unable to receive data from server&quot;+newline;
			this.abort(&quot;unable to send data to server&quot;);
			return;
		}

		trace(&quot;testing bandwidth from server&quot;);
		conn_stat.text += &quot;testing bandwidth from server&quot;+newline;
		this.bwInfoTimeout = setInterval(this, &quot;onBWInTimeout&quot;, 5*1000);
		this.serverToClient();
	};
	this.clientToServer = function() {
		this.time = getTimer();
		size = 0;
		bwinfo = this;
		this.nc.ack = function(pingVal) {
			if (!bwinfo.bBWOutStop) {
				bwinfo.bwOutHistory[bwinfo.headOut++%bwinfo.maxLength] = Math.floor(size/(getTimer()-bwinfo.time)*1000);
				bwinfo.pingHistory[bwinfo.headPing++%bwinfo.maxLength] = pingVal;
				bwinfo.nc.call(&quot;recData&quot;, 0, data);
				size += 4000;
				bwinfo.bwOutCtr++;
			}
		};
		this.nc.call(&quot;recData&quot;, 0, data);
		this.nc.call(&quot;recData&quot;, 0, data);
	};
	this.serverToClient = function() {
		this.time = getTimer();
		size = 0;
		bwinfo = this;
		nc.onEcho = function() {
			if (!bwinfo.bBWInStop) {
				bwinfo.bwInHistory[bwinfo.headIn++%bwinfo.maxLength] = Math.floor(size/(getTimer()-bwinfo.time)*1000);
				this.call(&quot;echoData&quot;, 0, 0);
				size += 4000;
				bwinfo.bwInCtr++;
			}
		};
		nc.call(&quot;echoData&quot;, 0, 0);
		nc.call(&quot;echoData&quot;, 0, 0);
	};
	this.start = function() {
		conn_stat.text += &quot;testing upload speed&quot;+newline;
		trace(&quot;testing upload speed&quot;);
		clearInterval(this.bwInfoTimeout);
		this.bwInfoTimeout = null;
		delete this.bwInfoTimeout;
		this.bwInfoTimeout = setInterval(this, &quot;onBWOutTimeout&quot;, 5*1000);
		this.clientToServer();
	};
	this.stop = function() {
		this.nc = null;
		var ping_rtt = 0;
		var bw_out = 0;
		var bw_in = 0;
		for (var i = 0; i&lt;this.maxLength &amp;&amp; i&lt;this.bwOutCtr; i++) {
			ping_rtt = Math.max(ping_rtt, this.pingHistory[i]);
		}
		for (var i = 0; i&lt;this.maxLength &amp;&amp; i&lt;this.bwOutCtr; i++) {
			bw_out += this.bwOutHistory[i];
		}
		bw_out /= Math.min(this.maxLength, this.bwOutCtr);
		bw_out = Math.round((bw_out/1024)*8);
		for (var i = 0; i&lt;this.maxLength &amp;&amp; i&lt;this.bwInCtr; i++) {
			bw_in += this.bwInHistory[i];
		}
		bw_in /= Math.min(this.maxLength, this.bwInCtr);
		bw_in = Math.round((bw_in/1024)*8);
		var s;
		s = &quot;bandwidth results:\n&quot;;
		s += &quot;   upstream: &quot;+bw_out+&quot; kbps\n&quot;;
		s += &quot;   downstream: &quot;+bw_in+&quot; kbps\n&quot;;
		s += &quot;   latency: &quot;+ping_rtt+&quot; ms\n&quot;;
		if (ping_rtt&gt;1000) {
			s += &quot;network appears to have a very high delay\n\n&quot;;
		}
		if ((bw_in&gt;500) &amp;&amp; (bw_out&gt;200)) {
			s += &quot;connection supports high quality speed\n\n&quot;;
		} else if ((bw_in&gt;=200) &amp;&amp; (bw_out&gt;=100)) {
			s += &quot;connection supports good quality speed\n\n&quot;;
		} else if ((bw_in&gt;100) &amp;&amp; (bw_out&gt;80)) {//(bw_in&lt;250) &amp;&amp; (bw_out&lt;80) &amp;&amp;
			s += &quot;connection supports mid quality speed\n\n&quot;;
		} else if ((bw_in&gt;20) &amp;&amp; (bw_out&gt;15)) {
			s += &quot;connection supports slow quality speed\n\n&quot;;
		} else {
			s += &quot;connection supports very slow quality speed\n\n&quot;;
		}
		trace(s);
		conn_stat.text += s+newline;
	};
	this.abort = function(reason) {
		conn_stat.text += &quot;failed &quot;+reason+newline;
		trace(&quot;failed &quot;+reason);
	};
}

connectMe();
</pre>
<p>
Next, lets setup our NetConnManager.as file. This external Actionscript class allows the ncm object to iterate through all of the available ports on the Flash Media Server, and lets you know which port it has connected successfully on the server. This is useful if you are dealing with a firewall that has blocked the default port of 1935.</p>
<pre class="brush: as3;">
import mx.events.EventDispatcher;
class NetConnManager extends Object {
	//EventDispatcher needs these
	var addEventListener:Function;
	var removeEventListener:Function;
	var dispatchEvent:Function;
	var dispatchQueue:Function;
	//Constants
	private var k_DEFAULTCONNLIST = [{protocol:&quot;rtmp&quot;, port:1935}, {protocol:&quot;rtmp&quot;, port:443}, {protocol:&quot;rtmpt&quot;, port:80}, {protocol:&quot;rtmps&quot;, port:443}];
	private var k_TIMEOUT:Number = 60000;
	//Variables
	private var m_connList:Array;
	private var m_serverName:String;
	private var m_appName:String;
	private var m_streamName:String;
	private var m_connListCounter:Number;
	private var m_flashComConnectTimeOut:Number;
	private var m_validNetConnection:NetConnection;
	//Constructor
	function NetConnManager() {
		EventDispatcher.initialize(this);
	}
	//Public
	//Initiates all the connection attempts.
	//Note: If no connection list is passed, the default list is used
	function connect(p_serverName:String, p_appName:String, p_connList:Array) {
		m_serverName = p_serverName;
		m_appName = p_appName;
		m_connList = (p_connList != undefined) ? p_connList : k_DEFAULTCONNLIST;
		//Set a timeout function, just in case we never connect successfully
		clearInterval(m_flashComConnectTimeOut);
		m_flashComConnectTimeOut = setInterval(this, &quot;onFlashComConnectTimeOut&quot;, k_TIMEOUT, k_TIMEOUT);
		//Creates a NetConnection for each of the protocols/ports listed in the m_connList list.
		//Connection attempts occur at intervals of 1.5 seconds. The first connection to succeed
		//will be used, all the others will be closed.
		for (var i = 0; i&lt;m_connList.length; i++) {
			this[&quot;nc&quot;+i] = new NetConnection();
			this[&quot;nc&quot;+i].owner = this;
			this[&quot;nc&quot;+i].connIndex = i;
			this[&quot;nc&quot;+i].onStatus = function(info) {
				this.pending = false;
				this.owner.m_validNetConnection = this.owner[&quot;nc&quot;+this.connIndex];
				if (info.code == &quot;NetConnection.Connect.Success&quot;) {
					clearInterval(this.owner.m_flashComConnectTimeOut);
					this.owner.dispatchEvent({type:&quot;ncConnected&quot;, nc:this.owner.m_validNetConnection, protocol:this.owner.m_connList[this.connIndex].protocol, port:this.owner.m_connList[this.connIndex].port});
					for (var i = 0; i&lt;this.owner.m_connList.length; i++) {
						if (i == this.connIndex) {
							continue;
						}
						if (this.owner[&quot;nc&quot;+i].pending) {
							clearInterval(this.owner[&quot;ncInt&quot;+i]);
							this.owner[&quot;nc&quot;+i].onStatus = null;
							this.owner[&quot;nc&quot;+i].close();
							this.owner[&quot;nc&quot;+i] = null;
							delete this.owner[&quot;nc&quot;+i];
						}
					}
				} else {
					trace(this.owner.m_connList[this.connIndex].protocol+&quot;: &quot;+this.owner.m_connList[this.connIndex].port+&quot;, onStatus: &quot;+info.code+&quot; : &quot;+info.description);
				}
			};
			this[&quot;nc&quot;+i].pending = true;
		}
		m_connListCounter = 0;
		nextConnect();
	}
	//Public
	//Returns the active connection or null if it does not exist.
	function getActiveConnection(Void):NetConnection {
		return m_validNetConnection == undefined ? null : m_validNetConnection;
	}
	function closeConnections() {
		m_validNetConnection.close();
	}
	//Private
	//Walks through the connection list to try every protocol.
	private function nextConnect(Void):Void {
		clearInterval(this[&quot;ncInt&quot;+m_connListCounter]);
		this[&quot;nc&quot;+m_connListCounter].connect(m_connList[m_connListCounter].protocol+&quot;://&quot;+m_serverName+&quot;:&quot;+m_connList[m_connListCounter].port+&quot;/&quot;+m_appName);
		if (m_connListCounter&lt;(m_connList.length-1)) {
			m_connListCounter++;
			this[&quot;ncInt&quot;+m_connListCounter] = setInterval(this, &quot;nextConnect&quot;, 1500);
		}
	}
	//Private
	//Cleans up all conenctions if none have succeeded by the timeout interval
	private function onFlashComConnectTimeOut(timeout:Number):Void {
		clearInterval(m_flashComConnectTimeOut);
		this.dispatchEvent({type:&quot;ncFailedToConnect&quot;, timeout:timeout});
		for (var i = 0; i&lt;m_connList.length; i++) {
			if (this[&quot;nc&quot;+i].pending) {
				clearInterval(this[&quot;ncInt&quot;+i]);
				this[&quot;nc&quot;+i].onStatus = null;
				this[&quot;nc&quot;+i].close();
				this[&quot;nc&quot;+i] = null;
				delete this[&quot;nc&quot;+i];
			}
		}
	}
}
</pre>
<p>
We now have our Flash file ready, but we still need our application setup on the Flash Server. Create a new application on your Flash Media Server, and name it however you want. That application name then goes into the connect function above, along with the url for the server.</p>
<p>Next, we want to create the server side code that will allow our final swf to call server side functions in order to return the correct upload, download, and latency values.</p>
<pre class="brush: as3;">
application.onAppStart = function (info){
	for ( i = 0; i &lt; 500; i++ ) {
		data += &quot;S-&gt;C&quot;;
	}
	Client.prototype.recData = function(data) {
		this.ping();
		var v = this.getStats();
		this.call(&quot;ack&quot;, 0, v.ping_rtt);
	}
	Client.prototype.echoData = function() {
		this.call(&quot;onEcho&quot;, 0, data);
	};
	Client.prototype.getBWInfo = function() {
		return this.getStats();
	};
	Client.prototype.onConnTimeout = function(){
		clearInterval( this.connTimeout );
		this.connTimeout = null;
		application.disconnect(this);
	}
}
application.onConnect = function(client_obj, id) {
	application.acceptConnection(client_obj);
}
</pre>
<p>
And, there you have it. These scripts allow you to check the users upload and download bandwidth capabilities, check how slow the server is allowing you to connect using latency detection, and provides you with the correct port that may be available from within your current network.</p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmFuZHdpZHRoX2V4YW1wbGVfdHdvLw==" target=\"_blank\">Click here to see your bandwidth results</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vZG93bmxvYWRzL2JhbmR3aWR0aF9wYXJ0X3R3by56aXA=">Download the source</a></p>
<p>Finally, be sure to have a look at my next tutorial using these same techniques. In part three, I will be adding the functionality to check multiple servers using this same code.</p>
<p>Here are the links for this tutorial in its entirety:</p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0xLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLw==">Flash Media Server Streaming Speed Testing [Part 1] &#8211; Detect Upload, Download, and Latency Speeds</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0yLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLWFuZC1wb3J0LWNvbm5lY3Rpb24v">Flash Media Server Streaming Speed Testing [Part 2] &#8211; Detect Upload, Download, and Latency Speeds, and Port Connection</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0zLWNvbXBhcmUtbXVsdGlwbGUtc2VydmVyLXJlc291cmNlcy1wb3J0LWNvbm5lY3Rpb25zLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWQv">Flash Media Server Streaming Speed Testing [Part 3] &#8211; Compare Multiple Server Resources, Port Connections, Detect Upload, Download, and Latency Speed</a></p>
 <img src="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=216" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.derekentringer.com/blog/flash-media-server-streaming-speed-testing-part-2-detect-upload-download-and-latency-speeds-and-port-connection/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Flash Media Server Streaming Speed Testing [Part 1] &#8211; Detect Upload, Download, and Latency Speeds</title>
		<link>http://www.derekentringer.com/blog/flash-media-server-streaming-speed-testing-part-1-detect-upload-download-and-latency-speeds/</link>
		<comments>http://www.derekentringer.com/blog/flash-media-server-streaming-speed-testing-part-1-detect-upload-download-and-latency-speeds/#comments</comments>
		<pubDate>Tue, 12 May 2009 20:18:19 +0000</pubDate>
		<dc:creator>Derek J Entringer</dc:creator>
				<category><![CDATA[Code Samples]]></category>
		<category><![CDATA[FMS]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[bandwidth]]></category>
		<category><![CDATA[detection]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[flash media server]]></category>
		<category><![CDATA[Influxis]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[speed]]></category>
		<category><![CDATA[streaming media]]></category>
		<category><![CDATA[upload]]></category>

		<guid isPermaLink="false">http://www.derekentringer.com/blog/?p=214</guid>
		<description><![CDATA[
			
				
			
		

This tutorial is the first in a series of three that builds upon the first Flash Bandwidth &#038; Port Detection tutorial I created a while back. These three articles look to make it even easier than the original post, and go more in depth on some of the streaming options, and have better structured server side code.
If you are interested in the original article, you can find it here.
Bandwidth detection is most important when connecting your users to the correctly compressed media to be streamed, recorded, or delivered via a ...]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="clear:left; float:left; margin-top:10px; margin-bottom: 10px; margin-right:12px; margin-left:2px;">
			<a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2FwaS50d2VldG1lbWUuY29tL3NoYXJlP3VybD1odHRwJTNBJTJGJTJGd3d3LmRlcmVrZW50cmluZ2VyLmNvbSUyRmJsb2clMkZmbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0xLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzJTJG"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.derekentringer.com%2Fblog%2Fflash-media-server-streaming-speed-testing-part-1-detect-upload-download-and-latency-speeds%2F&amp;source=derekentringer&amp;style=normal&amp;service=TinyURL.com" height="61" width="50" /><br />
			</a>
		</div>
<p><!--PLAIN_TEXT--><br />
This tutorial is the first in a series of three that builds upon the first Flash Bandwidth &#038; Port Detection tutorial I created a while back. These three articles look to make it even easier than the original post, and go more in depth on some of the streaming options, and have better structured server side code.</p>
<p>If you are interested in the original article, you can find it <a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1iYW5kd2lkdGgtcG9ydC1kZXRlY3Rpb24v">here</a>.</p>
<p>Bandwidth detection is most important when connecting your users to the correctly compressed media to be streamed, recorded, or delivered via a Flash Media Server. This example will walk you through the process of being able to detect a users download bandwidth, upload bandwidth, and the latency between the client computer and the host server. All of the code is Actionscript 2.0, and I&#8217;ve setup a Flash Media Server 3.5 to host the server side scripting. I use Influxis as my Flash Media Server host for all of these tutorials and smaller examples.</p>
<p>Now, onto the code.</p>
<p>First, lets put together our Flash Actionscript. Here our goal is to setup our connection manager, and create a BandwidthInfo object that will call to our main.asc file (this is explained next) for sending packets to the Flash Media server to the client, and vice versa.</p>
<pre class="brush: as3;">
function connectMe() {
	rec_nc = new NetConnection();
	rec_nc.onStatus = function(info) {
		trace(&quot;Level: &quot; + info.level + &quot; Code: &quot; + info.code);
		if (info.code == &quot;NetConnection.Connect.Success&quot;) {
			trace(&quot;connected to: &quot;+this.uri);
			conn_stat.text += &quot;connected to: &quot;+this.uri+newline;
			startTest(rec_nc);
		} else if (info.code == &quot;NetConnection.Connect.Failed&quot; || info.code == &quot;NetConnection.Connect.Closed&quot;) {
			trace(&quot;no connection to app&quot;);
			conn_stat.text += &quot;error connection failed&quot;+newline;
		}
	};
	rec_nc.connect(&quot;rtmp://your.host.com/application_name/&quot;);
}

function startTest(nc) {
	_global.bwInfo = new BandwidthInfo(nc);
	_global.bwInfo.start();
}

for (i=0; i&lt;1000; i++) {
	data += &quot;C-&gt;S&quot;;
}
function BandwidthInfo(nc) {
	this.nc = nc;
	this.maxLength = 10;
	this.bwInHistory = new Array(this.maxLength);
	this.bwInCtr = 0;
	this.bwOutHistory = new Array(this.maxLength);
	this.bwOutCtr = 0;
	this.pingHistory = new Array(this.maxLength);
	this.headIn = 0;
	this.headOut = 0;
	this.headPing = 0;
	this.bBWOutStop = false;
	this.bBWInStop = false;
	this.onBWInTimeout = function() {
		clearInterval(this.bwInfoTimeout);
		this.bwInfoTimeout = null;
		delete this.bwInfoTimeout;
		this.bBWInStop = true;

		if (this.bwInCtr == 0) {
			conn_stat.text += &quot;unable to receive data from server.&quot;+newline;
			this.abort(&quot;unable to receive data from server.&quot;);
			return;
		}

		this.stop();
	};
	this.onBWOutTimeout = function() {
		clearInterval(this.bwInfoTimeout);
		this.bwInfoTimeout = null;
		delete this.bwInfoTimeout;
		this.bBWOutStop = true;

		if (this.bwOutCtr == 0) {
			conn_stat.text += &quot;unable to receive data from server&quot;+newline;
			this.abort(&quot;unable to send data to server&quot;);
			return;
		}

		trace(&quot;testing bandwidth from server&quot;);
		conn_stat.text += &quot;testing bandwidth from server&quot;+newline;
		this.bwInfoTimeout = setInterval(this, &quot;onBWInTimeout&quot;, 5*1000);
		this.serverToClient();
	};
	this.clientToServer = function() {
		this.time = getTimer();
		size = 0;
		bwinfo = this;
		this.nc.ack = function(pingVal) {
			if (!bwinfo.bBWOutStop) {
				bwinfo.bwOutHistory[bwinfo.headOut++%bwinfo.maxLength] = Math.floor(size/(getTimer()-bwinfo.time)*1000);
				bwinfo.pingHistory[bwinfo.headPing++%bwinfo.maxLength] = pingVal;
				bwinfo.nc.call(&quot;recData&quot;, 0, data);
				size += 4000;
				bwinfo.bwOutCtr++;
			}
		};
		this.nc.call(&quot;recData&quot;, 0, data);
		this.nc.call(&quot;recData&quot;, 0, data);
	};
	this.serverToClient = function() {
		this.time = getTimer();
		size = 0;
		bwinfo = this;
		nc.onEcho = function() {
			if (!bwinfo.bBWInStop) {
				bwinfo.bwInHistory[bwinfo.headIn++%bwinfo.maxLength] = Math.floor(size/(getTimer()-bwinfo.time)*1000);
				this.call(&quot;echoData&quot;, 0, 0);
				size += 4000;
				bwinfo.bwInCtr++;
			}
		};
		nc.call(&quot;echoData&quot;, 0, 0);
		nc.call(&quot;echoData&quot;, 0, 0);
	};
	this.start = function() {
		conn_stat.text += &quot;testing upload speed&quot;+newline;
		trace(&quot;testing upload speed&quot;);
		clearInterval(this.bwInfoTimeout);
		this.bwInfoTimeout = null;
		delete this.bwInfoTimeout;
		this.bwInfoTimeout = setInterval(this, &quot;onBWOutTimeout&quot;, 5*1000);
		this.clientToServer();
	};
	this.stop = function() {
		this.nc = null;
		var ping_rtt = 0;
		var bw_out = 0;
		var bw_in = 0;
		for (var i = 0; i&lt;this.maxLength &amp;&amp; i&lt;this.bwOutCtr; i++) {
			ping_rtt = Math.max(ping_rtt, this.pingHistory[i]);
		}
		for (var i = 0; i&lt;this.maxLength &amp;&amp; i&lt;this.bwOutCtr; i++) {
			bw_out += this.bwOutHistory[i];
		}
		bw_out /= Math.min(this.maxLength, this.bwOutCtr);
		bw_out = Math.round((bw_out/1024)*8);
		for (var i = 0; i&lt;this.maxLength &amp;&amp; i&lt;this.bwInCtr; i++) {
			bw_in += this.bwInHistory[i];
		}
		bw_in /= Math.min(this.maxLength, this.bwInCtr);
		bw_in = Math.round((bw_in/1024)*8);
		var s;
		s += &quot;bandwidth\n&quot;;
		s += &quot;   upstream: &quot;+bw_out+&quot; kbps\n&quot;;
		s += &quot;   downstream: &quot;+bw_in+&quot; kbps\n&quot;;
		s += &quot;   latency: &quot;+ping_rtt+&quot; ms\n&quot;;
		if (ping_rtt&gt;1000) {
			s += &quot;network appears to have a very high delay\n\n&quot;;
		}
		if ((bw_in&gt;500) &amp;&amp; (bw_out&gt;200)) {
			s += &quot;connection supports high quality speed\n\n&quot;;
		} else if ((bw_in&gt;=200) &amp;&amp; (bw_out&gt;=100)) {
			s += &quot;connection supports good quality speed\n\n&quot;;
		} else if ((bw_in&gt;100) &amp;&amp; (bw_out&gt;80)) {//(bw_in&lt;250) &amp;&amp; (bw_out&lt;80) &amp;&amp;
			s += &quot;connection supports mid quality speed\n\n&quot;;
		} else if ((bw_in&gt;20) &amp;&amp; (bw_out&gt;15)) {
			s += &quot;connection supports slow quality speed\n\n&quot;;
		} else {
			s += &quot;connection supports very slow quality speed\n\n&quot;;
		}
		trace(s);
		conn_stat.text += s+newline;
	};
	this.abort = function(reason) {
		conn_stat.text += &quot;failed &quot;+reason+newline;
		trace(&quot;failed &quot;+reason);
	};
}

connectMe();
</pre>
<p>
In order to get the above to work correctly with your own Flash Media Server, you simply need to edit the following line.</p>
<pre class="brush: as3;">
rec_nc.connect(&quot;rtmp://your.host.com/application_name/&quot;);
</pre>
<p>
We now have our Flash file ready, but we still need our application setup on the Flash Server. Create a new application on your Flash Media Server, and name it however you want. That application name then goes into the connect function above, along with the url for the server.</p>
<p>Next, we want to create the server side code that will allow our final swf to call server side functions in order to return the correct upload, download, and latency values.</p>
<pre class="brush: as3;">
application.onAppStart = function (info){
	for ( i = 0; i &lt; 500; i++ ) {
		data += &quot;S-&gt;C&quot;;
	}
	Client.prototype.recData = function(data) {
		this.ping();
		var v = this.getStats();
		this.call(&quot;ack&quot;, 0, v.ping_rtt);
	}
	Client.prototype.echoData = function() {
		this.call(&quot;onEcho&quot;, 0, data);
	};
	Client.prototype.getBWInfo = function() {
		return this.getStats();
	};
	Client.prototype.onConnTimeout = function(){
		clearInterval( this.connTimeout );
		this.connTimeout = null;
		application.disconnect(this);
	}
}
application.onConnect = function(client_obj, id) {
	application.acceptConnection(client_obj);
}
</pre>
<p>
<a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmFuZHdpZHRoX2V4YW1wbGVfb25lLw==" target=\"_blank\">Click here to see your bandwidth results</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vZG93bmxvYWRzL2JhbmR3aWR0aF9wYXJ0X29uZS56aXA=">Download the source</a></p>
<p>Next, take a look at how you can use the above code along with Port Detection to be sure that your users can connect to your Flash Media Server applications from behind certain firewall setting in the <a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9iYW5kd2lkdGgtdXBsb2FkLWRvd25sb2FkLWxhdGVuY3ktc3BlZWQtYW5kLXBvcnQtZGV0ZWN0aW9uLXBhcnQtMg==">part two</a> of this three part tutorial series.</p>
<p>Here are the links for this tutorial in its entirety:</p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0xLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLw==">Flash Media Server Streaming Speed Testing [Part 1] &#8211; Detect Upload, Download, and Latency Speeds</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0yLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLWFuZC1wb3J0LWNvbm5lY3Rpb24v">Flash Media Server Streaming Speed Testing [Part 2] &#8211; Detect Upload, Download, and Latency Speeds, and Port Connection</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0zLWNvbXBhcmUtbXVsdGlwbGUtc2VydmVyLXJlc291cmNlcy1wb3J0LWNvbm5lY3Rpb25zLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWQv">Flash Media Server Streaming Speed Testing [Part 3] &#8211; Compare Multiple Server Resources, Port Connections, Detect Upload, Download, and Latency Speed</a></p>
 <img src="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=214" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.derekentringer.com/blog/flash-media-server-streaming-speed-testing-part-1-detect-upload-download-and-latency-speeds/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Flash Bandwidth &amp; Port Detection</title>
		<link>http://www.derekentringer.com/blog/flash-bandwidth-port-detection/</link>
		<comments>http://www.derekentringer.com/blog/flash-bandwidth-port-detection/#comments</comments>
		<pubDate>Wed, 29 Oct 2008 18:42:16 +0000</pubDate>
		<dc:creator>Derek J Entringer</dc:creator>
				<category><![CDATA[Code Samples]]></category>
		<category><![CDATA[FMS]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[1935]]></category>
		<category><![CDATA[443]]></category>
		<category><![CDATA[80]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[bandwidth]]></category>
		<category><![CDATA[calculate]]></category>
		<category><![CDATA[check]]></category>
		<category><![CDATA[detection]]></category>
		<category><![CDATA[flash media server]]></category>
		<category><![CDATA[netConnection]]></category>
		<category><![CDATA[port]]></category>
		<category><![CDATA[RTMP]]></category>
		<category><![CDATA[rtmps]]></category>
		<category><![CDATA[rtmpt]]></category>
		<category><![CDATA[test]]></category>

		<guid isPermaLink="false">http://derekentringer.com/blog/?p=118</guid>
		<description><![CDATA[
			
				
			
		

Being able to detect a users bandwidth can be an important part of serving them streaming video. Using their bandwidth you can stream a video that will play well using their connection speeds.
The first step is to create our NetConnection.as file. This is used by our bandwidth checking script to connect to our Flash Media Server via RTMP, select an available port, and talk with our bw_check.asc to report the users available bandwidth.

import mx.events.EventDispatcher;
class NCManager extends Object {
	// EventDispatcher needs these
	var addEventListener:Function;
	var removeEventListener:Function;
	var dispatchEvent:Function;
	var dispatchQueue:Function;
	// Constants
	private var k_DEFAULTCONNLIST = [{protocol:&#34;rtmp&#34;, ...]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="clear:left; float:left; margin-top:10px; margin-bottom: 10px; margin-right:12px; margin-left:2px;">
			<a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2FwaS50d2VldG1lbWUuY29tL3NoYXJlP3VybD1odHRwJTNBJTJGJTJGd3d3LmRlcmVrZW50cmluZ2VyLmNvbSUyRmJsb2clMkZmbGFzaC1iYW5kd2lkdGgtcG9ydC1kZXRlY3Rpb24lMkY="><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.derekentringer.com%2Fblog%2Fflash-bandwidth-port-detection%2F&amp;source=derekentringer&amp;style=normal&amp;service=TinyURL.com" height="61" width="50" /><br />
			</a>
		</div>
<p><!--PLAIN_TEXT--><br />
Being able to detect a users bandwidth can be an important part of serving them streaming video. Using their bandwidth you can stream a video that will play well using their connection speeds.</p>
<p>The first step is to create our NetConnection.as file. This is used by our bandwidth checking script to connect to our Flash Media Server via RTMP, select an available port, and talk with our bw_check.asc to report the users available bandwidth.</p>
<pre class="brush: as3;">
import mx.events.EventDispatcher;
class NCManager extends Object {
	// EventDispatcher needs these
	var addEventListener:Function;
	var removeEventListener:Function;
	var dispatchEvent:Function;
	var dispatchQueue:Function;
	// Constants
	private var k_DEFAULTCONNLIST = [{protocol:&quot;rtmp&quot;, port:1935}, {protocol:&quot;rtmp&quot;, port:443}, {protocol:&quot;rtmpt&quot;, port:80}, {protocol:&quot;rtmps&quot;, port:443}];
	private var k_TIMEOUT:Number = 60000;
	// Variables
	private var m_connList:Array;
	private var m_serverName:String;
	private var m_appName:String;
	private var m_streamName:String;
	private var m_connListCounter:Number;
	private var m_flashComConnectTimeOut:Number;
	private var m_validNetConnection:NetConnection;
	// Constructor
	function NCManager() {
		trace(&quot;NCManager initialized&quot;);
		EventDispatcher.initialize(this);
	}
	// Public
	// Initiates all the connection attempts.
	// Note: If no connection list is passed, the default list is used
	function connect(p_serverName:String, p_appName:String, p_connList:Array) {
		m_serverName = p_serverName;
		m_appName = p_appName;
		m_connList = (p_connList != undefined) ? p_connList : k_DEFAULTCONNLIST;
		// Set a timeout function, just in case we never connect successfully
		clearInterval(m_flashComConnectTimeOut);
		m_flashComConnectTimeOut = setInterval(this, &quot;onFlashComConnectTimeOut&quot;, k_TIMEOUT, k_TIMEOUT);
		// Creates a NetConnection for each of the protocols/ports listed in the m_connList list.
		// Connection attempts occur at intervals of 1.5 seconds. The first connection to succeed
		// will be used, all the others will be closed.
		for (var i = 0; i&lt;m_connList.length; i++) {
			this[&quot;nc&quot;+i] = new NetConnection();
			this[&quot;nc&quot;+i].owner = this;
			this[&quot;nc&quot;+i].connIndex = i;
			this[&quot;nc&quot;+i].onBWDone = function(p_bw) {
				this.owner.dispatchEvent({type:&quot;ncBandWidth&quot;, kbps:p_bw});
			};
			this[&quot;nc&quot;+i].onBWCheck = function(counter) {
				return ++counter;
			};
			this[&quot;nc&quot;+i].onStatus = function(info) {
				this.pending = false;
				this.owner.m_validNetConnection = this.owner[&quot;nc&quot;+this.connIndex];
				if (info.code == &quot;NetConnection.Connect.Success&quot;) {
					// We have a successfull connection
					clearInterval(this.owner.m_flashComConnectTimeOut);
					this.owner.dispatchEvent({type:&quot;ncConnected&quot;, nc:this.owner.m_validNetConnection, protocol:this.owner.m_connList[this.connIndex].protocol, port:this.owner.m_connList[this.connIndex].port});
					for (var i = 0; i&lt;this.owner.m_connList.length; i++) {
						if (i == this.connIndex) {
							continue;
						}
						if (this.owner[&quot;nc&quot;+i].pending) {
							clearInterval(this.owner[&quot;ncInt&quot;+i]);
							this.owner[&quot;nc&quot;+i].onStatus = null;
							this.owner[&quot;nc&quot;+i].close();
							this.owner[&quot;nc&quot;+i] = null;
							delete this.owner[&quot;nc&quot;+i];
						}
					}
				} else {
					trace(this.owner.m_connList[this.connIndex].protocol+&quot;: &quot;+this.owner.m_connList[this.connIndex].port+&quot;, onStatus: &quot;+info.code+&quot; : &quot;+info.description);
				}
			};
			this[&quot;nc&quot;+i].pending = true;
		}
		m_connListCounter = 0;
		nextConnect();
	}
	// Public
	// Returns the stream length for a given stream name.
	// Note: requires matching server function to be present on the server.
	function getStreamLength(streamName:String) {
		var res = new Object();
		res.owner = this;
		res.name = streamName;
		res.onResult = function(p_length) {
			this.owner.dispatchEvent({type:&quot;ncStreamLength&quot;, length:p_length, name:res.name});
		};
		m_validNetConnection.call(&quot;getStreamLength&quot;,res,streamName);
	}
	// Public
	// Calls a server-side function to initiate a bandwdith check.
	// Note: requires matching server function to be present on the server.
	function getBandWidth(Void):Void {
		m_validNetConnection.call(&quot;checkBandwidth&quot;,null);
	}
	// Public
	// Returns the active connection or null if it does not exist.
	function getActiveConnection(Void):NetConnection {
		trace(m_validNetConnection == undefined ? null : m_validNetConnection);
		return m_validNetConnection == undefined ? null : m_validNetConnection;
	}
	function closeConnections() {
		trace(&quot;CLOSING= &quot;+m_validNetConnection);
		m_validNetConnection.close();
	}
	// Private
	// Walks through the connection list to try every protocol.
	private function nextConnect(Void):Void {
		clearInterval(this[&quot;ncInt&quot;+m_connListCounter]);
		this[&quot;nc&quot;+m_connListCounter].connect(m_connList[m_connListCounter].protocol+&quot;://&quot;+m_serverName+&quot;:&quot;+m_connList[m_connListCounter].port+&quot;/&quot;+m_appName);
		if (m_connListCounter&lt;(m_connList.length-1)) {
			m_connListCounter++;
			this[&quot;ncInt&quot;+m_connListCounter] = setInterval(this, &quot;nextConnect&quot;, 1500);
		}
	}
	// Private
	// Cleans up all conenctions if none have succeeded by the timeout interval
	private function onFlashComConnectTimeOut(timeout:Number):Void {
		clearInterval(m_flashComConnectTimeOut);
		this.dispatchEvent({type:&quot;ncFailedToConnect&quot;, timeout:timeout});
		for (var i = 0; i&lt;m_connList.length; i++) {
			if (this[&quot;nc&quot;+i].pending) {
				clearInterval(this[&quot;ncInt&quot;+i]);
				this[&quot;nc&quot;+i].onStatus = null;
				this[&quot;nc&quot;+i].close();
				this[&quot;nc&quot;+i] = null;
				delete this[&quot;nc&quot;+i];
			}
		}
	}
}
</pre>
<p>The second step is to create our FMS server side code. The bwcheck.asc file sends packets at a size of about 16Kb from the FMS and calculates the response latency over the users network.</p>
<pre class="brush: as3;">
application.onConnect = function(p_client, p_autoSenseBW) {
	this.acceptConnection(p_client);
	if (p_autoSenseBW)
		this.calculateClientBw(p_client);
	else
		p_client.call(&quot;onBWDone&quot;);
}
Client.prototype.getStreamLength = function(p_streamName) {
	return Stream.length(p_streamName);
}
Client.prototype.checkBandwidth = function() {
	application.calculateClientBw(this);
}
application.calculateClientBw = function(p_client) {
	p_client.payload = new Array();
	for (var i=0; i&lt;1200; i++){
		p_client.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.client = p_client;
	var stats = p_client.getStats();
	var now = (new Date()).getTime()/1;
	res.pakSent = new Array();
	res.pakRecv = new Array();
	res.beginningValues = {b_down:stats.bytes_out, b_up:stats.bytes_in, time:now};
	res.onResult = function(p_val) {
		var now = (new Date()).getTime()/1;
		this.pakRecv[this.count] = now;
		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);
		}
		if ( this.count == 2 &amp;&amp; (timePassed&lt;2000)) {
			this.pakSent[res.sent++] = now;
			this.cumLatency++;
			this.client.call(&quot;onBWCheck&quot;, res, this.client.payload);
		} else if ( this.sent == this.count ) {
			//see if we need to normalize latency
			if ( this.latency &gt;= 100 ) {
				if (  this.pakRecv[1] - this.pakRecv[0] &gt; 1000 ) {
					this.latency = 100;
				}
			}
			delete this.client.payload;
			//got back responses for all the packets compute the bandwidth
			var stats = this.client.getStats();
			var deltaDown = (stats.bytes_out - this.beginningValues.b_down)*8/1000;
			var deltaTime = ((now - this.beginningValues.time) - (this.latency * this.cumLatency) )/1000;
			if ( deltaTime &lt;= 0 )
				deltaTime = (now - this.beginningValues.time)/1000;

			var kbitDown = Math.round(deltaDown/deltaTime);
			trace(&quot;onBWDone: kbitDown = &quot; + kbitDown + &quot;, deltaDown= &quot; + deltaDown + &quot;, deltaTime = &quot; + deltaTime + &quot;, latency = &quot; + this.latency + &quot;KBytes &quot; + (stats.bytes_out - this.beginningValues.b_down)/1024) ;
			this.client.call(&quot;onBWDone&quot;, null, kbitDown,  deltaDown, deltaTime, this.latency );
		}
	}
	res.pakSent[res.sent++] = now;
	p_client.call(&quot;onBWCheck&quot;, res, &quot;&quot;);
	res.pakSent[res.sent++] = now;
	p_client.call(&quot;onBWCheck&quot;, res, p_client.payload);
}
</pre>
<p>Third step. Bring everything together within our flash file, and print our results to text fields on the stage.</p>
<pre class="brush: as3;">
stop();

import NCManager;

var ns:NetStream;
var fileName:String;
var k_STARTTIME:Number = getTimer();

//server info
var k_SERVERNAME:String = &quot;server_name&quot;;
var k_APPNAME:String = &quot;application_folder_name&quot;;
var k_ASC_PATH:String = &quot;rtmp://&quot;+k_SERVERNAME+&quot;/&quot;+k_APPNAME+&quot;/bwcheck.asc&quot;;

nc = new NetConnection();
nc.connect(k_ASC_PATH,true);
nc.onStatus = function(info) {
	trace(&quot;Level: &quot;+info.level+&quot; Code: &quot;+info.code);
	if (info.code == &quot;NetConnection.Connect.Success&quot;) {
		trace(&quot;loaded: &quot;+this.uri);
	}
};

//the variable p_bw returned by bwcheck.asc holds a value equal to the detected download speed in kilobits per second
//for best results we should serve video that is encoded at a rate less than or equal to kbitsDown
NetConnection.prototype.onBWDone = function(p_bw) {
	trace(&quot;BANDWIDTH= &quot;+p_bw);
	bandwidth.text = &quot;Bandwidth= &quot;+p_bw
	//close the Netconnection to bwcheck
	this.close();
};

NetConnection.prototype.onBWCheck = function() {
	return ++counter;
};

var ncm:NCManager = new NCManager();
var ncmListener:Object = new Object();

//fires when it has found a successfull connection
ncmListener.ncConnected = function(evt:Object) {
	trace(&quot;[&quot;+Math.round(getTimer()-k_STARTTIME)+&quot;ms] Successfully connected using &quot;+evt.protocol+&quot;:&quot;+evt.port);
	port.text = &quot;connected using &quot;+evt.protocol+&quot;:&quot;+evt.port
};

//fires when it has timed-out trying to find a good connection
ncmListener.ncFailedToConnect = function(evt:Object) {
	trace(&quot;Failed to connect after &quot;+evt.timeout+&quot; milliseconds.&quot;);
};

//fires when streamlength has been detected
ncmListener.ncStreamLength = function(evt:Object) {
	trace(&quot;[&quot;+Math.round(getTimer()-k_STARTTIME)+&quot;ms] Streamlength of &quot;+evt.name+&quot; is &quot;+evt.length+&quot; seconds.&quot;);
};

//set listeners on the NCM instance
ncm.addEventListener(&quot;ncConnected&quot;,ncmListener);
ncm.addEventListener(&quot;ncFailedToConnect&quot;,ncmListener);
ncm.addEventListener(&quot;ncBandWidth&quot;,ncmListener);
ncm.addEventListener(&quot;ncStreamLength&quot;,ncmListener);

//call the connect method on NCM instance
ncm.connect(k_SERVERNAME,k_APPNAME);
</pre>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vZmxhc2hfYmFuZHdpZHRoX2FuZF9wb3J0X2RldGVjdGlvbi8=" target=\"_blank\">Click here to see your bandwidth results.</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vZG93bmxvYWRzL2ZsYXNoX2JhbmR3aWR0aF9hbmRfcG9ydF9kZXRlY3Rpb24uemlw">Download the source</a></p>
<p>This tutorial has been updated, and is available in the following 3-part series:</p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0xLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLw==">Flash Media Server Streaming Speed Testing [Part 1] &#8211; Detect Upload, Download, and Latency Speeds</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0yLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWRzLWFuZC1wb3J0LWNvbm5lY3Rpb24v">Flash Media Server Streaming Speed Testing [Part 2] &#8211; Detect Upload, Download, and Latency Speeds, and Port Connection</a></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vYmxvZy9mbGFzaC1tZWRpYS1zZXJ2ZXItc3RyZWFtaW5nLXNwZWVkLXRlc3RpbmctcGFydC0zLWNvbXBhcmUtbXVsdGlwbGUtc2VydmVyLXJlc291cmNlcy1wb3J0LWNvbm5lY3Rpb25zLWRldGVjdC11cGxvYWQtZG93bmxvYWQtYW5kLWxhdGVuY3ktc3BlZWQv">Flash Media Server Streaming Speed Testing [Part 3] &#8211; Compare Multiple Server Resources, Port Connections, Detect Upload, Download, and Latency Speed</a></p>
 <img src="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=118" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.derekentringer.com/blog/flash-bandwidth-port-detection/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
