The example will be a basic Media player with play/pause and stop functionality. Here's a quick screen shot:
On Android you can create a Media object using one of three ways. The first way is referencing a file in your "android_asset" directory. For instance if you have a file called "test.mp3" in your projects "assets/www" directory you would create a new media object by doing:
myMedia = new Media("/android_asset/www/test.mp3");The second way to create a media object is by referencing a file on your devices file system. Say for instance, you have a file at "/sdcard/test.mp3" of your device you would create the media object by doing:
myMedia = new Media("test.mp3");You'll notice the "/sdcard/" portion of the file name is omitted. This is because on Android the Media object makes an assumption that the file is stored on your "/sdcard". Note: I may change this behaviour in an upcoming version of PhoneGap but I'll strive to retain backward compatibility.
The third and final way to create a media object is by URL:
myMedia = new Media("http://audio.ibeat.org/content/p1rj1s/p1rj1s_-_rockGuitar.mp3");Now that we've got our media object we want to be able to do the sensible thing and be able to play the audio. For that we'll create a play button:
<a href="#" onclick="playAudio()"><img id="play" src="images/play.png" /></a>and corresponding function:
function playAudio() {
myMedia.play();
}Now the stop button is just as simple:<a href="#" onclick="stopAudio()"><img id="stop" src="images/stop.png" /></a>
function stopAudio() {
myMedia.stop();
}However, that's pretty lame as it would be great to be able to pause the audio playback so let's enhance out play and stop functions:function playAudio() { if (!playing) { myMedia.play(); document.getElementById('play').src = "images/pause.png"; playing = true; } else { myMedia.pause(); document.getElementById('play').src = "images/play.png"; playing = false; } } function stopAudio() { myMedia.stop(); playing = false; document.getElementById('play').src = "images/play.png"; }Now when the user is playing some audio the play button image is changed to a pause button and hitting the pause button again will, well, pause the playing of the audio. I'm cheating a little bit by using a global variable called playing as it could easily be changed to check what the currently set image is and doing the correct action.
Of course it is always nice to know where we are at in a given audio clip so we can add some functionality to get the current position of where we are at in the file. So let's create a function that will run every second and update our HTML with the current position of the audio file.
<p id="audio_position">0.000 sec</p> var mediaTimer = setInterval(function() { myMedia.getCurrentPosition( function(position) { if (position > -1) { document.getElementById('audio_position').innerHTML = (position/1000) + " sec"; } }, function(e) { console.log("Error getting pos=" + e); } ); }, 1000);
That's all well and good but there is one thing that's slipped by our notice so far. When an audio clip finishes playing the pause button should become a play button in case the user wants to play the clip again. That can be accomplished by adding a success call back to our Media object constructor. The success call back is executed when the clip has finished playing. So we'll now instantiate our media like this:
myMedia = new Media("/android_asset/www/test.mp3", stopAudio);So what we have here are the beginnings of a audio player application for Android. In part two of this article I'll enhance the app with the File System and Directory API showing you how to scan your device for audio files.
The HTML and images can be found here and below is a listing of the HTML code uses in this article. I added a select box so that users could switch between the different ways of creating a Media object. You'll have to supply your own MP3 file as I don't want the RIAA coming after me.

