Recipe 16.14. Determining User Bandwidth


Problem

You want to optimize a user's video playback by determining her network bandwidth.

Solution

Download an image file and time the download to calculate the speed of the user's network connection.

Discussion

Unfortunately, the Flash Player doesn't have a built-in bandwidth detection system. And because actual bandwidth varies based on many factors (such as network usage, interference in wireless networks, applications running on the same system competing for bandwidth, etc.), there is no way to accurately predict what a user's bandwidth will be for the next 10 minutes, hour, or any amount of time. However, you can measure a user's actual bandwidth over a period of time and use that to determine what her bandwidth could be in the near future.

To measure a user's bandwidth, you need to download a (noncompressed) file, such as a JPEG file using Flash Player. Using ActionScript, you can measure both the total bytes downloaded and the amount of time it took to download those bytes. Using those two values, you can calculate an average amount of data downloaded per unit of time. For the purposes of video, bandwidth is usually measured as bit rate in units of kilobits per second. There are 8 bits in a byte and 1,000 bytes per kilobyte. That means you can use the following to convert from bytes to kilobits:

kilobits = bytes / 1000 * 8;

The ratio of bytes/kilobytes and bits/kilobits is different if you are talking about data communication or disk storage. For disk storage, the ratio is 1/1024, while for data communications it is 1/1000.


The larger the file that the user has to download, the more accurate the measurement is likely to be. For example, if the user downloads a 10 kilobyte file, it may be that the request hits a network lag and the measurement can be significantly lower than the actual average bandwidth. On the other hand, you don't want to force the user to download too large a file, since that would cause the user to have to wait too long while testing bandwidth.

One option is to use a moderately sized file (something in the 50100 kilobytes range) and run the test several times. That way, if the first two tests are within a certain range of each other you can assume subsequent tests would also be relatively close, and you don't need to run further tests. If the first two tests have a wide margin, then you can run additional tests. If the same file is downloaded several times, you need to make sure that you use a unique URL each time so the Flash Player doesn't retrieve the file from a browser's cache. The following class illustrates how this sort of bandwidth test works:

package com.oreilly.as3cb.util {     import flash.events.EventDispatcher;     import flash.net.URLLoader;     import flash.net.URLRequest;     import flash.events.Event;     import flash.util.getTimer;          public class BandwidthTest extends EventDispatcher {                  private var _downloadCount:uint;         private var _bandwidthTests:Array;         private var _detectedBandwidth:Number;         private var _startTime:uint;                  public function get detectedBandwidth(  ):Number {             return _detectedBandwidth;         }                  public function BandwidthTest(  ) {             _downloadCount = 0;             _bandwidthTests = new Array(  );         }                  // Run the bandwidth test.         public function test(  ):void {             // Use a URLLoader to load the data.             var loader:URLLoader = new URLLoader(  );             // Use a URL with a unique query string to ensure the data is              // loaded from the server and not from browser cache.             var request:URLRequest = new URLRequest("bandwidthtestimage.jpg?unique="              + (new Date(  )).getTime(  ));             loader.load(request);             loader.addEventListener(Event.OPEN, onStart);             loader.addEventListener(Event.COMPLETE, onLoad);         }                  // When the file starts to download get the current timer value.         private function onStart(event:Event):void {             _startTime = getTimer(  );         }                  private function onLoad(event:Event):void {             // The download time is the timer value when the file has downloaded              // minus the timer value when the value started downloading. Then               // divide by 1000 to convert from milliseconds to seconds.             var downloadTime:Number = (getTimer(  ) - _startTime) / 1000;             _downloadCount++;             // Convert from bytes to kilobits.             var kilobits:Number = event.target.bytesTotal / 1000 * 8;             // Divide the kilobits by the download time.             var kbps:Number = kilobits / downloadTime;             // Add the test value to the array.             _bandwidthTests.push(kbps);             if(_downloadCount == 1) {                 // If it's only run one test then run the second.                 test(  );             }             else if(_downloadCount == 2) {                 // If it's run two tests then determine the margin between the                  // first two tests.                 // If the margin is small (in this example, less than 50 kbps)                  // then dispatch a complete event. If not run a test.                 if(Math.abs(_bandwidthTests[0] - _bandwidthTests[1]) < 50) {                     dispatchCompleteEvent(  );                 }                 else {                     test(  );                 }             }             else {                 // Following the third test dispatch a complete event.                 dispatchCompleteEvent(  );             }                      }         private function dispatchCompleteEvent(  ):void {             // Determine the avarage bandwidth detection value.             _detectedBandwidth = 0;             var i:uint;             for(i = 0; i < _bandwidthTests.length; i++) {                 _detectedBandwidth += _bandwidthTests[i];             }             _detectedBandwidth /= _downloadCount;             // Dispatch a complete event.             dispatchEvent(new Event(Event.COMPLETE));         }              } }

You can use instances of the preceding class to run a bandwidth test. To do so, create a new instance, add a listener, and run the test( ) method.

var bandwidthTester:BandwidthTest = new BandwidthTest(  ); bandwidthTester.addEventListener(Event.COMPLETE, onBandwidthTest); bandwidthTester.test(  );

When the complete event occurs, you can retrieve the detected bandwidth using the detectedBandwidth property.

private function onBandwidthTest(event:Event):void {   trace(event.target.detectedBandwidth); }

See Also

Recipes 19.1 (the APIs that load binary data, such as image files, can be used) and 19.4




ActionScript 3. 0 Cookbook
ActionScript 3.0 Cookbook: Solutions for Flash Platform and Flex Application Developers
ISBN: 0596526954
EAN: 2147483647
Year: 2007
Pages: 351

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net