<?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; download</title>
	<atom:link href="http://www.derekentringer.com/blog/tag/download/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>AS3 MP3 Player</title>
		<link>http://www.derekentringer.com/blog/as3-mp3-player/</link>
		<comments>http://www.derekentringer.com/blog/as3-mp3-player/#comments</comments>
		<pubDate>Fri, 05 Sep 2008 16:22:33 +0000</pubDate>
		<dc:creator>Derek J Entringer</dc:creator>
				<category><![CDATA[Code Samples]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[as3]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[mp3]]></category>
		<category><![CDATA[player]]></category>

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

I have an upcoming project that will require an mp3 player that can load multiple songs, and let users choose which track they would like to listen to. I created this as a test, and will be developing it further for use on the site itself.
The player loads in mp3&#8242;s from an external file based on xml settings.
Here&#8217;s the actionscript 3 that is involved:

var getMusic:URLRequest;
var music:Sound = new Sound();
var soundChannel:SoundChannel;
var currentSound:Sound = music;
var pos:Number;
var currentIndex:Number = 0;
var songPlaying:Boolean = false;
var xml:XML;
var songlist:XMLList;
//preloader
function loadProgress(event:ProgressEvent):void {
    var percentLoaded:Number = ...]]></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=aHR0cDovL2FwaS50d2VldG1lbWUuY29tL3NoYXJlP3VybD1odHRwJTNBJTJGJTJGd3d3LmRlcmVrZW50cmluZ2VyLmNvbSUyRmJsb2clMkZhczMtbXAzLXBsYXllciUyRg=="><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.derekentringer.com%2Fblog%2Fas3-mp3-player%2F&amp;source=derekentringer&amp;style=normal&amp;service=TinyURL.com" height="61" width="50" /><br />
			</a>
		</div>
<p><!--PLAIN_TEXT--><br />
I have an upcoming project that will require an mp3 player that can load multiple songs, and let users choose which track they would like to listen to. I created this as a test, and will be developing it further for use on the site itself.</p>
<p>The player loads in mp3&#8242;s from an external file based on xml settings.</p>
<p>Here&#8217;s the actionscript 3 that is involved:</p>
<pre class="brush: as3;">
var getMusic:URLRequest;
var music:Sound = new Sound();
var soundChannel:SoundChannel;
var currentSound:Sound = music;
var pos:Number;
var currentIndex:Number = 0;
var songPlaying:Boolean = false;
var xml:XML;
var songlist:XMLList;
//preloader
function loadProgress(event:ProgressEvent):void {
    var percentLoaded:Number = event.bytesLoaded/event.bytesTotal;
    percentLoaded = Math.round(percentLoaded * 100);
	if(percentLoaded &lt; 20){
		trace(&quot;loading&quot;);
	} else{
	}
}
function completeHandler(event):void {
    trace(&quot;DONE&quot;);
}
//load the xml
var loader:URLLoader = new URLLoader(); //create a new URLLoader Object
loader.addEventListener(Event.COMPLETE, whenLoaded); //add an event listener to that object
loader.load(new URLRequest(&quot;songs.xml&quot;)); //Requests our xml file that contains our song data
function whenLoaded(e:Event):void //WhenLoaded function(see line 50) runs when line 50 is complete
{
	xml = new XML(e.target.data);
	songlist = xml.song; //accesses our song tag in our xml file
	getMusic = new URLRequest(songlist[0].url);//get music from songlist
	music.load(getMusic);//load music
	soundChannel = music.play();//plays the music
	songTXT.text = songlist[0].title; //gets song name from xml
	artistTXT.text = songlist[0].artist; //gets artist name
	albumTXT.text = songlist[0].album;  //gets album name
	soundChannel.addEventListener(Event.SOUND_COMPLETE, nextSong);//runs the next song function when a song completes
}
//add mouse events
next_btn.addEventListener(MouseEvent.CLICK, nextSong);
prev_btn.addEventListener(MouseEvent.CLICK, prevSong);
pause_btn.addEventListener(MouseEvent.CLICK,pauseSong);
/*--------Skips Songs----------------------------------------*/
function nextSong(e:Event):void
{
	if (currentIndex &gt; (songlist.length() - 1))
	{
		currentIndex++;
	}
	else
	{
		currentIndex = 0;
	}
	var nextReq:URLRequest = new URLRequest(songlist[currentIndex].url);
	var nextTitle:Sound = new Sound(nextReq);
	soundChannel.stop();
	songTXT.text = songlist[currentIndex].title;
	artistTXT.text = songlist[currentIndex].artist;
	albumTXT.text = songlist[currentIndex].album;
	soundChannel = nextTitle.play();
	songPlaying = true;
	currentSound = nextTitle;
	soundChannel.addEventListener(Event.SOUND_COMPLETE, nextSong);
}
//manage songs, and load their info
function prevSong(e:Event):void
{
	if (currentIndex &lt; 0)
	{
		currentIndex--;
	}
	else
	{
		currentIndex = songlist.length() - 1;
	}
	var nextReq:URLRequest = new URLRequest(songlist[currentIndex].url);
	var prevTitle:Sound = new Sound(nextReq);
	soundChannel.stop();
	songTXT.text = songlist[currentIndex].title;
	artistTXT.text = songlist[currentIndex].artist;
	albumTXT.text = songlist[currentIndex].album;
	soundChannel = prevTitle.play();
	songPlaying = true;
	currentSound = prevTitle;
	soundChannel.addEventListener(Event.SOUND_COMPLETE, nextSong);
}
function pauseSong(e:Event):void
{
	pos = soundChannel.position; //pause song at current position
	soundChannel.stop(); //stop sound
	songPlaying = false; // songPlaying is now equal to false
	play_btn.addEventListener(MouseEvent.CLICK,playSong);
}
function playSong(e:Event):void
{
	if(songPlaying == false) //if songplaying is equal to false run function below
	{
		soundChannel = currentSound.play(pos); //play from current position(used if it was paused)
		soundChannel.addEventListener(Event.SOUND_COMPLETE, nextSong);//run nextSong function if current song is complete
		songPlaying = true; //songPlaying is now true
		play_btn.removeEventListener(MouseEvent.CLICK,playSong);
	}
}
</pre>
<p>
Here is the xml:</p>
<pre class="brush: xml;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
&lt;ipod&gt;
	&lt;song&gt;
		&lt;title&gt;My Hero&lt;/title&gt;
		&lt;artist&gt;Foo Fighters&lt;/artist&gt;
		&lt;album&gt;The Colour And The Shape&lt;/album&gt;
		&lt;url&gt;songs/Hero.mp3&lt;/url&gt;
	&lt;/song&gt;
	&lt;song&gt;
		&lt;title&gt;Learn To Fly&lt;/title&gt;
		&lt;artist&gt;Foo Fighters&lt;/artist&gt;
		&lt;album&gt;Theres Nothing Left To Lose&lt;/album&gt;
		&lt;url&gt;songs/Fly.mp3&lt;/url&gt;
	&lt;/song&gt;
