1/* 2 * jPlayer Plugin for jQuery JavaScript Library 3 * http://www.jplayer.org 4 * 5 * Copyright (c) 2009 - 2014 Happyworm Ltd 6 * Licensed under the MIT license. 7 * http://opensource.org/licenses/MIT 8 * 9 * Author: Robert M. Hall 10 * Date: 7th August 2012 11 * Custom NetConnection Manager for more robust RTMP support 12 * Based in part on work by Will Law for the old Akamai NCManager.as 13 * and some of Will's new work in the OVP base classes (Open Video Player) 14 * as well as similar approaches by many other NetConnection managers 15 * 16 */ 17 18 /* 19 TODO LIST 08/18/2011: 20 1. Wired up errors to dispatch events to Jplayer events to allow them to bubble up to JS 21 2. Rework event dispatch to handoff netconnection instead of a passed in reference 22 3. Allow a customizeable list of protocols and ports to be used instead of entire list 23 4. Allow a specific port/protocol (1 connect type) to be used first, and then optionally fallback on a custom list or the default list 24 5. Remove some traces and check a few other items below where I've made notes 25 */ 26 27package happyworm.jPlayer { 28 29 import flash.events.*; 30 import flash.net.*; 31 32 import flash.utils.Timer; 33 import flash.utils.getTimer; 34 import flash.utils.clearInterval; 35 import flash.utils.setInterval; 36 37 public class ConnectManager extends Object { 38 39 private var protocols_arr:Array = new Array("rtmp","rtmpt","rtmpe","rtmpte","rtmps"); 40 private var ports_arr:Array = new Array("",":1935",":80",":443"); 41 private const protCount:Number = 5; 42 private const portCount:Number = 4; 43 44 private var _ncRef:Object; 45 46 private var _aNC:Array; 47 48 private var k_TIMEOUT:Number = 30000; 49 private var k_startConns:Number; 50 private var m_connList:Array = []; 51 private var m_serverName:String; 52 private var m_appName:String; 53 private var m_streamName:String; 54 private var m_connListCounter:Number; 55 private var m_flashComConnectTimeOut:Number; 56 private var m_validNetConnection:NetConnection; 57 58 private var connectSuccess:Boolean=false; 59 60 private var negotiating:Boolean=false; 61 private var idleTimeOut:Boolean=false; 62 63 public function ConnectManager() { 64 trace ("ConnectManager Initialized Version: 1.00 DT"); 65 createPortsProtocolsArray(); 66 } 67 68 private function createPortsProtocolsArray():void { 69 var outerLoop:Number=0; 70 var innerLoop:Number=0; 71 for (outerLoop=0; outerLoop<protocols_arr.length; outerLoop++) { 72 73 for (innerLoop=0; innerLoop<ports_arr.length; innerLoop++) { 74 m_connList.push( { protocol: protocols_arr[outerLoop], port: ports_arr[innerLoop] } ); 75 } 76 77 } 78 } 79 80 public function negotiateConnect(ncRef:Object,p_serverName:String,p_appName:String):void 81 { 82 negotiating=true; 83 _ncRef=ncRef; 84 trace("*** SERVER NAME: "+p_serverName); 85 trace("*** APP NAME: "+p_serverName); 86 k_startConns = getTimer(); 87 m_serverName = p_serverName; 88 m_appName = p_appName; 89 90 // Set a timeout function, just in case we never connect successfully 91 clearInterval(m_flashComConnectTimeOut); 92 m_flashComConnectTimeOut = setInterval(onFlashComConnectTimeOut,k_TIMEOUT,k_TIMEOUT); 93 94 // Createe a NetConnection for each of the protocols/ports listed in the m_connList list. 95 // Connection attempts occur at intervals of 1.5 seconds. 96 // The first connection to succeed will be used, all the others will be closed. 97 _aNC = new Array(); 98 for (var i:uint = 0; i < m_connList.length; i++) 99 { 100 _aNC[i] = new NetConnection(); 101 _aNC[i].addEventListener(NetStatusEvent.NET_STATUS,netStatus); 102 _aNC[i].addEventListener(SecurityErrorEvent.SECURITY_ERROR,netSecurityError); 103 _aNC[i].addEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncError); 104 _aNC[i].client = new Object; 105 _aNC[i].client.owner = this; 106 _aNC[i].client.connIndex = i; 107 _aNC[i].client.id = i; 108 _aNC[i].client.pending = true; 109 110 /* Revisit this chunk - not needed at the moment as NC is handed off and this 111 // is handled elsewhere 112 // Need to put in some event dispatching as a more elegant solution and leave it here 113 114 _aNC[i].client.onBWDone = function (p_bw, deltaDown, deltaTime, latency) { 115 //this.owner.dispatchEvent ({type:"ncBandWidth", kbps:p_bw, latency:latency}); 116 }; 117 118 _aNC[i].client.onBWCheck = function (counter) { 119 return ++counter; 120 }; 121 122 _aNC[i].client.onStatus = function (info) { 123 // 124 }; 125 */ 126 127 } 128 m_connListCounter = 0; 129 nextConnect (); 130 } 131 132 private function nextConnect():void 133 { 134 trace("*** Connection: "+ m_connListCounter + ": "+m_connList[m_connListCounter].protocol + "://" + m_serverName + m_connList[m_connListCounter].port + "/" + m_appName); 135 136 try { 137 _aNC[m_connListCounter].connect(m_connList[m_connListCounter].protocol + "://" + m_serverName + m_connList[m_connListCounter].port + "/" + m_appName); 138 139 } catch (error:Error) { 140 // statements 141 trace("*** Caught an error condition: "+error); 142 m_connListCounter = m_connList.length+1; 143 } 144 // statements 145 clearInterval(_aNC["ncInt" + m_connListCounter]); 146 147 if ((m_connListCounter < m_connList.length - 1)) 148 { 149 m_connListCounter++; 150 _aNC["ncInt" + m_connListCounter] = setInterval(nextConnect,1500); 151 } 152 153 } 154 155 // Cleans up all connections if none have succeeded by the timeout interval 156 private function onFlashComConnectTimeOut(timeout:Number):void 157 { 158 stopAll(); 159 } 160 161 private function handleGoodConnect(_nc:NetConnection):void { 162 negotiating=false; 163 trace("Handing OFF NetConnection"); 164 clearInterval(m_flashComConnectTimeOut); 165 _ncRef.connectStream(); 166 _ncRef.onBWDone(null,_nc); 167 //dispatchEvent(event); 168 // Need to enable and pass to Jplayer event system- revisit 169 // right now handing back a hardcoded reference that is passed in 170 // Should come up with a more loosely coupled way via event dispatch 171 172 } 173 174 public function getNegotiating():Boolean { 175 return negotiating; 176 } 177 178 public function setNegotiating(bool:Boolean):void { 179 negotiating=bool; 180 } 181 182 183 public function stopAll(bool:Boolean=false):void { 184 185 //this.dispatchEvent ({type:"ncFailedToConnect", timeout:timeout}); 186 // Need to enable and pass to Jplayer event system- revisit 187 // trace(_aNC+":"+m_flashComConnectTimeOut+":"+m_connList.length) 188 if(_aNC!=null && !isNaN(m_flashComConnectTimeOut) ) { 189 clearInterval(m_flashComConnectTimeOut); 190 for (var i:uint = 0; i < m_connList.length; i++) 191 { 192 if (_aNC[i]!=null) 193 { 194 clearInterval(_aNC["ncInt" + i]); 195 _aNC[i].close(); 196 if(bool==false) { 197 _aNC[i].client = null; 198 } 199 _aNC[i] = null; 200 delete _aNC[i]; 201 } 202 } 203 } 204 205 } 206 207 208 private function netStatus(event:NetStatusEvent):void { 209 210 trace(event.info.code); 211 if(event.info.description != undefined) { 212 trace(event.info.description); 213 } 214 _aNC[event.target.client.id].client.pending = true; 215 216 // this.owner.m_validNetConnection = this.client.owner[this.client.connIndex]; 217 // if (info.description == "[ License.Limit.Exceeded ]") { 218 219 switch (event.info.code) { 220 case "NetConnection.Connect.IdleTimeOut": 221 trace("IDLE TIMEOUT OCCURRED!") 222 negotiating=true; 223 idleTimeOut=true; 224 _ncRef.shutDownNcNs(); 225 break; 226 case "NetConnection.Connect.Closed": 227 if(!negotiating && !idleTimeOut) { 228 idleTimeOut = false; 229 _ncRef.doneYet(); 230 } 231 break; 232 case "NetConnection.Connect.InvalidApp": 233 case "NetConnection.Connect.Rejected": 234 //handleRejectedOrInvalid(event) 235 break; 236 case "NetConnection.Call.Failed": 237 /* 238 if (event.info.description.indexOf("_checkbw") != -1) { 239 event.target.expectBWDone = true; 240 event.target.call("checkBandwidth",null); 241 } 242 */ 243 break; 244 case "NetConnection.Connect.Success": 245 var i:uint=0; 246 for ( i = 0; i<_aNC.length; i++) { 247 if (_aNC[i] && (i != event.target.client.id)) { 248 _aNC[i].close(); 249 _aNC[i] = null; 250 } 251 } 252 var _nc:NetConnection = NetConnection(event.target); 253 var connID:Number = event.target.client.id; 254 var _actualPort:String = m_connList[m_connListCounter].port; 255 var _actualProtocol:String = m_connList[m_connListCounter].protocol; 256 257 // See if we have version info 258 var _serverVersion:String = "UNKNOWN"; 259 if (event.info.data && event.info.data.version) { 260 _serverVersion = event.info.data.version; 261 } 262 trace("Connect ID: "+connID+" - PORT: "+_actualPort+" - PROTOCOL: "+_actualProtocol+" - FMS Version: "+_serverVersion); 263 264 clearInterval(_aNC["ncInt" + connID]); 265 clearInterval(_aNC["ncInt" + m_connListCounter]); 266 267 handleGoodConnect(_nc); 268 break; 269 } 270 } 271 272 273 /** Catches any netconnection net security errors 274 * @private 275 */ 276 private function netSecurityError(event:SecurityErrorEvent):void { 277 trace("SECURITY ERROR:"+event); 278 //dispatchEvent(event); 279 // Need to enable and pass to Jplayer event system- revisit 280 } 281 282 /** Catches any async errors 283 * @private 284 */ 285 private function asyncError(event:AsyncErrorEvent):void { 286 trace("ASYNC ERROR:"+event.error); 287 //dispatchEvent(event); 288 // Need to enable and pass to Jplayer event system- revisit 289 } 290 291 292 293 }// class 294 295} //package 296