Using Mobile Media API (MMAPI)
 
A D V E R T I S E M E N T 
Perhaps the easiest way to learn about MMAPI is to start by acquiring and 
playing a simple audio file. All multimedia operations, whether simple audio 
playback or complex video capture, will follow similar patterns. The 
Manager class will be used to create a Player instance using 
a String locator. The Player will then be realized, 
prefetched and played till it is time to close it. There are small differences, 
and I will point these out as we go along. 
Figure 3 shows part of the operation of this simple audio file playback. 
  
Figure 3. Simple audio file playback 
When the user launches the MIDlet, he is given the option of playing the only 
item in the list, which is a "Siren from jar" item. On selecting this item, the 
screen changes to show the text "Playing media" and two commands become 
available to the user: pause and stop. The media starts playing in the 
background and the user can pause the audio or stop and return to the one item 
list. 
The corresponding code is shown in Listing 1. 
package com.j2me.part4;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.media.Player;
import javax.microedition.media.Control;
import javax.microedition.media.Manager;
import javax.microedition.media.PlayerListener;
public class MediaMIDlet extends MIDlet
  implements CommandListener, PlayerListener {
  private Display display;
  private List itemList;
  private Form form;
  private Command stopCommand;
  private Command pauseCommand;
  private Command startCommand;
  private Hashtable items;
  private Hashtable itemsInfo;
  private Player player;
  public MediaMIDlet() {
    display = Display.getDisplay(this);
    // creates an item list to let you select multimedia files to play
    itemList = new List("Select an item to play", List.IMPLICIT);
    // stop, pause and restart commands
    stopCommand = new Command("Stop", Command.STOP, 1);
    pauseCommand = new Command("Pause", Command.ITEM, 1);
    startCommand = new Command("Start", Command.ITEM, 1);
    // a form to display when items are being played
    form = new Form("Playing media");
    // the form acts as the interface to stop and pause the media
    form.addCommand(stopCommand);
    form.addCommand(pauseCommand);
    form.setCommandListener(this);
    // create a hashtable of items
    items = new Hashtable();
    // and a hashtable to hold information about them
    itemsInfo = new Hashtable();
    // and populate both of them
    items.put("Siren from jar", "file://siren.wav");
    itemsInfo.put("Siren from jar", "audio/x-wav");
  }
  public void startApp() {
    // when MIDlet is started, use the item list to display elements
    for(Enumeration en = items.keys(); en.hasMoreElements();) {
    itemList.append((String)en.nextElement(), null);
  }
    itemList.setCommandListener(this);
    // show the list when MIDlet is started
    display.setCurrent(itemList);
  }
  public void pauseApp() {
    // pause the player
    try {
      if(player != null) player.stop();
    } catch(Exception e) {}
  }
  public void destroyApp(boolean unconditional) {
    if(player != null) player.close(); // close the player
  }
  public void commandAction(Command command, Displayable disp) {
    // generic command handler
    // if list is displayed, the user wants to play the item
    if(disp instanceof List) {
      List list = ((List)disp);
      String key = list.getString(list.getSelectedIndex());
      // try and play the selected file
      try {
        playMedia((String)items.get(key), key);
      } catch (Exception e) {
        System.err.println("Unable to play: " + e);
        e.printStackTrace();
      }
    } else if(disp instanceof Form) {
      // if showing form, means the media is being played
      // and the user is trying to stop or pause the player
      try {
        if(command == stopCommand) { // if stopping the media play
          player.close(); // close the player
          display.setCurrent(itemList); // redisplay the list of media
          form.removeCommand(startCommand); // remove the start command
          form.addCommand(pauseCommand); // add the pause command
        } else if(command == pauseCommand) { // if pausing
          player.stop(); // pauses the media, note that it is called stop
          form.removeCommand(pauseCommand); // remove the pause command
          form.addCommand(startCommand); // add the start (restart) command
        } else if(command == startCommand) { // if restarting
          player.start(); // starts from where the last pause was called
          form.removeCommand(startCommand);
          form.addCommand(pauseCommand);
        }
      } catch(Exception e) {
        System.err.println(e);
      }
    }
  }
  /* Creates Player and plays media for the first time */
  private void playMedia(String locator, String key) throws Exception {
    // locate the actual file, we are only dealing
    // with file based media here
    String file = locator.substring(
      locator.indexOf("file://") + 6,
      locator.length());
    // create the player
    // loading it as a resource and using information about it
    // from the itemsInfo hashtable
    player = Manager.createPlayer(
        getClass().getResourceAsStream(file), (String)itemsInfo.get(key));
    // a listener to handle player events like starting, closing etc
    player.addPlayerListener(this);
    player.setLoopCount(-1); // play indefinitely
    player.prefetch(); // prefetch
    player.realize(); // realize
    player.start(); // and start
  }
  /* Handle player events */
  public void playerUpdate(Player player, String event, Object eventData) {
    // if the event is that the player has started, show the form
    // but only if the event data indicates that the event relates to newly
    // stated player, as the STARTED event is fired even if a player is
    // restarted. Note that eventData indicates the time at which the start
    // event is fired.
    if(event.equals(PlayerListener.STARTED) &&
      new Long(0L).equals((Long)eventData)) {
      display.setCurrent(form);
    } else if(event.equals(PlayerListener.CLOSED)) {
      form.deleteAll(); // clears the form of any previous controls
    }
  }
}
 
