/** * * NCManagerAuto.as * * Adds automatic bandwidth detection to FLVPlayback components when using * SMIL files. * * @author matthew at exanimo dot com * @author Ryan Sprake () * @version 2008.03.19 * */ package com.exanimo.video { import com.exanimo.net.BandwidthChecker; import com.exanimo.video.SMILManager; import com.exanimo.utils.URLUtil; import fl.video.flvplayback_internal; import fl.video.INCManager; import fl.video.NCManager; import fl.video.ParseResults; import fl.video.VideoError; import flash.display.Loader; import flash.events.Event; import flash.events.IOErrorEvent; import flash.events.SecurityErrorEvent; import flash.events.ProgressEvent; use namespace flvplayback_internal; public class NCManagerAuto extends NCManager implements INCManager { /** * * Overridden to provide automatic bandwidth detection for SMIL + * progressive downloads. * */ public override function helperDone(helper:Object, success:Boolean):void { if (!success) { _nc = null; _ncConnected = false; _owner.ncConnected(); _smilMgr = null; _fpadMgr = null; return; } var parseResults:ParseResults; var url:String; var protocolDetermined:Boolean = false; if (helper == _fpadMgr) { url = _fpadMgr.rtmpURL; _fpadMgr = null; parseResults = parseURL(url); _isRTMP = parseResults.isRTMP; _protocol = parseResults.protocol; _serverName = parseResults.serverName; _portNumber = parseResults.portNumber; _wrappedURL = parseResults.wrappedURL; _appName = parseResults.appName; _streamName = parseResults.streamName; // if fpad autodetect is set up and we used the fpad // xml instead, we need to set fpadZone to NaN or we // will autodetect on top of our xml detection and // things will not work! var fpadZoneCached:Number = _fpadZone; _fpadZone = NaN; connectRTMP(); // after connecting, set fpadZone back to previous // value _fpadZone = fpadZoneCached; return; } if (helper != _smilMgr) return; // success! // grab width and height _streamWidth = _smilMgr.width; _streamHeight = _smilMgr.height; // get correct streamname url = _smilMgr.baseURLAttr[0]; if (url != null && url != "") { if (url.charAt(url.length - 1) != "/") { url += "/"; } parseResults = parseURL(url); _isRTMP = parseResults.isRTMP; protocolDetermined = true; _streamName = parseResults.streamName; if (_isRTMP) { _protocol = parseResults.protocol; _serverName = parseResults.serverName; _portNumber = parseResults.portNumber; _wrappedURL = parseResults.wrappedURL; _appName = parseResults.appName; if (_appName == null || _appName == "") { _smilMgr = null; throw new VideoError(VideoError.INVALID_XML, "Base RTMP URL must include application name: " + url); } if (_smilMgr.baseURLAttr.length > 1) { parseResults = parseURL(_smilMgr.baseURLAttr[1]); if (parseResults.serverName != null) { fallbackServerName = parseResults.serverName; } } } } _streams = _smilMgr.videoTags; _smilMgr = null; for (var i:uint = 0; i < _streams.length; i++) { url = _streams[i].src; parseResults = parseURL(url); if (!protocolDetermined) { _isRTMP = parseResults.isRTMP; protocolDetermined = true; if (_isRTMP) { _protocol = parseResults.protocol; if (_streams.length > 1) { throw new VideoError(VideoError.INVALID_XML, "Cannot switch between multiple absolute RTMP URLs, must use meta tag base attribute."); } _serverName = parseResults.serverName; _portNumber = parseResults.portNumber; _wrappedURL = parseResults.wrappedURL; _appName = parseResults.appName; if (_appName == null || _appName == "") { throw new VideoError(VideoError.INVALID_XML, "Base RTMP URL must include application name: " + url); } } else if (parseResults.streamName.indexOf("/fms/fpad") >= 0 && _streams.length > 1) { throw new VideoError(VideoError.INVALID_XML, "Cannot switch between multiple absolute fpad URLs, must use meta tag base attribute."); } } else if ( _streamName != null && _streamName != "" && !parseResults.isRelative && _streams.length > 1 ) { throw new VideoError(VideoError.INVALID_XML, "When using meta tag base attribute, cannot use absolute URLs for video or ref tag src attributes."); } _streams[i].parseResults = parseResults; } _autoSenseBW = _streams.length > 1; if (!_autoSenseBW) { if (_streamName != null) { _streamName += _streams[0].parseResults.streamName; } else { _streamName = _streams[0].parseResults.streamName; } if (_isRTMP && _streamName.substr(-4).toLowerCase() == ".flv") { _streamName = _streamName.substr(0, _streamName.length - 4); } _streamLength = _streams[0].dur; } if (_isRTMP) { connectRTMP(); } else if (_streamName != null && _streamName.indexOf("/fms/fpad") >= 0) { connectFPAD(_streamName); } // // New stuff here. // else if (!this.bitrate) { // Check bandwidth. var myBandwidthChecker:BandwidthChecker = new BandwidthChecker(URLUtil.getFullURL(new Loader().contentLoaderInfo.loaderURL.split('/').slice(0, -1).join('/'), URLUtil.getFullURL(_streamName, _streams[0].src))); myBandwidthChecker.units = BandwidthChecker.BITS_PER_SECOND; myBandwidthChecker.maximumBytes = 35000; myBandwidthChecker.addEventListener(Event.COMPLETE, this._completeHandler); myBandwidthChecker.addEventListener(IOErrorEvent.IO_ERROR, this._completeHandler); myBandwidthChecker.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this._completeHandler); } else { this._completeHandler(); } } /** * * Match the bitrate after it has been detected. * */ private function _completeHandler(e:Event = null):void { if (e) { e.currentTarget.removeEventListener(Event.COMPLETE, this._completeHandler); e.currentTarget.removeEventListener(IOErrorEvent.IO_ERROR, this._completeHandler); e.currentTarget.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this._completeHandler); this._bitrate = e.currentTarget.bandwidth || 0; } if (this._autoSenseBW) { this.bitrateMatch(); } this.connectHTTP(); this._owner.ncConnected(); } /** * * Exactly the same thing as super.connectToURL. By overriding the function, * we force it to create an instance of com.exanimo.video.SMILManager instead * of the (apparently broken) fl.video.SMILManager. * */ public override function connectToURL(url:String):Boolean { //ifdef DEBUG //debugTrace("connectToURL(" + url + ")"); //endif // init initOtherInfo(); _contentPath = url; if (_contentPath == null || _contentPath == "") { throw new VideoError(VideoError.INVALID_SOURCE); } // parse URL to determine what to do with it var parseResults:ParseResults = parseURL(_contentPath); if (parseResults.streamName == null || parseResults.streamName == "") { throw new VideoError(VideoError.INVALID_SOURCE, url); } // connect to either rtmp or http or download and parse smil var canReuse:Boolean; if (parseResults.isRTMP) { canReuse = canReuseOldConnection(parseResults); _isRTMP = true; _protocol = parseResults.protocol; _streamName = parseResults.streamName; _serverName = parseResults.serverName; _wrappedURL = parseResults.wrappedURL; _portNumber = parseResults.portNumber; _appName = parseResults.appName; if ( _appName == null || _appName == "" || _streamName == null || _streamName == "" ) { throw new VideoError(VideoError.INVALID_SOURCE, url); } _autoSenseBW = (_streamName.indexOf(",") >= 0); return (canReuse || connectRTMP()); } else { if ( parseResults.streamName.indexOf("?") < 0 && parseResults.streamName.slice(-4).toLowerCase() == ".flv" ) { canReuse = canReuseOldConnection(parseResults); _isRTMP = false; _streamName = parseResults.streamName; return (canReuse || connectHTTP()); } if (parseResults.streamName.indexOf("/fms/fpad") >= 0) { try { return connectFPAD(parseResults.streamName); } catch (err:Error) { // just use SMILManager if there is any error //ifdef DEBUG //debugTrace("fpad error: " + err); //endif } } _smilMgr = new SMILManager(this); return _smilMgr.connectXML(parseResults.streamName); } } } }