In our last lesson we learned how to save our game settings, the Sound On/Off screen, but why we have this option, if we don’t have any sound in our game? It’s time to learn about Java Mobile Multimedia API (MMAPI) and add some sound to our game. Let’s rock!
MMAPI offers a set of multimedia capabilities for mobile devices, including playback and recording of audio and video data from a variety of sources. Of course, not all mobile devices support all the options, but MMAPI is designed in such a way that it takes full advantage of the capabilities that are available, while ignoring those that it cannot support.
MMAPI Info
The MMAPI is built on a high-level abstraction of all the multimedia devices. This abstraction is implemented in three classes that form the core of operations that you do with this API. These classes are the Player and Control interfaces, and the Manager class. Another class, the DataSource abstract class, is used to locate resources, but unless you define a new way of reading data you will probably never need to use it directly.
In a nutshell, you use the Manager class to create Player instances for different media by specifying DataSource instances. The Player instances thus created are configurable by using Control instances. For example, almost all Player instances would theoretically support a VolumeControl to control the volume of the Player. Check the following diagram:
So let’s start with the Manager class, basically its a factory of players supporting the following creation methods:
- createPlayer(DataSource source), creates a player based on a DataSource
- createPlayer(InputStream stream, String type), creates a player using the input stream as source and assuming the the media type provided. For a list of media types check at IANA web site.
- createPlayer(String locator), creates a player using a URL type parameter to identify the source data
This last method allows you to alocate different types of media depending of the URL protocol you choose. Here is a list of supported types:
- Midi Player - “device://midi”, creates a midi Player.
- Tone Player - “device://tone”, creates a tone Player.
- Capture Audio - “capture://audio”, allows to capture audio from the device mic.
- Capture Video - “capture://video”, allows to capture video from the device camera.
- Capture Radio - “capture://radio?f=105.1&st=stereo”, allow to capture radio.
If you want to know what content types and protocols are supported for your device, use the following methods of Manager class:
- getSupportedContentTypes(), provides a list of available content types for all protocols or to a specific one.
- getSupportedProtocols(), provides a list of available protocols for all content types or to a specific one.
After you created a Player, you can start using it by simple calling the start() method, when it reach the end of media it will automatically stop.
This is the more simplistic view of the Player class, actually it has five states:
- UNREALIZED, this is the initial state of Player when obtain from the Manager.
- REALIZED, when realized() is called the Player switch to this state obtaining the information required to acquire the media resources. Realizing a Player can be a resource and time consuming process. The Player may have to communicate with a server, read a file, or interact with a set of objects.
- PREFETCHED, after a player is realized, it may still need to acquire scarce or exclusive resources, fill buffers with media data, or perform other start-up processing. This is done by calling the prefetch() method that switch the player to this state.
- STARTED, when start() is called the Player starts to play the media resource until it reach the end of the media.
- CLOSED, when close() is called the Player switch to this state, releasing all the resources acquired. It can’t be used again.
The following figure shows the various states and the transitions possible between them:
If your application needs information about the state changes you need to implement the PlayerListerner interface.
Play a Sound
Now that he have all the background information about MMAPI, let’s start using it in our Arkanoid clone. The idea is to play a sound each time the ball hits a brick or the pad. To do this we are going to create a class called Multimedia with a playSound() method:
//multimedia libraries
import javax.microedition.media.Manager;
import javax.microedition.media.Player;
import javax.microedition.media.MediaException;
public class Multimedia {
public void playSound(String file, String format) {
try {
InputStream is = getClass().getResourceAsStream(file);
Player p = Manager.createPlayer(is, format);
p.start();
} catch (IOException ioe) {
} catch (MediaException me) {
}
}
Now he just need to use this method each time we detect a collision between the ball and the other entities. I created for this purpose a sound named “click.wav” that i added to our resource folder.
public void updateGameState(){
...
byte colision = ball.colided(pad);
if (colision != Entity.COLLISION_NONE){
if (midlet.soundOn){
midlet.multimedia.playSound("click.wav", "audio/X-wav");
}
}
...
}
If you run your application, you will finally hear some sound on your game.
Capture video
Now that we have sound let’s add another cool feature, let’s capture the player photo each time he achieves a high score. For that we first need to access the camera video and show it to the player, the following method captures the camera video stream to an Item.
Player p;
VideoControl vc;
public Item showVideo(String url){
Item result = null;
try {
p = Manager.createPlayer(url);
p.realize();
// Grab the video control .
vc = (VideoControl)p.getControl("VideoControl");
if (vc != null) {
// create the Item with the video image
result =((Item)vc.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, null));
// add a label
result.setLabel("Photo");
}
// start capture
p.start();
} catch (IOException ioe) {
} catch (MediaException me) { }
return result;
}
As you can see we are using a Control, the VideoControl, to create the Item to use in our Form.
public Displayable initNewHighScore(int score, int pos) {
...
newHighScoreForm.append(multimedia.showVideo("capture://video"));
...
}
Now we need to use our VideoControl to capture an image from the camera,
public Image captureVideo(){
Image result = null;
try {
// grab data
byte[] imageData = vc.getSnapshot("encoding=png");
// create image;
result = Image.createImage(imageData, 0, imageData.length);
} catch (MediaException me) {
me.printStackTrace();
}
return result;
}
and then call this method when we save a high score.
// we added an extra field to Score to store the image scores[pos].image = multimedia.captureVideo();
After this we just need to show our images in the high scores screen.
public Displayable initScoreForm() {
...
if (scores[i].image != null){
highScoreForm.append(scores[i].image);
}
...
}
Just run the application to check our new feature! With this we end this lesson, next lesson we are going to see how to use the network capabilities of your phone. See you soon.
Downloads:


Thank you so much for this amazing blog
j2me is so a pleasure with you
Can’t wait to read the next lesson
Nicolas
Thank you for your tutorial, I got one question. I’m trying to exactly the same that you do, in eclipse using the sun java wireless toolkit, and when I do the final part, when the camera it’s showing the animated image. This shows up in my console:
Warning: To avoid potential deadlock, operations that may block, such as networking, should be performed in a different thread than the
commandAction() handler.
and when I press save, it ask “the midlet suite wants to record a snapshot image. is it OK to record”, and when I press YES, it just freeze up.
WHAT CAN I DO?
THANK YOUR SO MUCH FOR YOUR HELP.
Hi Javier
The problem here is that we are trying to do a time consuming task in the UI Thread. To avoid this we need to create a separated thread to do this task. In lesson 7 - (http://sergioestevao.com/midp/?p=48) I show how to do this for the network access you can use the same approach for the video capture.
If you need further help just tell me.
Thanks
Sérgio
Why for years you all went arount blatering about the compatibility if J2ME when every user knows perfectly that the finest application are never compatible among mobiles?
What is this acknowledging silence?
I am disgusted.
I program java since 10 years, I know what I write.
STOP THIS FAKE THAT J2ME IS CROSS-PHONE OK? THANK YOU. It’s only true for basic API usage.
But you NEVER tell this clearly. Oh yes, you tell it once a year… so sorry.. my bad.
PUAH!
Hello, I’ve one question: I need to play mp3 from a server using bluetooth connection. Which is the best way to do it? http, file… and how can i do?