source: trunk/as3/com/jeroenwijering/plugins/Accessibility.as @ 88

Revision 88, 5.8 KB checked in by jeroen, 5 years ago (diff)

merged 4.2 player to trunk

Line 
1/**
2* Plugin for synchronized closed captions and audiodescription.
3*
4* @todo         Hook up controlbar buttons.
5**/
6package com.jeroenwijering.plugins {
7
8
9import com.jeroenwijering.events.*;
10import com.jeroenwijering.parsers.SRTParser;
11import com.jeroenwijering.parsers.TTParser;
12import flash.display.MovieClip;
13import flash.events.Event;
14import flash.events.MouseEvent;
15import flash.external.ExternalInterface;
16import flash.media.*;
17import flash.net.URLLoader;
18import flash.net.URLRequest;
19import flash.text.*;
20
21
22public class Accessibility extends MovieClip implements PluginInterface {
23
24
25
26        /** List with configuration settings. **/
27        private var config:Object = {
28                audio:undefined,
29                captions:undefined,
30                fontsize:13,
31                hide:false,
32                listener:undefined,
33                mute:false,
34                volume:50
35        }
36        /** Reference to the MVC view. **/
37        private var view:AbstractView;
38        /** XML connect and parse object. **/
39        private var loader:URLLoader;
40        /** The array the captions are loaded into. **/
41        private var captions:Array;
42        /** Textformat entry for the captions. **/
43        private var format:TextFormat;
44        /** Displayelement to load the captions into. **/
45        private var clip:MovieClip;
46        /** Currently active caption. **/
47        private var current:Number;
48        /** sound object to be instantiated. **/
49        private var sound:Sound;
50        /** Sound channel object. **/
51        private var channel:SoundChannel;
52
53
54
55        public function Accessibility():void {
56                loader = new URLLoader();
57                loader.addEventListener(Event.COMPLETE,loaderHandler);
58        };
59
60
61        /** Show/hide the captions **/
62        private function hideCaptions(stt:Boolean) {
63                config['hide'] = !stt;
64                clip.visible = config['hide'];
65        };
66
67
68        /** Initing the plugin. **/
69        public function initializePlugin(vie:AbstractView):void {
70                view = vie;
71                if(view.skin['accessibility']) {
72                        clip =  view.skin['accessibility'];
73                } else {
74                        clip = this['accessibility'];
75                }
76                loadVars();
77                view.addControllerListener(ControllerEvent.ITEM,itemHandler);
78                view.addControllerListener(ControllerEvent.RESIZE,resizeHandler);
79                view.addModelListener(ModelEvent.TIME,timeHandler);
80                view.addModelListener(ModelEvent.STATE,stateHandler);
81                if(ExternalInterface.available && view.skin.loaderInfo.url.indexOf('http') == 0) {
82                        try {
83                                ExternalInterface.addCallback("hideCaptions",hideCaptions);
84                                ExternalInterface.addCallback("muteAudio",muteAudio);
85                        } catch (err:Error) {}
86                }
87                clip.tf.autoSize = TextFieldAutoSize.CENTER;
88                format = new TextFormat(null,config['fontsize']);
89                hideCaptions(config['hide'])
90                muteAudio(config['mute']);
91        };
92
93
94        /** Check for captions with a new item. **/
95        private function itemHandler(evt:ControllerEvent=null):void {
96                setCaption(-1);
97                captions = new Array();
98                var cap:String = view.playlist[view.config['item']]['captions'];
99                if(cap) { config['captions'] = cap; }
100                if(config['captions']) {
101                        try {
102                                loader.load(new URLRequest(config['captions']));
103                        } catch (err:Error) {
104                                view.sendEvent('ERROR','Captions: '+err.message);
105                        }
106                }
107                var aud:String = view.playlist[view.config['item']]['audio'];
108                if(aud) { config['audio'] = aud; }
109                if(config['audio']) { setAudio(); }
110        };
111
112
113        /** Captions are loaded; now display them. **/
114        private function loaderHandler(evt:Event):void {
115                if(config['captions'].substr(-3) == 'srt') {
116                        captions = SRTParser.parseCaptions(String(evt.target.data));
117                } else {
118                        captions = TTParser.parseCaptions(XML(evt.target.data));
119                }
120                if(captions.length == 0) {
121                        view.sendEvent('TRACE','Acessibility: Captions are not a valid TimedText or SRT file.');
122                }
123        };
124
125
126
127        /** Load variables from the main config. **/
128        private function loadVars() {
129                config['audio'] = view.config['audio'];
130                config['captions'] = view.config['captions'];
131                for(var str:String in config) {
132                        if(view.config['accessibility.'+str]) {
133                                config[str] = view.config['accessibility.'+str];
134                        }
135                }
136        }
137
138
139        /** Mute/unmute the audiodesc. **/
140        private function muteAudio(stt:Boolean) {
141                config['mute'] = stt;
142                setVolume();
143        };
144
145
146        /** Resize the captions if the display changes. **/
147        private function resizeHandler(evt:ControllerEvent=undefined):void {
148                clip.width = view.config['width'];
149                clip.scaleY = clip.scaleX;
150                clip.y = view.config['height']-clip.height-config['fontsize']*clip.scaleX;
151        };
152
153
154        /** Set the audidescription volume level. **/
155        public function setAudio():void {
156                sound = new Sound(new URLRequest(config['audio']));
157                channel = sound.play();
158                setVolume();
159        };
160
161
162        /** Set a caption on screen. **/
163        private function setCaption(idx:Number):void {
164                var txt:String = '';
165                if(idx > -1) { txt = captions[idx]['text']; }
166                current = idx;
167                clip.tf.htmlText = txt;
168                clip.tf.setTextFormat(format);
169                view.sendEvent('TRACE','caption: '+txt);
170                resizeHandler();
171                if(config['listener']) {
172                        try {
173                                ExternalInterface.call(config['listener'],txt);
174                        } catch(err:Error) {}
175                }
176        };
177
178
179        /** Set the volume level. **/
180        private function setVolume():void {
181                var trf:SoundTransform = new SoundTransform(config['volume']/100);
182                if(config['mute']) { trf.volume = 0; }
183                if(channel) { channel.soundTransform = trf; }
184        };
185
186
187        /** The statehandler manages audio pauses. **/
188        private function stateHandler(evt:ModelEvent) {
189                switch(evt.data.newstate) {
190                        case ModelStates.PAUSED:
191                        case ModelStates.COMPLETED:
192                        case ModelStates.IDLE:
193                                if(channel) {
194                                        channel.stop();
195                                }
196                                break;
197                        }
198        };
199
200
201        /** Check timing of the player to sync captions. **/
202        private function timeHandler(evt:ModelEvent):void {
203                var cur:Number = -1;
204                var pos:Number = evt.data.position;
205                // sync up the captions (only if needed).
206                for(var i:Number=0; i<captions.length; i++) {
207                        if(captions[i]['begin'] < pos && captions[i]['end'] > pos) {
208                                cur = i;
209                                break;
210                        }
211                }
212                if(cur != current) { setCaption(cur); }
213                // and sync up the audio (only if needed).
214                if(channel && view.config['state'] == ModelStates.PLAYING &&
215                        Math.abs(pos-channel.position/1000) > 1) {
216                        channel.stop();
217                        channel = sound.play(pos*1000);
218                        setVolume();
219                }
220        };
221
222
223};
224
225
226}
Note: See TracBrowser for help on using the repository browser.