Jplayer.as 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. * jPlayer Plugin for jQuery JavaScript Library
  3. * http://www.happyworm.com/jquery/jplayer
  4. *
  5. * Copyright (c) 2009 - 2011 Happyworm Ltd
  6. * Dual licensed under the MIT and GPL licenses.
  7. * - http://www.opensource.org/licenses/mit-license.php
  8. * - http://www.gnu.org/copyleft/gpl.html
  9. *
  10. * Author: Mark J Panaghiston
  11. * Version: 2.1.0
  12. * Date: 1st September 2011
  13. *
  14. * FlashVars expected: (AS3 property of: loaderInfo.parameters)
  15. * id: (URL Encoded: String) Id of jPlayer instance
  16. * vol: (Number) Sets the initial volume
  17. * muted: (Boolean in a String) Sets the initial muted state
  18. * jQuery: (URL Encoded: String) Sets the jQuery var name. Used with: someVar = jQuery.noConflict(true);
  19. *
  20. * Compiled using: Adobe Flex Compiler (mxmlc) Version 4.5.1 build 21328
  21. */
  22. package {
  23. import flash.system.Security;
  24. import flash.external.ExternalInterface;
  25. import flash.utils.Timer;
  26. import flash.events.TimerEvent;
  27. import flash.text.TextField;
  28. import flash.text.TextFormat;
  29. import flash.events.KeyboardEvent;
  30. import flash.display.Sprite;
  31. import happyworm.jPlayer.*;
  32. import flash.display.StageAlign;
  33. import flash.display.StageScaleMode;
  34. import flash.events.Event;
  35. import flash.events.MouseEvent;
  36. import flash.ui.ContextMenu;
  37. import flash.ui.ContextMenuItem;
  38. import flash.events.ContextMenuEvent;
  39. import flash.net.URLRequest;
  40. import flash.net.navigateToURL;
  41. public class Jplayer extends Sprite {
  42. private var jQuery:String;
  43. private var sentNumberFractionDigits:uint = 2;
  44. public var commonStatus:JplayerStatus = new JplayerStatus(); // Used for inital ready event so volume is correct.
  45. private var myInitTimer:Timer = new Timer(100, 0);
  46. private var myMp3Player:JplayerMp3;
  47. private var myMp4Player:JplayerMp4;
  48. private var isMp3:Boolean = false;
  49. private var isVideo:Boolean = false;
  50. private var txLog:TextField;
  51. private var debug:Boolean = false; // Set debug to false for release compile!
  52. public function Jplayer() {
  53. flash.system.Security.allowDomain("*");
  54. jQuery = loaderInfo.parameters.jQuery + "('#" + loaderInfo.parameters.id + "').jPlayer";
  55. commonStatus.volume = Number(loaderInfo.parameters.vol);
  56. commonStatus.muted = loaderInfo.parameters.muted == "true";
  57. stage.scaleMode = StageScaleMode.NO_SCALE;
  58. stage.align = StageAlign.TOP_LEFT;
  59. stage.addEventListener(Event.RESIZE, resizeHandler);
  60. stage.addEventListener(MouseEvent.CLICK, clickHandler);
  61. var initialVolume:Number = commonStatus.volume;
  62. if(commonStatus.muted) {
  63. initialVolume = 0;
  64. }
  65. myMp3Player = new JplayerMp3(initialVolume);
  66. addChild(myMp3Player);
  67. myMp4Player = new JplayerMp4(initialVolume);
  68. addChild(myMp4Player);
  69. setupListeners(!isMp3, isMp3); // Set up the listeners to the default isMp3 state.
  70. // The ContextMenu only partially works. The menu select events never occur.
  71. // Investigated and it is something to do with the way jPlayer inserts the Flash on the page.
  72. // A simple test inserting the Jplayer.swf on a page using: 1) SWFObject 2.2 works. 2) AC_FL_RunContent() works.
  73. // jPlayer Flash insertion is based on SWFObject 2.2 and the resaon behind this failure is not clear. The Flash insertion HTML on the page looks similar.
  74. var myContextMenu:ContextMenu = new ContextMenu();
  75. myContextMenu.hideBuiltInItems();
  76. var menuItem_jPlayer:ContextMenuItem = new ContextMenuItem("jPlayer " + JplayerStatus.VERSION);
  77. var menuItem_happyworm:ContextMenuItem = new ContextMenuItem("© 2009-2011 Happyworm Ltd", true);
  78. menuItem_jPlayer.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, menuSelectHandler_jPlayer);
  79. menuItem_happyworm.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, menuSelectHandler_happyworm);
  80. myContextMenu.customItems.push(menuItem_jPlayer, menuItem_happyworm);
  81. contextMenu = myContextMenu;
  82. // Log console for dev compile option: debug
  83. if(debug) {
  84. txLog = new TextField();
  85. txLog.x = 5;
  86. txLog.y = 5;
  87. txLog.width = 540;
  88. txLog.height = 390;
  89. txLog.border = true;
  90. txLog.background = true;
  91. txLog.backgroundColor = 0xEEEEFF;
  92. txLog.multiline = true;
  93. txLog.text = "jPlayer " + JplayerStatus.VERSION;
  94. txLog.visible = false;
  95. this.addChild(txLog);
  96. this.stage.addEventListener(KeyboardEvent.KEY_UP, keyboardHandler);
  97. myMp3Player.addEventListener(JplayerEvent.DEBUG_MSG, debugMsgHandler);
  98. myMp4Player.addEventListener(JplayerEvent.DEBUG_MSG, debugMsgHandler);
  99. }
  100. // Delay init() because Firefox 3.5.7+ developed a bug with local testing in Firebug.
  101. myInitTimer.addEventListener(TimerEvent.TIMER, init);
  102. myInitTimer.start();
  103. }
  104. private function init(e:TimerEvent):void {
  105. myInitTimer.stop();
  106. if(ExternalInterface.available) {
  107. ExternalInterface.addCallback("fl_setAudio_mp3", fl_setAudio_mp3);
  108. ExternalInterface.addCallback("fl_setAudio_m4a", fl_setAudio_m4a);
  109. ExternalInterface.addCallback("fl_setVideo_m4v", fl_setVideo_m4v);
  110. ExternalInterface.addCallback("fl_clearMedia", fl_clearMedia);
  111. ExternalInterface.addCallback("fl_load", fl_load);
  112. ExternalInterface.addCallback("fl_play", fl_play);
  113. ExternalInterface.addCallback("fl_pause", fl_pause);
  114. ExternalInterface.addCallback("fl_play_head", fl_play_head);
  115. ExternalInterface.addCallback("fl_volume", fl_volume);
  116. ExternalInterface.addCallback("fl_mute", fl_mute);
  117. ExternalInterface.call(jQuery, "jPlayerFlashEvent", JplayerEvent.JPLAYER_READY, extractStatusData(commonStatus)); // See JplayerStatus() class for version number.
  118. }
  119. }
  120. private function setupListeners(oldMP3:Boolean, newMP3:Boolean):void {
  121. if(oldMP3 != newMP3) {
  122. if(newMP3) {
  123. listenToMp3(true);
  124. listenToMp4(false);
  125. } else {
  126. listenToMp3(false);
  127. listenToMp4(true);
  128. }
  129. }
  130. }
  131. private function listenToMp3(active:Boolean):void {
  132. if(active) {
  133. myMp3Player.addEventListener(JplayerEvent.JPLAYER_ERROR, jPlayerFlashEvent);
  134. myMp3Player.addEventListener(JplayerEvent.JPLAYER_PROGRESS, jPlayerFlashEvent);
  135. myMp3Player.addEventListener(JplayerEvent.JPLAYER_TIMEUPDATE, jPlayerFlashEvent);
  136. myMp3Player.addEventListener(JplayerEvent.JPLAYER_ENDED, jPlayerFlashEvent);
  137. myMp3Player.addEventListener(JplayerEvent.JPLAYER_PLAY, jPlayerFlashEvent);
  138. myMp3Player.addEventListener(JplayerEvent.JPLAYER_PAUSE, jPlayerFlashEvent);
  139. myMp3Player.addEventListener(JplayerEvent.JPLAYER_LOADSTART, jPlayerFlashEvent);
  140. myMp3Player.addEventListener(JplayerEvent.JPLAYER_SEEKING, jPlayerFlashEvent);
  141. myMp3Player.addEventListener(JplayerEvent.JPLAYER_SEEKED, jPlayerFlashEvent);
  142. } else {
  143. myMp3Player.removeEventListener(JplayerEvent.JPLAYER_ERROR, jPlayerFlashEvent);
  144. myMp3Player.removeEventListener(JplayerEvent.JPLAYER_PROGRESS, jPlayerFlashEvent);
  145. myMp3Player.removeEventListener(JplayerEvent.JPLAYER_TIMEUPDATE, jPlayerFlashEvent);
  146. myMp3Player.removeEventListener(JplayerEvent.JPLAYER_ENDED, jPlayerFlashEvent);
  147. myMp3Player.removeEventListener(JplayerEvent.JPLAYER_PLAY, jPlayerFlashEvent);
  148. myMp3Player.removeEventListener(JplayerEvent.JPLAYER_PAUSE, jPlayerFlashEvent);
  149. myMp3Player.removeEventListener(JplayerEvent.JPLAYER_LOADSTART, jPlayerFlashEvent);
  150. myMp3Player.removeEventListener(JplayerEvent.JPLAYER_SEEKING, jPlayerFlashEvent);
  151. myMp3Player.removeEventListener(JplayerEvent.JPLAYER_SEEKED, jPlayerFlashEvent);
  152. }
  153. }
  154. private function listenToMp4(active:Boolean):void {
  155. if(active) {
  156. myMp4Player.addEventListener(JplayerEvent.JPLAYER_ERROR, jPlayerFlashEvent);
  157. myMp4Player.addEventListener(JplayerEvent.JPLAYER_PROGRESS, jPlayerFlashEvent);
  158. myMp4Player.addEventListener(JplayerEvent.JPLAYER_TIMEUPDATE, jPlayerFlashEvent);
  159. myMp4Player.addEventListener(JplayerEvent.JPLAYER_ENDED, jPlayerFlashEvent);
  160. myMp4Player.addEventListener(JplayerEvent.JPLAYER_PLAY, jPlayerFlashEvent);
  161. myMp4Player.addEventListener(JplayerEvent.JPLAYER_PAUSE, jPlayerFlashEvent);
  162. myMp4Player.addEventListener(JplayerEvent.JPLAYER_LOADSTART, jPlayerFlashEvent);
  163. myMp4Player.addEventListener(JplayerEvent.JPLAYER_SEEKING, jPlayerFlashEvent);
  164. myMp4Player.addEventListener(JplayerEvent.JPLAYER_SEEKED, jPlayerFlashEvent);
  165. myMp4Player.addEventListener(JplayerEvent.JPLAYER_LOADEDMETADATA, jPlayerMetaDataHandler); // Note the unique handler
  166. } else {
  167. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_ERROR, jPlayerFlashEvent);
  168. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_PROGRESS, jPlayerFlashEvent);
  169. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_TIMEUPDATE, jPlayerFlashEvent);
  170. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_ENDED, jPlayerFlashEvent);
  171. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_PLAY, jPlayerFlashEvent);
  172. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_PAUSE, jPlayerFlashEvent);
  173. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_LOADSTART, jPlayerFlashEvent);
  174. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_SEEKING, jPlayerFlashEvent);
  175. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_SEEKED, jPlayerFlashEvent);
  176. myMp4Player.removeEventListener(JplayerEvent.JPLAYER_LOADEDMETADATA, jPlayerMetaDataHandler); // Note the unique handler
  177. }
  178. }
  179. private function fl_setAudio_mp3(src:String):Boolean {
  180. if (src != null) {
  181. log("fl_setAudio_mp3: "+src);
  182. setupListeners(isMp3, true);
  183. isMp3 = true;
  184. isVideo = false;
  185. myMp4Player.clearFile();
  186. myMp3Player.setFile(src);
  187. return true;
  188. } else {
  189. log("fl_setAudio_mp3: null");
  190. return false;
  191. }
  192. }
  193. private function fl_setAudio_m4a(src:String):Boolean {
  194. if (src != null) {
  195. log("fl_setAudio_m4a: "+src);
  196. setupListeners(isMp3, false);
  197. isMp3 = false;
  198. isVideo = false;
  199. myMp3Player.clearFile();
  200. myMp4Player.setFile(src);
  201. return true;
  202. } else {
  203. log("fl_setAudio_m4a: null");
  204. return false;
  205. }
  206. }
  207. private function fl_setVideo_m4v(src:String):Boolean {
  208. if (src != null) {
  209. log("fl_setVideo_m4v: "+src);
  210. setupListeners(isMp3, false);
  211. isMp3 = false;
  212. isVideo = true;
  213. myMp3Player.clearFile();
  214. myMp4Player.setFile(src);
  215. return true;
  216. } else {
  217. log("fl_setVideo_m4v: null");
  218. return false;
  219. }
  220. }
  221. private function fl_clearMedia():void {
  222. log("clearMedia.");
  223. myMp3Player.clearFile();
  224. myMp4Player.clearFile();
  225. }
  226. private function fl_load():Boolean {
  227. log("load.");
  228. if(isMp3) {
  229. return myMp3Player.load();
  230. } else {
  231. return myMp4Player.load();
  232. }
  233. }
  234. private function fl_play(time:Number = NaN):Boolean {
  235. log("play: time = " + time);
  236. if(isMp3) {
  237. return myMp3Player.play(time * 1000); // Flash uses milliseconds
  238. } else {
  239. return myMp4Player.play(time * 1000); // Flash uses milliseconds
  240. }
  241. }
  242. private function fl_pause(time:Number = NaN):Boolean {
  243. log("pause: time = " + time);
  244. if(isMp3) {
  245. return myMp3Player.pause(time * 1000); // Flash uses milliseconds
  246. } else {
  247. return myMp4Player.pause(time * 1000); // Flash uses milliseconds
  248. }
  249. }
  250. private function fl_play_head(percent:Number):Boolean {
  251. log("play_head: "+percent+"%");
  252. if(isMp3) {
  253. return myMp3Player.playHead(percent);
  254. } else {
  255. return myMp4Player.playHead(percent);
  256. }
  257. }
  258. private function fl_volume(v:Number):void {
  259. log("volume: "+v);
  260. commonStatus.volume = v;
  261. if(!commonStatus.muted) {
  262. myMp3Player.setVolume(v);
  263. myMp4Player.setVolume(v);
  264. }
  265. }
  266. private function fl_mute(mute:Boolean):void {
  267. log("mute: "+mute);
  268. commonStatus.muted = mute;
  269. if(mute) {
  270. myMp3Player.setVolume(0);
  271. myMp4Player.setVolume(0);
  272. } else {
  273. myMp3Player.setVolume(commonStatus.volume);
  274. myMp4Player.setVolume(commonStatus.volume);
  275. }
  276. }
  277. private function jPlayerFlashEvent(e:JplayerEvent):void {
  278. log("jPlayer Flash Event: " + e.type + ": " + e.target);
  279. if(ExternalInterface.available) {
  280. ExternalInterface.call(jQuery, "jPlayerFlashEvent", e.type, extractStatusData(e.data));
  281. }
  282. }
  283. private function extractStatusData(data:JplayerStatus):Object {
  284. var myStatus:Object = {
  285. version: JplayerStatus.VERSION,
  286. src: data.src,
  287. paused: !data.isPlaying, // Changing this name requires inverting all assignments and conditional statements.
  288. srcSet: data.srcSet,
  289. seekPercent: data.seekPercent,
  290. currentPercentRelative: data.currentPercentRelative,
  291. currentPercentAbsolute: data.currentPercentAbsolute,
  292. currentTime: data.currentTime / 1000, // JavaScript uses seconds
  293. duration: data.duration / 1000, // JavaScript uses seconds
  294. volume: commonStatus.volume,
  295. muted: commonStatus.muted
  296. };
  297. log("extractStatusData: sp="+myStatus.seekPercent+" cpr="+myStatus.currentPercentRelative+" cpa="+myStatus.currentPercentAbsolute+" ct="+myStatus.currentTime+" d="+myStatus.duration);
  298. return myStatus;
  299. }
  300. private function jPlayerMetaDataHandler(e:JplayerEvent):void {
  301. log("jPlayerMetaDataHandler:" + e.target);
  302. if(ExternalInterface.available) {
  303. resizeHandler(new Event(Event.RESIZE));
  304. ExternalInterface.call(jQuery, "jPlayerFlashEvent", e.type, extractStatusData(e.data));
  305. }
  306. }
  307. private function resizeHandler(e:Event):void {
  308. log("resizeHandler: stageWidth = " + stage.stageWidth + " | stageHeight = " + stage.stageHeight);
  309. var mediaX:Number = 0;
  310. var mediaY:Number = 0;
  311. var mediaWidth:Number = 0;
  312. var mediaHeight:Number = 0;
  313. if(stage.stageWidth > 0 && stage.stageHeight > 0 && myMp4Player.myVideo.width > 0 && myMp4Player.myVideo.height > 0) {
  314. var aspectRatioStage:Number = stage.stageWidth / stage.stageHeight;
  315. var aspectRatioVideo:Number = myMp4Player.myVideo.width / myMp4Player.myVideo.height;
  316. if(aspectRatioStage < aspectRatioVideo) {
  317. mediaWidth = stage.stageWidth;
  318. mediaHeight = stage.stageWidth / aspectRatioVideo;
  319. mediaX = 0;
  320. mediaY = (stage.stageHeight - mediaHeight) / 2;
  321. } else {
  322. mediaWidth = stage.stageHeight * aspectRatioVideo;
  323. mediaHeight = stage.stageHeight;
  324. mediaX = (stage.stageWidth - mediaWidth) / 2;
  325. mediaY = 0;
  326. }
  327. resizeEntity(myMp4Player, mediaX, mediaY, mediaWidth, mediaHeight);
  328. }
  329. if(debug && stage.stageWidth > 20 && stage.stageHeight > 20) {
  330. txLog.width = stage.stageWidth - 10;
  331. txLog.height = stage.stageHeight - 10;
  332. }
  333. }
  334. private function resizeEntity(entity:Sprite, mediaX:Number, mediaY:Number, mediaWidth:Number, mediaHeight:Number):void {
  335. entity.x = mediaX;
  336. entity.y = mediaY;
  337. entity.width = mediaWidth;
  338. entity.height = mediaHeight;
  339. }
  340. private function clickHandler(e:MouseEvent):void {
  341. if(isMp3) {
  342. jPlayerFlashEvent(new JplayerEvent(JplayerEvent.JPLAYER_CLICK, myMp3Player.myStatus, "click"))
  343. } else {
  344. jPlayerFlashEvent(new JplayerEvent(JplayerEvent.JPLAYER_CLICK, myMp4Player.myStatus, "click"))
  345. }
  346. }
  347. // This event is never called. See comments in class constructor.
  348. private function menuSelectHandler_jPlayer(e:ContextMenuEvent):void {
  349. navigateToURL(new URLRequest("http://jplayer.org/"), "_blank");
  350. }
  351. // This event is never called. See comments in class constructor.
  352. private function menuSelectHandler_happyworm(e:ContextMenuEvent):void {
  353. navigateToURL(new URLRequest("http://happyworm.com/"), "_blank");
  354. }
  355. private function log(t:String):void {
  356. if(debug) {
  357. txLog.text = t + "\n" + txLog.text;
  358. }
  359. }
  360. private function debugMsgHandler(e:JplayerEvent):void {
  361. log(e.msg);
  362. }
  363. private function keyboardHandler(e:KeyboardEvent):void {
  364. log("keyboardHandler: e.keyCode = " + e.keyCode);
  365. switch(e.keyCode) {
  366. case 68 : // d
  367. txLog.visible = !txLog.visible;
  368. log("Toggled log display: " + txLog.visible);
  369. break;
  370. case 76 : // l
  371. if(e.ctrlKey && e.shiftKey) {
  372. txLog.text = "Cleared log.";
  373. }
  374. break;
  375. }
  376. }
  377. }
  378. }