/***************************************************** * * Copyright 2009 Akamai Technologies, Inc. All Rights Reserved. * ***************************************************** * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * * The Initial Developer of the Original Code is Akamai Technologies, Inc. * Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai * Technologies, Inc. All Rights Reserved. * * Contributor: Adobe Systems Inc. * *****************************************************/ package org.osmf.net { import flash.events.EventDispatcher; import flash.events.NetStatusEvent; import flash.events.TimerEvent; import flash.net.NetStream; import flash.utils.Timer; CONFIG::LOGGING { import org.osmf.logging.Logger; import org.osmf.logging.Log; } /** * The NetStreamMetricsBase class serves as a base class for a provider of * run-time metrics to the NetStreamSwitchManager and its set of switching * rules. It calculates running averages for metrics that apply to all * delivery methods. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public class NetStreamMetricsBase extends EventDispatcher { /** * Constructor. * * Note that for correct operation of this class, the caller must set the * resource which the monitored stream is playing. * * @param netStream The NetStream instance the class will monitor. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function NetStreamMetricsBase(netStream:NetStream) { super(); _netStream = netStream; _droppedFPS = 0; _lastFrameDropCounter = 0; _lastFrameDropValue = 0; _maxFPS = 0; _averageDroppedFPSArray = new Array(); _timer = new Timer(DEFAULT_UPDATE_INTERVAL); _timer.addEventListener(TimerEvent.TIMER, onTimerEvent); netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent); } /** * Returns the DynamicStreamingResource which the class is referencing. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get resource():DynamicStreamingResource { return _resource; } public function set resource(value:DynamicStreamingResource):void { _resource = value; _maxAllowedIndex = value != null ? value.streamItems.length - 1 : 0; } /** * The NetStream object supplied to the constructor. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get netStream():NetStream { return _netStream; } /** * The current stream index. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get currentIndex():int { return _currentIndex; } public function set currentIndex(value:int):void { _currentIndex = value; } /** * The maximum allowed index value. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get maxAllowedIndex():int { return _maxAllowedIndex; } public function set maxAllowedIndex(value:int):void { _maxAllowedIndex = value; } /** * The update interval (in milliseconds) at which metrics are recalculated. If * set to zero, then metrics will not be recalculated. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get updateInterval():Number { return _timer.delay; } public function set updateInterval(value:Number):void { _timer.delay = value; if (value <= 0) { _timer.stop(); } } /** * The maximum achieved frame rate for this NetStream. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get maxFPS():Number { return _maxFPS; } /** * The frame drop rate calculated over the last interval. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get droppedFPS():Number { return _droppedFPS; } /** * The average frame-drop rate calculated over the life of the NetStream. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get averageDroppedFPS():Number { return _averageDroppedFPS; } // Protected // /** * Method invoked when the metrics should be recalculated. If * updateInterval is set, this method will be invoked whenever the * updateInterval is reached. **/ protected function calculateMetrics():void { try { // Estimate max (true) framerate. _maxFPS = netStream.currentFPS > _maxFPS ? netStream.currentFPS : _maxFPS; // Frame drop rate, per second, calculated over last second. if (_timer.currentCount - _lastFrameDropCounter > 1000 / _timer.delay) { _droppedFPS = (netStream.info.droppedFrames - _lastFrameDropValue) / ((_timer.currentCount - _lastFrameDropCounter) * _timer.delay/1000); _lastFrameDropCounter = _timer.currentCount; _lastFrameDropValue = netStream.info.droppedFrames; } _averageDroppedFPSArray.unshift(_droppedFPS); if (_averageDroppedFPSArray.length > DEFAULT_AVG_FRAMERATE_SAMPLE_SIZE) { _averageDroppedFPSArray.pop(); } var totalDroppedFrameRate:Number = 0; for (var f:uint=0;f < _averageDroppedFPSArray.length;f++) { totalDroppedFrameRate += _averageDroppedFPSArray[f]; } _averageDroppedFPS = _averageDroppedFPSArray.length < DEFAULT_AVG_FRAMERATE_SAMPLE_SIZE ? 0 : totalDroppedFrameRate / _averageDroppedFPSArray.length; } catch (error:Error) { CONFIG::LOGGING { logger.debug(".calculateMetrics() - " + error); } throw(error); } } // Internals // private function onNetStatusEvent(event:NetStatusEvent):void { switch (event.info.code) { case NetStreamCodes.NETSTREAM_PLAY_START: if (!_timer.running && updateInterval > 0) { _timer.start(); } break; case NetStreamCodes.NETSTREAM_PLAY_STOP: _timer.stop(); break; } } private function onTimerEvent(event:TimerEvent):void { if (isNaN(netStream.time)) { _timer.stop(); } else { calculateMetrics(); } } private var _netStream:NetStream; private var _resource:DynamicStreamingResource; private var _currentIndex:int; private var _maxAllowedIndex:int; private var _timer:Timer; private var _averageDroppedFPSArray:Array; private var _averageDroppedFPS:Number; private var _droppedFPS:Number; private var _lastFrameDropValue:Number; private var _lastFrameDropCounter:Number; private var _maxFPS:Number; private static const DEFAULT_UPDATE_INTERVAL:Number = 100; private static const DEFAULT_AVG_FRAMERATE_SAMPLE_SIZE:Number = 50; CONFIG::LOGGING { private static const logger:Logger = Log.getLogger("org.osmf.net.NetStreamMetricsBase"); } } }