&lt;/ipod&gt;
</pre>
<p>
<a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vZG93bmxvYWRzL21wM19wbGF5ZXIuemlw">Download the source</a> (Note: The mp3&#8242;s used are not included in the download)</p>
 <img src="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=70" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.derekentringer.com/blog/as3-mp3-player/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FLV Player (Progressive Download) with Preloader</title>
		<link>http://www.derekentringer.com/blog/flv-player-progressive-download-with-preloader/</link>
		<comments>http://www.derekentringer.com/blog/flv-player-progressive-download-with-preloader/#comments</comments>
		<pubDate>Thu, 21 Aug 2008 16:41:02 +0000</pubDate>
		<dc:creator>Derek J Entringer</dc:creator>
				<category><![CDATA[Code Samples]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[as2]]></category>
		<category><![CDATA[controls]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[flv]]></category>
		<category><![CDATA[pause]]></category>
		<category><![CDATA[play]]></category>
		<category><![CDATA[player]]></category>
		<category><![CDATA[progressive]]></category>
		<category><![CDATA[rewind]]></category>
		<category><![CDATA[scrubbing]]></category>
		<category><![CDATA[simple]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[volume]]></category>

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

Here I have all of the code necessary to setup a simple AS2 flv player using progressive download. All of this script is in the first frame of the movie with the appropriate movie clips available on the stage.
First, We setup all of our controls including our Play/Pause button, Rewind, Scrubbing, and volume controls.


stop();

/*--------------------------------------------------------------------------------*/
//sound settings/controls
/*--------------------------------------------------------------------------------*/

globalsound = new Sound();
globalsound.setVolume(100);
volume_slide.volume_slider._x = volume_slide.volume_bar._width-volume_slide.volume_slider._width;

b_volume.onRelease = function() {
	if(globalsound.getVolume() == 100){
		b_volume.gotoAndStop(2);
		globalsound.setVolume(0);
	}else if(globalsound.getVolume() == 0){
		b_volume.gotoAndStop(1);
		globalsound.setVolume(100);
	}
}

