source: trunk/fl5/src/com/longtailvideo/jwplayer/media/RTMPMediaProvider.as @ 1268

Revision 1268, 25.6 KB checked in by pablo, 4 years ago (diff)
  • Fixes a bug where locking the player during the BUFFERING state would suppress BUFFER_FULL events (1014)
  • Cleans up the controlbar's "removeButton" method (1037)
Line 
1/**
2 * Wrapper for playback of _video streamed over RTMP.
3 *
4 * All playback functionalities are cross-server (FMS, Wowza, Red5)
5 **/
6package com.longtailvideo.jwplayer.media {
7    import com.longtailvideo.jwplayer.events.MediaEvent;
8    import com.longtailvideo.jwplayer.events.PlayerEvent;
9    import com.longtailvideo.jwplayer.model.PlayerConfig;
10    import com.longtailvideo.jwplayer.model.PlaylistItem;
11    import com.longtailvideo.jwplayer.model.PlaylistItemLevel;
12    import com.longtailvideo.jwplayer.parsers.LoadbalanceParser;
13    import com.longtailvideo.jwplayer.player.PlayerState;
14    import com.longtailvideo.jwplayer.utils.AssetLoader;
15    import com.longtailvideo.jwplayer.utils.Configger;
16    import com.longtailvideo.jwplayer.utils.Logger;
17    import com.longtailvideo.jwplayer.utils.NetClient;
18    import com.wowza.encryptionAS3.TEA;
19   
20    import flash.events.*;
21    import flash.media.*;
22    import flash.net.*;
23    import flash.utils.*;
24
25    /**
26     * Wrapper for playback of video streamed over RTMP. Can playback MP4, FLV, MP3, AAC and live streams.
27     **/
28    public class RTMPMediaProvider extends MediaProvider {
29                /** Save if the bandwidth checkin already occurs. **/
30                private var _bandwidthChecked:Boolean;
31                /** Whether to connect to a stream when bandwidth is detected. **/
32                private var _bandwidthSwitch:Boolean;
33                /** Save that we're connected to either the tunneled or untunneled connection. **/
34                private var _connection:Number = -1;
35        /** Array with the two netconnections; tunneled and untunneled **/
36        private var _connections:Array;
37        /** Timeout ID for the attempt to connect to tunneled connection. **/
38        private var _connectionTimeout:Number;
39        /** Is dynamic streaming possible. **/
40        private var _dynamic:Boolean;
41                /** The currently playing RTMP stream. **/
42                private var _currentFile:String;
43        /** ID for the position interval. **/
44        private var _positionInterval:Number;
45        /** Loaders for loading SMIL files. **/
46        private var _xmlLoaders:Dictionary;
47        /** NetStream instance that handles the stream IO. **/
48        private var _stream:NetStream;
49        /** Number of subcription attempts. **/
50        private var _subscribeCount:Number = 0;
51        /** Interval ID for subscription pings. **/
52        private var _subscribeInterval:Number;
53        /** Offset in seconds of the last seek. **/
54        private var _timeoffset:Number = -1;
55        /** Sound control object. **/
56        private var _transformer:SoundTransform;
57        /** Save that a stream is streaming. **/
58        private var _isStreaming:Boolean;
59        /** Level to which we're transitioning. **/
60        private var _transitionLevel:Number = -1;
61        /** Video object to be instantiated. **/
62        private var _video:Video;
63                /** Whether or not the buffer is full **/
64                private var _bufferFull:Boolean = false;
65                /** Duration of the DVR stream at the time the client connects. **/
66                private var _dvrStartDuration:Number = 0;
67                /** Is the DVR stream currently recording? **/
68                private var _dvrStartDate:Number = 0;
69                /** Whether we should pause the stream when we first connect to it **/
70                private var     _lockOnStream:Boolean = false;
71                /** Do we need to request loadbalance SMILs on switch. **/
72                private var _loadbalanceOnSwitch:Boolean;
73                /** Number of frames dropped at present. **/
74                private var _streamInfo:Array;
75                /** Interval for bw checking - with dynamic streaming. **/
76                private var _streamInfoInterval:Number;
77                /** Set if the duration comes from the configuration **/
78                private var _userDuration:Boolean;
79
80        public function RTMPMediaProvider() {
81            super('rtmp');
82        }
83
84
85        /** Constructor; sets up the connection and display. **/
86                public override function initializeMediaProvider(cfg:PlayerConfig):void {
87                        super.initializeMediaProvider(cfg);
88                        _connections = new Array();
89            var untunneled:NetConnection = new NetConnection();
90            untunneled.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
91            untunneled.objectEncoding = ObjectEncoding.AMF0;
92            untunneled.client = new NetClient(this);
93            _connections.push(untunneled);
94            var tunneled:NetConnection = new NetConnection();
95            tunneled = new NetConnection();
96            tunneled.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
97            tunneled.objectEncoding = ObjectEncoding.AMF0;
98            tunneled.client = new NetClient(this);
99            _connections.push(tunneled);
100                        _xmlLoaders = new Dictionary();
101            _transformer = new SoundTransform();
102            _video = new Video(320, 240);
103            _video.smoothing = config.smoothing;
104        }
105
106        /** Check if the player can use dynamic streaming (server versions and no load balancing). **/
107        private function checkDynamic(str:String):void {
108            var clt:Number = Number((new PlayerEvent('')).client.split(' ')[2].split(',')[0]);
109            var mjr:Number = Number(str.split(',')[0]);
110            var mnr:Number = Number(str.split(',')[1]);
111            if (clt > 9 && (mjr > 3 || (mjr == 3 && mnr > 4))) {
112                _dynamic = true;
113            } else {
114                _dynamic = false;
115            }
116        }
117
118
119        /** Connect to a tunneled version of the connection; in case the firewall blocks 1935. **/
120        private function connectTunneled():void {
121            var streamer:String = item.streamer;
122            if(item.streamer.substr(0,7) == 'rtmp://') {
123                streamer = streamer.replace('rtmp://','rtmpt://');
124            } else if(item.streamer.substr(0,8) == 'rtmpe://') {
125                streamer = streamer.replace('rtmpe://','rtmpte://');
126            }
127            _connections[1].connect(streamer);
128        };
129
130
131                /** Try pulling info from a DVRCast application. **/
132                private function doDVRInfo(id:String):void {
133                        _connections[_connection].call("DVRGetStreamInfo", new Responder(doDVRInfoCallback), id);
134                };
135
136
137                /** Callback from the DVRCast application. **/
138                private function doDVRInfoCallback(info:Object):void {
139                        _subscribeCount++;
140                        if(info.code == "NetStream.DVRStreamInfo.Success") {
141                                if(info.data.currLen < 10) {
142                                        setTimeout(doDVRInfo,4000,getID(item.file))
143                                } else {
144                                        _dvrStartDuration = info.data.currLen - 20;
145                                        if(info.data.isRec) {
146                                                _dvrStartDate = new Date().valueOf();
147                                                if(_dvrStartDuration > 20) {
148                                                        _timeoffset = _dvrStartDuration - 10;
149                                                }
150                                        }
151                                        setStream();
152                                }
153                        } else if (info.code == "NetStream.DVRStreamInfo.Retry") {
154                                if(_subscribeCount > 3) {
155                                        clearInterval(_subscribeInterval);
156                                        stop();
157                                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_ERROR,
158                                                {message: "Subscribing to the dvr stream timed out."});
159                                } else {
160                                        setTimeout(doDVRInfo,2000,getID(item.file));
161                                }
162                        }
163                        for (var itm:String in info.data) {
164                                info[itm] = info.data[itm];
165                        }
166                        delete info.data;
167                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: info});
168                };
169
170
171        /** Try subscribing to livestream **/
172                private function doSubscribe(id:String):void {
173                        _subscribeCount++;
174                        if(_subscribeCount > 3) {
175                                clearInterval(_subscribeInterval);
176                                stop();
177                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_ERROR,
178                                        {message: "Subscribing to the live stream timed out."});
179                        } else {
180                                _connections[_connection].call("FCSubscribe", null, id);
181                        }
182                };
183
184
185        /** Catch security errors. **/
186        private function errorHandler(evt:ErrorEvent):void {
187            stop();
188                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_ERROR, {message: evt.text});
189                }
190
191
192                /** Bandwidth and Framedrop checking for dynamic streaming. **/
193                private function getStreamInfo():void {
194                        var bwd:Number = Math.round(_stream.info.maxBytesPerSecond * 8 / 1024);
195                        var drf:Number = _stream.info.droppedFrames;
196                        _streamInfo.push({bwd:bwd,drf:drf});
197                        var len:Number = _streamInfo.length;
198                        if(len > 5) {
199                                bwd = Math.round((_streamInfo[len-1].bwd + _streamInfo[len-2].bwd + _streamInfo[len-3].bwd +
200                                        _streamInfo[len-4].bwd+ + _streamInfo[len-5].bwd)/5);
201                                drf = Math.round((_streamInfo[len-1].drf - _streamInfo[len-5].drf)*2)/10;
202                                if(item.levels.length > 0 && item.getLevel(bwd,config.width) != item.currentLevel) {
203                                        Logger.log("swapping to another level b/c of bandwidth",bwd.toString());
204                                        swap(item.getLevel(bwd, config.width));
205                                }
206                                if(item.levels.length > 0 && drf > 7 && item.currentLevel < item.levels.length-1) {
207                                        var lvl:Number = item.currentLevel;
208                                        item.blacklistLevel(lvl);
209                                        setTimeout(unBlacklist,30000,lvl);
210                                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: {type:'blacklist',level:lvl,state:true}});
211                                        Logger.log("swapping to another level b/c of framedrops",drf.toString());
212                                        swap(item.getLevel(bwd, config.width));
213                                }
214                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: {bandwidth:bwd,droppedFrames:drf}});
215                        }
216                };
217
218
219                private function unBlacklist(level:Number):void {
220                        item.blacklistLevel(level,false);
221                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: {type:'blacklist',level:level,state:false}});
222                };
223
224
225        /** Extract the correct rtmp syntax from the file string. **/
226        private function getID(url:String):String {
227                        var parts:Array = url.split("?");
228            var ext:String = parts[0].substr(-4);
229                        parts[0] = parts[0].substr(0, parts[0].length-4);
230            if (url.indexOf(':') > -1) {
231                return url;
232            } else if (ext == '.mp3') {
233                return 'mp3:' + parts.join("?");
234            } else if (ext == '.mp4' || ext == '.mov' || ext == '.m4v' || ext == '.aac' || ext == '.m4a' || ext == '.f4v') {
235                return 'mp4:' + url;
236            } else if (ext == '.flv') {
237                return parts.join("?");
238            } else {
239                return url;
240            }
241        }
242
243        /** Load content. **/
244        override public function load(itm:PlaylistItem):void {
245            _item = itm;
246            _position = 0;
247                        _bufferFull = false;
248                        _bandwidthSwitch = false;
249                        _lockOnStream = false;
250                        _userDuration = (_item.duration > 0);
251                       
252                        if (_timeoffset < 0) {
253                _timeoffset = item.start;
254                        }
255                       
256                        if (item.levels.length > 0) { item.setLevel(item.getLevel(config.bandwidth, config.width)); }
257                       
258                        clearInterval(_positionInterval);
259                       
260                        if (getConfigProperty('loadbalance')) {
261                                loadSmil();
262                        } else {
263                                finishLoad();
264                        }
265                       
266                        setState(PlayerState.BUFFERING);
267                        sendBufferEvent(0);
268        }
269
270                /** Load a SMIL file for load-balancing **/
271                private function loadSmil():void {
272                        if (!item.hasOwnProperty('smil')) {
273                                item.smil = [];                         
274                                if (item.levels.length > 0) {
275                                        for (var i:Number = 0; i < item.levels.length; i++) {
276                                                item.smil[i] = (item.levels[i] as PlaylistItemLevel).file;
277                                        }
278                                } else {
279                                        item.smil[0] = item.file;
280                                }
281                        }
282                       
283                        var smilFile:String = item.levels.length > 0 ? item.smil[item.currentLevel] : item.smil[0];
284                       
285                        var loader:AssetLoader = new AssetLoader();
286                        loader.addEventListener(Event.COMPLETE, loaderHandler);
287                        loader.addEventListener(ErrorEvent.ERROR, errorHandler);
288                        _xmlLoaders[loader] = smilFile;
289                        loader.load(smilFile, XML);
290                }
291               
292                /** Finalizes the loading process **/
293                private function finishLoad():void {
294                        if (item.file.substr(-4) == '.mp3' ||
295                                item.file.substr(0,4) == 'mp3:' ||
296                                item.file.substr(-4) == '.aac' ||
297                                item.file.substr(-4) == '.m4a') {
298                                media = null;
299                        } else if (!media) {
300                                media = _video;
301                        }
302                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_LOADED);
303                        try {
304                                _connections[0].connect(item.streamer);
305                                _connectionTimeout = setTimeout(connectTunneled,500);
306                        } catch(e:Error) {
307                                error("Could not connect to streamer: " + e.message);
308                        }
309                }
310
311
312                /** Get one or more levels from the loadbalancing XML. **/
313                private function loaderHandler(evt:Event):void {
314                        var arr:Array = LoadbalanceParser.parse((evt.target as AssetLoader).loadedObject);
315                        var smilLocation:String = _xmlLoaders[evt.target];
316                        delete _xmlLoaders[evt.target];
317                        if(arr.length > 1) {
318                                for(var i:Number=0; i<arr.length; i++) { item.addLevel(arr[i]); }
319                                item.setLevel(item.getLevel(config.bandwidth, config.width));
320                        } else if (item.levels.length > 0) {
321                                var level:PlaylistItemLevel = item.levels[(item.smil as Array).indexOf(smilLocation)] as PlaylistItemLevel;
322                                level.streamer = arr[0].streamer;
323                                level.file = arr[0].file;
324                                _loadbalanceOnSwitch = true;
325                        } else {
326                                item.streamer = arr[0].streamer;
327                                item.file = arr[0].file;
328                        }
329                        finishLoad();
330                };
331
332
333        /** Get metadata information from netstream class. **/
334        public function onClientData(dat:Object):void {
335                        if (!dat) return;
336            if (dat.type == 'fcsubscribe') {
337                if (dat.code == "NetStream.Play.StreamNotFound") {
338                                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_ERROR,{message: "Subscription failed: " + item.file});
339                } else if (dat.code == "NetStream.Play.Start") {
340                                        if (item.levels.length > 0) {
341                                                if (_dynamic || _bandwidthChecked) {
342                                                        setStream();
343                                                } else {
344                                                        _bandwidthChecked = true;
345                                                        _bandwidthSwitch = true;
346                                                        _connections[_connection].call('checkBandwidth', null);
347                                                }
348                                        } else {
349                                                setStream();
350                                        }
351                }
352                clearInterval(_subscribeInterval);
353            }
354            if (dat.width) {
355                                _video.width = dat.width;
356                                _video.height = dat.height;
357                                super.resize(_width, _height);
358            }
359                        if (dat.code == 'NetStream.Play.TransitionComplete') {
360                                if (_transitionLevel >= 0) { _transitionLevel = -1; }
361                        } else if (dat.type == "metadata") {
362                                if (dat.duration && !_userDuration) {
363                                        item.duration = dat.duration;
364                                }
365                        }
366            if (dat.type == 'complete') {
367                clearInterval(_positionInterval);
368                                complete();
369            }
370            if (dat.type == 'close') {
371                stop();
372            }
373            if (dat.type == 'bandwidth') {
374                config.bandwidth = dat.bandwidth;
375                Configger.saveCookie('bandwidth', dat.bandwidth);
376                                if (_bandwidthSwitch) {
377                                        _bandwidthSwitch = false;
378                        setStream();
379                                }
380            }
381                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: dat});
382        }
383
384
385        /** Pause playback. **/
386        override public function pause():void {
387                        if (isLivestream) {
388                                stop();
389                                return;
390                        }
391                        //clearInterval(_positionInterval);
392                        super.pause();
393            if (_stream) {
394                                _stream.pause();
395                        } else {
396                                _lockOnStream = true;
397                        }
398        }
399
400
401        /** Resume playing. **/
402        override public function play():void {
403                        if (!_stream) return;
404                        if (_lockOnStream) {
405                                _lockOnStream = false;
406                                seek(_timeoffset);
407                        } else if (state == PlayerState.PAUSED) {
408                                _stream.resume();
409                        }
410                        super.play();
411                        clearInterval(_positionInterval);
412                        _positionInterval = setInterval(positionInterval, 100);
413        }
414
415        /** Interval for the position progress. **/
416        private function positionInterval():void {
417            var pos:Number = Math.round((_stream.time) * 100) / 100;
418                        var bfr:Number = _stream.bufferLength / _stream.bufferTime;
419
420                        if (bfr < 0.25 && pos < duration - 5 && state != PlayerState.BUFFERING) {
421                                _bufferFull = false;
422                                setState(PlayerState.BUFFERING);
423            } else if (bfr > 1 && state != PlayerState.PLAYING && !_bufferFull && !isLivestream) {
424                                _bufferFull = true;
425                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_BUFFER_FULL, {bufferPercent: bfr});
426            }
427                       
428            if (!getConfigProperty('dvr') && state != PlayerState.PLAYING) {
429                return;
430            }
431            if (pos < duration) {
432                                _position = pos;
433                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_TIME, {position: position, duration: duration});
434            } else if (position > 0 && duration > 0) {
435                _stream.pause();
436                clearInterval(_positionInterval);
437                                complete();
438            }
439        }
440
441        /** Check if the level must be switched on resize. **/
442        override public function resize(width:Number, height:Number):void {
443            super.resize(width, height);
444                        if (state == PlayerState.PLAYING) {
445                if (item.levels.length > 0 && item.currentLevel != item.getLevel(config.bandwidth, config.width)) {
446                        if (_dynamic) {
447                                                Logger.log("swapping to another level b/c of size");
448                            swap(item.getLevel(config.bandwidth, config.width));
449                        } else {
450                            seek(position);
451                        }
452                                }
453            }
454        }
455
456        /** Seek to a new position. **/
457                override public function seek(pos:Number):void {
458                        _transitionLevel = -1;
459                        if(getConfigProperty('dvr') && _dvrStartDate && pos > duration - 10) {
460                                pos = duration - 10;
461                        }
462                        _timeoffset = pos;
463            clearInterval(_positionInterval);
464                        if (item.levels.length > 0 && item.getLevel(config.bandwidth, config.width) != item.currentLevel) {
465                item.setLevel(item.getLevel(config.bandwidth, config.width));
466                if (_loadbalanceOnSwitch) {
467                    load(item);
468                    return;
469                }
470            }
471                       
472                        if (state == PlayerState.PAUSED) {
473                                play();
474                        }
475
476                        if (_currentFile != item.file) {
477                                _currentFile = item.file;
478                                try {
479                                        if(_dvrStartDate) {
480                                                _stream.play(getID(item.file),10);
481                                                Logger.log("dvring "+item.file,"rtmp");
482                                        } else {
483                                                _stream.play(getID(item.file));
484                                                if (_dynamic) {
485                                                        _streamInfo = new Array();
486                                                        clearInterval(_streamInfoInterval);
487                                                        _streamInfoInterval = setInterval(getStreamInfo, 1000);
488                                                }
489                                        }
490                                } catch(e:Error) {
491                                        Logger.log("Error: " + e.message);
492                                }
493                        }
494                        if ((_timeoffset > 0 || _position > _timeoffset || state == PlayerState.IDLE)) {
495                                _stream.seek(_timeoffset);
496                        }
497                        _isStreaming = true;
498                        clearInterval(_positionInterval);
499                        _positionInterval = setInterval(positionInterval, 100);
500                }
501
502
503                /** Start the netstream object. **/
504                private function setStream():void {
505                        _stream = new NetStream(_connections[_connection]);
506                        _stream.checkPolicyFile = true;
507                        _stream.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
508                        _stream.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
509                        _stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, errorHandler);
510                        if(getConfigProperty('dvr')) {
511                                _stream.bufferTime = 5;
512                        } else {
513                                _stream.bufferTime = config.bufferlength;
514                        }
515                        _stream.client = new NetClient(this);
516                        _video.attachNetStream(_stream);
517                        streamVolume(config.mute ? 0 : config.volume);
518                        if (!_lockOnStream) {
519                                seek(_timeoffset);
520                        }
521                };
522
523        /** Receive NetStream status updates. **/
524        private function statusHandler(evt:NetStatusEvent):void {
525            switch (evt.info.code) {
526                case 'NetConnection.Connect.Success':
527                    if(_connection == -1) {
528                        if(evt.target == _connections[0]) {
529                            _connection = 0;
530                        } else {
531                            _connection = 1;
532                            evt.info['connection'] = 'tunneled';
533                        }
534                        _connections[_connection].addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
535                        _connections[_connection].addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
536                        _connections[_connection].addEventListener(AsyncErrorEvent.ASYNC_ERROR, errorHandler);
537                        clearTimeout(_connectionTimeout);
538                    } else {
539                        return;
540                    }
541                    if (evt.info.secureToken != undefined) {
542                        _connections[_connection].call("secureTokenResponse", null, TEA.decrypt(evt.info.secureToken,
543                                                                                  config.token));
544                    }
545                    if (evt.info.data) {
546                        checkDynamic(evt.info.data.version);
547                                        }
548                                        if(getConfigProperty('dvr')) {
549                                                _connections[_connection].call("DVRSubscribe", null, getID(item.file));
550                                                setTimeout(doDVRInfo,2000,getID(item.file));
551                                        } else if (getConfigProperty('subscribe')) {
552                                                _subscribeInterval = setInterval(doSubscribe, 2000, getID(item.file));
553                                        } else {
554                        if (item.levels.length > 0) {
555                            if (_dynamic || _bandwidthChecked) {
556                                setStream();
557                            } else {
558                                                                _bandwidthChecked = true;
559                                                                _bandwidthSwitch = true;
560                                _connections[_connection].call('checkBandwidth', null);
561                            }
562                        } else {
563                            setStream();
564                        }
565                        if (item.file.substr(-4) == '.mp3' || item.file.substr(0,4) == 'mp3:') {
566                            _connections[_connection].call("getStreamLength", new Responder(streamlengthHandler), getID(item.file));
567                        }
568                    }
569                    break;
570                case 'NetStream.Seek.Notify':
571                    clearInterval(_positionInterval);
572                                        _positionInterval = setInterval(positionInterval, 100);
573                    break;
574                case 'NetConnection.Connect.Rejected':
575                    try {
576                        if (evt.info.ex.code == 302) {
577                            item.streamer = evt.info.ex.redirect;
578                            setTimeout(load, 100, item);
579                            return;
580                        }
581                    } catch (err:Error) {
582                        stop();
583                        var msg:String = evt.info.code;
584                        if (evt.info['description']) {
585                            msg = evt.info['description'];
586                        }
587                        stop();
588                                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_ERROR, {message: msg});
589                    }
590                    break;
591                                case 'NetStream.Failed':
592                case 'NetStream.Play.StreamNotFound':
593                    if (!_isStreaming) {
594                        onClientData({type: 'complete'});
595                    } else {
596                        stop();
597                                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_ERROR, {message: "Stream not found: " + item.file});
598                    }
599                    break;
600                                case 'NetStream.Seek.Failed':
601                                        if (!_isStreaming) {
602                                                onClientData({type: 'complete'});
603                                        } else {
604                                                stop();
605                                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_ERROR, {message: "Could not seek: " + item.file});
606                                        }
607                                        break;
608                case 'NetConnection.Connect.Failed':
609                    stop();
610                                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_ERROR, {message: "Server not found: " + item.streamer});
611                    break;
612                case 'NetStream.Play.UnpublishNotify':
613                    stop();
614                    break;
615                                case 'NetStream.Buffer.Full':
616                                        if (!_bufferFull) {
617                                                _bufferFull = true;
618                                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_BUFFER_FULL);
619                                        }
620                                        break;
621                                case 'NetStream.Play.Transition':
622                                        onClientData(evt.info);
623                                        break;
624                                case 'NetStream.Play.Stop':
625                                        if(getConfigProperty('dvr')) { stop(); }
626                                        break;
627                                       
628            }
629                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: evt.info});
630        }
631
632                /** Destroy the stream. **/
633                override public function stop():void {
634                        if (_stream && _stream.time) {
635                                _stream.close();
636                        }
637                        _stream = null;
638                        _isStreaming = false;
639                        _currentFile = undefined;
640                        _video.clear();
641                        if(_connection > -1) {
642                                _connections[_connection].close();
643                                _connection = -1;
644                        }
645                        clearInterval(_positionInterval);
646                        _position = 0;
647                        _timeoffset = -1;
648                        _dvrStartDuration = _dvrStartDate = _subscribeCount = 0;
649                        _streamInfo = new Array();
650                        clearInterval(_streamInfoInterval);
651                        super.stop();
652                        if (item && item.hasOwnProperty('smil')) {
653                                /** Replace file values with original redirects **/
654                                if (item.levels.length > 0) {
655                                        for each (var level:PlaylistItemLevel in item.levels) {
656                                                for (var i:Number = 0; i < (item.smil as Array).length; i++) {
657                                                        level.file = item.smil[i];
658                                                }
659                                        }
660                                } else {
661                                        item.file = item.smil[0];
662                                }
663                        }
664                }
665
666
667                /** Get the streamlength returned from the connection. **/
668                private function streamlengthHandler(len:Number):void {
669                        item.duration = len;
670                }
671
672
673                /** Dynamically switch streams **/
674                private function swap(newLevel:Number):void {
675                        if (_transitionLevel == -1) {
676                                _transitionLevel = newLevel;
677                                item.setLevel(newLevel);
678                                var nso:NetStreamPlayOptions = new NetStreamPlayOptions();
679                                nso.streamName = getID(item.file);
680                                nso.transition = NetStreamPlayTransitions.SWITCH;
681                                clearInterval(_streamInfoInterval);
682                                _streamInfo = new Array();
683                                _streamInfoInterval = setInterval(getStreamInfo, 1000);
684                                _stream.play2(nso);
685                        }
686                }
687
688        /** Set the volume level. **/
689        override public function setVolume(vol:Number):void {
690                        streamVolume(vol);
691                        super.setVolume(vol);
692        }
693               
694                /** Set the stream's volume, without sending a volume event **/
695                protected function streamVolume(level:Number):void {
696                        _transformer.volume = level / 100;
697                        if (_stream) {
698                                _stream.soundTransform = _transformer;
699                        }
700                }
701               
702                /** Completes video playback **/
703                override protected function complete():void {
704                        stop();
705                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_COMPLETE);
706                }
707               
708                /** Determines if the stream is a live stream **/
709                protected function get isLivestream():Boolean {
710                        // We assume it's a livestream until we hear otherwise.
711                        return (!(duration > 0) && _stream && _stream.bufferLength > 0);
712                }
713
714
715                protected function get duration():Number {
716                        if(getConfigProperty('dvr')) {
717                                var dur:Number = _dvrStartDuration;
718                                if(_dvrStartDate) {
719                                        dur += (new Date().valueOf() - _dvrStartDate) / 1000;
720                                }
721                                return Math.round(dur);
722                        } else {
723                                return item.duration;
724                        }
725                }
726               
727    }
728}
Note: See TracBrowser for help on using the repository browser.