Love the web

Love the web is a design, programming, and usability blog

Detecting Bandwidth with Flash and loading the right content

Diogo Freire 01 Apr 2009

With the good bandwidth from nowadays, finding a beautiful Flash site with lots of cool features and animations is a joy. However the reality for many users with low bandwidth is unmanageable load times and frustrating experiences when trying to access the Flash enabled functionality.

In factn Flash can offer a solution to the problem. By taking a sample of the user's download speed it can decide whether to show an application or not. A simplified way of doing this is described below. You may have to adapt the formula on a case-to-case basis.

import flash.external.ExternalInterface; var time:Number = 5; //the amount of time we want to measure the connection var bandwidthLimit:Number = 60; //in Kbps (Kbits/second) //function to calculate the kbps function getkbps(elapsedTime,sizeInBytes) { //bandwidth on internet are measured in bits/second, so we convert bytes to bits //then we divide for 1024 and convert it to Kbits var sizeInKBits = sizeInBytes * 8 / 1024; //TCP/IP uses around 7% of the bandwidth to manage itself, so we take it off. var kbps = (sizeInKBits/elapsedTime) * 0.93 ; return kbps; } //Start all variables just once, as we have a 2 stages preloader working on the timeline when this example was written if ((typeof startTime) == "undefined") var startTime = getTimer(); //exclude what is already loaded (out of the beginning of the timer) from the math if ((typeof initialLoad) == "undefined") var initialLoad = stage.loaderInfo.bytesLoaded; if ((typeof keepgetkbps) == "undefined") var keepgetkbps=true; //get variable from the root to check if we want to load the preloader anyway or not var flashvars:Object = LoaderInfo(this.root.loaderInfo).parameters; var letLoad:String = flashvars['letLoad']; //Event handler function checkBW(event) { if(keepgetkbps && letLoad != "true") { if(stage.loaderInfo.bytesLoaded < stage.loaderInfo.bytesTotal){ // not yet loaded //get time difference from the start of the swf loading and now var elapsedTimeMS:Number = getTimer() - startTime; //get time comes in miliseconds so we convert it var elapsedTime:Number = elapsedTimeMS/1000; var kbps=getkbps(elapsedTime,stage.loaderInfo.bytesLoaded-initialLoad); //if we reached the time limit for testing... if(elapsedTime>time) { //stop measuring (fall back in case flash already piped another call to checkBw) keepgetkbps=false; //remove event removeEventListener(Event.ENTER_FRAME, checkBW); //if the detected bandwidth is less then what we want, take care with javascript if(kbps<bandwidthLimit) { ExternalInterface.call("loadAlternateFlashContent"); } } } else { //if it's loaded already remove the event removeEventListener(Event.ENTER_FRAME, checkBW); } } } //add the event if we don't want to load it anyway if(letLoad!="true") addEventListener(Event.ENTER_FRAME, checkBW);

The comments next to the code make it pretty straight forward to understand. The JavaScript function "loadAlternateFlashContent()" completes the deal by loading the alternate lighter content for the user. Additionally we can add a cookie to the users browser so we never load the flash again (unless the user wants too!)

The JavaScript handler can be applied like this:

var contentBeforeFlash; //here using the old swfObject //and considering the #flash_wrapper is our div of choice to hold the flash (and the alternate content!) //function to load the flash function loadFlash(reloading) { //check if the cookie is not set or the user is not forcing the flash load if(readCookie("lowbandwidth")!="true" || reloading==true) { //save the old div content contentBeforeFlash = document.getElementById("flash_wrapper").innerHTML; //clean the cookie eraseCookie("lowbandwidth"); //load the flash var flashLoader = new SWFObject("flashWithBWDetection.swf", "flash_wrapper", "200", "220", "9", "#000000"); //if we're forcing reload we let flash know so it doesn't use the bandwidth measurement if(reloading!=undefined && reloading==true) flashLoader.addVariable("letLoad", "true"); flashLoader.write("flash_wrapper"); } } //auxiliar function if you have a button like "Load Flash anyway, event though my connection is slow" on your alternate content function reloadFlash() { loadFlash(true); return false; } //function called by the flash function loadAlternateFlashContent() { //set the cookie createCookie("lowbandwidth","true"); //reset the content document.getElementById("flash_wrapper").innerHTML = contentBeforeFlash; } //from quirksmode function createCookie(name,value,days) { if (days!=undefined) { var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); var expires = "; expires="+date.toGMTString(); } else var expires = ""; document.cookie = name+"="+value+expires+"; path=/"; } function readCookie(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) { var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } function eraseCookie(name) { createCookie(name,"",-1); }


Improving and tweaking all the code for your application should make it work better and look more beautiful, getting the right kind of connection with the right content. You can even choose which features to apply inside Flash itself. Just find the bit of function you need and boost it up.

See you all next time!

Read the next post - Choosing a JavaScript framework - will it fly?

Submit a comment

Submit comment