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

Revision 662, 16.2 KB checked in by pablo, 3 years ago (diff)

Removed conditional compiling flag
Made some player classes subclassable

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