//volume scrubbing
var pTop_volume:Number = volume_slide.volume_slider._y;
var pLeft_volume:Number = 0;
var pBottom_volume:Number = volume_slide.volume_slider._y;
var pRight_volume:Number = volume_slide.volume_bar._width-volume_slide.volume_slider._width;

volume_slide.volume_slider.onPress = function() {
	startDrag(&#34;volume_slide.volume_slider&#34;, false, pLeft_volume, pTop_volume, pRight_volume, pBottom_volume);
	dragging = ...]]></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=aHR0cDovL2FwaS50d2VldG1lbWUuY29tL3NoYXJlP3VybD1odHRwJTNBJTJGJTJGd3d3LmRlcmVrZW50cmluZ2VyLmNvbSUyRmJsb2clMkZmbHYtcGxheWVyLXByb2dyZXNzaXZlLWRvd25sb2FkLXdpdGgtcHJlbG9hZGVyJTJG"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.derekentringer.com%2Fblog%2Fflv-player-progressive-download-with-preloader%2F&amp;source=derekentringer&amp;style=normal&amp;service=TinyURL.com" height="61" width="50" /><br />
			</a>
		</div>
<p><!--PLAIN_TEXT--></p>
<p>Here I have all of the code necessary to setup a simple AS2 flv player using progressive download. All of this script is in the first frame of the movie with the appropriate movie clips available on the stage.</p>
<p>First, We setup all of our controls including our Play/Pause button, Rewind, Scrubbing, and volume controls.</p>
<pre class="brush: as3;">

stop();

/*--------------------------------------------------------------------------------*/
//sound settings/controls
/*--------------------------------------------------------------------------------*/

globalsound = new Sound();
globalsound.setVolume(100);
volume_slide.volume_slider._x = volume_slide.volume_bar._width-volume_slide.volume_slider._width;

b_volume.onRelease = function() {
	if(globalsound.getVolume() == 100){
		b_volume.gotoAndStop(2);
		globalsound.setVolume(0);
	}else if(globalsound.getVolume() == 0){
		b_volume.gotoAndStop(1);
		globalsound.setVolume(100);
	}
}

//volume scrubbing
var pTop_volume:Number = volume_slide.volume_slider._y;
var pLeft_volume:Number = 0;
var pBottom_volume:Number = volume_slide.volume_slider._y;
var pRight_volume:Number = volume_slide.volume_bar._width-volume_slide.volume_slider._width;

volume_slide.volume_slider.onPress = function() {
	startDrag(&quot;volume_slide.volume_slider&quot;, false, pLeft_volume, pTop_volume, pRight_volume, pBottom_volume);
	dragging = true;
	this.onEnterFrame = function() {
		globalsound.setVolume((volume_slide.volume_slider._x)*(volume_slide.volume_bar._width/25));
		trace((volume_slide.volume_slider._x)*(volume_slide.volume_bar._width/25));
	};
};
volume_slide.volume_slider.onRelease = function() {
	dragging = false;
	stopDrag();
	delete this.onEnterFrame;
};
volume_slide.volume_slider.onReleaseOutside = function() {
	dragging = false;
	stopDrag();
	delete this.onEnterFrame;
};

/*--------------------------------------------------------------------------------*/
//play/pause controls
/*--------------------------------------------------------------------------------*/

b_play.onRelease = function() {
	if (b_play._currentframe == 1) {
		ns.pause();
		b_play.gotoAndStop(2);
	} else {
		ns.pause();
		b_play.gotoAndStop(1);
	}
};
b_rewind.onRelease = function() {
	ns.seek(0);
}
</pre>
<p>Next, we tell flash where to find our flv file. I have not included any automatic Meta Data Handlers, so we also have to specify the length of the video in order to properly setup the scrub bar. Again, this is just to keep it simple.</p>
<pre class="brush: as3;">

/*--------------------------------------------------------------------------------*/
//video loading/controls
/*--------------------------------------------------------------------------------*/

//main video directory
var dir = &quot;path/to/your/flv&quot;;

//video properties
var vid = &quot;name of your flv&quot;;
var vid_length = &quot;length of your flv in seconds&quot;;
</pre>
<p>Here we have our NetConnection setup with our bufferTime, and I am also calling two custom functions: drawLoader, and timing. The drawLoader function is the preloader, and the timing will setup our scrub bar.</p>
<pre class="brush: as3;">

