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

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