- Nov 12, 2009 | 4 comment(s)
- Posted in: Flash
AS3 Bandwidth Checker
A while back I worked on an FLV player where it gave the user a choice between viewing the high or low quality version of each video. But because the video automatically started when the player loaded (much like YouTube) I wanted to determine which video to show initially based on each visitors bandwidth. And so, my BandwidthChecker class came about. Basically it loads an image you specify and based on the time it takes to load, determines whether it’s high or low. I’ve only used public and protected namespaces so you can easily extend the class if you want to enhance it. Not only for video players, this could also be used for an image gallery to determine whether to show larger, higher quality images or smaller, more compressed ones. Simple I guess, but has come in handy for me at least. Here it is:
/**
*
* BandwidthChecker utiltiy
*
* Copyright (c) 2009 Ben Kanizay
* This software is released under the MIT License
*
*/
package beekay.core.utils {
import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLRequest;
import flash.system.Capabilities;
import flash.utils.getTimer;
public class BandwidthChecker extends EventDispatcher {
public static const DEFAULT_BANDWIDTH : String = "low";
public static const DEFAULT_BANDWIDTH_SPEED : Number = 900;
protected var bandwidthDetected : String;
protected var bandwidthSpeedDetected : Number;
protected var startTime : uint;
protected var testFile : String;
protected var loader : Loader;
protected var request : URLRequest;
public function BandwidthChecker() {
}
/////////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
/////////////////////////////////////////////////////////////////////////////
public function check(testImage:String) : void {
this.testFile = testImage;
this.loader = new Loader();
this.request = new URLRequest(this.testFile + this.getCacheBlocker());
this.addLoaderListeners();
this.loader.load(this.request);
}
/////////////////////////////////////////////////////////////////////////////
// EVENT HANDLERS
/////////////////////////////////////////////////////////////////////////////
protected function onLoadStart(event:Event) : void {
this.startTime = getTimer();
}
protected function onLoadError(event:Event) : void {
this.bandwidthDetected = DEFAULT_BANDWIDTH;
this.bandwidthSpeedDetected = DEFAULT_BANDWIDTH_SPEED;
this.complete();
}
protected function onLoadComplete(event:Event) : void {
var time : Number = (getTimer() - this.startTime) / 1000;
this.bandwidthSpeedDetected = Math.round(( this.loader.contentLoaderInfo.bytesTotal / 1000 * 8 ) / time);
this.bandwidthDetected = (this.bandwidthSpeedDetected > DEFAULT_BANDWIDTH_SPEED) ? "high" : "low";
this.complete();
}
/////////////////////////////////////////////////////////////////////////////
// HELPERS
/////////////////////////////////////////////////////////////////////////////
protected function getCacheBlocker() : String {
if ((Capabilities.playerType == "External" || Capabilities.playerType == "StandAlone")) {
return "";
}
else {
var date : Date = new Date();
var time : Number = date.getTime();
return "?t=" + time.toString();
}
}
protected function addLoaderListeners() : void {
this.loader.contentLoaderInfo.addEventListener(Event.OPEN, this.onLoadStart, false, 0, true);
this.loader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.onLoadComplete, false, 0, true);
this.loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, this.onLoadError, false, 0, true);
this.loader.contentLoaderInfo.addEventListener(IOErrorEvent.NETWORK_ERROR, this.onLoadError, false, 0, true);
this.loader.contentLoaderInfo.addEventListener(IOErrorEvent.DISK_ERROR, this.onLoadError, false, 0, true);
this.loader.contentLoaderInfo.addEventListener(IOErrorEvent.VERIFY_ERROR, this.onLoadError, false, 0, true);
this.loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onLoadError, false, 0, true);
}
protected function removeLoaderListeners() : void {
this.loader.contentLoaderInfo.removeEventListener(Event.OPEN, this.onLoadStart);
this.loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, this.onLoadComplete);
this.loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, this.onLoadError);
this.loader.contentLoaderInfo.removeEventListener(IOErrorEvent.NETWORK_ERROR, this.onLoadError);
this.loader.contentLoaderInfo.removeEventListener(IOErrorEvent.DISK_ERROR, this.onLoadError);
this.loader.contentLoaderInfo.removeEventListener(IOErrorEvent.VERIFY_ERROR, this.onLoadError);
this.loader.contentLoaderInfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onLoadError);
}
protected function complete() : void {
this.removeLoaderListeners();
this.loader = null;
this.request = null;
this.testFile = null;
this.dispatchEvent(new Event(Event.COMPLETE));
}
/////////////////////////////////////////////////////////////////////////////
// GETTERS
/////////////////////////////////////////////////////////////////////////////
public function getBandwidth() : String {
return this.bandwidthDetected;
}
public function getBandwidthSpeed() : Number {
return this.bandwidthSpeedDetected;
}
}
}
Simple usage example (you can use this as a document class):
package {
import beekay.core.utils.BandwidthChecker;
import flash.events.Event;
import flash.display.Sprite;
public class Example extends Sprite {
private var bandwidthChecker : BandwidthChecker;
private var testFile : String = "path/to/your/image.jpg";
private var bandwidth:String;
public function Example() {
this.bandwidthChecker = new BandwidthChecker();
this.bandwidthChecker.addEventListener(Event.COMPLETE, this.onBandwidthCheckComplete, false, 0, true);
trace("Checking bandwidth...");
this.bandwidthChecker.check(this.testFile);
}
private function onBandwidthCheckComplete(event : Event) : void {
this.bandwidthChecker.removeEventListener(Event.COMPLETE, this.onBandwidthCheckComplete);
this.bandwidth = this.bandwidthChecker.getBandwidth();
trace("Detected bandwidth: " + this.bandwidth);
}
}
}
Because my usage of it was fairly basic, if it detects errors BandwidthChecker still just dispatches a Event.COMPLETE event and applies the default bandwidth as set by the constants. Because it actually listens for errors, this can easily be changed by extending the class and creating your own error event handlers.
Also, it’s probably a good idea not to use too large or too small an image to load for the test. If too small, the calculation may not be so accurate and if too large the user could be waiting a while (if they’re on a slow connection). I usually test with an image around 30 – 40kb.
As internet speeds get faster this may not be as useful as it once was. But then again you may want to do adjust it and check whether a user is on just a fast, or blow-your-mind, snap-your-head-back-in-your-chair connection speed.
Click here to download the BackwidthChecker and Example classes.
Enjoy.
- Tweet this post (will automatically use the short url below)
- Short url for this post: http://bit.ly/3KbTFs
Ben Kanizay
[...] This post was mentioned on Twitter by Ben, Savvas Malamas. Savvas Malamas said: RT @BK4D New post: #AS3 Bandwidth Checker http://bit.ly/3KbTFs #FlashDev [...]
Nice post!
What’s happening on line 65?
Cheers
Thanks Riccardo. Looks like Wordpress was converting a couple of the characters into a smiley (it was the number eight followed by a closing parenthesis) A little annoying. Will look into it . Added a space for now.
No worries mate. I’m going to use it for a streaming videoplayer.
I’ll give you some feedback asap…