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.
Archived Comments
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.
Just curious - what would you like to see added?
I just wanted it normalized so that you don't have to do things like "if android" in your code.
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
@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?
@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.
eg: https://github.com/crosswal...
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.
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!
"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.
Hi. Can you post one with multiple variables?
Why? It should work relatively similar. If you don't see that, share code via a pastebin.
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.
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?
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
}
Call the release() in the media success callback.
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);
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. :)
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!
It might be worth pointing out, Cordova's media plugin does not work with .wav files but .mp3 files.
Hi, I just try your code, but can you put some sample with pause and stop button. Thank you
For the most part, they just work as is. Are you having trouble with them?
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 ?
I'm confused - are you using the API or video tags?
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! ;)
Nope. Docs here: https://github.com/apache/c...
Do you have an example where you record audio using this plugin?
Sorry, no, not yet.
You saved my life
Happy to help. :)
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...
Also consider: http://www.raymondcamden.co...
Hi, can you put some sample with pause and stop button.
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.
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) :)
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.
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 ?
No idea. Did you try? :)
Yes and it's not work. Maybe I'm doing something wrong :(
What did you see in the browser console? (When you remote debug I mean.)
When I click on the play button after a short time shows: " Media Player error (1, -1004)"
Ok, so next I'd check the Media player docs and see what error code 1 equals.
Thanks :)
Yes, you can do! But you need the real url, in this case http://icecast.omroep.nl/ra...
For basic test,
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
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
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!
Hmm. Does the case match? I ran into that once. And you have "sounds" as a subfolder under www, right? What platform?
Did you find any result ? :)
Are you asking about how Cordova differs from PhoneGap?
You should check the PhoneGap Build docs on how to enable plugins.
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.
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.
No, but it may just work. If you have the file location, try using it and see what happens.
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!!!!
I honestly don't know - I'd check with the plugin itself. (And if you find something cool, let us know!)
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...
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.
This perhaps: https://github.com/homerour...
Yes but i really need a well explained example on this? can you help
Not any time soon. Best I can suggest is giving the plugin a try. :)
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
Raymond, good job. Can you please share some idea, pointer or code to sniff/record audio packets while talking on phone.
I'm not aware of any plugin that can do that - but you can check the plugin directory of course.
Thanks for you post, you made my evening.
Works like a charm
You are most welcome.
wow nice tutorial, can u solve my problem http://stackoverflow.com/qu...
No, sorry, but your comment isn't about this blog post and isn't appropriate.
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?
Sorry - I don't.
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?
No hablo espanol.
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.