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

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