// Copyright © 2004-2007. Adobe Systems Incorporated. All Rights Reserved.
package fl.video {
import flash.net.*;
import flash.events.TimerEvent;
import flash.events.NetStatusEvent;
import flash.utils.Timer;
use namespace flvplayback_internal;
/**
* Creates the NetConnection object for the VideoPlayer class, a
* helper class for that user facing class.
*
*
The NCManager class searches a URL and assumes the following:
*fallbackServerName property indirectly or directly.
*
* fallbackServerName property uses that base attribute.
* (The fallbackServerName property uses the server name only,
* nothing else.)ncMgr property in
* FLVPlayback or VideoPlayer and set the
* fallbackServerName property or use
* the setProperty() method.bitrate property
* returns the value calculated from autodetection,
* not the value set through the bitrate() property.
*
* @see INCManager#bitrate
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get bitrate():Number {
return _bitrate;
}
/**
* @private
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set bitrate(b:Number):void {
if (!_isRTMP) {
_bitrate = b;
}
}
/**
* @copy INCManager#videoPlayer
* @see INCManager#videoPlayer
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get videoPlayer():VideoPlayer {
return _owner;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set videoPlayer(v:VideoPlayer):void {
_owner = v;
}
/**
* @copy INCManager#netConnection
* @see INCManager#netConnection
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get netConnection():NetConnection {
return _nc;
}
/**
* @copy INCManager#streamName
* @see INCManager#streamName
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get streamName():String {
return _streamName;
}
/**
* @copy INCManager#isRTMP
* @see INCManager#isRTMP
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get isRTMP():Boolean {
return _isRTMP;
}
/**
* @copy INCManager#streamLength
* @see INCManager#streamLength
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get streamLength():Number {
return _streamLength;
}
/**
* @copy INCManager#streamWidth
* @see INCManager#streamWidth
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get streamWidth():int {
return _streamWidth;
}
/**
* @copy INCManager#streamHeight
* @see INCManager#streamHeight
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get streamHeight():int {
return _streamHeight;
}
/**
* Allows getting of the fallbackServerName, fpadZone, objectEncoding,
* and proxyType properties. See setProperty() for
* an explanation of these properties.
*
* @param propertyName The name of the property that the getProperty
* method is calling.
*
* @see #setProperty()
* @see #fallbackServerName
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function getProperty(propertyName:String):* {
switch (propertyName) {
case "fallbackServerName":
return fallbackServerName;
case "fpadZone":
return _fpadZone;
case "objectEncoding":
return _objectEncoding;
case "proxyType":
return _proxyType;
default:
throw new VideoError(VideoError.UNSUPPORTED_PROPERTY, propertyName);
}
}
/**
* Allows setting of the fallbackServerName, fpadZone, objectEncoding,
* and proxyType properties.
*
* The fallbackServerName property specifies a Flash Media Server (FMS) URL
* to be used if the primary server address derived from the URL passed
* into connectToURL() cannot be reached. This property can also be set
* directly through the fallbackServerName property.
The fpadZone property specifies the fpadZone property for Flash Media Server (FMS).
* If the returned value is not a number (NaN),
* then no zone is set.
* The fpadZone property must be set before
* the connection process begins to have effect.
* If you do not want to set a zone, set the fpadZone property to NaN.
NaN.
*
* The objectEncoding property specifies the value to be used for the objectEncoding
* property on NetConnection instances. Default is flash.net.ObjectEncoding.AMF0.
The proxyType property specifies the value to be used for the proxyType
* property on NetConnection instances. Default is "best".
setProperty
* method is calling.
*
* @param value The property value.
*
* @see #getProperty()
* @see #fallbackServerName
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function setProperty(propertyName:String, value:*):void {
switch (propertyName) {
case "fallbackServerName":
fallbackServerName = String(value);
break;
case "fpadZone":
_fpadZone = Number(value);
break;
case "objectEncoding":
_objectEncoding = uint(value);
break;
case "proxyType":
_proxyType = String(value);
break;
default:
throw new VideoError(VideoError.UNSUPPORTED_PROPERTY, propertyName);
}
}
/**
* @copy INCManager#connectToURL()
* @see INCManager#connectToURL()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public 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 {
var name:String = parseResults.streamName;
if ( name.indexOf("?") < 0 &&
(name.length < 4 || name.slice(-4).toLowerCase() != ".txt") &&
(name.length < 4 || name.slice(-4).toLowerCase() != ".xml") &&
(name.length < 5 || name.slice(-5).toLowerCase() != ".smil") ) {
canReuse = canReuseOldConnection(parseResults);
_isRTMP = false;
_streamName = name;
return (canReuse || connectHTTP());
}
if (name.indexOf("/fms/fpad") >= 0) {
try {
return connectFPAD(name);
} 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(name);
}
}
/**
* @copy INCManager#connectAgain()
* @see INCManager#connectAgain()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function connectAgain():Boolean {
//ifdef DEBUG
//debugTrace("connectAgain()");
//endif
var slashIndex:int = _appName.indexOf("/");
if (slashIndex < 0) {
// return the appName and streamName back to original form
// so we can start this process all over again with the
// fallback server if necessary
slashIndex = _streamName.indexOf("/");
if (slashIndex >= 0) {
_appName += "/";
_appName += _streamName.slice(0, slashIndex);
_streamName = _streamName.slice(slashIndex + 1);
}
return false;
}
var newStreamName:String = _appName.slice(slashIndex + 1);
newStreamName += "/";
newStreamName += _streamName;
_streamName = newStreamName;
_appName = _appName.slice(0, slashIndex);
close();
_payload = 0;
_connTypeCounter = 0;
cleanConns();
connectRTMP();
return true;
}
/**
* @copy INCManager#reconnect()
* @see INCManager#reconnect()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function reconnect():void {
//ifdef DEBUG
//debugTrace("reconnect()");
//endif
if (!_isRTMP) {
throw new Error("Cannot call reconnect on an http connection");
}
_nc.client = new ReconnectClient(this);
_nc.addEventListener(NetStatusEvent.NET_STATUS, reconnectOnStatus);
//ifdef DEBUG
//debugTrace("_ncUri = " + _ncUri);
//endif
_nc.connect(_ncUri, false);
}
/**
* Dispatches reconnect event, called by internal class method
* ReconnectClient.onBWDone()
* @private
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
flvplayback_internal function onReconnected():void {
_ncConnected = true;
_owner.ncReconnected();
}
/**
* @copy INCManager#close()
* @see INCManager#close()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function close():void {
if (_nc) {
_nc.close();
_ncConnected = false;
}
}
/**
*
* @copy INCManager#helperDone()
*
* @see INCManager#helperDone()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public 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);
} else {
if (_autoSenseBW) bitrateMatch();
connectHTTP();
_owner.ncConnected();
}
}
/**
* Matches bitrate with stream.
*
* @private
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
flvplayback_internal function bitrateMatch():void {
var checkBitrate:Number = _bitrate;
if (isNaN(checkBitrate)) {
checkBitrate = 0;
}
var whichStream:uint = _streams.length;
for (var j:uint = 0; j < _streams.length; j++) {
if (isNaN(_streams[j].bitrate) || checkBitrate >= _streams[j].bitrate) {
whichStream = j;
break;
}
}
if (whichStream == _streams.length) {
throw new VideoError(VideoError.NO_BITRATE_MATCH);
}
if (_streamName != null) {
_streamName += _streams[whichStream].src;
} else {
_streamName = _streams[whichStream].src;
}
if (_isRTMP && _streamName.substr(-4).toLowerCase() == ".flv") {
_streamName = _streamName.substr(0, _streamName.length - 4);
}
_streamLength = _streams[whichStream].dur;
}
/**
* Parses URL to determine if it is http or rtmp. If it is rtmp,
* breaks it into pieces to extract server URL and port, application
* name and stream name. If .flv is at the end of an rtmp URL, it
* will be stripped off.
*
* @private
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
flvplayback_internal function parseURL(url:String):ParseResults {
//ifdef DEBUG
//debugTrace("parseURL()");
//endif
var parseResults:ParseResults = new ParseResults();
// get protocol
var startIndex:int = 0;
var endIndex:int = url.indexOf(":/", startIndex);
if (endIndex >= 0) {
endIndex += 2;
parseResults.protocol = url.slice(startIndex, endIndex).toLowerCase();
parseResults.isRelative = false;
} else {
parseResults.isRelative = true;
}
if ( parseResults.protocol != null &&
( parseResults.protocol == "rtmp:/" ||
parseResults.protocol == "rtmpt:/" ||
parseResults.protocol == "rtmps:/" ||
parseResults.protocol == "rtmpe:/" ||
parseResults.protocol == "rtmpte:/" ) ) {
parseResults.isRTMP = true;
startIndex = endIndex;
if (url.charAt(startIndex) == '/') {
startIndex++;
// get server (and maybe port)
var colonIndex:int = url.indexOf(":", startIndex);
var slashIndex:int = url.indexOf("/", startIndex);
if (slashIndex < 0) {
if (colonIndex < 0) {
parseResults.serverName = url.slice(startIndex);
} else {
endIndex = colonIndex;
parseResults.portNumber = url.slice(startIndex, endIndex);
startIndex = endIndex + 1;
parseResults.serverName = url.slice(startIndex);
}
return parseResults;
}
if (colonIndex >= 0 && colonIndex < slashIndex) {
endIndex = colonIndex;
parseResults.serverName = url.slice(startIndex, endIndex);
startIndex = endIndex + 1;
endIndex = slashIndex;
parseResults.portNumber = url.slice(startIndex, endIndex);
} else {
endIndex = slashIndex;
parseResults.serverName = url.slice(startIndex, endIndex);
}
startIndex = endIndex + 1;
}
// handle wrapped RTMP servers bit recursively, if it is there
if (url.charAt(startIndex) == '?') {
var subURL:String = url.slice(startIndex + 1);
var subParseResults:ParseResults = parseURL(subURL);
if (subParseResults.protocol == null || !subParseResults.isRTMP) {
throw new VideoError(VideoError.INVALID_SOURCE, url);
}
parseResults.wrappedURL = "?";
parseResults.wrappedURL += subParseResults.protocol;
if (subParseResults.serverName != null) {
parseResults.wrappedURL += "/";
parseResults.wrappedURL += subParseResults.serverName;
}
if (subParseResults.portNumber != null) {
parseResults.wrappedURL += ":" + subParseResults.portNumber;
}
if (subParseResults.wrappedURL != null) {
parseResults.wrappedURL += "/";
parseResults.wrappedURL += subParseResults.wrappedURL;
}
parseResults.appName = subParseResults.appName;
parseResults.streamName = subParseResults.streamName;
return parseResults;
}
// get application name
endIndex = url.indexOf("/", startIndex);
if (endIndex < 0) {
parseResults.appName = url.slice(startIndex);
return parseResults;
}
parseResults.appName = url.slice(startIndex, endIndex);
startIndex = endIndex + 1;
// check for instance name to be added to application name
endIndex = url.indexOf("/", startIndex);
if (endIndex < 0) {
parseResults.streamName = url.slice(startIndex);
// strip off .flv if included
if (parseResults.streamName.slice(-4).toLowerCase() == ".flv") {
parseResults.streamName = parseResults.streamName.slice(0, -4);
}
return parseResults;
}
parseResults.appName += "/";
parseResults.appName += url.slice(startIndex, endIndex);
startIndex = endIndex + 1;
// get flv name
parseResults.streamName = url.slice(startIndex);
// strip off .flv if included
if (parseResults.streamName.slice(-4).toLowerCase() == ".flv") {
parseResults.streamName = parseResults.streamName.slice(0, -4);
}
} else {
// is http, just return the full url received as streamName
parseResults.isRTMP = false;
parseResults.streamName = url;
}
return parseResults;
}
/**
* Compares connection info with previous NetConnection, * will reuse existing connection if possible.
* * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function canReuseOldConnection(parseResults:ParseResults):Boolean { // no reuse if no prior connection if (_nc == null || !_ncConnected) return false; // http connection if (!parseResults.isRTMP) { // can reuse if prev connection was http if (!_isRTMP) return true; // cannot reuse if was rtmp--close _owner.close(); _nc = null; _ncConnected = false; initNCInfo(); return false; } // rtmp connection if (_isRTMP) { if ( parseResults.serverName == _serverName && parseResults.appName == _appName && parseResults.protocol == _protocol && parseResults.portNumber == _portNumber && parseResults.wrappedURL == _wrappedURL ) { return true; } // cannot reuse this rtmp--close _owner.close(); _nc = null; _ncConnected = false; } initNCInfo(); return false; } /** *Handles creating NetConnection instance for
* progressive download of FLV via http.
Top level function for creating NetConnection
* instance for streaming playback of FLV via rtmp. Actually
* tries to create several different connections using different
* protocols and ports in a pipeline, so multiple connection
* attempts may be occurring simultaneously, and will use the
* first one that connects successfully.
Top level function for downloading fpad XML from FMS 2.0 * server. Creates and kicks off a FPADManager instance * which does all the work.
* * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function connectFPAD(url:String):Boolean { //ifdef DEBUG //debugTrace("connectFPAD( " + url + ")"); //endif // extract uri from requesting url var results:Object = /^(.+)(\?|\&)(uri=)([^&]+)(\&.*)?$/.exec(url); if (results == null) { throw new VideoError(VideoError.INVALID_SOURCE, "fpad url must include uri parameter: " + url); } var urlPrefix:String = results[1] + results[2]; var uriParam:String = results[4]; var urlSuffix:String = (results[5] == undefined) ? "" : results[5]; var uriParamParseResults:ParseResults = parseURL(uriParam); if (!uriParamParseResults.isRTMP) { throw new VideoError(VideoError.INVALID_SOURCE, "fpad url uri parameter must be rtmp url: " + url); } _fpadMgr = new FPADManager(this); return _fpadMgr.connectXML(urlPrefix, uriParam, urlSuffix, uriParamParseResults); } /** *Does work of trying to open rtmp connections. Called either
* by connectRTMP or on an interval set up in
* that method.
For creating rtmp connections.
* * @see #connectRTMP() * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function nextConnect(e:TimerEvent=null):void { //ifdef DEBUG //debugTrace("nextConnect()"); //endif var protocol:String; var port:String; if (_connTypeCounter == 0) { protocol = _protocol; port = _portNumber; } else { port = null; if (_protocol == "rtmp:/") { protocol = "rtmpt:/" } else if (_protocol == "rtmpe:/") { protocol = "rtmpte:/" } else { _tryNC.pop(); return; } } var xnURL:String = protocol + ((_serverName == null) ? "" : "/" + _serverName + ((port == null) ? "" : (":" + port)) + "/") + ((_wrappedURL == null) ? "" : _wrappedURL + "/") + _appName; //ifdef DEBUG //debugTrace( "_tryNC[" + _connTypeCounter + "] connecting to room: " + xnURL ); //endif _tryNC[_connTypeCounter].client.pending = true; _tryNC[_connTypeCounter].connect( xnURL, _autoSenseBW); if (_connTypeCounter < (_tryNC.length-1)) { _connTypeCounter++; _tryNCTimer.reset(); _tryNCTimer.start(); } } /** *Stops all intervals, closes all unneeded connections, and other
* cleanup related to the connectRTMP strategy of
* pipelining connection attempts to different protocols and
* ports.
For creating rtmp connections.
* * @see #connectRTMP() * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function cleanConns():void { //ifdef DEBUG //debugTrace("cleanConns()"); //endif _tryNCTimer.reset(); if (_tryNC != null) { for (var i:uint = 0; i < _tryNC.length; i++) { if (_tryNC[i] != null) { //ifdef DEBUG //debugTrace("_tryNC[" + i + "] = " + _tryNC[i]); //endif _tryNC[i].removeEventListener(NetStatusEvent.NET_STATUS, connectOnStatus); if (_tryNC[i].client.pending) { _tryNC[i].addEventListener(NetStatusEvent.NET_STATUS, disconnectOnStatus); } else { _tryNC[i].close(); } } _tryNC[i] = null; } _tryNC = null; } } /** *Starts another pipelined connection attempt with
* connectRTMP with the fallback server.
For creating rtmp connections.
* * @see #connectRTMP() * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function tryFallBack():void { //ifdef DEBUG //debugTrace("tryFallBack()"); //endif if (_serverName == fallbackServerName || fallbackServerName == null) { //ifdef DEBUG //debugTrace("Already tried to fall back!"); //endif //it's not connected _nc = null; _ncConnected = false; _owner.ncConnected(); } else { _connTypeCounter = 0; cleanConns(); _serverName = fallbackServerName; //ifdef DEBUG //debugTrace("connect: " + _serverName); //endif connectRTMP(); } } /** *Starts another pipelined connection attempt with
* connectRTMP with the fallback server.
For creating rtmp connections.
* * @see #connectRTMP() * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function onConnected(p_nc:NetConnection, p_bw:Number):void { //ifdef DEBUG //debugTrace("onConnected()"); //endif // avoid timeout _timeoutTimer.stop(); // ditch these now unneeded functions and listeners p_nc.removeEventListener(NetStatusEvent.NET_STATUS, connectOnStatus); // store pointers to the successful xn and uri _nc = p_nc; _ncUri = _nc.uri; _ncConnected = true; if (_autoSenseBW) { _bitrate = p_bw * 1024; if (_streams != null) { bitrateMatch(); } else { var sSplit:Array = _streamName.split(","); // remove leading and trailing whitespace from string for (var i:uint = 0; i < sSplit.length; i+=2) { var sName:String = stripFrontAndBackWhiteSpace(sSplit[i]); if (i + 1 < sSplit.length) { // If we have less bw than the next threshold or if // there isn't another threshold (last string) if (p_bw <= Number(sSplit[i+1])) { _streamName = sName; break; } } else { _streamName = sName; break; } } // for // strip off .flv if included if (_streamName.slice(-4).toLowerCase() == ".flv") { _streamName = _streamName.slice(0, -4); } } } // if we need to get the stream length from the server, do it here if (!_owner.isLive && isNaN(_streamLength)) { _nc.call("getStreamLength", new Responder(getStreamLengthResult), _streamName); } else { _owner.ncConnected(); } } /** * netStatus event listener when connecting * * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function connectOnStatus(e:NetStatusEvent):void { //ifdef DEBUG //debugTrace("_tryNC["+e.target.client.connIndex+"].onStatus: " + e.info.code); //var stuff; //for (stuff in e.info) { // debugTrace("e.info[" + stuff + "] = " + e.info[stuff]); //} //endif e.target.client.pending = false; if (e.info.code == "NetConnection.Connect.Success") { //ifdef DEBUG //debugTrace( "Connection " + e.target.uri + " succeeded!" ); //endif _nc = _tryNC[e.target.client.connIndex]; cleanConns(); } else if (e.info.code == "NetConnection.Connect.Rejected" && e.info.ex != null && e.info.ex.code == 302) { _connTypeCounter = 0; cleanConns(); var parseResults:ParseResults = parseURL(e.info.ex.redirect); if (parseResults.isRTMP) { _protocol = parseResults.protocol; _serverName = parseResults.serverName; _wrappedURL = parseResults.wrappedURL; _portNumber = parseResults.portNumber; _appName = parseResults.appName; if (parseResults.streamName != null) { _appName += ("/" + parseResults.streamName); } connectRTMP(); } else { tryFallBack(); } } else if ( ( (e.info.code == "NetConnection.Connect.Failed") || (e.info.code == "NetConnection.Connect.Rejected") ) && ( e.target.client.connIndex == (_tryNC.length - 1) ) ) { // Try rearranging the app URL, then the fallbackServer if (!connectAgain()) { tryFallBack(); } } else { //ifdef DEBUG //debugTrace( "Connection " + e.target.uri + " onStatus:" + e.info.code); //endif } } /** * @private * netStatus event listener when reconnecting * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function reconnectOnStatus(e:NetStatusEvent):void { //ifdef DEBUG //debugTrace("reconnectOnStatus: " + e.info.code); //endif if ( (e.info.code == "NetConnection.Connect.Failed") || (e.info.code == "NetConnection.Connect.Rejected") ) { // Try the fallbackServer _nc = null; _ncConnected = false; _owner.ncReconnected(); } } /** * @private * * netStatus event listener for disconnecting extra * NetConnections that were opened in parallel * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function disconnectOnStatus(e:NetStatusEvent):void { //ifdef DEBUG //debugTrace("disconnectOnStatus: " + e.info.code); //endif if (e.info.code == "NetConnection.Connect.Success") { e.target.removeEventListener(NetStatusEvent.NET_STATUS, disconnectOnStatus); //ifdef DEBUG //debugTrace("Closing myself"); //endif e.target.close(); } } /** * @private * * Responder function to receive streamLength result from * server after making rpc * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function getStreamLengthResult(length:Number):void { //ifdef DEBUG //debugTrace("getStreamLengthResult(" + length + ")"); //endif if (length > 0) _streamLength = length; _owner.ncConnected(); } /** * @private * * Called on interval to timeout all connection attempts. * *For creating rtmp connections.
* * @see #connectRTMP() * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal function _onFMSConnectTimeOut(e:TimerEvent=null):void { //ifdef DEBUG //debugTrace("_onFMSConnectTimeOut()"); //endif cleanConns(); _nc = null; _ncConnected = false; if (!connectAgain()) { _owner.ncConnected(); } } /** * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ flvplayback_internal static function stripFrontAndBackWhiteSpace(p_str:String):String { var i:uint; var l:uint = p_str.length; var startIndex:int = 0 var endIndex:int = l; for (i = 0; i < l; i++) { switch (p_str.charCodeAt(i)) { case 9: // tab case 10: // new line case 13: // carriage return case 32: // space continue; } startIndex = i; break; } for (i = l; i >= 0; i--) { switch (p_str.charCodeAt(i)) { case 9: // tab case 10: // new line case 13: // carriage return case 32: // space continue; } endIndex = i + 1; break; } if (endIndex <= startIndex) { return ""; } return p_str.slice(startIndex, endIndex); } //ifdef DEBUG //public function debugTrace(s:*):void //{ // if (_owner != null) { // _owner.debugTrace("#NCManager# " + s); // } //} //endif } // class NCManager } // package fl.video