54 comments:
Hi Simon,
So there seems to be a fourth way to create a Media object and that is with src=null. For iOS, this seems to create something like "documents://1203044830072" where the numbered part is unique with each creation.
What is it creating?
Thanks for your help,
Jo
If I'm not mistaken if you pass src=null to the Media class on iOS it will make it's own file name using the current date. This file name will be used if you call the startAudioRecord() method.
media.getCurrentPosition and media.getDuration currently do not seem to work in ios , is this support coming in a future release?
Correct, those methods don't work on iOS yet but we are looking into including them for 1.0 due end of July early August.
I've just started developing a media application with PhoneGap, and I noticed that when loading an audio file from a URL, the app becomes unresponsive until it is ready to play. Could this be mitigated by using Web Workers to load them in a different thread?
in simulator it works
but in real device its not work
i want to stream shoutcast
@Rob Archer
I think it has to do with the OpenCore instance being allocated by the Android OS.
@Ibnu Maksum
I'll help you over on the google group.
Hi Simon, i have one cuestion... I made all what u said.. but allways, no matter what i do and what function use i allways get a prompt with this:
gap:["Media","startPlayingAudio","Media0",true]
????... U have any idea what is this... i found the code in phonegap-1.0.0.0.js this code:
var r = prompt(PhoneGap.stringify(args), "gap:"+PhoneGap.stringify([service, action, callbackId, true]));
and this is the prompt what i getting... Plis help!
PS: sorry for my inglish, i just starting with it
thanks for the code!
Hi again Simon.. a few seconds I realized that in the BROWSER allways going to get the prompt, in the divice it s Work Amazin! Both codes, your and mine.
Thanks again.
Best regards
In the example above - with the file page "/android_asset/www/test.mp3" ... will this work "out of the box" on an iPhone is the test.mp3 file is in the same place (www/test.mp3)?
@Dr Senior
No, it won't work out of the box on iOS as it has no concept of the android_asset directory. You'll need to do a conditional for now to determine if you are on iOS or Android and pass the appropriate path.
I'm advocating we spend some time in 1.1 to make Media sane across all platforms.
Hello, does media.getDuration work yet on iOS?
@anh
It should but if it doesn't open an issue on github and we'll get it fixed.
https://github.com/phonegap/phonegap-iphone/issues
hi, can you explain, how to use a playlist (play several files sequentially)?
@Lars
I've been meaning to write some code to do exactly that. I would keep and array of file names or urls then in my onSuccess method of the Media constructor, which is stopAudio in the example, I would add one to my array index create the new Media object and start playing.
To make things faster I'd probably keep a buffer of 3 to 5 Media objects so that people could skip or go back in the play list.
Hi Simon,
i wanna add the ID3 in the player,
i used from this library :
http://web.ist.utl.pt/antonio.afonso/www.aadsm.net//libraries/id3/
http://github.com/aadsm/JavaScript-ID3-Reader
this is my code:
var file="/sdcard/music.mp3";
function callback() {
var pic = ID3.getTag(file, "picture");
var artist = ID3.getTag(file, "artist");
var title = ID3.getTag(file, "title");
document.getElementById('judul').innerHTML = artist+ "\r\n";
document.getElementById('judul').innerHTML += title+ "\r\n";
document.getElementById('urlartis').src = "data:" + pic.format + ";base64," + Base64.encodeBytes(pic.data);
}
myMedia.play();
ID3.loadTags(file, callback, ["picture", "artist", "title"]);
playing = true;
it took 40 second to show the artist & title. but the picture not showed at all.
is there a way to speed up this, and also why the image does'nt show.
thanks before for your help.
Ali
@Arkan
Sorry, I can't help you here as I've never used that library but it looks like a cool one. If I had to guess what it is slow is that they are using JavaScript to read a binary file which it doesn't support out of the box. I number of tricks have to be done for the library to read the binary data.
Hi simon....
Thanks for the tutorial...
I tried it, it working fine in emulator, but it is not working in my device sony erricsson xperia... what is the problem....
@Jithin
The first thing that jumps out at me is that your Sony may not have to proper codec for playing the file. Run "adb logcat" to see what is going on.
Hi simon, thanks for the quick response.
Can i add volume controller for this app. ?
Regard
Jithin
@Jithin yes, you can. There is a setVolume() method on the Android PhoneGap Media class. It is coming to other platforms.
Hi simon,
Can u explay how to run "adb log cat", because a m very new to android.
thanks
jithin
@jithin
adb logcat docs.
thanks simon
Hi simon,
your demo url http://audio.ibeat.org/content/p1rj1s/p1rj1s_-_rockGuitar.mp3 is working fine in both emulator and device. But i applied another url http://live.ardanradio.com:8228/;audio.mp3. but it is working only in emulator, not working in device. i run adb logcat, it showing D/dalvikvm( 2335): GC freed 7225 objects / 344040 bytes in 100ms
W/MediaPlayer( 2335): info/warning (1, 32)
I/MediaPlayer( 2335): Info (1,32)
D/dalvikvm( 2335): GC freed 20579 objects / 799192 bytes in 118ms
D/dalvikvm( 2335): GC freed 17355 objects / 657824 bytes in 115ms.
and also i checked with this shoutcast url:http://62.75.216.8:8008/;audio.mp3. but same problem
@Jithin
Can't test right now as I am at a conference but try removing the /;audio.mp3 from the end of the URL.
hi simon
thanks for the quick response,
i tried with http://62.75.216.8:8008 this url. But working only in emulator but not in emulator.
hello sir me new to phonegap n android development i have audio in binary i.e base 64 format however it does not play on android audio tag.....please help me...
@Unknown the "audio" tag does not work in the WebView for some strange reason. Use the Media class instead.
@Jithin that URL plays fine in the emulator and my Samsung Galaxy S phone. What version of Android is your phone using?
Hai simon,
i am using samsung galaxy s5570(android 2.3)...
Sorry @Jithin I can't reproduce your problem. I wonder if it is a missing codec problem on your phone as, as you say, it works in the emulator.
Hi simon,
I don't know what wrong thing i did. i checked with these two url 1. http://62.75.216.8:8008
2. http://stream.lexandterry.com:8000
But first one working only in emulator and second one working in both device(samsung galaxy s) and emulator. After that i checked with sony Ericsson experia. But same problem happening.
Sorry @Jithin, I don't know what to tell you. Some devices may not support streaming audio. I know you need Android 2.2 or better for this to work though.
hello Simon Sir,
my application requires me to play mp3 BASE64 audio..
phonegap my media doesn't play bas64 audio source...
kindly help Thanks in advance...
@Unknown you'd have to write a plugin to convert your base64 encoded mp3 to a binary file and then pass that the the Media class to be played.
Dear Simon,
Thanks for writing this awesome tutorial. I'm having trouble getting the full filepath of the new recorded Media object and uploading it to the server. I wonder if you could suggest how to do it? I've already tried just saving it to android_asset but file upload doesn't work with /android_asset/www/myrecording.mp3 - I know the problem isn't with my file upload methods because I can already upload other files. I just can't get the fullpath of this recording I've made using your recorder/player code.
@Andrea Levinge
That's because the Media class isn't following any know spec. The file name you pass in is assumed to be under /sdcard. So if you pass in temp/data/record.mp3 the file will end up at /sdcard/temp/data/record.mp3.
You cannot save files to the android_assets directory as that is a "virtual" directory that is part of your .apk.
Hi Simon,
Thank you so much for replying!
I created a new Media file:
mediaRec = new Media('myrecording.amr', onSuccess, onError);
mediaRec.startRecord();
I want to get that mediaRec's fullPath.
I check where the file is actually located on my sdcard and it's located at /mnt/sdcard/external_sd/
I've tried the following filepaths for uploading:
/mnt/sdcard/external_sd/myrecording.amr
/sdcard/myrecording.amr
myrecording.amr
but the upload always fails as if the file does not exist.
I've successfully uploaded photos and videos already but those were captured using the example code from the API. This recording uses a new Media object. I suspect it is saving it at content://media/external but I don't know how to get the URI of the new Media object I've created. All I know is that photos are getting temporarily saved to content://media/external/images/media/ but I'm sure that's different for audio recordings. I've tried grabbing it from the onSuccess method, but it seems to pass nothing to the onSuccess method when creating a new Media file.
Let us know when your book comes out, I will be ordering it for sure.
Kukulako from Puerto Rico...
Can I put seek bar or progres bar?
@kukulako
Sure, but you'd have to implement it yourself using getDuration and getCurrentPosition.
Simon,
How does this work with PhoneGap Build and PhoneGap 1.2? Where are the media files that are packaged with the application placed and how would I access them cleanly from any platform?
@John
I'm not sure how it would work on the build service as I don't use it. For regular PhoneGap you'd have to do an OS detection and pass the correct prefix along with your file name to the Media constructor.
This has the potential to be great, but can I have a looping background track with an independent volume, while playing a foreground track, or playlist?
@John A
These are some great ideas and we should make the Media class better for people making games. You should raise a ticket at:
https://issues.apache.org/jira/browse/CB
Hi Simon,
Please help me out in displaying the All Songs and playlists of android device and how to access android device media table to display the list using phone gap.
Thanks in advance.
Hi Uday, I haven't written the code yet but what you'd need to do is query the content provider for the available music.
http://developer.android.com/guide/topics/providers/content-providers.html
Thanks Simon for reply,
Is there any way in phonegap to get the data using content provider and display using phonegap javascript and html5. Do i need to write any phone gag plug in to read data using content provider.
@Uday
Yes, you'd need to write a plugin for that type of functionality.
@Andrea
Sorry I missed your comment. After you call stopRecord() the file should be moved to /sdcard. So you should be able to use:
/sdcard/myrecording.amr
of
file:///sdcard/myrecording.amr
In my app, setVolume() possible values are 0.0 - 1.0. It's looking for a float value.
Hi Devgeeks,
I'm testing your demo with a shoutcast streaming url and it does'nt work :(
I tested with the streaming url somebody said in this google group.
The debug window in Xcode stucks on this line:
2012-02-08 15:02:21.274 altafullaradio[3219:13403] Will use resource 'http://live.ardanradio.com:8228/;audio.mp3' from the Internet.
I'm using the latest version of phonegap, and iOS 5.0.1
With a normal mp3 url it works good. But with a streaming url it does'nt
What I should try?
Thank you.
Kind regards,
@MrReview
Sounds like a bug in iOS. I'll let Becky or Shaz address this on the google group where you also asked your question.
Post a Comment