FLAudio.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. define("dojox/av/FLAudio", ['dojo', 'dojox/embed/Flash', 'dojox/timing/doLater'],function(dojo, dijit){
  2. dojo.experimental("dojox.av.FLVideo");
  3. dojo.declare("dojox.av.FLAudio", null, {
  4. // summary:
  5. // Play MP3 files through the Flash SWF built in the
  6. // DEFT project.
  7. // description:
  8. // This class is brand new, so there is a lot of
  9. // functionality not yet available. The initial
  10. // purpose is for playing "event" sounds like button
  11. // clicks, and for loading and controlling multiple
  12. // sounds at once. As of yet, streaming is not supported
  13. // and polling the sounds for events during playback
  14. // may still be missing information. Markup is not
  15. // supported, as it may not be needed.
  16. //
  17. // TODO:
  18. // Streaming, playback events, crossdomain, CDN support,
  19. // (alternate SWF location), global volume, ID3 tag,
  20. // factor out doLater, onLoadStatus needs work,
  21. // play(position) / seek()
  22. //
  23. // example:
  24. // | new dojox.av.FLAudio({
  25. // | initialVolume:.7,
  26. // | initialPan:0,
  27. // | autoPlay:false
  28. // | });
  29. //
  30. // id: String?
  31. // The id of this widget and the id of the SWF movie.
  32. id:"",
  33. //
  34. // initialVolume: Number
  35. // From 0-1
  36. // Sets volume for all files unless changed with doPlay
  37. // or setVolume
  38. initialVolume: 0.7,
  39. //
  40. // initialPan: Number
  41. // From -1 to 1 (-1 is left, 1 is right, 0 is middle)
  42. // Sets pan for all files unless changed with play
  43. // or setPan
  44. initialPan: 0,
  45. //
  46. // autoPlay: Boolean
  47. // If true, all files will play upon load. If false,
  48. // they load and wait for doPlay() command.
  49. //
  50. // isDebug: Boolean?
  51. // Setting to true tells the SWF to output log messages to Firebug.
  52. isDebug: false,
  53. //
  54. // statusInterval: Number
  55. // How often in milliseconds that the status of the
  56. // player is checked - both load and play
  57. statusInterval:200,
  58. //
  59. // _swfPath: Uri
  60. // The path to the video player SWF resource
  61. _swfPath: dojo.moduleUrl("dojox.av", "resources/audio.swf"),
  62. //
  63. //
  64. // allowScriptAccess: String
  65. // Whether the SWF can access the container JS
  66. allowScriptAccess:"always",
  67. //
  68. // allowNetworking: String
  69. // Whether SWF is restricted to a domain
  70. allowNetworking: "all",
  71. //
  72. constructor: function(/*Object*/options){
  73. // Provide this function for the SWF to ensure that the it is playing
  74. // in HTML.
  75. dojo.global.swfIsInHTML = function(){ return true; }
  76. dojo.mixin(this, options || {});
  77. if(!this.id){ this.id = "flaudio_"+new Date().getTime(); }
  78. this.domNode = dojo.doc.createElement("div");
  79. dojo.style(this.domNode, {
  80. position:"relative",
  81. width:"1px",
  82. height:"1px",
  83. top:"1px",
  84. left:"1px"
  85. });
  86. dojo.body().appendChild(this.domNode);
  87. this.init();
  88. },
  89. init: function(){
  90. // summary:
  91. // Initialize the media.
  92. //
  93. //
  94. this._subs = [];
  95. this.initialVolume = this._normalizeVolume(this.initialVolume);
  96. var args = {
  97. path:this._swfPath.uri,
  98. width:"1px",
  99. height:"1px",
  100. minimumVersion:9, // this may need to be 10, not sure
  101. expressInstall:true,
  102. params:{
  103. wmode:"transparent",
  104. allowScriptAccess:this.allowScriptAccess,
  105. allowNetworking:this.allowNetworking
  106. },
  107. // only pass in simple variables - no deep objects
  108. vars:{
  109. id:this.id,
  110. autoPlay:this.autoPlay,
  111. initialVolume:this.initialVolume,
  112. initialPan:this.initialPan,
  113. statusInterval:this.statusInterval,
  114. isDebug:this.isDebug
  115. }
  116. };
  117. this._sub("mediaError", "onError");
  118. this._sub("filesProgress", "onLoadStatus");
  119. this._sub("filesAllLoaded", "onAllLoaded");
  120. this._sub("mediaPosition", "onPlayStatus");
  121. this._sub("mediaEnd", "onComplete");
  122. this._sub("mediaMeta", "onID3");
  123. this._flashObject = new dojox.embed.Flash(args, this.domNode);
  124. this._flashObject.onError = function(err){
  125. console.warn("Flash Error:", err);
  126. };
  127. this._flashObject.onLoad = dojo.hitch(this, function(mov){
  128. this.flashMedia = mov;
  129. this.isPlaying = this.autoPlay;
  130. this.isStopped = !this.autoPlay;
  131. this.onLoad(this.flashMedia);
  132. });
  133. },
  134. // ============== //
  135. // Loading Files //
  136. // ============== //
  137. load: function(/*Object*/options){
  138. // summary:
  139. // Adds a media object to the playlist
  140. // ***This can be called repeatedly to add multiple items.
  141. // options: Object
  142. // url: String
  143. // (required) path to MP3 media
  144. // url must be absolute or relative to SWF,
  145. // not dojo or the html. An effort will be made
  146. // to fix incorrect paths.
  147. // id: String
  148. // (optional) an identifier to later determine
  149. // which media to control.
  150. // returns:
  151. // The normalized url, which can be used to identify the
  152. // audio.
  153. //
  154. if(dojox.timing.doLater(this.flashMedia, this)){ return false; }
  155. if(!options.url){
  156. throw new Error("An url is required for loading media");
  157. return false;
  158. }else{
  159. options.url = this._normalizeUrl(options.url);
  160. }
  161. this.flashMedia.load(options);
  162. return options.url; // String
  163. },
  164. // ============================= //
  165. // Methods to control the sound //
  166. // ============================= //
  167. doPlay: function(/*Object*/options){
  168. // summary:
  169. // Tell media to play, based on
  170. // the options passed.
  171. // options: Object
  172. // volume: Number
  173. // Sets the volume
  174. // pan: Number
  175. // Sets left/right pan
  176. // index:Number OR id:String OR url:String
  177. // Choose one of the above to indentify
  178. // the media you wish to control. id is
  179. // set by you. index is the order in which
  180. // media was added (zero based)
  181. // NOTE: lack of an identifier will default
  182. // to first (or only) item.
  183. // NOTE: Can't name this method "play()" as it causes
  184. // an IE error.
  185. this.flashMedia.doPlay(options);
  186. },
  187. pause: function(/*Object*/options){
  188. // summary:
  189. // Tell media to pause, based on identifier in
  190. // the options passed.
  191. // options: Object
  192. // index:Number OR id:String OR url:String
  193. // See doPlay()
  194. //
  195. this.flashMedia.pause(options);
  196. },
  197. stop: function(/*Object*/options){
  198. // summary:
  199. // Tell media to stop, based on identifier in
  200. // the options passed.
  201. // options:
  202. // index:Number OR id:String OR url:String
  203. // See doPlay()
  204. //
  205. this.flashMedia.doStop(options);
  206. },
  207. setVolume: function(/*Object*/options){
  208. // summary:
  209. // Set media volume, based on identifier in
  210. // the options passed.
  211. // options:
  212. // volume: Number
  213. // 0 to 1
  214. // index:Number OR id:String OR url:String
  215. // See doPlay()
  216. //
  217. this.flashMedia.setVolume(options);
  218. },
  219. setPan: function(/*Object*/options){
  220. // summary:
  221. // Set media pan, based on identifier in
  222. // the options passed.
  223. // options:
  224. // pan:Number
  225. // -1 to 1
  226. // index:Number OR id:String OR url:String
  227. // See doPlay()
  228. //
  229. this.flashMedia.setPan(options);
  230. },
  231. getVolume: function(/*Object*/options){
  232. // summary:
  233. // Get media volume, based on identifier in
  234. // the options passed.
  235. // options:
  236. // index:Number OR id:String OR url:String
  237. // See doPlay()
  238. //
  239. return this.flashMedia.getVolume(options);
  240. },
  241. getPan: function(/*Object*/options){
  242. // summary:
  243. // Set media pan, based on identifier in
  244. // the options passed.
  245. // options:
  246. // index:Number OR id:String OR url:String
  247. // See doPlay()
  248. //
  249. return this.flashMedia.getPan(options);
  250. },
  251. getPosition: function(/*Object*/options){
  252. // summary:
  253. // Get the current time.
  254. // options:
  255. // index:Number OR id:String OR url:String
  256. // See doPlay()
  257. //
  258. return this.flashMedia.getPosition(options);
  259. },
  260. // ============= //
  261. // Sound Events //
  262. // ============= //
  263. onError: function(msg){
  264. // summary:
  265. // stub fired when an error occurs
  266. console.warn("SWF ERROR:", msg)
  267. },
  268. onLoadStatus: function(/*Array*/events){
  269. // summary:
  270. },
  271. onAllLoaded: function(){
  272. // summary:
  273. // stub fired
  274. },
  275. onPlayStatus: function(/*Array*/events){
  276. // summary:
  277. },
  278. onComplete: function(/*Array*/events){
  279. // summary:
  280. // Fired at the end of a media file.
  281. },
  282. onLoad: function(){
  283. // summary:
  284. // stub fired when SWF is ready
  285. },
  286. onID3: function(evt){
  287. // summary:
  288. // Fired when the ID3 data is received.
  289. },
  290. destroy: function(){
  291. // summary:
  292. // destroys flash
  293. if(!this.flashMedia){
  294. this._cons.push(dojo.connect(this, "onLoad", this, "destroy"));
  295. return;
  296. }
  297. dojo.forEach(this._subs, function(s){
  298. dojo.unsubscribe(s);
  299. });
  300. dojo.forEach(this._cons, function(c){
  301. dojo.disconnect(c);
  302. });
  303. this._flashObject.destroy();
  304. //dojo._destroyElement(this.flashDiv);
  305. },
  306. _sub: function(topic, method){
  307. // summary:
  308. // helper for subscribing to topics
  309. dojo.subscribe(this.id+"/"+topic, this, method);
  310. },
  311. _normalizeVolume: function(vol){
  312. // summary:
  313. // Ensures volume is less than one
  314. //
  315. if(vol>1){
  316. while(vol>1){
  317. vol*=.1
  318. }
  319. }
  320. return vol;
  321. },
  322. _normalizeUrl: function(_url){
  323. // summary:
  324. // Checks that path is relative to HTML file or
  325. // convertes it to an absolute path.
  326. //
  327. if(_url && _url.toLowerCase().indexOf("http")<0){
  328. //
  329. // Appears to be a relative path. Attempt to convert it to absolute,
  330. // so it will better target the SWF.
  331. var loc = window.location.href.split("/");
  332. loc.pop();
  333. loc = loc.join("/")+"/";
  334. _url = loc+_url;
  335. }
  336. return _url;
  337. }
  338. });
  339. return dojox.av.FLAudio;
  340. });