| 1 | /** |
|---|
| 2 | * Wraps all media APIs (all models) and manages thumbnail display. |
|---|
| 3 | **/ |
|---|
| 4 | package com.jeroenwijering.player { |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | import com.jeroenwijering.events.*; |
|---|
| 8 | import com.jeroenwijering.models.BasicModel; |
|---|
| 9 | import com.jeroenwijering.player.*; |
|---|
| 10 | import com.jeroenwijering.utils.*; |
|---|
| 11 | |
|---|
| 12 | import flash.display.*; |
|---|
| 13 | import flash.events.*; |
|---|
| 14 | import flash.net.URLRequest; |
|---|
| 15 | import flash.system.LoaderContext; |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | public class Model extends EventDispatcher { |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | /** Object with all configuration variables. **/ |
|---|
| 22 | public var config:Object; |
|---|
| 23 | /** Reference to the skin MovieClip. **/ |
|---|
| 24 | public var skin:MovieClip; |
|---|
| 25 | /** Object with all display variables. **/ |
|---|
| 26 | private var sploader:SPLoader; |
|---|
| 27 | /** Reference to the player's controller. **/ |
|---|
| 28 | private var controller:Controller; |
|---|
| 29 | /** The list with all active models. **/ |
|---|
| 30 | private var models:Object; |
|---|
| 31 | /** Loader for the preview image. **/ |
|---|
| 32 | private var thumb:Loader; |
|---|
| 33 | /** Save the currently playing playlist item. **/ |
|---|
| 34 | private var item:Object; |
|---|
| 35 | /** Save the current image url to prevent duplicate loading. **/ |
|---|
| 36 | private var image:String; |
|---|
| 37 | |
|---|
| 38 | |
|---|
| 39 | /** Constructor, save references, setup listeners and init thumbloader. **/ |
|---|
| 40 | public function Model(cfg:Object,skn:MovieClip,ldr:SPLoader,ctr:Controller):void { |
|---|
| 41 | config = cfg; |
|---|
| 42 | skin = skn; |
|---|
| 43 | sploader = ldr; |
|---|
| 44 | controller = ctr; |
|---|
| 45 | controller.addEventListener(ControllerEvent.ITEM,itemHandler); |
|---|
| 46 | controller.addEventListener(ControllerEvent.MUTE,muteHandler); |
|---|
| 47 | controller.addEventListener(ControllerEvent.PLAY,playHandler); |
|---|
| 48 | controller.addEventListener(ControllerEvent.PLAYLIST,playlistHandler); |
|---|
| 49 | controller.addEventListener(ControllerEvent.RESIZE,resizeHandler); |
|---|
| 50 | controller.addEventListener(ControllerEvent.SEEK,seekHandler); |
|---|
| 51 | controller.addEventListener(ControllerEvent.STOP,stopHandler); |
|---|
| 52 | controller.addEventListener(ControllerEvent.VOLUME,volumeHandler); |
|---|
| 53 | thumb = new Loader(); |
|---|
| 54 | thumb.contentLoaderInfo.addEventListener(Event.COMPLETE,thumbHandler); |
|---|
| 55 | Draw.clear(skin.display.media); |
|---|
| 56 | skin.display.addChildAt(thumb,skin.display.getChildIndex(skin.display.media)+1); |
|---|
| 57 | skin.display.media.visible = false; |
|---|
| 58 | models = new Object(); |
|---|
| 59 | }; |
|---|
| 60 | |
|---|
| 61 | |
|---|
| 62 | /** Item change: stop the old model and start the new one. **/ |
|---|
| 63 | private function itemHandler(evt:ControllerEvent):void { |
|---|
| 64 | if(item) { |
|---|
| 65 | models[item['type']].stop(); |
|---|
| 66 | } |
|---|
| 67 | item = controller.playlist[config['item']]; |
|---|
| 68 | if(models[item['type']]) { |
|---|
| 69 | models[item['type']].load(item); |
|---|
| 70 | } else { |
|---|
| 71 | sendEvent(ModelEvent.ERROR,{message:'No suiteable model found for playback of this file.'}); |
|---|
| 72 | } |
|---|
| 73 | if(item['image'] && item['image'] != image) { |
|---|
| 74 | image = item['image']; |
|---|
| 75 | thumb.load(new URLRequest(item['image']),new LoaderContext(true)); |
|---|
| 76 | } |
|---|
| 77 | }; |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | /** Load a new playback model. **/ |
|---|
| 81 | public function loadModel(mdl:BasicModel,typ:String):void { |
|---|
| 82 | models[typ] = mdl; |
|---|
| 83 | }; |
|---|
| 84 | |
|---|
| 85 | |
|---|
| 86 | /** |
|---|
| 87 | * Place the mediafile fro the current model on stage. |
|---|
| 88 | * |
|---|
| 89 | * @param obj The displayobject (MovieClip/Video/Loader) to display. |
|---|
| 90 | **/ |
|---|
| 91 | public function mediaHandler(obj:DisplayObject=undefined):void { |
|---|
| 92 | Draw.clear(skin.display.media); |
|---|
| 93 | skin.display.media.addChild(obj); |
|---|
| 94 | resizeHandler(); |
|---|
| 95 | }; |
|---|
| 96 | |
|---|
| 97 | |
|---|
| 98 | /** Make the current model toggle its mute state. **/ |
|---|
| 99 | private function muteHandler(evt:ControllerEvent):void { |
|---|
| 100 | if(item) { |
|---|
| 101 | if(evt.data.state == true) { |
|---|
| 102 | models[item['type']].volume(0); |
|---|
| 103 | } else { |
|---|
| 104 | models[item['type']].volume(config['volume']); |
|---|
| 105 | } |
|---|
| 106 | } |
|---|
| 107 | }; |
|---|
| 108 | |
|---|
| 109 | |
|---|
| 110 | /** Make the current model play or pause. **/ |
|---|
| 111 | private function playHandler(evt:ControllerEvent):void { |
|---|
| 112 | if(item) { |
|---|
| 113 | if(evt.data.state == true) { |
|---|
| 114 | models[item['type']].play(); |
|---|
| 115 | } else { |
|---|
| 116 | models[item['type']].pause(); |
|---|
| 117 | } |
|---|
| 118 | } |
|---|
| 119 | }; |
|---|
| 120 | |
|---|
| 121 | |
|---|
| 122 | /** Load a new thumbnail. **/ |
|---|
| 123 | private function playlistHandler(evt:ControllerEvent):void { |
|---|
| 124 | var img:String = controller.playlist[config['item']]['image']; |
|---|
| 125 | if(img && img != image) { |
|---|
| 126 | image = img; |
|---|
| 127 | thumb.load(new URLRequest(img),new LoaderContext(true)); |
|---|
| 128 | } |
|---|
| 129 | }; |
|---|
| 130 | |
|---|
| 131 | |
|---|
| 132 | /** Resize the media and thumb. **/ |
|---|
| 133 | private function resizeHandler(evt:Event=null):void { |
|---|
| 134 | var cfg:Object = sploader.getPluginConfig(sploader.getPlugin('display')); |
|---|
| 135 | Stretcher.stretch(skin.display.media,cfg['width'],cfg['height'],config['stretching']); |
|---|
| 136 | if(thumb.width > 10) { |
|---|
| 137 | Stretcher.stretch(thumb,cfg['width'],cfg['height'],config['stretching']); |
|---|
| 138 | } |
|---|
| 139 | }; |
|---|
| 140 | |
|---|
| 141 | |
|---|
| 142 | /** Make the current model seek. **/ |
|---|
| 143 | private function seekHandler(evt:ControllerEvent):void { |
|---|
| 144 | if(item) { |
|---|
| 145 | models[item['type']].seek(evt.data.position); |
|---|
| 146 | } |
|---|
| 147 | }; |
|---|
| 148 | |
|---|
| 149 | |
|---|
| 150 | /** Make the current model stop and show the thumb. **/ |
|---|
| 151 | private function stopHandler(evt:ControllerEvent=undefined):void { |
|---|
| 152 | image = undefined; |
|---|
| 153 | if(item) { |
|---|
| 154 | models[item['type']].stop(); |
|---|
| 155 | } |
|---|
| 156 | }; |
|---|
| 157 | |
|---|
| 158 | |
|---|
| 159 | /** |
|---|
| 160 | * Dispatch events to the View/ Controller. |
|---|
| 161 | * When switching states, the thumbnail is shown/hidden. |
|---|
| 162 | * |
|---|
| 163 | * @param typ The eventtype to dispatch. |
|---|
| 164 | * @param dat An object with data to send along. |
|---|
| 165 | * @see ModelEvent |
|---|
| 166 | **/ |
|---|
| 167 | public function sendEvent(typ:String,dat:Object):void { |
|---|
| 168 | switch(typ) { |
|---|
| 169 | case ModelEvent.STATE: |
|---|
| 170 | dat['oldstate'] = config['state']; |
|---|
| 171 | config['state'] = dat.newstate; |
|---|
| 172 | dispatchEvent(new ModelEvent(typ,dat)); |
|---|
| 173 | switch(dat['newstate']) { |
|---|
| 174 | case ModelStates.IDLE: |
|---|
| 175 | sendEvent(ModelEvent.LOADED,{loaded:0,offset:0,total:0}); |
|---|
| 176 | case ModelStates.COMPLETED: |
|---|
| 177 | thumb.visible = true; |
|---|
| 178 | skin.display.media.visible = false; |
|---|
| 179 | sendEvent(ModelEvent.TIME,{position:0,duration:item['duration']}); |
|---|
| 180 | break; |
|---|
| 181 | case ModelStates.PLAYING: |
|---|
| 182 | if(item['file'].indexOf('m4a') == -1 |
|---|
| 183 | && item['file'].indexOf('mp3') == -1 |
|---|
| 184 | && item['file'].indexOf('aac') == -1) { |
|---|
| 185 | thumb.visible = false; |
|---|
| 186 | skin.display.media.visible = true; |
|---|
| 187 | } else { |
|---|
| 188 | thumb.visible = true; |
|---|
| 189 | skin.display.media.visible = false; |
|---|
| 190 | } |
|---|
| 191 | break; |
|---|
| 192 | } |
|---|
| 193 | break; |
|---|
| 194 | case ModelEvent.META: |
|---|
| 195 | if(dat.width) { resizeHandler(); } |
|---|
| 196 | default: |
|---|
| 197 | dispatchEvent(new ModelEvent(typ,dat)); |
|---|
| 198 | break; |
|---|
| 199 | } |
|---|
| 200 | }; |
|---|
| 201 | |
|---|
| 202 | |
|---|
| 203 | /** Thumb loaded, try to antialias it before resizing. **/ |
|---|
| 204 | private function thumbHandler(evt:Event) { |
|---|
| 205 | try { |
|---|
| 206 | Bitmap(thumb.content).smoothing = true; |
|---|
| 207 | } catch (err:Error) {} |
|---|
| 208 | resizeHandler(); |
|---|
| 209 | }; |
|---|
| 210 | |
|---|
| 211 | |
|---|
| 212 | /** Make the current model change volume. **/ |
|---|
| 213 | private function volumeHandler(evt:ControllerEvent):void { |
|---|
| 214 | if(item) { |
|---|
| 215 | models[item['type']].volume(evt.data.percentage); |
|---|
| 216 | } |
|---|
| 217 | }; |
|---|
| 218 | |
|---|
| 219 | |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | |
|---|
| 223 | } |
|---|