var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
video.attachVideo(ns);
ns.setBufferTime(15);
ns.play(dir+vid);
ns.pause();
drawLoader();
timing(vid_length);

/*--------------------------------------------------------------------------------*/
//scrubber functions
/*--------------------------------------------------------------------------------*/

function timing(fTime:Number) {
	//the length of the movie
	var finalTime:Number = fTime;
	var time_interval:Number = setInterval(checkTime, 10, ns);
	//function for the interval
	function checkTime(ns:NetStream) {
	   //movie time
	   var ns_seconds:Number = ns.time;
	   //parameters for the scrubber
	   var finalWidth:Number = timer_bar.slider._width-timer_bar.scrubber._width;
	   var movVar:Number = finalWidth/finalTime;
	   timer_bar.scrubber._x = movVar*ns_seconds;
	   //values for the scrubber position
	   var pTop:Number = timer_bar.scrubber._y;
	   var pLeft:Number = 0;
	   var pBottom:Number = timer_bar.scrubber._y;
	   var pRight:Number = timer_bar.slider._width-timer_bar.scrubber._width;
	   //scrubber is pressed
	   timer_bar.scrubber.onPress = function() {
	       clearInterval(time_interval);
	       //dragging
	       startDrag(&quot;timer_bar.scrubber&quot;, false, pLeft, pTop, pRight, pBottom);
	       dragging = true;
	       //seek as scrubber is moved
	       this.onEnterFrame = function() {
	           ns_seconds = this._x/movVar;
	           ns.seek(ns_seconds);
	       };
	   };
	   timer_bar.scrubber.onRelease = function() {
	       dragging = false;
	       stopDrag();
	       delete this.onEnterFrame;
	       time_interval = setInterval(checkTime, 10, ns);
	   };
	   timer_bar.scrubber.onReleaseOutside = function() {
	       dragging = false;
	       stopDrag();
	       delete this.onEnterFrame;
	       time_interval = setInterval(checkTime, 10, ns);
	   };
	}
}

/*--------------------------------------------------------------------------------*/
//preloading functions
/*--------------------------------------------------------------------------------*/

function drawLoader() {

	video.clear();

	loading._visible = true;
	progressBar_mc._visible = true;
	createEmptyMovieClip(&quot;progressBar_mc&quot;,getNextHighestDepth());
	progressBar_mc.createEmptyMovieClip(&quot;bar_mc&quot;,progressBar_mc.getNextHighestDepth());

	with (progressBar_mc.bar_mc) {
		beginFill(0xD7D7D9);
		moveTo(0,0);
		lineTo(100,0);
		lineTo(100,10);
		lineTo(0,10);
		lineTo(0,0);
		endFill();
		_xscale = 0;
		_alpha = 90;
	}
	progressBar_mc.createEmptyMovieClip(&quot;stroke_mc&quot;,progressBar_mc.getNextHighestDepth());

	with (progressBar_mc.stroke_mc) {
		lineStyle(0,0xD7D7D9);
		moveTo(0,0);
		lineTo(100,0);
		lineTo(100,10);
		lineTo(0,10);
		lineTo(0,0);
		_alpha = 90;
	}
	progressBar_mc._x = 140;
	progressBar_mc._y = 115;

	var loaded_interval:Number = setInterval(checkBytesLoaded, 150);

	function checkBytesLoaded() {

		var pctLoaded_1:Number = Math.round(ns.bytesLoaded/ns.bytesTotal*100);
		pctLoaded_total = pctLoaded_1;
		trace(&quot;total loaded= &quot;+pctLoaded_total);
		progressBar_mc.bar_mc._xscale = pctLoaded_total*2;

		if (pctLoaded_total&gt;=50) {

			ns.seek(0);
			ns.pause();

			clearInterval(loaded_interval);
			progressBar_mc._visible = false;
			loading._visible = false;
			unloadMovie(progressBar_mc.stroke_mc);
			unloadMovie(progressBar_mc.bar_mc);
			unloadMovie(progressBar_mc);

		}
	}
}
</pre>
<p>The result:</p>
<p><img src="http://www.derekentringer.com/img/flv_player_example.jpg" border="0" /></p>
<p><a href="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kZXJla2VudHJpbmdlci5jb20vZG93bmxvYWRzL2Zsdl9wbGF5ZXIuemlw">Download the source</a></p>
 <img src="http://www.derekentringer.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=47" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.derekentringer.com/blog/flv-player-progressive-download-with-preloader/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
