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

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