source: trunk/fl5/src/com/longtailvideo/jwplayer/controller/Controller.as @ 1419

Revision 1419, 18.1 KB checked in by jeroen, 3 years ago (diff)

made idle seek call working and fixed http streaming autoadvance buffer issue

Line 
1package com.longtailvideo.jwplayer.controller {
2        import com.jeroenwijering.events.ModelStates;
3        import com.longtailvideo.jwplayer.events.GlobalEventDispatcher;
4        import com.longtailvideo.jwplayer.events.MediaEvent;
5        import com.longtailvideo.jwplayer.events.PlayerEvent;
6        import com.longtailvideo.jwplayer.events.PlayerStateEvent;
7        import com.longtailvideo.jwplayer.events.PlaylistEvent;
8        import com.longtailvideo.jwplayer.events.ViewEvent;
9        import com.longtailvideo.jwplayer.model.Model;
10        import com.longtailvideo.jwplayer.model.PlaylistItem;
11        import com.longtailvideo.jwplayer.parsers.JWParser;
12        import com.longtailvideo.jwplayer.player.IPlayer;
13        import com.longtailvideo.jwplayer.player.PlayerState;
14        import com.longtailvideo.jwplayer.plugins.IPlugin;
15        import com.longtailvideo.jwplayer.utils.Configger;
16        import com.longtailvideo.jwplayer.utils.Logger;
17        import com.longtailvideo.jwplayer.utils.RootReference;
18        import com.longtailvideo.jwplayer.view.View;
19       
20        import flash.events.ErrorEvent;
21        import flash.events.Event;
22        import flash.net.URLRequest;
23        import flash.net.navigateToURL;
24
25        /**
26         * Sent when the player has been initialized and skins and plugins have been successfully loaded.
27         *
28         * @eventType com.longtailvideo.jwplayer.events.PlayerEvent.JWPLAYER_READY
29         */
30        [Event(name="jwplayerReady", type = "com.longtailvideo.jwplayer.events.PlayerEvent")]
31
32        /**
33         * Sent when the player has entered the ERROR state
34         *
35         * @eventType com.longtailvideo.jwplayer.events.PlayerEvent.JWPLAYER_ERROR
36         */
37        [Event(name="jwplayerError", type = "com.longtailvideo.jwplayer.events.PlayerEvent")]
38
39        /**
40         * Sent when the player has been locked
41         *
42         * @eventType com.longtailvideo.jwplayer.events.PlayerEvent.JWPLAYER_LOCKED
43         */
44        [Event(name="jwplayerLocked", type = "com.longtailvideo.jwplayer.events.PlayerEvent")]
45
46        /**
47         * Sent when the player has been unlocked
48         *
49         * @eventType com.longtailvideo.jwplayer.events.PlayerEvent.JWPLAYER_UNLOCKED
50         */
51        [Event(name="jwplayerUnlocked", type = "com.longtailvideo.jwplayer.events.PlayerEvent")]
52
53        /**
54         * Sent when the player has gone into or out of fullscreen mode
55         *
56         * @eventType com.longtailvideo.jwplayer.events.PlayerEvent.JWPLAYER_FULLSCREEN
57         */
58        [Event(name="jwplayerFullscreen", type = "com.longtailvideo.jwplayer.events.PlayerEvent")]
59
60        /**
61         * The Controller is responsible for handling Model / View events and calling the appropriate responders
62         *
63         * @author Pablo Schklowsky
64         */
65        public class Controller extends GlobalEventDispatcher {
66
67                /** MVC References **/
68                protected var _player:IPlayer;
69                protected var _model:Model;
70                protected var _view:View;
71
72                /** Setup completed **/
73                protected var _setupComplete:Boolean = false;
74                /** Setup finalized **/
75                protected var _setupFinalized:Boolean = false;
76                /** Whether to autostart on unlock **/
77                protected var _unlockAutostart:Boolean = false;
78                /** Whether to resume on unlock **/
79                protected var _lockingResume:Boolean = false;
80                /** Lock manager **/
81                protected var _lockManager:LockManager;
82                /** Load after unlock - My favorite variable ever **/
83                protected var _unlockAndLoad:Boolean;
84                /** Whether the playlist has been loaded yet **/
85                protected var _playlistReady:Boolean = false;
86                /** Set this value if a seek request comes in before the seek is possible **/           
87                protected var _queuedSeek:Number = -1;
88               
89                /** A list with legacy CDN classes that are now redirected to buit-in ones. **/
90                protected var cdns:Object = {
91                                bitgravity:{'http.startparam':'starttime', provider:'http'},
92                                edgecast:{'http.startparam':'ec_seek', provider:'http'},
93                                flvseek:{'http.startparam':'fs', provider:'http'},
94                                highwinds:{'rtmp.loadbalance':true, provider:'rtmp'},
95                                lighttpd:{'http.startparam':'start', provider:'http'},
96                                vdox:{'rtmp.loadbalance':true, provider:'rtmp'}
97                };
98               
99                /** Reference to a PlaylistItem which has triggered an external MediaProvider load **/
100                protected var _delayedItem:PlaylistItem;
101                /** Loader for external MediaProviders **/
102                protected var _mediaLoader:MediaProviderLoader;
103               
104                public function Controller(player:IPlayer, model:Model, view:View) {
105                        _player = player;
106                        _model = model;
107                        _view = view;
108                        _lockManager = new LockManager();
109                }
110
111                /**
112                 * Begin player setup
113                 * @param readyConfig If a PlayerConfig object is already available, use it to configure the player.
114                 * Otherwise, load the config from XML / flashvars.
115                 */
116                public function setupPlayer():void {
117                        var setup:PlayerSetup = new PlayerSetup(_player, _model, _view);
118
119                        setup.addEventListener(Event.COMPLETE, setupComplete);
120                        setup.addEventListener(ErrorEvent.ERROR, setupError);
121
122                        addViewListeners();
123
124                        setup.setupPlayer();
125                }
126
127                protected function addViewListeners():void {
128                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_PLAY, playHandler);
129                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_PAUSE, pauseHandler);
130                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_STOP, stopHandler);
131                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_NEXT, nextHandler);
132                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_PREV, prevHandler);
133                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_SEEK, seekHandler);
134                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_MUTE, muteHandler);
135                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_VOLUME, volumeHandler);
136                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_FULLSCREEN, fullscreenHandler);
137                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_LOAD, loadHandler);
138                        _view.addEventListener(ViewEvent.JWPLAYER_VIEW_REDRAW, redrawHandler);
139                }
140
141                protected function playHandler(evt:ViewEvent):void { play(); }
142                protected function stopHandler(evt:ViewEvent):void { stop(); }
143                protected function pauseHandler(evt:ViewEvent):void { pause(); }
144                protected function nextHandler(evt:ViewEvent):void { next(); }
145                protected function prevHandler(evt:ViewEvent):void { previous(); }
146                protected function seekHandler(evt:ViewEvent):void { seek(evt.data); }
147                protected function muteHandler(evt:ViewEvent):void { mute(evt.data); }
148                protected function volumeHandler(evt:ViewEvent):void { setVolume(evt.data); }
149                protected function fullscreenHandler(evt:ViewEvent):void { fullscreen(evt.data); }
150                protected function loadHandler(evt:ViewEvent):void { load(evt.data); }
151                protected function redrawHandler(evt:ViewEvent):void { redraw(); }
152
153
154                protected function setupComplete(evt:Event):void {
155                        _setupComplete = true;
156                        RootReference.stage.dispatchEvent(new Event(Event.RESIZE));
157                        _view.completeView();
158                        finalizeSetup();
159                }
160
161
162                protected function setupError(evt:ErrorEvent):void {
163                        Logger.log("STARTUP: Error occurred during player startup: " + evt.text);
164                        _view.completeView(true, evt.text);
165                        dispatchEvent(evt.clone());
166                }
167
168
169                protected function finalizeSetup():void {
170                        if (!locking && _setupComplete && !_setupFinalized) {
171                                _setupFinalized = true;
172
173                                _player.addEventListener(ErrorEvent.ERROR, errorHandler);
174
175                                _player.addEventListener(PlaylistEvent.JWPLAYER_PLAYLIST_LOADED, playlistLoadHandler, false, -1);
176                                _player.addEventListener(PlaylistEvent.JWPLAYER_PLAYLIST_ITEM, playlistItemHandler, false, 1000);
177                                _player.addEventListener(MediaEvent.JWPLAYER_MEDIA_COMPLETE, completeHandler, false);
178                               
179                                dispatchEvent(new PlayerEvent(PlayerEvent.JWPLAYER_READY));
180
181                                // Broadcast playlist loaded (which was swallowed during player setup);
182                                if (_model.playlist.length > 0) {
183                                        _model.dispatchEvent(new PlaylistEvent(PlaylistEvent.JWPLAYER_PLAYLIST_LOADED, _model.playlist));
184                                }
185
186                               
187                        }
188                }
189
190
191                protected function playlistLoadHandler(evt:PlaylistEvent=null):void {
192                        _playlistReady = true;
193                       
194                        if (_model.config.shuffle) {
195                                shuffleItem();
196                        } else {
197                                if (_model.config.item >= _model.playlist.length) {
198                                        _model.config.item = _model.playlist.length - 1;
199                                }
200                                _model.playlist.currentIndex = _model.config.item;
201                        }
202
203                        if(_model.config.autostart) {
204                                if (locking) {
205                                        _unlockAutostart = true;
206                                } else {
207                                        play();
208                                }
209                        }
210                }
211
212
213                protected function shuffleItem():void {
214                        _model.playlist.currentIndex = Math.floor(Math.random() * _model.playlist.length);
215                }
216
217
218                protected function playlistItemHandler(evt:PlaylistEvent):void {
219                        _model.config.item = _model.playlist.currentIndex;
220                        load(_model.playlist.currentItem);
221                }
222
223
224                protected function errorHandler(evt:ErrorEvent):void {
225                        _delayedItem = null;
226                        _mediaLoader = null;
227                        errorState(evt.text);
228                }
229
230
231                protected function errorState(message:String=""):void {
232                        dispatchEvent(new PlayerEvent(PlayerEvent.JWPLAYER_ERROR, message));
233                }
234
235
236                protected function completeHandler(evt:MediaEvent):void {
237                        switch (_model.config.repeat) {
238                                case RepeatOptions.SINGLE:
239                                        play();
240                                        break;
241                                case RepeatOptions.ALWAYS:
242                                        if (_model.playlist.currentIndex == _model.playlist.length - 1 && !_model.config.shuffle) {
243                                                _model.playlist.currentIndex = 0;
244                                                play();
245                                        } else {
246                                                next();
247                                        }
248                                        break;
249                                case RepeatOptions.LIST:
250                                        if (_model.playlist.currentIndex == _model.playlist.length - 1 && !_model.config.shuffle) {
251                                                _lockingResume = false;
252                                                _model.playlist.currentIndex = 0;
253                                        } else {
254                                                next();
255                                        }
256                                        break;
257                        }
258                }
259
260
261                ////////////////////
262                // Public methods //
263                ////////////////////
264
265                public function get locking():Boolean {
266                        return _lockManager.locked();
267                }
268
269
270                /**
271                 * @private
272                 * @copy com.longtailvideo.jwplayer.player.Player#lockPlayback
273                 */
274                public function lockPlayback(plugin:IPlugin, callback:Function):void {
275                        var wasLocked:Boolean = locking;
276                        if (_lockManager.lock(plugin, callback)) {
277                                // If it was playing, pause playback and plan to resume when you're done
278                                if (_player.state == PlayerState.PLAYING || _player.state == PlayerState.BUFFERING) {
279                                        _model.media.pause();
280                                        _lockingResume = true;
281                                }
282                               
283                                // Tell everyone you're locked
284                                if (!wasLocked) {
285                                        Logger.log(plugin.id + " locking playback", "LOCK");
286                                        dispatchEvent(new PlayerEvent(PlayerEvent.JWPLAYER_LOCKED));
287                                        _lockManager.executeCallback();
288                                }
289                        }
290                }
291
292
293                /**
294                 * @private
295                 * @copy com.longtailvideo.jwplayer.player.Player#unlockPlayback
296                 */
297                public function unlockPlayback(target:IPlugin):Boolean {
298                        if (_lockManager.unlock(target)) {
299                                if (!locking) {
300                                        dispatchEvent(new PlayerEvent(PlayerEvent.JWPLAYER_UNLOCKED));
301                                }
302                                if (_setupComplete && !_setupFinalized) {
303                                        finalizeSetup();
304                                }
305                                if (!locking) {
306                                        if (_unlockAndLoad) {
307                                                load(_player.playlist.currentItem);
308                                                _unlockAndLoad = false;
309                                        }
310                                        if (_lockingResume || _unlockAutostart) {
311                                                _lockingResume = false;
312                                                play();
313                                                if (_unlockAutostart) {
314                                                        _unlockAutostart = false;
315                                                }
316                                        }
317                                        return true;
318                                }
319                        }
320                        return false;
321                }
322
323
324                public function setVolume(vol:Number):Boolean {
325                        if (locking) {
326                                return false;
327                        }
328                        if (_model.media) {
329                                mute(false);
330                                _model.config.volume = vol;
331                                _model.media.setVolume(vol);
332                                setCookie('volume', vol);
333                                return true;
334                        }
335                        return false;
336                }
337
338
339                public function mute(muted:Boolean):Boolean {
340                        if (locking) {
341                                return false;
342                        }
343                        if (muted && !_model.mute) {
344                                _model.mute = true;
345                                setCookie('mute', true);
346                                return true;
347                        } else if (!muted && _model.mute) {
348                                _model.mute = false;
349                                setCookie('mute', false);
350                                return true;
351                        }
352                        return false;
353                }
354
355
356                public function play():Boolean {
357                        if (!_playlistReady) {
358                                Logger.log("Attempted to begin playback before playlist is ready");
359                                return false;
360                        }
361                       
362                        if (_mediaLoader) {
363                                _delayedItem = _model.playlist.currentItem;
364                                return false;
365                        }
366
367                        if (locking) {
368                                return false;
369                        }
370
371                        if (_model.playlist.currentItem) {
372                                switch (_player.state) {
373                                        case PlayerState.IDLE:
374                                                _model.media.addEventListener(MediaEvent.JWPLAYER_MEDIA_BUFFER_FULL, bufferFullHandler);
375                                                _model.media.load(_model.playlist.currentItem);
376                                                break;
377                                        case PlayerState.PAUSED:
378                                                _model.media.seek(_queuedSeek);
379                                                _model.media.play();
380                                                break;
381                                }
382                        }
383                        return true;
384                }
385
386
387                public function pause():Boolean {
388                        if (locking) {
389                                return false;
390                        }
391                        if (!_model.media)
392                                return false;
393
394                        switch (_model.media.state) {
395                                case PlayerState.PLAYING:
396                                case PlayerState.BUFFERING:
397                                        _model.media.pause();
398                                        return true;
399                                        break;
400                        }
401
402                        return false;
403                }
404
405
406                public function stop():Boolean {
407                        if (locking) {
408                                return false;
409                        }
410                        if (!_model.media)
411                                return false;
412
413                        switch (_model.media.state) {
414                                case PlayerState.PLAYING:
415                                case PlayerState.BUFFERING:
416                                case PlayerState.PAUSED:
417                                        _model.media.stop();
418                                        return true;
419                                        break;
420                        }
421
422                        return false;
423                }
424
425
426                public function next():Boolean {
427                        if (locking) {
428                                _unlockAndLoad = true;
429                                return false;
430                        }
431
432                        _lockingResume = true;
433                        stop();
434                        if (_model.config.shuffle) {
435                                shuffleItem();
436                        } else if (_model.playlist.currentIndex == _model.playlist.length - 1) {
437                                _player.playlist.currentIndex = 0;
438                        } else {
439                                _player.playlist.currentIndex = _player.playlist.currentIndex + 1;
440                        }
441                        play();
442                       
443                        return true;
444                }
445
446
447                public function previous():Boolean {
448                        if (locking) {
449                                _unlockAndLoad = true;
450                                return false;
451                        }
452
453                        _lockingResume = true;
454                        stop();
455                        if (_model.config.shuffle) {
456                                shuffleItem();
457                        } else if (_model.playlist.currentIndex <= 0) {
458                                _model.playlist.currentIndex = _model.playlist.length - 1;
459                        } else {
460                                _player.playlist.currentIndex = _player.playlist.currentIndex - 1;
461                        }
462                        play();
463                       
464                        return true;
465                }
466
467
468                public function setPlaylistIndex(index:Number):Boolean {
469                        if (locking) {
470                                _unlockAndLoad = true;
471                                return false;
472                        }
473
474                        _lockingResume = true;
475                        if (0 <= index && index < _player.playlist.length) {
476                                stop();
477                                _player.playlist.currentIndex = index;
478                                play();
479                                return true;
480                        }
481                        return false;
482                }
483
484                public function seek(pos:Number):Boolean {
485                        if (locking) {
486                                return false;
487                        }
488                        if (!_model.media || pos == -1) {
489                                return false;
490                        }
491
492                        switch (_model.media.state) {
493                                case PlayerState.PLAYING:
494                                case PlayerState.PAUSED:
495                                        _model.media.seek(pos);
496                                        return true;
497                                case PlayerState.IDLE:
498                                        _model.playlist.currentItem.start = pos;
499                                        play();
500                                        return true;
501                                case PlayerState.BUFFERING:
502                                        _queuedSeek = pos;
503                                        break;
504                        }
505
506                        return false;
507                }
508
509
510                public function load(item:*):Boolean {
511                        if (locking) {
512                                _unlockAndLoad = true;
513                                return false;
514                        }
515                       
516                        if (_model.state != ModelStates.IDLE) {
517                                _model.media.stop();
518                        }
519                        if (item is PlaylistItem) {
520                                return loadPlaylistItem(item as PlaylistItem);
521                        } else if (item is String) {
522                                return loadString(item as String);
523                        } else if (item is Number) {
524                                return loadNumber(item as Number);
525                        } else if (item is Array) {
526                                return loadArray(item as Array);
527                        } else if (item is Object) {
528                                return loadObject(item as Object);
529                        }
530                        return false;
531                }
532
533
534                protected function loadPlaylistItem(item:PlaylistItem):Boolean {
535                        if (locking) {
536                                _lockingResume = true;
537                                return false;
538                        }
539
540                        if (!_model.playlist.contains(item)) {
541                                _model.playlist.load(item);
542                                return false;
543                        }
544                       
545                        try {
546                                if (!item.streamer && _model.config.streamer) { item.streamer = _model.config.streamer; }
547                                if (!item.provider) { item.provider = JWParser.getProvider(item); }
548                               
549                                if (!setProvider(item) && item.file) {
550                                        _model.playlist.load(item.file);
551                                } else if(_mediaLoader) {
552                                        _model.setActiveMediaProvider('default');
553                                        dispatchEvent(new PlayerStateEvent(PlayerStateEvent.JWPLAYER_PLAYER_STATE, PlayerState.BUFFERING, PlayerState.IDLE));
554                                }
555                        } catch (err:Error) {
556                                Logger.log(err.message, "ERROR");
557                                return false;
558                        }
559                        Logger.log("Loading PlaylistItem: " + item.toString(), "LOAD");
560                        return true;
561                }
562
563
564                protected function loadString(item:String):Boolean {
565                        _model.playlist.load(new PlaylistItem({file: item}));
566                        return true;
567                }
568
569
570                protected function loadArray(item:Array):Boolean {
571                        if (item.length > 0) {
572                                _model.playlist.load(item);
573                                return true;
574                        }
575                        return false;
576                }
577
578                protected function loadNumber(item:Number):Boolean {
579                        if (item >= 0 && item < _model.playlist.length) {
580                                _model.playlist.currentIndex = item;
581                                return loadPlaylistItem(_model.playlist.currentItem);
582                        }
583                        return false;
584                }
585
586
587                protected function loadObject(item:Object):Boolean {
588                        if (item.hasOwnProperty('file') || item.hasOwnProperty('levels')) {
589                                _model.playlist.load(new PlaylistItem(item));
590                                return true;
591                        }
592                        return false;
593                }
594
595
596                protected function setProvider(item:PlaylistItem):Boolean {
597                        var provider:String = item.provider;
598
599                        if (provider) {
600
601                                // Backwards compatibility for CDNs in the 'type' flashvar.
602                                if (cdns.hasOwnProperty(provider)) {
603                                        _model.config.setConfig(cdns[provider]);
604                                        provider = cdns[provider]['provider'];
605                                }
606
607                                // If the model doesn't have an instance of the provider, load & instantiate it
608                                if (!_model.hasMediaProvider(provider)) {
609                                        _mediaLoader = new MediaProviderLoader();
610                                        _mediaLoader.addEventListener(Event.COMPLETE, mediaSourceLoaded);
611                                        _mediaLoader.addEventListener(ErrorEvent.ERROR, errorHandler);
612                                        _mediaLoader.loadSource(provider);
613                                        return true;
614                                }
615
616                                _model.setActiveMediaProvider(provider);
617                                return true;
618                        }
619
620                        return false;
621                }
622
623
624                protected function mediaSourceLoaded(evt:Event):void {
625                        var loader:MediaProviderLoader = _mediaLoader;
626                        _mediaLoader = null;
627                        if (_delayedItem) {
628                                _model.setMediaProvider(_delayedItem.provider, loader.loadedSource);
629                                _model.setActiveMediaProvider(_delayedItem.provider);
630                                _delayedItem = null;
631                                play();
632                        } else {
633                                _model.setMediaProvider(_model.playlist.currentItem.provider, loader.loadedSource);
634                                _model.setActiveMediaProvider(_model.playlist.currentItem.provider);
635                        }
636                }
637
638
639                private function bufferFullHandler(evt:MediaEvent):void {
640                        if (!locking) {
641                                if (_queuedSeek >= 0) {
642                                        _model.media.seek(_queuedSeek);
643                                        _queuedSeek = -1;
644                                } else {
645                                        _model.media.play();
646                                }
647                        } else {
648                                _lockingResume = true;
649                        }
650                }
651
652
653                public function redraw():Boolean {
654                        if (locking) {
655                                return false;
656                        }
657                        _view.redraw();
658                        return true;
659                }
660
661
662                public function fullscreen(mode:Boolean):Boolean {
663                        _view.fullscreen(mode);
664                        _model.fullscreen = mode;
665                        dispatchEvent(new PlayerEvent(PlayerEvent.JWPLAYER_FULLSCREEN, mode.toString()));
666                        return true;
667                }
668
669
670                protected function setCookie(name:String, value:*):void {
671                        Configger.saveCookie(name, value);
672                }
673
674        }
675}
Note: See TracBrowser for help on using the repository browser.