[cvs] / ossdk / InnerServiceRIAC / lib / V2Components / mx / video / NCManager.as Repository:
Cosoft CVS

Annotation of /ossdk/InnerServiceRIAC/lib/V2Components/mx/video/NCManager.as

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (view) (download)

1 : thiswind 1.1 //****************************************************************************
2 :     //Copyright (C) 2004-2005 Macromedia, Inc. All Rights Reserved.
3 :     //The following is Sample Code and is subject to all restrictions on
4 :     //such code as contained in the End User License Agreement accompanying
5 :     //this product.
6 :     //****************************************************************************
7 :    
8 :     import mx.video.*;
9 :    
10 :     /**
11 :     * <p>Creates <code>NetConnection</code> for <code>VideoPlayer</code>, a
12 :     * helper class for that user facing class.</p>
13 :     *
14 :     * <p>NCManager supports a subset of SMIL to handle multiple streams
15 :     * for multiple bandwidths. NCManager assumes any URL that does not
16 :     * being with "rtmp://" and does not end with ".flv" is a SMIL url.
17 :     * See SMILParser for more on SMIL support.</p>
18 :     *
19 :     * @see SMILParser
20 :     */
21 :    
22 :     class mx.video.NCManager implements INCManager {
23 :    
24 :     #include "ComponentVersion.as"
25 :    
26 :     // my VideoPlayer
27 :     private var _owner:VideoPlayer;
28 :    
29 :     // server connection info
30 :     private var _contentPath:String;
31 :     private var _protocol:String;
32 :     private var _serverName:String;
33 :     private var _portNumber:String;
34 :     private var _wrappedURL:String;
35 :     private var _appName:String;
36 :     private var _streamName:String;
37 :     private var _streamLength:Number;
38 :     private var _streamWidth:Number;
39 :     private var _streamHeight:Number;
40 :     private var _streams:Array;
41 :     private var _isRTMP:Boolean;
42 :     private var _smilMgr:SMILManager;
43 :     private var _bitrate:Number;
44 :    
45 :     /**
46 :     * <p>fallbackServerName is exposed in two ways:</p>
47 :     *
48 :     * <p>User can supply second <meta base> in smil and that base
49 :     * attr will be taken as the fallbackServerName (note that only
50 :     * the server name will be taken from this and not the application
51 :     * name or anything else).</p>
52 :     *
53 :     * <p>The second way is the user can directly set this by
54 :     * accessing the ncMgr property in FLVPlayback or VideoPlayer and
55 :     * set fallbackServerName property directly.</p>
56 :     */
57 :     public var fallbackServerName:String;
58 :    
59 :     // interval for xn timeout
60 :     private var _timeoutIntervalId:Number;
61 :     private var _timeout:Number;
62 :    
63 :     /**
64 :     * Default connection timeout in milliseconds.
65 :     *
66 :     * @see #getTimeout()
67 :     * @see #setTimeout()
68 :     */
69 :     public var DEFAULT_TIMEOUT:Number = 60000;
70 :    
71 :     // bandwidth detection stuff
72 :     public var _payload:Number;
73 :     private var _autoSenseBW:Boolean;
74 :    
75 :     // info on successful xn
76 :     private var _nc:NetConnection;
77 :     private var _ncUri:String;
78 :    
79 :     // info on mult xns we try
80 :     public var _tryNC:Array;
81 :     private var _tryNCIntervalId:Number;
82 :    
83 :     // List of connections tried by connectRTMP, in order tried
84 :     private static var RTMP_CONN:Array = [
85 :     { protocol: "rtmp:/", port:"1935" }
86 :     , { protocol: "rtmp:/", port:"443" }
87 :     , { protocol: "rtmpt:/", port:"80" }
88 :     , { protocol: "rtmps:/", port:"443" }
89 :     ];
90 :    
91 :     // Counter that tracks the next type to try in RTMP_CONN.
92 :     private var _connTypeCounter:Number;
93 :    
94 :     public function NCManager() {
95 :     initNCInfo();
96 :     initOtherInfo();
97 :    
98 :     // intervals
99 :     _timeoutIntervalId = 0;
100 :     _tryNCIntervalId = 0;
101 :    
102 :     // actually calls setter
103 :     _timeout = DEFAULT_TIMEOUT;
104 :     }
105 :    
106 :     private function initNCInfo():Void {
107 :     _isRTMP = undefined;
108 :     _serverName = undefined;
109 :     _wrappedURL = undefined;
110 :     _portNumber = undefined;
111 :     _appName = undefined;
112 :     }
113 :    
114 :     private function initOtherInfo():Void {
115 :     _contentPath = undefined;
116 :     _streamName = undefined;
117 :     _streamLength = undefined;
118 :     _streamWidth = undefined;
119 :     _streamHeight = undefined;
120 :     _streams = undefined;
121 :     _autoSenseBW = false;
122 :    
123 :     _payload = 0;
124 :     _connTypeCounter = 0;
125 :     cleanConns();
126 :     }
127 :    
128 :     /*
129 :     * @see INCManager#getTimeout()
130 :     */
131 :     public function getTimeout():Number {
132 :     return _timeout;
133 :     }
134 :    
135 :     /*
136 :     * @see INCManager#setTimeout()
137 :     */
138 :     public function setTimeout(t:Number):Void {
139 :     _timeout = t;
140 :     if (_timeoutIntervalId != 0) {
141 :     clearInterval(_timeoutIntervalId);
142 :     _timeoutIntervalId = setInterval(this, "_onFCSConnectTimeOut", _timeout);
143 :     }
144 :     }
145 :    
146 :     /**
147 :     * For RTMP streams, returns value calculated from autodetection,
148 :     * not value set via setBitrate().
149 :     *
150 :     * @see INCManager#getBitrate()
151 :     */
152 :     public function getBitrate():Number {
153 :     return _bitrate;
154 :     }
155 :    
156 :     /**
157 :     * This value is only used with progressive download (HTTP), with
158 :     * RTMP streaming uses autodetection.
159 :     *
160 :     * @see INCManager#getBitrate()
161 :     */
162 :     public function setBitrate(b:Number):Void {
163 :     if (_isRTMP == undefined || !_isRTMP) {
164 :     _bitrate = b;
165 :     }
166 :     }
167 :    
168 :     /**
169 :     * @see INCManager#getVideoPlayer()
170 :     */
171 :     public function getVideoPlayer():VideoPlayer {
172 :     return _owner;
173 :     }
174 :    
175 :     /**
176 :     * @see INCManager#setVideoPlayer()
177 :     */
178 :     public function setVideoPlayer(v:VideoPlayer):Void {
179 :     _owner = v;
180 :     }
181 :    
182 :     /**
183 :     * @see INCManager#getNetConnection()
184 :     */
185 :     public function getNetConnection():NetConnection {
186 :     return _nc;
187 :     }
188 :    
189 :     /**
190 :     * @see INCManager#getStreamName()
191 :     */
192 :     public function getStreamName():String {
193 :     return _streamName;
194 :     }
195 :    
196 :     /**
197 :     * @see INCManager#isRTMP()
198 :     */
199 :     public function isRTMP():Boolean {
200 :     return _isRTMP;
201 :     }
202 :    
203 :     /**
204 :     * @see INCManager#getStreamLength()
205 :     */
206 :     public function getStreamLength():Number {
207 :     return _streamLength;
208 :     }
209 :    
210 :     /**
211 :     * @see INCManager#getStreamWidth()
212 :     */
213 :     public function getStreamWidth():Number {
214 :     return _streamWidth;
215 :     }
216 :    
217 :     /**
218 :     * @see INCManager#getStreamHeight()
219 :     */
220 :     public function getStreamHeight():Number {
221 :     return _streamHeight;
222 :     }
223 :    
224 :     /**
225 :     * @see INCManager#connectToURL()
226 :     */
227 :     public function connectToURL(url:String):Boolean {
228 :     //ifdef DEBUG
229 :     //debugTrace("connectToURL(" + url + ")");
230 :     //endif
231 :    
232 :     // init
233 :     initOtherInfo();
234 :     _contentPath = url;
235 :     if (_contentPath == null || _contentPath == undefined || _contentPath == "") {
236 :     throw new VideoError(VideoError.INVALID_CONTENT_PATH);
237 :     }
238 :    
239 :     // parse URL to determine what to do with it
240 :     var parseResults:Object = parseURL(_contentPath);
241 :     if (parseResults.streamName == undefined || parseResults.streamName == "") {
242 :     throw new VideoError(VideoError.INVALID_CONTENT_PATH, url);
243 :     }
244 :    
245 :     // connect to either rtmp or http or download and parse smil
246 :     if (parseResults.isRTMP) {
247 :     var canReuse:Boolean = canReuseOldConnection(parseResults);
248 :     _isRTMP = true;
249 :     _protocol = parseResults.protocol;
250 :     _streamName = parseResults.streamName;
251 :     _serverName = parseResults.serverName;
252 :     _wrappedURL = parseResults.wrappedURL;
253 :     _portNumber = parseResults.portNumber;
254 :     _appName = parseResults.appName;
255 :     if ( _appName == undefined || _appName == "" ||
256 :     _streamName == undefined || _streamName == "" ) {
257 :     throw new VideoError(VideoError.INVALID_CONTENT_PATH, url);
258 :     }
259 :     _autoSenseBW = (_streamName.indexOf(",") != -1);
260 :     return (canReuse || connectRTMP());
261 :     } else {
262 :     if (parseResults.streamName.slice(-4).toLowerCase() == ".flv") {
263 :     var canReuse:Boolean = canReuseOldConnection(parseResults);
264 :     _isRTMP = false;
265 :     _streamName = parseResults.streamName;
266 :     return (canReuse || connectHTTP());
267 :     } else {
268 :     _smilMgr = new SMILManager(this);
269 :     return _smilMgr.connectXML(parseResults.streamName);
270 :     }
271 :     }
272 :     }
273 :    
274 :     /**
275 :     * @see INCManager#connectAgain()
276 :     */
277 :     public function connectAgain():Boolean
278 :     {
279 :     //ifdef DEBUG
280 :     //debugTrace("connectAgain()");
281 :     //endif
282 :    
283 :     var slashIndex:Number = _appName.indexOf("/");
284 :     if (slashIndex < 0) {
285 :     // return the appName and streamName back to original form
286 :     // so we can start this process all over again with the
287 :     // fallback server if necessary
288 :     slashIndex = _streamName.indexOf("/");
289 :     if (slashIndex >= 0) {
290 :     _appName += "/";
291 :     _appName += _streamName.slice(0, slashIndex);
292 :     _streamName = _streamName.slice(slashIndex + 1);
293 :     }
294 :     return false;
295 :     }
296 :    
297 :     var newStreamName = _appName.slice(slashIndex + 1);
298 :     newStreamName += "/";
299 :     newStreamName += _streamName;
300 :     _streamName = newStreamName;
301 :     _appName = _appName.slice(0, slashIndex);
302 :     close();
303 :     _payload = 0;
304 :     _connTypeCounter = 0;
305 :     cleanConns();
306 :     connectRTMP();
307 :     return true;
308 :     }
309 :    
310 :     /**
311 :     * @see INCManager#reconnect()
312 :     */
313 :     public function reconnect():Void
314 :     {
315 :     //ifdef DEBUG
316 :     //debugTrace("reconnect()");
317 :     //endif
318 :    
319 :     if (!_isRTMP) {
320 :     throw new Error("Cannot call reconnect on an http connection");
321 :     }
322 :     _nc.onStatus = function(info:Object):Void { this.mc.reconnectOnStatus(this, info); };
323 :     _nc.onBWDone = function():Void { this.mc.onReconnected(); };
324 :     //ifdef DEBUG
325 :     //debugTrace("_ncUri = " + _ncUri);
326 :     //endif
327 :     _nc.connect(_ncUri, false);
328 :     }
329 :    
330 :     /**
331 :     * dispatches reconnect event, called by
332 :     * <code>NetConnection.onBWDone</code>
333 :     *
334 :     * @private
335 :     */
336 :     public function onReconnected():Void {
337 :     delete _nc.onStatus;
338 :     delete _nc.onBWDone;
339 :     _owner.ncReconnected();
340 :     }
341 :    
342 :     /**
343 :     * @see INCManager#close
344 :     */
345 :     public function close():Void {
346 :     if (_nc) {
347 :     _nc.close();
348 :     }
349 :     }
350 :    
351 :     /**
352 :     * Called by <code>SMILManager</code> when done.
353 :     *
354 :     * @see INCManager#helperDone()
355 :     */
356 :     public function helperDone(helper:Object, success:Boolean) {
357 :     if (helper != _smilMgr) return;
358 :    
359 :     if (!success) {
360 :     _nc = undefined;
361 :     _owner.ncConnected();
362 :     delete _smilMgr;
363 :     return;
364 :     }
365 :    
366 :     // success!
367 :    
368 :     // grab width and height
369 :     _streamWidth = _smilMgr.width;
370 :     _streamHeight = _smilMgr.height;
371 :    
372 :     // get correct streamname
373 :     var parseResults:Object;
374 :     var url:String = _smilMgr.baseURLAttr[0];
375 :    
376 :     if (url != undefined && url != "") {
377 :     parseResults = parseURL(url);
378 :     _isRTMP = parseResults.isRTMP;
379 :     _streamName = parseResults.streamName;
380 :     if (_isRTMP) {
381 :     _protocol = parseResults.protocol;
382 :     _serverName = parseResults.serverName;
383 :     _portNumber = parseResults.portNumber;
384 :     _wrappedURL = parseResults.wrappedURL;
385 :     _appName = parseResults.appName;
386 :     if (_appName == undefined || _appName == "") {
387 :     throw new VideoError(VideoError.INVALID_XML, "Base RTMP URL must include application name: " + url);
388 :     }
389 :     if (_smilMgr.baseURLAttr.length > 1) {
390 :     var parseResults:Object = parseURL(_smilMgr.baseURLAttr[1]);
391 :     if (parseResults.serverName != undefined) {
392 :     fallbackServerName = parseResults.serverName;
393 :     }
394 :     }
395 :     }
396 :     }
397 :     _streams = _smilMgr.videoTags;
398 :     for (var i:Number = 0; i < _streams.length; i++) {
399 :     url = _streams[i].src;
400 :     parseResults = parseURL(url);
401 :     if (_isRTMP == undefined) {
402 :     _isRTMP = parseResults.isRTMP;
403 :     if (_isRTMP) {
404 :     _protocol = parseResults.protocol;
405 :     if (_streams.length > 1) {
406 :     throw new VideoError(VideoError.INVALID_XML, "Cannot switch between multiple absolute RTMP URLs, must use meta tag base attribute.");
407 :     }
408 :     _serverName = parseResults.serverName;
409 :     _portNumber = parseResults.portNumber;
410 :     _wrappedURL = parseResults.wrappedURL;
411 :     _appName = parseResults.appName;
412 :     if (_appName == undefined || _appName == "") {
413 :     throw new VideoError(VideoError.INVALID_XML, "Base RTMP URL must include application name: " + url);
414 :     }
415 :     }
416 :     } else if ( _streamName != undefined && _streamName != "" &&
417 :     !parseResults.isRelative && _streams.length > 1 ) {
418 :     throw new VideoError(VideoError.INVALID_XML, "When using meta tag base attribute, cannot use absolute URLs for video or ref tag src attributes.");
419 :     }
420 :     _streams[i].parseResults = parseResults;
421 :     }
422 :     _autoSenseBW = _streams.length > 1;
423 :    
424 :     if (!_autoSenseBW) {
425 :     if (_streamName != undefined) {
426 :     _streamName += _streams[0].parseResults.streamName;
427 :     } else {
428 :     _streamName = _streams[0].parseResults.streamName;
429 :     }
430 :     _streamLength = _streams[0].dur;
431 :     }
432 :     if (_isRTMP) {
433 :     connectRTMP();
434 :     } else {
435 :     if (_autoSenseBW) bitrateMatch();
436 :     connectHTTP();
437 :     _owner.ncConnected();
438 :     }
439 :     }
440 :    
441 :     /**
442 :     * matches bitrate with stream
443 :     *
444 :     * @private
445 :     */
446 :     private function bitrateMatch():Void {
447 :     var whichStream:Number;
448 :     if (isNaN(_bitrate)) {
449 :     whichStream = 0;
450 :     } else {
451 :     for (var j:Number = 0; j < _streams.length; j++) {
452 :     if (isNaN(_streams[j].bitrate) || _bitrate <= _streams[j].bitrate) {
453 :     whichStream = j;
454 :     break;
455 :     }
456 :     }
457 :     }
458 :     if (isNaN(whichStream)) {
459 :     throw new VideoError(VideoError.NO_BITRATE_MATCH);
460 :     }
461 :     if (_streamName != undefined) {
462 :     _streamName += _streams[whichStream].src;
463 :     } else {
464 :     _streamName = _streams[whichStream].src;
465 :     }
466 :     _streamLength = _streams[whichStream].dur;
467 :     }
468 :    
469 :     /**
470 :     * <p>Parses URL to determine if it is http or rtmp. If it is rtmp,
471 :     * breaks it into pieces to extract server URL and port, application
472 :     * name and stream name. If .flv is at the end of an rtmp URL, it
473 :     * will be stripped off.</p>
474 :     *
475 :     * @private
476 :     */
477 :     private function parseURL(url:String):Object {
478 :     //ifdef DEBUG
479 :     //debugTrace("parseURL()");
480 :     //endif
481 :    
482 :     var parseResults = new Object();
483 :    
484 :     // get protocol
485 :     var startIndex:Number = 0;
486 :     var endIndex:Number = url.indexOf(":/", startIndex);
487 :     if (endIndex >= 0) {
488 :     endIndex += 2;
489 :     parseResults.protocol = url.slice(startIndex, endIndex);
490 :     parseResults.isRelative = false;
491 :     } else {
492 :     parseResults.isRelative = true;
493 :     }
494 :    
495 :     if ( parseResults.protocol != undefined &&
496 :     ( parseResults.protocol == "rtmp:/" ||
497 :     parseResults.protocol == "rtmpt:/" ||
498 :     parseResults.protocol == "rtmps:/" ) ) {
499 :     parseResults.isRTMP = true;
500 :    
501 :     startIndex = endIndex;
502 :    
503 :     if (url.charAt(startIndex) == '/') {
504 :     startIndex++;
505 :     // get server (and maybe port)
506 :     var colonIndex:Number = url.indexOf(":", startIndex);
507 :     var slashIndex:Number = url.indexOf("/", startIndex);
508 :     if (slashIndex < 0) {
509 :     if (colonIndex < 0) {
510 :     parseResults.serverName = url.slice(startIndex);
511 :     } else {
512 :     endIndex = colonIndex;
513 :     parseResults.portNumber = url.slice(startIndex, endIndex);
514 :     startIndex = endIndex + 1;
515 :     parseResults.serverName = url.slice(startIndex);
516 :     }
517 :     return parseResults;
518 :     }
519 :     if (colonIndex >= 0 && colonIndex < slashIndex) {
520 :     endIndex = colonIndex;
521 :     parseResults.serverName = url.slice(startIndex, endIndex);
522 :     startIndex = endIndex + 1;
523 :     endIndex = slashIndex;
524 :     parseResults.portNumber = url.slice(startIndex, endIndex);
525 :     } else {
526 :     endIndex = slashIndex;
527 :     parseResults.serverName = url.slice(startIndex, endIndex);
528 :     }
529 :     startIndex = endIndex + 1;
530 :     }
531 :    
532 :     // handle wrapped RTMP servers bit recursively, if it is there
533 :     if (url.charAt(startIndex) == '?') {
534 :     var subURL = url.slice(startIndex + 1);
535 :     var subParseResults = parseURL(subURL);
536 :     if (subParseResults.protocol == undefined || !subParseResults.isRTMP) {
537 :     throw new VideoError(VideoError.INVALID_CONTENT_PATH, url);
538 :     }
539 :     parseResults.wrappedURL = "?";
540 :     parseResults.wrappedURL += subParseResults.protocol;
541 :     if (subParseResults.server != undefined) {
542 :     parseResults.wrappedURL += "/";
543 :     parseResults.wrappedURL += subParseResults.server;
544 :     }
545 :     if (subParseResults.wrappedURL != undefined) {
546 :     parseResults.wrappedURL += "/?";
547 :     parseResults.wrappedURL += subParseResults.wrappedURL;
548 :     }
549 :     parseResults.appName = subParseResults.appName;
550 :     parseResults.streamName = subParseResults.streamName;
551 :     return parseResults;
552 :     }
553 :    
554 :     // get application name
555 :     endIndex = url.indexOf("/", startIndex);
556 :     if (endIndex < 0) {
557 :     parseResults.appName = url.slice(startIndex);
558 :     return parseResults;
559 :     }
560 :     parseResults.appName = url.slice(startIndex, endIndex);
561 :     startIndex = endIndex + 1;
562 :    
563 :     // check for instance name to be added to application name
564 :     endIndex = url.indexOf("/", startIndex);
565 :     if (endIndex < 0) {
566 :     parseResults.streamName = url.slice(startIndex);
567 :     return parseResults;
568 :     }
569 :     parseResults.appName += "/";
570 :     parseResults.appName += url.slice(startIndex, endIndex);
571 :     startIndex = endIndex + 1;
572 :    
573 :     // get flv name
574 :     parseResults.streamName = url.slice(startIndex);
575 :    
576 :     } else {
577 :     // is http, just return the full url received as streamName
578 :     parseResults.isRTMP = false;
579 :     parseResults.streamName = url;
580 :     }
581 :     return parseResults;
582 :     }
583 :    
584 :     /**
585 :     * <p>Compares connection info with previous NetConnection,
586 :     * will reuse existing connection if possible.
587 :     */
588 :     private function canReuseOldConnection(parseResults:Object):Boolean {
589 :     // no reuse if no prior connection
590 :     if (_nc == undefined || _nc == null) return false;
591 :    
592 :     // http connection
593 :     if (!parseResults.isRTMP) {
594 :     // can reuse if prev connection was http
595 :     if (!_isRTMP) return true;
596 :     // cannot reuse if was rtmp--close
597 :     _owner.close();
598 :     _nc = null;
599 :     initNCInfo();
600 :     return false;
601 :     }
602 :    
603 :     // rtmp connection
604 :     if (_isRTMP) {
605 :     if ( parseResults.serverName == _serverName && parseResults.appName == _appName &&
606 :     parseResults.protocol == _protocol && parseResults.portNumber == _portNumber &&
607 :     parseResults.wrappedURL == _wrappedURL ) {
608 :     return true;
609 :     }
610 :     // cannot reuse this rtmp--close
611 :     _owner.close();
612 :     _nc = null;
613 :     }
614 :    
615 :     initNCInfo();
616 :     return false;
617 :     }
618 :    
619 :     /**
620 :     * <p>Handles creating <code>NetConnection</code> instance for
621 :     * progressive download of FLV via http.</p>
622 :     *
623 :     * @private
624 :     */
625 :     private function connectHTTP():Boolean {
626 :     //ifdef DEBUG
627 :     //debugTrace("connectHTTP()");
628 :     //endif
629 :    
630 :     _nc = new NetConnection();
631 :     _nc.connect(null);
632 :     return true;
633 :     }
634 :    
635 :     /**
636 :     * <p>Top level function for creating <code>NetConnection</code>
637 :     * instance for progressive download of FLV via rtmp. Actually
638 :     * tries to create several different connections using different
639 :     * protocols and ports in a pipeline, so multiple connection
640 :     * attempts may be occurring simultaneously, and will use the
641 :     * first one that connects successfully.</p>
642 :     *
643 :     * @private
644 :     */
645 :     private function connectRTMP():Boolean {
646 :     //ifdef DEBUG
647 :     //debugTrace("connectRTMP()");
648 :     //endif
649 :    
650 :     // setup timeout
651 :     clearInterval(_timeoutIntervalId);
652 :     _timeoutIntervalId = setInterval(this, "_onFCSConnectTimeOut", _timeout);
653 :    
654 :     _tryNC = new Array();
655 :     for (var i:Number = 0; i < RTMP_CONN.length; i++) {
656 :     //ifdef DEBUG
657 :     //debugTrace("Creating connection " + i);
658 :     //endif
659 :     _tryNC[i] = new NetConnection();
660 :     _tryNC[i].mc = this;
661 :     _tryNC[i].pending = false;
662 :     _tryNC[i].connIndex = i;
663 :     _tryNC[i].onBWDone = function(p_bw:Number):Void {
664 :     this.mc.onConnected(this, p_bw);
665 :     }
666 :     _tryNC[i].onBWCheck = function():Number {
667 :     return ++this.mc._payload;
668 :     }
669 :     _tryNC[i].onStatus = function(info:Object):Void { this.mc.connectOnStatus(this, info); };
670 :     }
671 :    
672 :     nextConnect();
673 :     return false;
674 :     }
675 :    
676 :     /**
677 :     * <p>Does work of trying to open rtmp connections. Called either
678 :     * by <code>connectRTMP</code> or on an interval set up in
679 :     * that method.</p>
680 :     *
681 :     * <p>For creating rtmp connections.</p>
682 :     *
683 :     * @see #connectRTMP()
684 :     * @private
685 :     */
686 :     private function nextConnect():Void {
687 :     //ifdef DEBUG
688 :     //debugTrace("nextConnect()");
689 :     //endif
690 :    
691 :     clearInterval(_tryNCIntervalId);
692 :     _tryNCIntervalId = 0;
693 :     var protocol:String;
694 :     var port:String;
695 :     if (_connTypeCounter == 0) {
696 :     protocol = _protocol;
697 :     if (_portNumber != undefined) {
698 :     port = _portNumber;
699 :     } else {
700 :     for (var i:Number = 0; i < RTMP_CONN.length; i++) {
701 :     if (protocol == RTMP_CONN[i].protocol) {
702 :     port = RTMP_CONN[i].port;
703 :     break;
704 :     }
705 :     }
706 :     }
707 :     } else {
708 :     protocol = RTMP_CONN[_connTypeCounter].protocol;
709 :     port = RTMP_CONN[_connTypeCounter].port;
710 :     }
711 :     var xnURL:String = protocol + ((_serverName == undefined) ? "" : "/" + _serverName + ":" + port + "/") + ((_wrappedURL == undefined) ? "" : _wrappedURL + "/") + _appName;
712 :     //ifdef DEBUG
713 :     //debugTrace( "_tryNC[" + _connTypeCounter + "] connecting to room: " + xnURL );
714 :     //endif
715 :     _tryNC[_connTypeCounter].pending = true;
716 :     _tryNC[_connTypeCounter].connect( xnURL, _autoSenseBW);
717 :     if (_connTypeCounter < (RTMP_CONN.length-1)) {
718 :     _connTypeCounter++;
719 :     _tryNCIntervalId = setInterval(this, "nextConnect", 1500);
720 :     }
721 :     }
722 :    
723 :     /**
724 :     * <p>Stops all intervals, closes all unneeded connections, and other
725 :     * cleanup related to the <code>connectRTMP</code> strategy of
726 :     * pipelining connection attempts to different protocols and
727 :     * ports.</p>
728 :     *
729 :     * <p>For creating rtmp connections.</p>
730 :     *
731 :     * @see #connectRTMP()
732 :     * @private
733 :     */
734 :     public function cleanConns() {
735 :     //ifdef DEBUG
736 :     //debugTrace("cleanConns()");
737 :     //endif
738 :    
739 :     clearInterval(_tryNCIntervalId);
740 :     _tryNCIntervalId = 0;
741 :     if (_tryNC != undefined) {
742 :     for (var i:Number = 0; i < _tryNC.length; i++) {
743 :     if (_tryNC[i] != undefined) {
744 :     //ifdef DEBUG
745 :     //debugTrace("_tryNC[" + i + "] = " + _tryNC[i]);
746 :     //endif
747 :     delete _tryNC[i].onStatus;
748 :     if (_tryNC[i].pending) {
749 :     _tryNC[i].onStatus = function(info:Object):Void { this.mc.disconnectOnStatus(this, info); };
750 :     } else {
751 :     delete _tryNC[i].onStatus;
752 :     _tryNC[i].close();
753 :     }
754 :     }
755 :     delete _tryNC[i];
756 :     }
757 :     delete _tryNC;
758 :     }
759 :     }
760 :    
761 :     /**
762 :     * <p>Starts another pipelined connection attempt with
763 :     * <code>connectRTMP</code> with the fallback server.</p>
764 :     *
765 :     * <p>For creating rtmp connections.</p>
766 :     *
767 :     * @see #connectRTMP()
768 :     * @private
769 :     */
770 :     private function tryFallBack():Void {
771 :     //ifdef DEBUG
772 :     //debugTrace("tryFallBack()");
773 :     //endif
774 :    
775 :     if (_serverName == fallbackServerName || fallbackServerName == undefined || fallbackServerName == null) {
776 :     //ifdef DEBUG
777 :     //debugTrace("Already tried to fall back!");
778 :     //endif
779 :     //it's not connected
780 :     delete _nc;
781 :     _nc = undefined;
782 :     _owner.ncConnected();
783 :     } else {
784 :     _connTypeCounter = 0;
785 :     cleanConns();
786 :     _serverName = fallbackServerName;
787 :     //ifdef DEBUG
788 :     //debugTrace("connect: " + _serverName);
789 :     //endif
790 :     connectRTMP();
791 :     }
792 :     }
793 :    
794 :     /**
795 :     * <p>Starts another pipelined connection attempt with
796 :     * <code>connectRTMP</code> with the fallback server.</p>
797 :     *
798 :     * <p>For creating rtmp connections.</p>
799 :     *
800 :     * @see #connectRTMP()
801 :     * @private
802 :     */
803 :     public function onConnected(p_nc:NetConnection, p_bw:Number):Void
804 :     {
805 :     //ifdef DEBUG
806 :     //debugTrace("onConnected()");
807 :     //endif
808 :    
809 :     // avoid timeout
810 :     clearInterval(_timeoutIntervalId);
811 :     _timeoutIntervalId = 0;
812 :    
813 :     // ditch these now unneeded functions and listeners
814 :     delete p_nc.onBWDone;
815 :     delete p_nc.onBWCheck;
816 :     delete p_nc.onStatus;
817 :    
818 :     // store pointers to the successful xn and uri
819 :     _nc = p_nc;
820 :     _ncUri = _nc.uri;
821 :    
822 :     if (_autoSenseBW) {
823 :     _bitrate = p_bw * 1024;
824 :    
825 :     if (_streams != undefined) {
826 :     bitrateMatch();
827 :     } else if (_streamName.indexOf(",") != -1) {
828 :     var sSplit:Array = _streamName.split(",");
829 :     // remove leading and trailing whitespace from string
830 :     for (var i:Number = 0; i < sSplit.length; i+=2) {
831 :     var sName = stripFrontAndBackWhiteSpace(sSplit[i]);
832 :     if (i + 1 < sSplit.length) {
833 :     // If we have less bw than the next threshold or if
834 :     // there isn't another threshold (last string)
835 :     if (p_bw <= Number(sSplit[i+1])) {
836 :     _streamName = sName;
837 :     break;
838 :     }
839 :     } else {
840 :     _streamName = sName;
841 :     break;
842 :     }
843 :     } // for
844 :     }
845 :     }
846 :    
847 :     // strip off .flv if included
848 :     if (_streamName.slice(-4).toLowerCase() == ".flv") {
849 :     _streamName = _streamName.slice(0, -4);
850 :     }
851 :    
852 :     // if we need to get the stream length from the server, do it here
853 :     if (!_owner.isLive && _streamLength == undefined) {
854 :     var res:Object = new Object();
855 :     res.mc = this;
856 :     res.onResult = function(length:Number) { this.mc.getStreamLengthResult(length); };
857 :     _nc.call("getStreamLength", res, _streamName);
858 :     } else {
859 :     _owner.ncConnected();
860 :     }
861 :     }
862 :    
863 :     /**
864 :     * netStatus event listener when connecting
865 :     *
866 :     * @private
867 :     */
868 :     public function connectOnStatus(target:NetConnection, info:Object):Void {
869 :     //ifdef DEBUG
870 :     //debugTrace("_tryNC["+target.connIndex+"].onStatus: " + info.code);
871 :     //var stuff;
872 :     //for (stuff in info) {
873 :     // debugTrace("info[" + stuff + "] = " + info[stuff]);
874 :     //}
875 :     //endif
876 :     target.pending = false;
877 :    
878 :     if (info.code == "NetConnection.Connect.Success") {
879 :     //ifdef DEBUG
880 :     //debugTrace( "Connection " + RTMP_CONN[target.connIndex].protocol +
881 :     // ":" + RTMP_CONN[target.connIndex].port + " succeeded!" );
882 :     //endif
883 :     _nc = _tryNC[target.connIndex];
884 :     _tryNC[target.connIndex] = undefined;
885 :     cleanConns();
886 :     } else if ( ( (info.code == "NetConnection.Connect.Failed") ||
887 :     (info.code == "NetConnection.Connect.Rejected") ) &&
888 :     ( target.connIndex == (RTMP_CONN.length - 1) ) ) {
889 :     // Try rearranging the app URL, then the fallbackServer
890 :     if (!connectAgain()) {
891 :     tryFallBack();
892 :     }
893 :     } else {
894 :     //ifdef DEBUG
895 :     //debugTrace( RTMP_CONN[target.connIndex].protocol + ":" +
896 :     // RTMP_CONN[target.connIndex].port +
897 :     // " onStatus:" + info.code);
898 :     //endif
899 :     }
900 :     }
901 :    
902 :     /**
903 :     * netStatus event listener when reconnecting
904 :     *
905 :     * @private
906 :     */
907 :     public function reconnectOnStatus(target:NetConnection, info:Object):Void
908 :     {
909 :     //ifdef DEBUG
910 :     //debugTrace("reconnectOnStatus: " + info.code);
911 :     //endif
912 :     if ( (info.code == "NetConnection.Connect.Failed") ||
913 :     (info.code == "NetConnection.Connect.Rejected") ) {
914 :     // Try the fallbackServer
915 :     delete _nc;
916 :     _nc = undefined;
917 :     _owner.ncReconnected();
918 :     }
919 :     }
920 :    
921 :     /**
922 :     * netStatus event listener for disconnecting extra
923 :     * NetConnections that were opened in parallel
924 :     *
925 :     * @private
926 :     */
927 :     public function disconnectOnStatus(target:NetConnection, info:Object):Void
928 :     {
929 :     //ifdef DEBUG
930 :     //debugTrace("disconnectOnStatus: " + info.code);
931 :     //endif
932 :     if (info.code == "NetConnection.Connect.Success") {
933 :     delete target.onStatus;
934 :     //ifdef DEBUG
935 :     //debugTrace("Closing myself");
936 :     //endif
937 :     target.close();
938 :     }
939 :     }
940 :    
941 :     /**
942 :     * Responder function to receive streamLength result from
943 :     * server after making rpc
944 :     *
945 :     * @private
946 :     */
947 :     public function getStreamLengthResult(length:Number):Void {
948 :     //ifdef DEBUG
949 :     //debugTrace("getStreamLengthResult(" + length + ")");
950 :     //endif
951 :     _streamLength = length;
952 :     _owner.ncConnected();
953 :     }
954 :    
955 :     /**
956 :     * <p>Called on interval to timeout all connection attempts.</p>
957 :     *
958 :     * <p>For creating rtmp connections.</p>
959 :     *
960 :     * @see #connectRTMP()
961 :     * @private
962 :     */
963 :     public function _onFCSConnectTimeOut():Void
964 :     {
965 :     //ifdef DEBUG
966 :     //debugTrace("_onFCSConnectTimeOut()");
967 :     //endif
968 :     cleanConns();
969 :     _nc = undefined;
970 :     if (!connectAgain()) {
971 :     _owner.ncConnected();
972 :     }
973 :     }
974 :    
975 :     private static function stripFrontAndBackWhiteSpace(p_str:String):String
976 :     {
977 :     var i:Number;
978 :     var l:Number = p_str.length;
979 :     var startIndex:Number = 0
980 :     var endIndex:Number = l;
981 :     for (i = 0; i < l; i++) {
982 :     switch (p_str.charCodeAt(i)) {
983 :     case 9: // tab
984 :     case 10: // new line
985 :     case 13: // carriage return
986 :     case 32: // space
987 :     continue;
988 :     }
989 :     startIndex = i;
990 :     break;
991 :     }
992 :    
993 :     for (i = l; i >= 0; i--) {
994 :     switch (p_str.charCodeAt(i)) {
995 :     case 9: // tab
996 :     case 10: // new line
997 :     case 13: // carriage return
998 :     case 32: // space
999 :     continue;
1000 :     }
1001 :     endIndex = i + 1;
1002 :     break;
1003 :     }
1004 :    
1005 :     if (endIndex <= startIndex) {
1006 :     return "";
1007 :     }
1008 :     return p_str.slice(startIndex, endIndex);
1009 :     }
1010 :    
1011 :     //ifdef DEBUG
1012 :     //public function debugTrace(s:String):Void
1013 :     //{
1014 :     // if (_owner != undefined) {
1015 :     // _owner.debugTrace("#NCManager# " + s);
1016 :     // }
1017 :     //}
1018 :     //endif
1019 :     } // class mx.video.NCManager

cvs-admin
ViewVC Help
Powered by ViewVC 1.0.0