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

Revision 779, 16.0 KB checked in by pablo, 3 years ago (diff)

SoundMediaProvider shouldn't send out buffer_complete unless it's in the buffering state.

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