PageRenderTime 86ms CodeModel.GetById 42ms RepoModel.GetById 1ms app.codeStats 0ms

/js/jPlayer/actionscript/happyworm/jPlayer/JplayerMp3.as

https://gitlab.com/alidz1982/php-mp3-jPlayer
ActionScript | 402 lines | 334 code | 47 blank | 21 comment | 79 complexity | 7ffb989a8ddb01ac4c5e657968cc387a MD5 | raw file
  1. /*
  2. * jPlayer Plugin for jQuery JavaScript Library
  3. * http://www.jplayer.org
  4. *
  5. * Copyright (c) 2009 - 2014 Happyworm Ltd
  6. * Licensed under the MIT license.
  7. * http://opensource.org/licenses/MIT
  8. *
  9. * Author: Mark J Panaghiston
  10. * Date: 15th December 2013
  11. */
  12. package happyworm.jPlayer {
  13. import flash.display.Sprite;
  14. import flash.media.Sound;
  15. import flash.media.SoundChannel;
  16. import flash.media.SoundLoaderContext;
  17. import flash.media.SoundTransform;
  18. import flash.net.URLRequest;
  19. import flash.utils.Timer;
  20. import flash.errors.IOError;
  21. import flash.events.*;
  22. public class JplayerMp3 extends Sprite {
  23. private var mySound:Sound = new Sound();
  24. private var myChannel:SoundChannel = new SoundChannel();
  25. private var myContext:SoundLoaderContext = new SoundLoaderContext(3000, false);
  26. private var myTransform:SoundTransform = new SoundTransform();
  27. private var myRequest:URLRequest = new URLRequest();
  28. private var timeUpdateTimer:Timer = new Timer(250, 0); // Matched to HTML event freq
  29. private var progressTimer:Timer = new Timer(250, 0); // Matched to HTML event freq
  30. private var seekingTimer:Timer = new Timer(100, 0); // Internal: How often seeking is checked to see if it is over.
  31. private var playingTimer:Timer = new Timer(100, 0); // Internal: How often waiting/playing is checked.
  32. private var waitingTimer:Timer = new Timer(3000, 0); // Internal: Check from loadstart to loadOpen. Generates a waiting event.
  33. public var myStatus:JplayerStatus = new JplayerStatus();
  34. public function JplayerMp3(volume:Number) {
  35. timeUpdateTimer.addEventListener(TimerEvent.TIMER, timeUpdateHandler);
  36. progressTimer.addEventListener(TimerEvent.TIMER, progressHandler);
  37. seekingTimer.addEventListener(TimerEvent.TIMER, seekingHandler);
  38. playingTimer.addEventListener(TimerEvent.TIMER, playingHandler);
  39. waitingTimer.addEventListener(TimerEvent.TIMER, waitingHandler);
  40. setVolume(volume);
  41. }
  42. public function setFile(src:String):void {
  43. this.dispatchEvent(new JplayerEvent(JplayerEvent.DEBUG_MSG, myStatus, "setFile: " + src));
  44. if (myStatus.isPlaying) {
  45. myChannel.stop();
  46. }
  47. progressUpdates(false);
  48. timeUpdates(false);
  49. waitingTimer.stop();
  50. try {
  51. mySound.close();
  52. } catch (err:IOError) {
  53. // Occurs if the file is either yet to be opened or has finished downloading.
  54. }
  55. mySound = null;
  56. mySound = new Sound();
  57. mySound.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
  58. mySound.addEventListener(Event.OPEN, loadOpen);
  59. mySound.addEventListener(Event.COMPLETE, loadComplete);
  60. myRequest = new URLRequest(src);
  61. myStatus.reset();
  62. myStatus.src = src;
  63. myStatus.srcSet = true;
  64. timeUpdateEvent();
  65. }
  66. public function clearFile():void {
  67. setFile("");
  68. myStatus.srcSet = false;
  69. }
  70. private function errorHandler(err:IOErrorEvent):void {
  71. // MP3 player needs to stop progress and timeupdate events as they are started before the error occurs.
  72. // NB: The MP4 player works differently and the error occurs before they are started.
  73. progressUpdates(false);
  74. timeUpdates(false);
  75. myStatus.error(); // Resets status except the src, and it sets srcError property.
  76. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_ERROR, myStatus));
  77. }
  78. private function loadOpen(e:Event):void {
  79. this.dispatchEvent(new JplayerEvent(JplayerEvent.DEBUG_MSG, myStatus, "loadOpen:"));
  80. waitingTimer.stop();
  81. myStatus.loading();
  82. if (myStatus.playOnLoad) {
  83. myStatus.playOnLoad = false; // Capture the flag
  84. // this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_LOADSTART, myStatus)); // So loadstart event happens before play event occurs.
  85. play();
  86. } else {
  87. // this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_LOADSTART, myStatus));
  88. pause();
  89. }
  90. progressUpdates(true);
  91. }
  92. private function loadComplete(e:Event):void {
  93. this.dispatchEvent(new JplayerEvent(JplayerEvent.DEBUG_MSG, myStatus, "loadComplete:"));
  94. myStatus.loaded();
  95. progressUpdates(false);
  96. progressEvent();
  97. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_LOADEDMETADATA, myStatus));
  98. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_DURATIONCHANGE, myStatus));
  99. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_CANPLAYTHROUGH, myStatus));
  100. }
  101. private function soundCompleteHandler(e:Event):void {
  102. myStatus.pausePosition = 0;
  103. myStatus.isPlaying = false;
  104. timeUpdates(false);
  105. timeUpdateEvent();
  106. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_ENDED, myStatus));
  107. }
  108. private function progressUpdates(active:Boolean):void {
  109. // Using a timer rather than Flash's load progress event, because that event gave data at about 200Hz. The 10Hz timer is closer to HTML5 norm.
  110. if (active) {
  111. progressTimer.start();
  112. } else {
  113. progressTimer.stop();
  114. }
  115. }
  116. private function progressHandler(e:TimerEvent):void {
  117. progressEvent();
  118. }
  119. private function progressEvent():void {
  120. this.dispatchEvent(new JplayerEvent(JplayerEvent.DEBUG_MSG, myStatus, "progressEvent:"));
  121. updateStatusValues();
  122. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_PROGRESS, myStatus));
  123. }
  124. private function timeUpdates(active:Boolean):void {
  125. if (active) {
  126. timeUpdateTimer.start();
  127. playingTimer.start();
  128. } else {
  129. timeUpdateTimer.stop();
  130. playingTimer.stop();
  131. }
  132. }
  133. private function timeUpdateHandler(e:TimerEvent):void {
  134. timeUpdateEvent();
  135. }
  136. private function timeUpdateEvent():void {
  137. updateStatusValues();
  138. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_TIMEUPDATE, myStatus));
  139. }
  140. private function seeking(active:Boolean):void {
  141. if (active) {
  142. seekingEvent();
  143. waitingEvent();
  144. seekingTimer.start();
  145. } else {
  146. seekingTimer.stop();
  147. }
  148. }
  149. private function seekingHandler(e:TimerEvent):void {
  150. if (myStatus.pausePosition <= getDuration()) {
  151. seekedEvent();
  152. seeking(false);
  153. if (myStatus.playOnSeek) {
  154. myStatus.playOnSeek = false; // Capture the flag.
  155. play();
  156. }
  157. } else if (myStatus.isLoaded && (myStatus.pausePosition > getDuration())) {
  158. // Illegal seek time
  159. seeking(false);
  160. seekedEvent();
  161. pause(0);
  162. }
  163. }
  164. private function seekingEvent():void {
  165. myStatus.isSeeking = true;
  166. updateStatusValues();
  167. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_SEEKING, myStatus));
  168. }
  169. private function seekedEvent():void {
  170. myStatus.isSeeking = false;
  171. updateStatusValues();
  172. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_SEEKED, myStatus));
  173. }
  174. private function playingHandler(e:TimerEvent):void {
  175. checkPlaying(false); // Without forcing playing event.
  176. }
  177. private function checkPlaying(force:Boolean):void {
  178. if (mySound.isBuffering) {
  179. if (!myStatus.isWaiting) {
  180. waitingEvent();
  181. }
  182. } else {
  183. if (myStatus.isWaiting || force) {
  184. playingEvent();
  185. }
  186. }
  187. }
  188. private function waitingEvent():void {
  189. myStatus.isWaiting = true;
  190. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_WAITING, myStatus));
  191. }
  192. private function playingEvent():void {
  193. myStatus.isWaiting = false;
  194. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_CANPLAY, myStatus));
  195. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_PLAYING, myStatus));
  196. }
  197. private function waitingHandler(e:TimerEvent):void {
  198. waitingTimer.stop();
  199. if (myStatus.playOnLoad) {
  200. waitingEvent();
  201. }
  202. }
  203. public function load():Boolean {
  204. if (myStatus.loadRequired()) {
  205. myStatus.startingDownload();
  206. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_LOADSTART, myStatus));
  207. waitingTimer.start();
  208. mySound.load(myRequest, myContext);
  209. return true;
  210. } else {
  211. return false;
  212. }
  213. }
  214. public function play(time:Number = NaN):Boolean {
  215. var wasPlaying:Boolean = myStatus.isPlaying;
  216. if (!isNaN(time) && myStatus.srcSet) {
  217. if (myStatus.isPlaying) {
  218. myChannel.stop();
  219. myStatus.isPlaying = false;
  220. }
  221. myStatus.pausePosition = time;
  222. }
  223. if (myStatus.isStartingDownload) {
  224. myStatus.playOnLoad = true; // Raise flag, captured in loadOpen()
  225. return true;
  226. } else if (myStatus.loadRequired()) {
  227. myStatus.playOnLoad = true; // Raise flag, captured in loadOpen()
  228. return load();
  229. } else if ((myStatus.isLoading || myStatus.isLoaded) && !myStatus.isPlaying) {
  230. if (myStatus.isLoaded && myStatus.pausePosition > getDuration()) { // The time is invalid, ie., past the end.
  231. myStatus.pausePosition = 0;
  232. timeUpdates(false);
  233. timeUpdateEvent();
  234. if (wasPlaying) { // For when playing and then get a play(huge)
  235. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_PAUSE, myStatus));
  236. }
  237. } else if (myStatus.pausePosition > getDuration()) {
  238. myStatus.playOnSeek = true;
  239. seeking(true);
  240. } else {
  241. myStatus.isPlaying = true; // Set immediately before playing. Could affects events.
  242. myChannel = mySound.play(myStatus.pausePosition);
  243. myChannel.soundTransform = myTransform;
  244. myChannel.addEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
  245. timeUpdates(true);
  246. if (!wasPlaying) {
  247. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_PLAY, myStatus));
  248. }
  249. checkPlaying(true); // Force the playing event unless waiting, which will be dealt with in the playingTimer.
  250. }
  251. return true;
  252. } else {
  253. return false;
  254. }
  255. }
  256. public function pause(time:Number = NaN):Boolean {
  257. myStatus.playOnLoad = false; // Reset flag in case load/play issued immediately before this command, ie., before loadOpen() event.
  258. myStatus.playOnSeek = false; // Reset flag in case play(time) issued before the command and is still seeking to time set.
  259. var wasPlaying:Boolean = myStatus.isPlaying;
  260. // To avoid possible loops with timeupdate and pause(time). A pause() does not have the problem.
  261. var alreadyPausedAtTime:Boolean = false;
  262. if (!isNaN(time) && myStatus.pausePosition == time) {
  263. alreadyPausedAtTime = true;
  264. }
  265. if (myStatus.isPlaying) {
  266. myStatus.isPlaying = false;
  267. myChannel.stop();
  268. if (myChannel.position > 0) { // Required otherwise a fast play then pause causes myChannel.position to equal zero and not the correct value. ie., When it happens leave pausePosition alone.
  269. myStatus.pausePosition = myChannel.position;
  270. }
  271. }
  272. if (!isNaN(time) && myStatus.srcSet) {
  273. myStatus.pausePosition = time;
  274. }
  275. if (wasPlaying) {
  276. this.dispatchEvent(new JplayerEvent(JplayerEvent.JPLAYER_PAUSE, myStatus));
  277. }
  278. if (myStatus.isStartingDownload) {
  279. return true;
  280. } else if (myStatus.loadRequired()) {
  281. if (time > 0) { // We do not want the stop() command, which does pause(0), causing a load operation.
  282. return load();
  283. } else {
  284. return true; // Technically the pause(0) succeeded. ie., It did nothing, since nothing was required.
  285. }
  286. } else if (myStatus.isLoading || myStatus.isLoaded) {
  287. if (myStatus.isLoaded && myStatus.pausePosition > getDuration()) { // The time is invalid, ie., past the end.
  288. myStatus.pausePosition = 0;
  289. } else if (myStatus.pausePosition > getDuration()) {
  290. seeking(true);
  291. }
  292. timeUpdates(false);
  293. // Need to be careful with timeupdate event, otherwise a pause in a timeupdate event can cause a loop.
  294. // Neither pause() nor pause(time) will cause a timeupdate loop.
  295. if (wasPlaying || !isNaN(time) && !alreadyPausedAtTime) {
  296. timeUpdateEvent();
  297. }
  298. return true;
  299. } else {
  300. return false;
  301. }
  302. }
  303. public function playHead(percent:Number):Boolean {
  304. var time:Number = percent * getDuration() / 100;
  305. if (myStatus.isPlaying || myStatus.playOnLoad || myStatus.playOnSeek) {
  306. return play(time);
  307. } else {
  308. return pause(time);
  309. }
  310. }
  311. public function setVolume(v:Number):void {
  312. myStatus.volume = v;
  313. myTransform.volume = v;
  314. myChannel.soundTransform = myTransform;
  315. }
  316. private function updateStatusValues():void {
  317. myStatus.seekPercent = 100 * getLoadRatio();
  318. myStatus.currentTime = getCurrentTime();
  319. myStatus.currentPercentRelative = 100 * getCurrentRatioRel();
  320. myStatus.currentPercentAbsolute = 100 * getCurrentRatioAbs();
  321. myStatus.duration = getDuration();
  322. }
  323. public function getLoadRatio():Number {
  324. if ((myStatus.isLoading || myStatus.isLoaded) && mySound.bytesTotal > 0) {
  325. return mySound.bytesLoaded / mySound.bytesTotal;
  326. } else {
  327. return 0;
  328. }
  329. }
  330. public function getDuration():Number {
  331. if (mySound.length > 0) {
  332. return mySound.length;
  333. } else {
  334. return 0;
  335. }
  336. }
  337. public function getCurrentTime():Number {
  338. if (myStatus.isPlaying) {
  339. return myChannel.position;
  340. } else {
  341. return myStatus.pausePosition;
  342. }
  343. }
  344. public function getCurrentRatioRel():Number {
  345. if ((getDuration() > 0) && (getCurrentTime() <= getDuration())) {
  346. return getCurrentTime() / getDuration();
  347. } else {
  348. return 0;
  349. }
  350. }
  351. public function getCurrentRatioAbs():Number {
  352. return getCurrentRatioRel() * getLoadRatio();
  353. }
  354. }
  355. }