tests.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020
  1. /*
  2. *
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. *
  20. */
  21. /* jshint jasmine: true */
  22. /* global Windows, Media, MediaError, LocalFileSystem, halfSpeedBtn */
  23. // increased timeout for actual playback to give device chance to download and play mp3 file
  24. // some emulators can be REALLY slow at this, so two minutes
  25. var ACTUAL_PLAYBACK_TEST_TIMEOUT = 2 * 60 * 1000;
  26. var isWindows = cordova.platformId == 'windows8' || cordova.platformId == 'windows';
  27. // detect whether audio hardware is available and enabled
  28. var isAudioSupported = isWindows ? Windows.Media.Devices.MediaDevice.getDefaultAudioRenderId(Windows.Media.Devices.AudioDeviceRole.default) : true;
  29. exports.defineAutoTests = function () {
  30. var failed = function (done, msg, context) {
  31. if (context && context.done) return;
  32. context.done = true;
  33. var info = typeof msg == 'undefined' ? 'Unexpected error callback' : msg;
  34. expect(true).toFailWithMessage(info);
  35. done();
  36. };
  37. var succeed = function (done, msg, context) {
  38. if (context && context.done) return;
  39. context.done = true;
  40. var info = typeof msg == 'undefined' ? 'Unexpected success callback' : msg;
  41. expect(true).toFailWithMessage(info);
  42. done();
  43. };
  44. describe('Media', function () {
  45. beforeEach(function () {
  46. // Custom Matcher
  47. jasmine.Expectation.addMatchers({
  48. toFailWithMessage : function () {
  49. return {
  50. compare : function (error, message) {
  51. var pass = false;
  52. return {
  53. pass : pass,
  54. message : message
  55. };
  56. }
  57. };
  58. }
  59. });
  60. });
  61. it("media.spec.1 should exist", function () {
  62. expect(Media).toBeDefined();
  63. expect(typeof Media).toBe("function");
  64. });
  65. it("media.spec.2 should have the following properties", function () {
  66. var media1 = new Media("dummy");
  67. expect(media1.id).toBeDefined();
  68. expect(media1.src).toBeDefined();
  69. expect(media1._duration).toBeDefined();
  70. expect(media1._position).toBeDefined();
  71. media1.release();
  72. });
  73. it("media.spec.3 should define constants for Media status", function () {
  74. expect(Media).toBeDefined();
  75. expect(Media.MEDIA_NONE).toBe(0);
  76. expect(Media.MEDIA_STARTING).toBe(1);
  77. expect(Media.MEDIA_RUNNING).toBe(2);
  78. expect(Media.MEDIA_PAUSED).toBe(3);
  79. expect(Media.MEDIA_STOPPED).toBe(4);
  80. });
  81. it("media.spec.4 should define constants for Media errors", function () {
  82. expect(MediaError).toBeDefined();
  83. expect(MediaError.MEDIA_ERR_NONE_ACTIVE).toBe(0);
  84. expect(MediaError.MEDIA_ERR_ABORTED).toBe(1);
  85. expect(MediaError.MEDIA_ERR_NETWORK).toBe(2);
  86. expect(MediaError.MEDIA_ERR_DECODE).toBe(3);
  87. expect(MediaError.MEDIA_ERR_NONE_SUPPORTED).toBe(4);
  88. });
  89. it("media.spec.5 should contain a play function", function () {
  90. var media1 = new Media("dummy");
  91. expect(media1.play).toBeDefined();
  92. expect(typeof media1.play).toBe('function');
  93. media1.release();
  94. });
  95. it("media.spec.6 should contain a stop function", function () {
  96. var media1 = new Media("dummy");
  97. expect(media1.stop).toBeDefined();
  98. expect(typeof media1.stop).toBe('function');
  99. media1.release();
  100. });
  101. it("media.spec.7 should contain a seekTo function", function () {
  102. var media1 = new Media("dummy");
  103. expect(media1.seekTo).toBeDefined();
  104. expect(typeof media1.seekTo).toBe('function');
  105. media1.release();
  106. });
  107. it("media.spec.8 should contain a pause function", function () {
  108. var media1 = new Media("dummy");
  109. expect(media1.pause).toBeDefined();
  110. expect(typeof media1.pause).toBe('function');
  111. media1.release();
  112. });
  113. it("media.spec.9 should contain a getDuration function", function () {
  114. var media1 = new Media("dummy");
  115. expect(media1.getDuration).toBeDefined();
  116. expect(typeof media1.getDuration).toBe('function');
  117. media1.release();
  118. });
  119. it("media.spec.10 should contain a getCurrentPosition function", function () {
  120. var media1 = new Media("dummy");
  121. expect(media1.getCurrentPosition).toBeDefined();
  122. expect(typeof media1.getCurrentPosition).toBe('function');
  123. media1.release();
  124. });
  125. it("media.spec.11 should contain a startRecord function", function () {
  126. var media1 = new Media("dummy");
  127. expect(media1.startRecord).toBeDefined();
  128. expect(typeof media1.startRecord).toBe('function');
  129. media1.release();
  130. });
  131. it("media.spec.12 should contain a stopRecord function", function () {
  132. var media1 = new Media("dummy");
  133. expect(media1.stopRecord).toBeDefined();
  134. expect(typeof media1.stopRecord).toBe('function');
  135. media1.release();
  136. });
  137. it("media.spec.13 should contain a release function", function () {
  138. var media1 = new Media("dummy");
  139. expect(media1.release).toBeDefined();
  140. expect(typeof media1.release).toBe('function');
  141. media1.release();
  142. });
  143. it("media.spec.14 should contain a setVolume function", function () {
  144. var media1 = new Media("dummy");
  145. expect(media1.setVolume).toBeDefined();
  146. expect(typeof media1.setVolume).toBe('function');
  147. media1.release();
  148. });
  149. it("media.spec.15 should contain a getCurrentAmplitude function", function () {
  150. var media1 = new Media("dummy");
  151. expect(media1.getCurrentAmplitude).toBeDefined();
  152. expect(typeof media1.getCurrentAmplitude).toBe('function');
  153. media1.release();
  154. });
  155. it("media.spec.16 should return MediaError for bad filename", function (done) {
  156. //bb10 dialog pops up, preventing tests from running
  157. if (cordova.platformId === 'blackberry10') {
  158. pending();
  159. }
  160. var context = this,
  161. fileName = 'invalid.file.name',
  162. badMedia = new Media(fileName, succeed.bind(null, done, ' badMedia = new Media , Unexpected succees callback, it should not create Media object with invalid file name'), function (result) {
  163. if (context.done) return;
  164. context.done = true;
  165. expect(result).toBeDefined();
  166. expect(result.code).toBe(MediaError.MEDIA_ERR_ABORTED);
  167. if (badMedia) {
  168. badMedia.release();
  169. }
  170. done();
  171. });
  172. badMedia.play();
  173. });
  174. describe('actual playback', function() {
  175. var checkInterval,
  176. media;
  177. afterEach(function() {
  178. clearInterval(checkInterval);
  179. if (media) {
  180. media.stop();
  181. media.release();
  182. media = null;
  183. }
  184. });
  185. it("media.spec.17 position should be set properly", function (done) {
  186. // no audio hardware available
  187. if (!isAudioSupported) {
  188. pending();
  189. }
  190. //context variable used as an extra security statement to ensure that the callback is processed only once,
  191. //in case the statusChange callback is reached more than one time with the same status code.
  192. //Some information about this kind of behaviour can be found at JIRA: CB-7099.
  193. var context = this,
  194. mediaFile = 'https://cordova.apache.org/downloads/BlueZedEx.mp3',
  195. successCallback = function () { },
  196. statusChange = function (statusCode) {
  197. if (!context.done && statusCode == Media.MEDIA_RUNNING) {
  198. checkInterval = setInterval(function () {
  199. if (context.done) return;
  200. media.getCurrentPosition(function successCallback(position) {
  201. if (position > 0.0) {
  202. context.done = true;
  203. expect(true).toBe(true);
  204. done();
  205. }
  206. }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
  207. }, 1000);
  208. }
  209. };
  210. media = new Media(mediaFile, successCallback, failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context), statusChange);
  211. media.play();
  212. }, ACTUAL_PLAYBACK_TEST_TIMEOUT);
  213. it("media.spec.18 duration should be set properly", function (done) {
  214. if (!isAudioSupported || cordova.platformId === 'blackberry10') {
  215. pending();
  216. }
  217. //context variable used as an extra security statement to ensure that the callback is processed only once,
  218. //in case the statusChange callback is reached more than one time with the same status code.
  219. //Some information about this kind of behaviour can be found at JIRA: CB-7099.
  220. var context = this,
  221. mediaFile = 'https://cordova.apache.org/downloads/BlueZedEx.mp3',
  222. successCallback = function () { },
  223. statusChange = function (statusCode) {
  224. if (!context.done && statusCode == Media.MEDIA_RUNNING) {
  225. checkInterval = setInterval(function () {
  226. if (context.done) return;
  227. media.getCurrentPosition(function (position) {
  228. if (position > 0.0) {
  229. context.done = true;
  230. expect(media.getDuration()).toBeGreaterThan(0.0);
  231. done();
  232. }
  233. }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
  234. }, 1000);
  235. }
  236. };
  237. media = new Media(mediaFile, successCallback, failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context), statusChange);
  238. media.play();
  239. }, ACTUAL_PLAYBACK_TEST_TIMEOUT);
  240. it("media.spec.19 should be able to resume playback after pause", function (done) {
  241. if (!isAudioSupported || cordova.platformId === 'blackberry10') {
  242. pending();
  243. }
  244. //context variable used as an extra security statement to ensure that the callback is processed only once,
  245. //in case the statusChange callback is reached more than one time with the same status code.
  246. //Some information about this kind of behaviour can be found at JIRA: CB-7099.
  247. var context = this;
  248. var resumed = false;
  249. var mediaFile = 'https://cordova.apache.org/downloads/BlueZedEx.mp3';
  250. var successCallback = function () { };
  251. var statusChange = function (statusCode) {
  252. if (context.done) return;
  253. if (statusCode == Media.MEDIA_RUNNING) {
  254. if (!resumed) {
  255. media.seekTo(20000);
  256. media.pause();
  257. return;
  258. }
  259. media.getCurrentPosition(function (position) {
  260. expect(position).toBeCloseTo(20, 0);
  261. context.done = true;
  262. done();
  263. }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
  264. }
  265. if (statusCode == Media.MEDIA_PAUSED) {
  266. resumed = true;
  267. media.play();
  268. }
  269. };
  270. media = new Media(mediaFile, successCallback, failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context), statusChange);
  271. // CB-10535: Play after a few secs, to give allow enough buffering of media file before seeking
  272. setTimeout(function() {
  273. media.play();
  274. }, 4000);
  275. }, ACTUAL_PLAYBACK_TEST_TIMEOUT);
  276. it("media.spec.20 should be able to seek through file", function (done) {
  277. if (!isAudioSupported || cordova.platformId === 'blackberry10') {
  278. pending();
  279. }
  280. //context variable used as an extra security statement to ensure that the callback is processed only once,
  281. //in case the statusChange callback is reached more than one time with the same status code.
  282. //Some information about this kind of behaviour can be found at JIRA: CB-7099.
  283. var context = this;
  284. var mediaFile = 'https://cordova.apache.org/downloads/BlueZedEx.mp3';
  285. var successCallback = function () { };
  286. var statusChange = function (statusCode) {
  287. if (!context.done && statusCode == Media.MEDIA_RUNNING) {
  288. checkInterval = setInterval(function () {
  289. if (context.done) return;
  290. media.seekTo(5000);
  291. media.getCurrentPosition(function (position) {
  292. expect(position).toBeCloseTo(5, 0);
  293. context.done = true;
  294. done();
  295. }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
  296. }, 1000);
  297. }
  298. };
  299. media = new Media(mediaFile, successCallback, failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context), statusChange);
  300. // CB-10535: Play after a few secs, to give allow enough buffering of media file before seeking
  301. setTimeout(function() {
  302. media.play();
  303. }, 4000);
  304. }, ACTUAL_PLAYBACK_TEST_TIMEOUT);
  305. });
  306. it("media.spec.21 should contain a setRate function", function () {
  307. var media1 = new Media("dummy");
  308. expect(media1.setRate).toBeDefined();
  309. expect(typeof media1.setRate).toBe('function');
  310. media1.release();
  311. });
  312. it("media.spec.22 playback rate should be set properly using setRate", function (done) {
  313. if (cordova.platformId !== 'ios') {
  314. expect(true).toFailWithMessage('Platform does not supported this feature');
  315. pending();
  316. return;
  317. }
  318. var mediaFile = 'https://cordova.apache.org/downloads/BlueZedEx.mp3',
  319. successCallback,
  320. context = this,
  321. flag = true,
  322. statusChange = function (statusCode) {
  323. console.log("status code: " + statusCode);
  324. if (statusCode == Media.MEDIA_RUNNING && flag) {
  325. //flag variable used to ensure an extra security statement to ensure that the callback is processed only once,
  326. //in case for some reason the statusChange callback is reached more than one time with the same status code.
  327. //Some information about this kind of behavior it can be found at JIRA: CB-7099
  328. flag = false;
  329. setTimeout(function () {
  330. media1.getCurrentPosition(function (position) {
  331. //in four seconds expect position to be between 4 & 10. Here, the values are chosen to give
  332. //a large enough buffer range for the position to fall in and are not based on any calculation.
  333. expect(position >= 4 && position < 10).toBeTruthy();
  334. media1.stop();
  335. media1.release();
  336. done();
  337. }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position'),context);
  338. }, 4000);
  339. }
  340. };
  341. var media1 = new Media(mediaFile, successCallback, failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context), statusChange); // jshint ignore:line
  342. //make audio playback two times faster
  343. media1.setRate(2);
  344. media1.play();
  345. }, ACTUAL_PLAYBACK_TEST_TIMEOUT);
  346. });
  347. };
  348. //******************************************************************************************
  349. //***************************************Manual Tests***************************************
  350. //******************************************************************************************
  351. exports.defineManualTests = function (contentEl, createActionButton) {
  352. //-------------------------------------------------------------------------
  353. // Audio player
  354. //-------------------------------------------------------------------------
  355. var media1 = null;
  356. var media1Timer = null;
  357. var audioSrc = null;
  358. var defaultaudio = "https://cordova.apache.org/downloads/BlueZedEx.mp3";
  359. //Play audio function
  360. function playAudio(url) {
  361. console.log("playAudio()");
  362. console.log(" -- media=" + media1);
  363. var src = defaultaudio;
  364. if (url) {
  365. src = url;
  366. }
  367. // Stop playing if src is different from currently playing source
  368. if (src !== audioSrc) {
  369. if (media1 !== null) {
  370. stopAudio();
  371. media1 = null;
  372. }
  373. }
  374. if (media1 === null) {
  375. // TEST STREAMING AUDIO PLAYBACK
  376. //var src = "http://nunzioweb.com/misc/Bon_Jovi-Crush_Mystery_Train.mp3"; // works
  377. //var src = "http://nunzioweb.com/misc/Bon_Jovi-Crush_Mystery_Train.m3u"; // doesn't work
  378. //var src = "http://www.wav-sounds.com/cartoon/bugsbunny1.wav"; // works
  379. //var src = "http://www.angelfire.com/fl5/html-tutorial/a/couldyou.mid"; // doesn't work
  380. //var src = "MusicSearch/mp3/train.mp3"; // works
  381. //var src = "bryce.mp3"; // works
  382. //var src = "/android_asset/www/bryce.mp3"; // works
  383. media1 = new Media(src,
  384. function () {
  385. console.log("playAudio():Audio Success");
  386. },
  387. function (err) {
  388. console.log("playAudio():Audio Error: " + err.code);
  389. setAudioStatus("Error: " + err.code);
  390. },
  391. function (status) {
  392. console.log("playAudio():Audio Status: " + status);
  393. setAudioStatus(Media.MEDIA_MSG[status]);
  394. // If stopped, then stop getting current position
  395. if (Media.MEDIA_STOPPED == status) {
  396. clearInterval(media1Timer);
  397. media1Timer = null;
  398. setAudioPosition("0 sec");
  399. }
  400. });
  401. }
  402. audioSrc = src;
  403. document.getElementById('durationValue').innerHTML = "";
  404. // Play audio
  405. media1.play();
  406. if (media1Timer === null && media1.getCurrentPosition) {
  407. media1Timer = setInterval(
  408. function () {
  409. media1.getCurrentPosition(
  410. function (position) {
  411. if (position >= 0.0) {
  412. setAudioPosition(position + " sec");
  413. }
  414. },
  415. function (e) {
  416. console.log("Error getting pos=" + e);
  417. setAudioPosition("Error: " + e);
  418. });
  419. },
  420. 1000);
  421. }
  422. // Get duration
  423. var counter = 0;
  424. var timerDur = setInterval(
  425. function () {
  426. counter = counter + 100;
  427. if (counter > 2000) {
  428. clearInterval(timerDur);
  429. }
  430. var dur = media1.getDuration();
  431. if (dur > 0) {
  432. clearInterval(timerDur);
  433. document.getElementById('durationValue').innerHTML = dur + " sec";
  434. }
  435. }, 100);
  436. }
  437. //Pause audio playback
  438. function pauseAudio() {
  439. console.log("pauseAudio()");
  440. if (media1) {
  441. media1.pause();
  442. }
  443. }
  444. //Stop audio
  445. function stopAudio() {
  446. console.log("stopAudio()");
  447. if (media1) {
  448. media1.stop();
  449. }
  450. clearInterval(media1Timer);
  451. media1Timer = null;
  452. }
  453. //Release audio
  454. function releaseAudio() {
  455. console.log("releaseAudio()");
  456. if (media1) {
  457. media1.stop(); //imlied stop of playback, resets timer
  458. media1.release();
  459. }
  460. }
  461. //Set audio status
  462. function setAudioStatus(status) {
  463. document.getElementById('statusValue').innerHTML = status;
  464. }
  465. //Set audio position
  466. function setAudioPosition(position) {
  467. document.getElementById('positionValue').innerHTML = position;
  468. }
  469. //Seek audio
  470. function seekAudio(mode) {
  471. var time = document.getElementById("seekInput").value;
  472. if (time === "") {
  473. time = 5000;
  474. } else {
  475. time = time * 1000; //we expect the input to be in seconds
  476. }
  477. if (media1 === null) {
  478. console.log("seekTo requested while media1 is null");
  479. if (audioSrc === null) {
  480. audioSrc = defaultaudio;
  481. }
  482. media1 = new Media(audioSrc,
  483. function () {
  484. console.log("seekToAudio():Audio Success");
  485. },
  486. function (err) {
  487. console.log("seekAudio():Audio Error: " + err.code);
  488. setAudioStatus("Error: " + err.code);
  489. },
  490. function (status) {
  491. console.log("seekAudio():Audio Status: " + status);
  492. setAudioStatus(Media.MEDIA_MSG[status]);
  493. // If stopped, then stop getting current position
  494. if (Media.MEDIA_STOPPED == status) {
  495. clearInterval(media1Timer);
  496. media1Timer = null;
  497. setAudioPosition("0 sec");
  498. }
  499. });
  500. }
  501. media1.getCurrentPosition(
  502. function (position) {
  503. var deltat = time;
  504. if (mode === "by") {
  505. deltat = time + position * 1000;
  506. }
  507. media1.seekTo(deltat,
  508. function () {
  509. console.log("seekAudioTo():Audio Success");
  510. //force an update on the position display
  511. updatePosition();
  512. },
  513. function (err) {
  514. console.log("seekAudioTo():Audio Error: " + err.code);
  515. });
  516. },
  517. function (e) {
  518. console.log("Error getting pos=" + e);
  519. setAudioPosition("Error: " + e);
  520. });
  521. }
  522. //for forced updates of position after a successful seek
  523. function updatePosition() {
  524. media1.getCurrentPosition(
  525. function (position) {
  526. if (position >= 0.0) {
  527. setAudioPosition(position + " sec");
  528. }
  529. },
  530. function (e) {
  531. console.log("Error getting pos=" + e);
  532. setAudioPosition("Error: " + e);
  533. });
  534. }
  535. //-------------------------------------------------------------------------
  536. // Audio recorder
  537. //-------------------------------------------------------------------------
  538. var mediaRec = null;
  539. var recTime = 0;
  540. var recordSrc = "myRecording.mp3";
  541. //Record audio
  542. function recordAudio() {
  543. console.log("recordAudio()");
  544. console.log(" -- media=" + mediaRec);
  545. releaseAudio();
  546. if (!mediaRec) {
  547. var src = recordSrc;
  548. mediaRec = new Media(src,
  549. function () {
  550. console.log("recordAudio():Audio Success");
  551. },
  552. function (err) {
  553. console.log("recordAudio():Audio Error: " + err.code);
  554. setAudioStatus("Error: " + err.code);
  555. },
  556. function (status) {
  557. console.log("recordAudio():Audio Status: " + status);
  558. setAudioStatus(Media.MEDIA_MSG[status]);
  559. });
  560. }
  561. // Record audio
  562. mediaRec.startRecord();
  563. // Stop recording after 10 sec
  564. recTime = 0;
  565. var recInterval = setInterval(function () {
  566. recTime = recTime + 1;
  567. setAudioPosition(recTime + " sec");
  568. if (recTime >= 10) {
  569. clearInterval(recInterval);
  570. if (mediaRec.stopAudioRecord) {
  571. mediaRec.stopAudioRecord();
  572. } else {
  573. mediaRec.stopRecord();
  574. }
  575. console.log("recordAudio(): stop");
  576. }
  577. }, 1000);
  578. }
  579. //Play back recorded audio
  580. function playRecording() {
  581. playAudio(recordSrc);
  582. }
  583. //Function to create a file for iOS recording
  584. function getRecordSrc() {
  585. var fsFail = function (error) {
  586. console.log("error creating file for iOS recording");
  587. };
  588. var gotFile = function (file) {
  589. recordSrc = file.fullPath;
  590. //console.log("recording Src: " + recordSrc);
  591. };
  592. var gotFS = function (fileSystem) {
  593. fileSystem.root.getFile("iOSRecording.wav", {
  594. create : true
  595. }, gotFile, fsFail);
  596. };
  597. window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, gotFS, fsFail);
  598. }
  599. //Function to create a file for BB recording
  600. function getRecordSrcBB() {
  601. var fsFail = function (error) {
  602. console.log("error creating file for BB recording");
  603. };
  604. var gotFile = function (file) {
  605. recordSrc = file.fullPath;
  606. };
  607. var gotFS = function (fileSystem) {
  608. fileSystem.root.getFile("BBRecording.amr", {
  609. create : true
  610. }, gotFile, fsFail);
  611. };
  612. window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, gotFS, fsFail);
  613. }
  614. //Function to create a file for Windows recording
  615. function getRecordSrcWin() {
  616. var fsFail = function (error) {
  617. console.log("error creating file for Win recording");
  618. };
  619. var gotFile = function (file) {
  620. recordSrc = file.name;
  621. };
  622. var gotFS = function (fileSystem) {
  623. fileSystem.root.getFile("WinRecording.m4a", {
  624. create: true
  625. }, gotFile, fsFail);
  626. };
  627. window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fsFail);
  628. }
  629. //Generate Dynamic Table
  630. function generateTable(tableId, rows, cells, elements) {
  631. var table = document.createElement('table');
  632. for (var r = 0; r < rows; r++) {
  633. var row = table.insertRow(r);
  634. for (var c = 0; c < cells; c++) {
  635. var cell = row.insertCell(c);
  636. cell.setAttribute("align", "center");
  637. for (var e in elements) {
  638. if (elements[e].position.row == r && elements[e].position.cell == c) {
  639. var htmlElement = document.createElement(elements[e].tag);
  640. var content;
  641. if (elements[e].content !== "") {
  642. content = document.createTextNode(elements[e].content);
  643. htmlElement.appendChild(content);
  644. }
  645. if (elements[e].type) {
  646. htmlElement.type = elements[e].type;
  647. }
  648. htmlElement.setAttribute("id", elements[e].id);
  649. cell.appendChild(htmlElement);
  650. }
  651. }
  652. }
  653. }
  654. table.setAttribute("align", "center");
  655. table.setAttribute("id", tableId);
  656. return table;
  657. }
  658. //Audio && Record Elements
  659. var elementsResultsAudio=
  660. [{
  661. id : "statusTag",
  662. content : "Status:",
  663. tag : "div",
  664. position : {
  665. row : 0,
  666. cell : 0
  667. }
  668. }, {
  669. id : "statusValue",
  670. content : "",
  671. tag : "div",
  672. position : {
  673. row : 0,
  674. cell : 2
  675. }
  676. }, {
  677. id : "durationTag",
  678. content : "Duration:",
  679. tag : "div",
  680. position : {
  681. row : 1,
  682. cell : 0
  683. }
  684. }, {
  685. id : "durationValue",
  686. content : "",
  687. tag : "div",
  688. position : {
  689. row : 1,
  690. cell : 2
  691. }
  692. }, {
  693. id : "positionTag",
  694. content : "Position:",
  695. tag : "div",
  696. position : {
  697. row : 2,
  698. cell : 0
  699. }
  700. }, {
  701. id : "positionValue",
  702. content : "",
  703. tag : "div",
  704. position : {
  705. row : 2,
  706. cell : 2
  707. }
  708. }],
  709. elementsAudio =
  710. [{
  711. id : "playBtn",
  712. content : "",
  713. tag : "div",
  714. position : {
  715. row : 0,
  716. cell : 0
  717. }
  718. }, {
  719. id : "pauseBtn",
  720. content : "",
  721. tag : "div",
  722. position : {
  723. row : 0,
  724. cell : 1
  725. }
  726. }, {
  727. id : "stopBtn",
  728. content : "",
  729. tag : "div",
  730. position : {
  731. row : 1,
  732. cell : 0
  733. }
  734. }, {
  735. id : "releaseBtn",
  736. content : "",
  737. tag : "div",
  738. position : {
  739. row : 1,
  740. cell : 1
  741. }
  742. }, {
  743. id : "seekByBtn",
  744. content : "",
  745. tag : "div",
  746. position : {
  747. row : 2,
  748. cell : 0
  749. }
  750. }, {
  751. id : "seekToBtn",
  752. content : "",
  753. tag : "div",
  754. position : {
  755. row : 2,
  756. cell : 1
  757. }
  758. }, {
  759. id : "seekInput",
  760. content : "",
  761. tag : "input",
  762. type : "number",
  763. position : {
  764. row : 2,
  765. cell : 2
  766. }
  767. }, {
  768. id: "halfSpeedBtn",
  769. content:"",
  770. tag:"div",
  771. position:{
  772. row:0,
  773. cell:2
  774. }
  775. }
  776. ],
  777. elementsRecord =
  778. [{
  779. id : "recordbtn",
  780. content : "",
  781. tag : "div",
  782. position : {
  783. row : 1,
  784. cell : 0
  785. }
  786. }, {
  787. id : "recordplayBtn",
  788. content : "",
  789. tag : "div",
  790. position : {
  791. row : 1,
  792. cell : 1
  793. }
  794. }, {
  795. id : "recordpauseBtn",
  796. content : "",
  797. tag : "div",
  798. position : {
  799. row : 2,
  800. cell : 0
  801. }
  802. }, {
  803. id : "recordstopBtn",
  804. content : "",
  805. tag : "div",
  806. position : {
  807. row : 2,
  808. cell : 1
  809. }
  810. }
  811. ];
  812. //Title audio results
  813. var div = document.createElement('h2');
  814. div.appendChild(document.createTextNode('Audio'));
  815. div.setAttribute("align", "center");
  816. contentEl.appendChild(div);
  817. //Generate and add results table
  818. contentEl.appendChild(generateTable('info', 3, 3, elementsResultsAudio));
  819. //Title audio actions
  820. div = document.createElement('h2');
  821. div.appendChild(document.createTextNode('Actions'));
  822. div.setAttribute("align", "center");
  823. contentEl.appendChild(div);
  824. //Generate and add buttons table
  825. contentEl.appendChild(generateTable('audioActions', 3, 3, elementsAudio));
  826. createActionButton('Play', function () {
  827. playAudio();
  828. }, 'playBtn');
  829. createActionButton('Pause', function () {
  830. pauseAudio();
  831. }, 'pauseBtn');
  832. createActionButton('HalfSpeed', function() {
  833. if(halfSpeedBtn.firstChild.firstChild.innerText == 'HalfSpeed') {
  834. halfSpeedBtn.firstChild.firstChild.innerText = 'FullSpeed';
  835. media1.setRate(0.5);
  836. }
  837. else if(halfSpeedBtn.firstChild.firstChild.innerText == 'FullSpeed') {
  838. halfSpeedBtn.firstChild.firstChild.innerText = 'DoubleSpeed';
  839. media1.setRate(1.0);
  840. }
  841. else {
  842. halfSpeedBtn.firstChild.firstChild.innerText = 'HalfSpeed';
  843. media1.setRate(2.0);
  844. }
  845. }, 'halfSpeedBtn');
  846. createActionButton('Stop', function () {
  847. stopAudio();
  848. }, 'stopBtn');
  849. createActionButton('Release', function () {
  850. releaseAudio();
  851. }, 'releaseBtn');
  852. createActionButton('Seek By', function () {
  853. seekAudio('by');
  854. }, 'seekByBtn');
  855. createActionButton('Seek To', function () {
  856. seekAudio('to');
  857. }, 'seekToBtn');
  858. //get Special path to record if iOS || Blackberry
  859. if (cordova.platformId === 'ios')
  860. getRecordSrc();
  861. else if (cordova.platformId === 'blackberry')
  862. getRecordSrcBB();
  863. else if (cordova.platformId === 'windows' || cordova.platformId === 'windows8')
  864. getRecordSrcWin();
  865. //testing process and details
  866. function addItemToList(_list, _text)
  867. {
  868. var item = document.createElement('li');
  869. item.appendChild(document.createTextNode(_text));
  870. _list.appendChild(item);
  871. }
  872. div = document.createElement('h4');
  873. div.appendChild(document.createTextNode('Recommended Test Procedure'));
  874. contentEl.appendChild(div);
  875. var list = document.createElement('ol');
  876. addItemToList(list, 'Press play - Will start playing audio. Status: Running, Duration: 61.333 sec, Position: Current position of audio track');
  877. addItemToList(list, 'Press pause - Will pause the audio. Status: Paused, Duration: 61.333 sec, Position: Position where track was paused');
  878. addItemToList(list, 'Press play - Will begin playing where track left off from the pause');
  879. addItemToList(list, 'Press stop - Will stop the audio. Status: Stopped, Duration: 61.333 sec, Position: 0 sec');
  880. addItemToList(list, 'Press play - Will begin playing the audio track from the beginning');
  881. addItemToList(list, 'Press release - Will stop the audio. Status: Stopped, Duration: 61.333 sec, Position: 0 sec');
  882. addItemToList(list, 'Press play - Will begin playing the audio track from the beginning');
  883. addItemToList(list, 'Type 10 in the text box beside Seek To button');
  884. addItemToList(list, 'Press seek by - Will jump 10 seconds ahead in the audio track. Position: should jump by 10 sec');
  885. addItemToList(list, 'Press stop if track is not already stopped');
  886. addItemToList(list, 'Type 30 in the text box beside Seek To button');
  887. addItemToList(list, 'Press play then seek to - Should jump to Position 30 sec');
  888. addItemToList(list, 'Press stop');
  889. addItemToList(list, 'Type 5 in the text box beside Seek To button');
  890. addItemToList(list, 'Press play, let play past 10 seconds then press seek to - should jump back to position 5 sec');
  891. div = document.createElement('div');
  892. div.setAttribute("style", "background:#B0C4DE;border:1px solid #FFA07A;margin:15px 6px 0px;min-width:295px;max-width:97%;padding:4px 0px 2px 10px;min-height:160px;max-height:200px;overflow:auto");
  893. div.appendChild(list);
  894. contentEl.appendChild(div);
  895. //Title Record Audio
  896. div = document.createElement('h2');
  897. div.appendChild(document.createTextNode('Record Audio'));
  898. div.setAttribute("align", "center");
  899. contentEl.appendChild(div);
  900. //Generate and add Record buttons table
  901. contentEl.appendChild(generateTable('recordContent', 3, 3, elementsRecord));
  902. createActionButton('Record Audio \n 10 sec', function () {
  903. recordAudio();
  904. }, 'recordbtn');
  905. createActionButton('Play', function () {
  906. playRecording();
  907. }, 'recordplayBtn');
  908. createActionButton('Pause', function () {
  909. pauseAudio();
  910. }, 'recordpauseBtn');
  911. createActionButton('Stop', function () {
  912. stopAudio();
  913. }, 'recordstopBtn');
  914. //testing process and details
  915. div = document.createElement('h4');
  916. div.appendChild(document.createTextNode('Recommended Test Procedure'));
  917. contentEl.appendChild(div);
  918. list = document.createElement('ol');
  919. addItemToList(list, 'Press Record Audio 10 sec - Will start recording audio for 10 seconds. Status: Running, Position: number of seconds recorded (will stop at 10)');
  920. addItemToList(list, 'Status will change to Stopped when finished recording');
  921. addItemToList(list, 'Press play - Will begin playing the recording. Status: Running, Duration: # of seconds of recording, Position: Current position of recording');
  922. addItemToList(list, 'Press stop - Will stop playing the recording. Status: Stopped, Duration: # of seconds of recording, Position: 0 sec');
  923. addItemToList(list, 'Press play - Will begin playing the recording from the beginning');
  924. addItemToList(list, 'Press pause - Will pause the playback of the recording. Status: Paused, Duration: # of seconds of recording, Position: Position where recording was paused');
  925. addItemToList(list, 'Press play - Will begin playing the recording from where it was paused');
  926. div = document.createElement('div');
  927. div.setAttribute("style", "background:#B0C4DE;border:1px solid #FFA07A;margin:15px 6px 0px;min-width:295px;max-width:97%;padding:4px 0px 2px 10px;min-height:160px;max-height:200px;overflow:auto");
  928. div.appendChild(list);
  929. contentEl.appendChild(div);
  930. };