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

Revision 628, 15.4 KB checked in by pablo, 4 years ago (diff)
  • Playlist ITEM timing issues
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                                        dispatchEvent(new PlaylistEvent(PlaylistEvent.JWPLAYER_PLAYLIST_LOADED, _model.playlist));
152                                }
153
154                                RootReference.stage.dispatchEvent(new Event(Event.RESIZE));
155
156                                if (_player.config.autostart) {
157                                        load(_model.playlist.currentItem);
158                                }
159                        }
160                }
161
162
163                private function playlistLoadHandler(evt:PlaylistEvent=null):void {
164                        dispatchEvent(new PlaylistEvent(PlaylistEvent.JWPLAYER_PLAYLIST_LOADED, _model.playlist));
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                                _player.playlist.currentIndex = 0;
374                        } else {
375                                _player.playlist.currentIndex = _player.playlist.currentIndex + 1;
376                        }
377                        loadPlaylistItem(_player.playlist.currentItem);
378                        return true;
379                }
380
381
382                public function previous():Boolean {
383                        if (locking) {
384                                return false;
385                        }
386                        if (_model.playlist.currentIndex <= 0) {
387                                _model.playlist.currentIndex = _model.playlist.length - 1;
388                        } else {
389                                _player.playlist.currentIndex = _player.playlist.currentIndex - 1;
390                        }
391                        loadPlaylistItem(_player.playlist.currentItem);
392                        return true;
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                        if (!_model.playlist.contains(item)) {
453                                _model.playlist.load(item);
454                        }
455                        dispatchEvent(new PlaylistEvent(PlaylistEvent.JWPLAYER_PLAYLIST_ITEM, _model.playlist));
456                        var result:Boolean = false;
457                        try {
458                                if (!item.provider) {
459                                        JWParser.updateProvider(item);
460                                }
461
462                                if (setProvider(item)) {
463                                        _model.media.addEventListener(MediaEvent.JWPLAYER_MEDIA_BUFFER_FULL, lockHandler);
464                                        _model.media.load(item);
465                                        result = true;
466                                } else if (item.file) {
467                                        _model.playlist.load(item.file)
468                                }
469                        } catch (err:Error) {
470                                result = false;
471                        }
472                        return result;
473                }
474
475
476                private function loadString(item:String):Boolean {
477                        if (Strings.extension(item) == "xml") {
478                                _model.playlist.load(item);
479                                return true;
480                        } else {
481                                return loadPlaylistItem(new PlaylistItem({file: item}));
482                        }
483                        return false;
484                }
485
486
487                private function loadNumber(item:Number):Boolean {
488                        if (item >= 0 && item < _model.playlist.length) {
489                                return loadPlaylistItem(_model.playlist.getItemAt(item));
490                        }
491                        return false;
492                }
493
494
495                private function loadObject(item:Object):Boolean {
496                        if ((item as Object).hasOwnProperty('file')) {
497                                return loadPlaylistItem(new PlaylistItem(item));
498                        }
499                        return false;
500                }
501
502
503                private function setProvider(item:PlaylistItem):Boolean {
504                        var provider:String = item.provider;
505                        if (provider) {
506
507                                // Backwards compatibility for CDNs in the 'type' flashvar.
508                                if (cdns.hasOwnProperty(provider)) {
509                                        _model.config.setConfig(cdns[provider]);
510                                        provider = cdns[provider]['provider'];
511                                }
512
513                                // If the model doesn't have an instance of the provider, load & instantiate it
514                                if (!_model.hasMediaProvider(provider)) {
515                                        _delayedItem = item;
516
517                                        var mediaLoader:MediaProviderLoader = new MediaProviderLoader();
518                                        mediaLoader.addEventListener(Event.COMPLETE, mediaSourceLoaded);
519                                        mediaLoader.addEventListener(ErrorEvent.ERROR, errorHandler);
520                                        mediaLoader.loadSource(provider);
521                                        return false;
522                                }
523
524                                _model.setActiveMediaProvider(provider);
525                                return true;
526                        }
527
528                        return false;
529                }
530
531
532                private function mediaSourceLoaded(evt:Event):void {
533                        var loader:MediaProviderLoader = evt.target as MediaProviderLoader;
534                        var item:PlaylistItem = _delayedItem;
535                        _delayedItem = null;
536                        _model.setMediaProvider(item.provider, loader.loadedSource);
537                        load(item);
538                }
539
540
541                private function lockHandler(evt:MediaEvent):void {
542                        _model.media.play();
543                }
544
545
546                public function redraw():Boolean {
547                        if (locking) {
548                                return false;
549                        }
550                        _view.redraw();
551                        return true;
552                }
553
554
555                public function fullscreen(mode:Boolean):Boolean {
556                        _model.fullscreen = mode;
557                        _view.fullscreen(mode);
558                        return true;
559                }
560
561
562                public function link(playlistIndex:Number=NaN):Boolean {
563                        if (locking) {
564                                return false;
565                        }
566                        if (isNaN(playlistIndex))
567                                playlistIndex = _model.playlist.currentIndex;
568
569                        if (playlistIndex >= 0 && playlistIndex < _model.playlist.length) {
570                                navigateToURL(new URLRequest(_model.playlist.getItemAt(playlistIndex).link), _model.config.linktarget);
571                                return true;
572                        }
573
574                        return false;
575                }
576
577
578                private function setCookie(name:String, value:*):void {
579                        Configger.saveCookie(name, value);
580                }
581
582        }
583}
Note: See TracBrowser for help on using the repository browser.