Cordova Media API Example

This post is more than 2 years old.

A few months ago I launched a new GitHub repo (https://github.com/cfjedimaster/Cordova-Examples) as a way to try to collect my various Cordova examples together under one roof. I had planned to add to it regularly but - life - as you know - gets in the way. I've finally gotten around to adding another example, this one for the Media API.

Specifically, my example looks at how to play a MP3 file that is shipped with your application. You would think this would be trivial. Assuming I've got a folder under www called sounds and a MP3 file called something.mp3, you would think this would do it:

var media = new Media("sounds/something.mp3", null, mediaError);
media.play();

Unfortunately, this breaks in Android. Why? Because Android. (No, no, I kid, sorry.) Specifically Android requires slightly different "pathing" to get to the same source. Specifically it requires this in front of the path: /android_asset/www/

So what I did was write a simple utility function that makes use of the Device API. Consider:

document.addEventListener('deviceready', onDeviceReady, false);

function onDeviceReady() {
	document.querySelector("#playMp3").addEventListener("touchend", playMP3, false);
};

function playMP3() {
    var mp3URL = getMediaURL("sounds/button-1.mp3");
    var media = new Media(mp3URL, null, mediaError);
    media.play();
}

function getMediaURL(s) {
    if(device.platform.toLowerCase() === "android") return "/android_asset/www/" + s;
    return s;
}

function mediaError(e) {
    alert('Media Error');
    alert(JSON.stringify(e));
}

All I've done is sniff for the Android platform and modify the passed-in path value to add the Android prefix. I did not test this outside of iOS and Android so I can't say if it will work in Blackberry or Firefox, but, it gives you a basic idea of how to use a MP3 in your application.

You can find the source for this particular project here: https://github.com/cfjedimaster/Cordova-Examples/tree/master/mp3. As a reminder, you can clone the entire repository, and when you make a new Cordova project, simply use the --copy-from attribute to copy in my source code.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Simon MacDonald posted on 6/24/2014 at 1:47 AM

It makes me sad that I wrote this blog post (http://simonmacdonald.blogs... back in 2011 and the state of the Media API still hasn't progressed.

Comment 2 by Raymond Camden posted on 6/24/2014 at 4:59 AM

Just curious - what would you like to see added?

Comment 3 by Simon MacDonald posted on 6/24/2014 at 6:39 AM

I just wanted it normalized so that you don't have to do things like "if android" in your code.

Comment 4 by dawesi posted on 6/24/2014 at 11:54 AM

I've heard the Intel crosswalk webview replacement is miles better than the standard one for audio, have you used crosswalk at all with pg/cordova?

https://crosswalk-project.org

Comment 5 by Raymond Camden posted on 6/24/2014 at 6:12 PM

@Simon: Ah. Query - and yeah - I could test this and will in a bit - but it seems odd that if you do an XHR to /foo.txt, it works (afaik). So it's just the Media object resolving / to app root in Android versus www.

@Dawesi: It looks Crosswalk would be used *instead* of Cordova, not with it. Am I reading right?

Comment 6 by dawesi posted on 6/25/2014 at 2:10 AM

@Ray, Apparently you can embed cakewalk in cordova also giving you a bunch of HTML5 full feature apis out of the box (webgl, audio, etc) and the browser is faster, you your app loads and runs snappier...

This would mean you could do things like slow down the track (for musician practice) without pitch bending and other music metadata beyond the basics so you can do waveforms and alike... and then use webgl for visualising those waveforms....

so I'm just starting to look into this, so was wondering if you or any of the internal Adobe guys had looked at cakewalk in this context.

Comment 7 by dawesi posted on 6/25/2014 at 2:34 AM
Comment 8 by Raymond Camden posted on 6/25/2014 at 6:33 AM

Oh interesting. I can't speak to if any of the Adobe folks are looking at this. I'm not on the PhoneGap team and am just doing documentation stuff - nothing related to PhoneGap, or web standards, at all.

Comment 9 by Nathan posted on 6/25/2014 at 3:32 PM

Hi Raymond. Great article, thanks for spending the time to post it.

I have a quick question regarding uri path used to store content if you don't mind. In your example you have used '/android_asset/www/', which would (I'm assuming) store the data on the devices internal memory. What would be the preferred path to use to store data on the devices external memory? I've seen file:/// and content:// and even /Android/data/<package-name> (for Android only) used, is there a best practice method that works across devices (possibly across iOS and Android?)

Many regards!

Comment 10 by Raymond Camden posted on 6/25/2014 at 5:37 PM

"which would (I'm assuming) store the data on the devices internal memory. "
to be clear, I'm not storing anything. I shipped a MP3 with my app itself. Which, I guess, is "storing" it, but the Media call *itself* is not storing anything.

The use of /android_asset/www is only there because on Android, the path requires it.

Comment 11 by Khan Cross posted on 6/27/2014 at 2:51 PM

Hi. Can you post one with multiple variables?

Comment 12 by Raymond Camden posted on 6/27/2014 at 5:53 PM

Why? It should work relatively similar. If you don't see that, share code via a pastebin.

Comment 13 by James Wong posted on 8/4/2014 at 6:44 AM

Does the Cordova dev team has no plan to improve Media API? I mean, getting rid of it entirely and implementing something that is closer to HTML5/ W3C standards.

As Simon MacDonald pointed out, things havent changed since 2011.

Comment 14 by Raymond Camden posted on 8/4/2014 at 6:52 AM

The Cordova "dev team" is anyone and everyone. Cordova is open source so if this is something you care about it, you could try to improve it yourself, right?

Comment 15 by Siddharth posted on 8/17/2014 at 6:26 AM

I agree with Simon. Conditionally testing for platform is no good. Also how do I release the resource occupied by the media file.

For example:

function playAudio(audioTrack){
var media = new Media(path_to_audioTrack);
media.play();
// Now the standard media.release() does not work as intended.
// If media.release() is included after the media.play(), the user cant hear
// the audio being played. I tried with releasing after time interval, but no success
}

Comment 16 (In reply to #15) by Steven Benjamin posted on 12/5/2014 at 11:58 AM

Call the release() in the media success callback.

Comment 17 by Steven Benjamin posted on 12/5/2014 at 12:19 PM

Ray, I think if you use the file API this will manage the file locations for you.

for example: fileSystem.root.getFile("recording.mp3", { create: false, exclusive: false }, _gotFileSuccess, _gotFileError);

Comment 18 (In reply to #17) by Raymond Camden posted on 12/5/2014 at 7:13 PM

Hmm, good point. I'd probably still go with my workaround as it requires one less callback and one less plugin. Although what you have may be more future proof too. :)

Comment 19 by David villota posted on 3/17/2015 at 6:36 AM

you are the best with your code i can use this service on my aplication !! thanks a lot for your post you help a lot dont you even imagine how much!! thanks!

Comment 20 by J Lee posted on 4/21/2015 at 2:17 PM

It might be worth pointing out, Cordova's media plugin does not work with .wav files but .mp3 files.

Comment 21 by PLa5teRz posted on 4/29/2015 at 5:32 PM

Hi, I just try your code, but can you put some sample with pause and stop button. Thank you

Comment 22 (In reply to #21) by Raymond Camden posted on 4/30/2015 at 1:39 AM

For the most part, they just work as is. Are you having trouble with them?

Comment 23 (In reply to #22) by Colin Hamilton posted on 6/2/2015 at 1:36 PM

Is there a solution to play local mp4? Nexus 7 seems to work for <video src="mylocal.mp4"> etc but not for Galaxy tab. this media API only works for audio? why not video ?

Comment 24 (In reply to #23) by Raymond Camden posted on 6/2/2015 at 2:43 PM

I'm confused - are you using the API or video tags?

Comment 25 (In reply to #24) by Colin Hamilton posted on 6/3/2015 at 10:19 AM

Sorry:
I am currently using <video> tags and looking to use the API. I see the API plays audio, does it play video? if so then that would probably sort out all my woes! ;)

Comment 26 (In reply to #25) by Raymond Camden posted on 6/3/2015 at 7:07 PM
Comment 27 by Luis Troya posted on 7/17/2015 at 3:39 PM

Do you have an example where you record audio using this plugin?

Comment 28 (In reply to #27) by Raymond Camden posted on 7/17/2015 at 7:53 PM

Sorry, no, not yet.

Comment 29 by Taehwa posted on 9/15/2015 at 1:47 PM

You saved my life

Comment 30 (In reply to #29) by Raymond Camden posted on 9/15/2015 at 1:53 PM

Happy to help. :)

Comment 31 (In reply to #27) by Victor Adrian Sosa Herrera posted on 9/15/2015 at 1:59 PM

Hello Luis. This is a somewhat old article, but maybe it can help you to use the audio in a Cordova app
http://www.ibm.com/develope...

Comment 32 (In reply to #27) by Raymond Camden posted on 9/15/2015 at 2:02 PM
Comment 33 (In reply to #22) by Fateen Ansyakira posted on 12/25/2015 at 3:33 PM

Hi, can you put some sample with pause and stop button.

Comment 34 (In reply to #33) by Raymond Camden posted on 12/26/2015 at 5:59 PM

I don't have one handy - but it is pretty simple. The Media object has a pause and stop method. If you have buttons and add touch handlers, it is pretty simple.

Comment 35 (In reply to #20) by Mitch Lillie posted on 1/4/2016 at 3:25 AM

This little note just fixed everything, thank you from 8 months into the future! Did you see this in the Cordova docs or just learn from experience? All I see there re: filetypes is notes on the types of audio allowed for recording. Also found there's no way to record and playback a file locally on an iPhone (recording only in .wav, playback only in .mp3) :)

Comment 36 (In reply to #35) by J Lee posted on 1/13/2016 at 3:40 PM

Unfortunately, it took hours of head scratching and a lucky hunch to realize the problem was with the .wav files. I'm glad this helped you but it's also a shame it hasn't been fixed yet.

Comment 37 by Sebastianor posted on 2/22/2016 at 12:20 PM

Do you have any idea how create this for streaming audio ? For example I would like add src="http://icecast.omroep.nl/ra..." Is this possible ?

Comment 38 (In reply to #37) by Raymond Camden posted on 2/22/2016 at 12:52 PM

No idea. Did you try? :)

Comment 39 (In reply to #38) by Sebastianor posted on 2/23/2016 at 7:26 AM

Yes and it's not work. Maybe I'm doing something wrong :(

Comment 40 (In reply to #39) by Raymond Camden posted on 2/23/2016 at 2:05 PM

What did you see in the browser console? (When you remote debug I mean.)

Comment 41 (In reply to #40) by Sebastianor posted on 2/24/2016 at 7:33 AM

When I click on the play button after a short time shows: " Media Player error (1, -1004)"

Comment 42 (In reply to #41) by Raymond Camden posted on 2/24/2016 at 11:55 AM

Ok, so next I'd check the Media player docs and see what error code 1 equals.

Comment 43 (In reply to #42) by Sebastianor posted on 2/25/2016 at 9:39 AM

Thanks :)

Comment 44 (In reply to #37) by Anderson posted on 2/25/2016 at 2:55 PM

Yes, you can do! But you need the real url, in this case http://icecast.omroep.nl/ra...

For basic test,

var media = new Media("http://icecast.omroep.nl/radio1-bb-mp3");
media.play();

If you have an exposed API, you can retrieve url's via JSON, or XML, if not, you need to parse the playlist first, to get url

Comment 45 by Ryan Phung posted on 3/8/2016 at 5:17 PM

Raymond Camden thanks for the article. I've been scratching my head over this problem for the whole evening, regardless of how I define the path to my mp3 file, it stubbornly gives me this error

"Cannot use audio file from resource 'sounds/button-1.mp3'"

And yes, I tried your example from github as well with the same error. Hope you or someone here has encountered this problem before and can enlighten. Thanks!

Comment 46 (In reply to #45) by Raymond Camden posted on 3/8/2016 at 9:05 PM

Hmm. Does the case match? I ran into that once. And you have "sounds" as a subfolder under www, right? What platform?

Comment 47 (In reply to #42) by Sebastianor posted on 3/14/2016 at 7:45 AM

Did you find any result ? :)

Comment 48 (In reply to #0) by Raymond Camden posted on 3/24/2016 at 12:57 PM

Are you asking about how Cordova differs from PhoneGap?

Comment 49 (In reply to #0) by Raymond Camden posted on 3/25/2016 at 1:25 PM

You should check the PhoneGap Build docs on how to enable plugins.

Comment 50 (In reply to #46) by Curtis Robinson posted on 6/24/2016 at 1:16 AM

I have the same problem. I'm on iOS. It doesn't matter if i use mp3 or wav I can't get anything to load. My wavs are in a folder called sounds in www. I used to instead use lowlatencyaudio plugin and that worked.

Comment 51 by Mikael Oliveira posted on 11/4/2016 at 11:07 AM

Hello Raymond. Do you have any example playing mp3 from the sdcard? With a input button where the user load the sound to pay it. Thanks.

Comment 52 (In reply to #51) by Raymond Camden posted on 11/4/2016 at 2:00 PM

No, but it may just work. If you have the file location, try using it and see what happens.

Comment 53 by Fabricio Echeverría posted on 11/21/2016 at 9:50 PM

Hi Raymond, excellent article. You know if exist alternative to play audio with this plugin using buffer array? I download a wav file and I dont know how to playing. AudioContext it's works for Lollipop but not for kitkat. Thansk!!!!

Comment 54 (In reply to #53) by Raymond Camden posted on 11/21/2016 at 11:22 PM

I honestly don't know - I'd check with the plugin itself. (And if you find something cool, let us know!)

Comment 55 by adedeji92 posted on 11/29/2016 at 5:32 PM

Hello Boss, excellent article, Can we have a way to add music controller(Like next, previous and
play/pause) in the notification bar. any help? Attached image is an
example https://uploads.disquscdn.c...

Comment 56 (In reply to #55) by Raymond Camden posted on 11/30/2016 at 11:21 AM

I'm not sure. I'd check the Cordova plugins directory to see if they have a way to add audio controls there. I've never seen that before myself.

Comment 57 (In reply to #56) by Raymond Camden posted on 11/30/2016 at 11:21 AM
Comment 58 (In reply to #57) by adedeji92 posted on 11/30/2016 at 6:11 PM

Yes but i really need a well explained example on this? can you help

Comment 59 (In reply to #58) by Raymond Camden posted on 11/30/2016 at 6:26 PM

Not any time soon. Best I can suggest is giving the plugin a try. :)

Comment 60 (In reply to #59) by Brahma chaitanya posted on 12/1/2016 at 11:21 AM

Raymond Camden well done with MusicControl App thanks a lot for pretty cool and well explained way . It will be a great help how to connect with html5 in ionic 2

Comment 61 by Nag posted on 12/6/2016 at 5:19 PM

Raymond, good job. Can you please share some idea, pointer or code to sniff/record audio packets while talking on phone.

Comment 62 (In reply to #61) by Raymond Camden posted on 12/6/2016 at 5:31 PM

I'm not aware of any plugin that can do that - but you can check the plugin directory of course.

Comment 63 by David Verriere posted on 1/2/2017 at 8:46 PM

Thanks for you post, you made my evening.
Works like a charm

Comment 64 (In reply to #63) by Raymond Camden posted on 1/2/2017 at 9:03 PM

You are most welcome.

Comment 65 by yokesh posted on 1/30/2017 at 10:22 AM

wow nice tutorial, can u solve my problem http://stackoverflow.com/qu...

Comment 66 (In reply to #65) by Raymond Camden posted on 1/30/2017 at 12:29 PM

No, sorry, but your comment isn't about this blog post and isn't appropriate.

Comment 67 by Şenol Ataç posted on 2/28/2017 at 3:26 PM

Raymond thanks for your post, I implement your example on my radio project. Most of radio streams work immediately by trigger play button but some of them has a delay approximately 40seconds. For example, "http://85.111.25.40:8000/stream/1/;" this stream works but there is a delay.
http://stackoverflow.com/qu...

Do you have any suggestion or solution?

Comment 68 (In reply to #67) by Raymond Camden posted on 2/28/2017 at 3:27 PM

Sorry - I don't.

Comment 69 by Rubens posted on 8/29/2017 at 7:27 PM

Excelete artigo Raymond, vocês americanos são previlegiados pelo Inglês, aqui no brasil tudo é meia boca, me tire uma dúvida, apesar de eu declarar valor 0: numberOfLoops:0, repete continuamente no android, Como faço para reproduzir o audio apenas 1 vez?

Comment 70 (In reply to #69) by Raymond Camden posted on 8/29/2017 at 7:37 PM

No hablo espanol.

Comment 71 (In reply to #0) by Raymond Camden posted on 9/6/2017 at 1:13 PM

If it isn't supported by the plugin, then I don't know. Best I can suggest is what I'd do - google for it.