Listing 1. Simple Audio playback 
You now have an audio player with code that leaves room to add playback for 
other media. To start, the MIDlet displays a list of items that can be played. 
At the moment, it only contains a single item called "Siren from jar". Notice 
that in the code, "Siren from jar" corresponds to a file-based access. This 
implies that the actual location of this media will be in the MIDlet jar file. 
When the user selects this item, a Player object is created 
specifically for it in the playMedia() method. This method loads 
this player, attaches a listener to it, prefetches it, realizes it and finally, 
starts it. Also notice that it plays the media continually. 
Because the listener for the Player is the MIDlet class itself, the 
playerUpdate() method catches the player events. Thus, when the user 
starts hearing the siren, the Form is displayed, allowing the user to stop or 
pause it. Stop takes the user back to the list, while pause pauses the siren and 
replays from the paused marker when restarted. 
Having created this generic class, it is now fairly easy to add other types 
of media to it. Besides audio, video is the primary media that would be played. 
To allow the MediaMIDlet to play video, the only change that needs to be made is 
in the playerUpdate() method, to create a video screen. This is 
shown in the following code snippet, with the changes highlighted in bold. 
/* Handle player events */
  public void playerUpdate(Player player, String event, Object eventData) {
    // if the event is that the player has started, show the form
	// but only if the event data indicates that the event relates to newly
	// stated player, as the STARTED event is fired even if a player is
	// restarted. Note that eventData indicates the time at which the start
	// event is fired.
	If(event.equals(PlayerListener.STARTED) &&
	  new Long(0L)Equals((Long)eventData)) {
        // see if we can show a video control, depending on whether the media
		// is a video or not
		VideoControl vc = null;
		if((vc = (VideoControl)player.getControl("VideoControl")) != null) {
		  Item videoDisp =
			(Item)vc.initDisplayMode(vc.USE_GUI_PRIMITIVE, null);
		  form.append(videoDisp);
		}
		display.setCurrent(form);
	} else if(event.equals(PlayerListener.CLOSED)) {
	  form.deleteAll(); // clears the form of any previous controls
	}
  } 
  
The change allows you to play video files with the help of this MediaMIDlet 
as well. If the method determines that the player has a VideoControl, it exposes 
it by creating a GUI for it. This GUI is then attached to the current form. Of 
course, now you need to attach a video file to the list so that you can test it.
 
Recall that not all mobile phones will play all video files (or audio files 
for that matter). To see the list of video files supported by a device, use the
Manager.getSupportedContentTypes(null) method. In the case of the 
Wireless Toolkit, video/mpeg is supported and therefore,
this video will 
play. Add this to the list as shown here 
items.put("Promo Video from jar", "file://promo.mpg");
itemsInfo.put("Promo Video from jar", "video/mpeg"); 
put the video in the res folder, and you should now be able to 
select and play it as well when the MIDlet is run. The result is shown in Figure 
4. 
  
Figure 4. Video playback with MediaMIDlet 
 |