Create the AudioCanvas
class
Import the
required classes and assign this class to the com.nokia.example.mmapi.mediasampler.viewer
package.
package com.nokia.example.mmapi.mediasampler.viewer; import java.util.Vector; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.media.MediaException; import com.nokia.example.mmapi.mediasampler.MediaSamplerMIDlet; import com.nokia.example.mmapi.mediasampler.data.Media; import com.nokia.example.mmapi.mediasampler.data.MediaFactory; import com.nokia.example.mmapi.mediasampler.model.PlayerPool;
Create the AudioCanvas
class
and set it to extend Canvas
and implement CommandListener
.
Define the required constants and create to constructor.
/** * Audio play canvas. Audio clip is played when a key is pressed. */ public class AudioCanvas extends Canvas implements CommandListener { private PlayerPool pool; private MediaSamplerMIDlet midlet; private Displayable returnScreen; protected String[] supportedMediaNames; protected String[] unsupportedMediaNames; protected int countOfPlayers = 0; protected int volume = 100; private boolean initDone; private boolean infoMode; private Command infoCommand = new Command("Info", Command.SCREEN, 1); private Command backCommand = new Command("Back", Command.BACK, 1); public AudioCanvas(MediaSamplerMIDlet midlet, Displayable returnScreen, int latency) { this.midlet = midlet; this.returnScreen = returnScreen; pool = new PlayerPool(midlet, latency); initSounds(); // Init volume level of Players in pool pool.setVolumeLevel(volume); addCommand(backCommand); addCommand(infoCommand); setCommandListener(this); }
Create a method for releasing loaded resources from the pool.
/** * Release loaded resources */ public void releaseResources() { pool.releaseResources(); }
Write code for monitoring commands.
/** * Implemented CommandListener method. */ public void commandAction(Command cmd, Displayable d) { if (cmd == backCommand) { if (infoMode) { infoMode = false; addCommand(infoCommand); repaint(); } else { Display.getDisplay(midlet).setCurrent(returnScreen); } } else if (cmd == infoCommand) { infoMode = true; removeCommand(infoCommand); repaint(); } }
Write code for monitoring key presses.
public void keyPressed(int key) { int keyCode = key - KEY_NUM0; int gameAction = getGameAction(key); // Check is the selected audio available for playing. if (keyCode > 0 && keyCode <= countOfPlayers) { try { pool.playSound(keyCode - 1); } catch (MediaException e) { // Swallow the exception. } } else if (gameAction == UP) { increaseVolume(); } else if (gameAction == DOWN) { decreaseVolume(); } }
Create the paint method for creating the visual outlook of the canvas.
/** * Paint the canvas. */ protected void paint(Graphics g) { int x = 0; int y = 0; int w = getWidth(); int h = getHeight(); g.setColor(0xFFFFFF); g.fillRect(x, y, w, h); Font fontPlain = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); Font fontBold = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL); g.setColor(0x000000); if (infoMode) { boolean multiSupport = pool.supportsMulplePlayers(); boolean mixSupport = "true".equals(System .getProperty("supports.mixing")); g.setFont(fontBold); y = paintTextRow(g, "Supports multiple players:", x, y); g.setFont(fontPlain); y = paintTextRow(g, "" + multiSupport, x, y); g.setFont(fontBold); y = paintTextRow(g, "Supports audio mixing:", x, y); g.setFont(fontPlain); y = paintTextRow(g, "" + mixSupport, x, y); if (unsupportedMediaNames.length > 0) { g.setFont(fontBold); g.setColor(0x000000); y = paintTextRow(g, "Unsupported sounds:", x, y); g.setFont(fontPlain); for (int i = 0; i < unsupportedMediaNames.length; i++) { String str = unsupportedMediaNames[i]; String strToPaint = str; y = paintTextRow(g, strToPaint, x, y); } } } else { g.setFont(fontBold); y = paintTextRow(g, "Sound key mapping:", x, y); g.setFont(fontPlain); for (int i = 0; i < supportedMediaNames.length; i++) { String str = supportedMediaNames[i]; String strToPaint = (i + 1) + " = " + str; y = paintTextRow(g, strToPaint, x, y); } y = paintTextRow(g, "Volume level: " + volume, x, y); } }
Create a method for rendering a row of text to the canvas.
/** * Renders a text row to Canvas. */ private int paintTextRow(Graphics g, String text, int x, int y) { int w = getWidth(); Font font = g.getFont(); for (int j = 0; j < text.length(); j++) { char c = text.charAt(j); int cw = font.charWidth(c); if (x + cw > w) { x = 0; y += font.getHeight(); } g.drawChar(c, x, y, Graphics.TOP | Graphics.LEFT); x += cw; } y += font.getHeight(); return y; }
Create the methods for increasing and decreasing the volume.
private void increaseVolume() { volume += 10; if (volume > 100) { volume = 100; } pool.setVolumeLevel(volume); repaint(); } private void decreaseVolume() { volume -= 10; if (volume < 0) { volume = 0; } pool.setVolumeLevel(volume); repaint(); }
Create a method for loading the sounds and tones to the canvas.
/** * Loads the medias available on this canvas. Loaded sounds are passed to * PlayerPool class which creates players and initializes player states. */ protected void initSounds() { if (!initDone) { countOfPlayers = 0; Vector supportedMedias = new Vector(); Vector unsupportedMedias = new Vector(); // Sound media clips Media[] medias = MediaFactory.getSoundMedias(); for (int i = 0; i < medias.length; i++) { Media media = medias[i]; String mediaName = null; try { mediaName = media.getFile() + " [" + media.getType() + "]"; pool.addMedia(media); supportedMedias.addElement(mediaName); countOfPlayers++; } catch (MediaException e) { System.out.println("unsupported media: " + media.getType()); unsupportedMedias.addElement(mediaName); } } // Tone sequences String mediaName = null; try { mediaName = "Tone sequence"; pool.addToneSequence(MediaFactory.getToneSequence()); supportedMedias.addElement(mediaName); countOfPlayers++; } catch (MediaException e) { System.out.println("Unsupported type: Tone sequence"); e.printStackTrace(); unsupportedMedias.addElement(mediaName); } // Stores results of success and failed Players to String array supportedMediaNames = new String[supportedMedias.size()]; supportedMedias.copyInto(supportedMediaNames); unsupportedMediaNames = new String[unsupportedMedias.size()]; unsupportedMedias.copyInto(unsupportedMediaNames); initDone = true; } } }
Create the MediaList
class
Import the
required classes and assign this class to the com.nokia.example.mmapi.mediasampler.viewer
package.
package com.nokia.example.mmapi.mediasampler.viewer; import javax.microedition.lcdui.*; import com.nokia.example.mmapi.mediasampler.MediaSamplerMIDlet; import com.nokia.example.mmapi.mediasampler.data.Media; import com.nokia.example.mmapi.mediasampler.data.MediaFactory; import com.nokia.example.mmapi.mediasampler.model.DRMPlayer;
Create the MediaList
class
and set it to extend List
and implement CommandListener
.
Define the constants and create the constructor.
/** * Media list is the main view in the MIDlet. From this view the user may swich * to other views. */ public class MediaList extends List implements CommandListener { private final MediaSamplerMIDlet midlet; private final VideoSourceSelector sourceSelector; private AudioCanvas audioCanvas; private SupportForm form; private final Command exitCommand; public MediaList(MediaSamplerMIDlet midlet) { super("Media Sampler", IMPLICIT); this.midlet = midlet; sourceSelector = new VideoSourceSelector(midlet, this); append("Play audio", null); append("Play video", null); append("DRM MIDI", null); append("Check MM API support", null); exitCommand = new Command("Exit", Command.EXIT, 1); addCommand(exitCommand); setCommandListener(this); }
Create a method for releasing all resources that have been loaded by subcomponents.
/** * Release all resources loaded by sub components. */ public void releaseResources() { if (audioCanvas != null) { audioCanvas.releaseResources(); } }
Write code for monitoring commands.
/** * Implemented CommandListener method. * * Sets the selected Example visible */ public void commandAction(Command cmd, Displayable disp) { if (cmd == List.SELECT_COMMAND) { int index = getSelectedIndex(); if (index != -1) // -1 means nothing selected { String selected = getString(index); if (selected.equals("Play video")) { Display.getDisplay(midlet).setCurrent(sourceSelector); } else if (selected.equals("DRM MIDI")) { Media media = MediaFactory.getDRMMidi(); DRMPlayer player = new DRMPlayer(midlet, this); player.playDRMprotected(media.getFile(), media.getType()); } else if (selected.equals("Play audio")) { if (audioCanvas == null) { audioCanvas = new AudioCanvas(midlet, this, 0); } Display.getDisplay(midlet).setCurrent(audioCanvas); } else if (selected.equals("Check MM API support")) { if (form == null) { form = new SupportForm(midlet, this); } Display.getDisplay(midlet).setCurrent(form); } } } else if (cmd == exitCommand) { midlet.listExit(); } } }
Create the SupportForm
class
Import the
required classes and assign this class to the com.nokia.example.mmapi.mediasampler.viewer
package.
package com.nokia.example.mmapi.mediasampler.viewer; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Form; import javax.microedition.media.Manager; import com.nokia.example.mmapi.mediasampler.MediaSamplerMIDlet;
Create the SupportForm
class
and set it to extend Form
and implement CommandListener
.
Define the constants and create the constructor.
/** * View that outputs MM API's System properties to a Form. */ public class SupportForm extends Form implements CommandListener { private MediaSamplerMIDlet midlet; private Displayable medialist; private Command backCmd = new Command("Back", Command.STOP, 1); public SupportForm(MediaSamplerMIDlet midlet, Displayable medialist) { super("MM API support check"); this.midlet = midlet; this.medialist = medialist; addCommand(backCmd); setCommandListener(this); init(); }
Create the init
method
that adds the various media properties to the Form
.
private void init() { String apiVersion = System.getProperty("microedition.media.version"); append("MM API version:" + apiVersion + "\n"); append("Mixing supported: " + System.getProperty("supports.mixing") + "\n"); append("Audio capture supported: " + System.getProperty("supports.audio.capture") + "\n"); append("Video capture supported: " + System.getProperty("supports.video.capture") + "\n"); append("Recording supported: " + System.getProperty("supports.recording") + "\n"); append("Supported audio encodings: " + System.getProperty("audio.encodings") + "\n"); append("Supported video encodings: " + System.getProperty("video.encodings") + "\n"); append("Supported video snaphot encodings: " + System.getProperty("video.snapshot.encodings") + "\n"); append("\n"); String streamable = System.getProperty("streamable.contents"); if (streamable == null) append("Streaming: not supported.\n"); else { append("Streamable contents: " + streamable); String[] rtp = Manager.getSupportedContentTypes("rtp"); if (rtp != null && rtp.length > 0) { append("RTP protocol supported."); } String rtsp[] = Manager.getSupportedContentTypes("rtsp"); if (rtsp != null && rtsp.length > 0) { append("RTSP protocol supported."); } } String[] contentTypes = Manager.getSupportedContentTypes(null); if (contentTypes != null) { append("\n\nAll supported content types:\n"); for (int i = 0; i < contentTypes.length; i++) { append(contentTypes[i] + "\n"); } } }
Write code for monitoring commands.
public void commandAction(Command cmd, Displayable d) { Display.getDisplay(midlet).setCurrent(medialist); } }
Create the VideoCanvas
class.
Import the
required classes and assign this class to the com.nokia.example.mmapi.mediasampler.viewer
package.
package com.nokia.example.mmapi.mediasampler.viewer; import java.io.*; import javax.microedition.io.Connector; import javax.microedition.io.HttpConnection; import javax.microedition.lcdui.*; import javax.microedition.media.*; import javax.microedition.media.control.*; import com.nokia.example.mmapi.mediasampler.MediaSamplerMIDlet;
Create the VideoCanvas
class
and set it to extend Canvas
and implement CommandListener
and PlayerListener
.
Define the constants and create the constructor.
/** * VideoCanvas renders video on Canvas. */ class VideoCanvas extends Canvas implements CommandListener, PlayerListener { private PlayerController controller; private MediaSamplerMIDlet midlet; private Displayable returnScreen; private String videoFile; private Command stopCommand; private Command replayCommand; private Command backCommand; private Player player; private boolean initDone; private boolean playPending = false; /** * Constructor. * * @param midlet * MediaSamplerMIDlet * @param returnScreen * Displayable to set visible when returned from this Canvas * @param videoFile * String as path of the source viudeo file. */ VideoCanvas(MediaSamplerMIDlet midlet, Displayable returnScreen, String videoFile) { this.midlet = midlet; this.returnScreen = returnScreen; this.videoFile = videoFile; controller = new PlayerController(); replayCommand = new Command("Replay", Command.SCREEN, 1); stopCommand = new Command("Stop", Command.SCREEN, 2); backCommand = new Command("Back", Command.BACK, 1); addCommand(backCommand); setCommandListener(this); }
Create a method for changing the play status to "pending" and a method for checking if the system screen is visible.
/** * Set play status to "pending". */ void prepareToPlay() { controller.start(); playPending = true; } /** * Play video only when we're displayed. Use playPending flag to avoid * restarting if a system screen is visiable. */ public void showNotify() { if (playPending) { playPending = false; controller.playVideo(); } }
Create a method for rendering the canvas.
/** * Renders the Canvas. */ public void paint(Graphics g) { g.setColor(0x00FFFF00); // yellow g.fillRect(0, 0, getWidth(), getHeight()); }
Write code for monitoring commands.
/** * Implemented CommandListener method. Indicates that a command event has * occurred on Displayable d. */ public void commandAction(Command c, Displayable d) { if (c == stopCommand) { controller.stopVideo(); } else if (c == replayCommand) { controller.playVideo(); } else if (c == backCommand) { discardPlayer(); } }
Write code for monitoring key presses.
/** * Overriden Canvas method. */ public void keyPressed(int keyCode) { if (getGameAction(keyCode) == FIRE) { int state = player.getState(); if (state == Player.STARTED) { controller.stopVideo(); } else { controller.playVideo(); } } }
Create a method
for fetching content from a specified HTTP URL and returning it as an InputStream
.
/** * Reads the content from the specified HTTP URL and returns InputStream * where the contents are read. * * @return InputStream * @throws IOException */ private InputStream urlToStream(String url) throws IOException { // Open connection to the http url... HttpConnection connection = (HttpConnection) Connector.open(url); DataInputStream dataIn = connection.openDataInputStream(); byte[] buffer = new byte[1000]; int read = -1; // Read the content from url. ByteArrayOutputStream byteout = new ByteArrayOutputStream(); while ((read = dataIn.read(buffer)) >= 0) { byteout.write(buffer, 0, read); } dataIn.close(); connection.close(); // Fill InputStream to return with content read from the URL. ByteArrayInputStream byteIn = new ByteArrayInputStream(byteout .toByteArray()); return byteIn; }
Create the methods for stopping and initializing and starting the player.
/** * Stops the Player. */ void doStop() { if (player != null) { try { player.stop(); } catch (MediaException e) { e.printStackTrace(); } } } /** * Initializes and starts the Player. */ void doPlay() { try { if (!initDone || player == null) { initPlayer(); } int state = player.getState(); if (state == Player.CLOSED) { player.prefetch(); } else if (state == Player.UNREALIZED) { player.realize(); } else if (state == Player.REALIZED) { player.prefetch(); } player.start(); } catch (MediaException me) { discardPlayer(); midlet.alertError("MediaException: " + me.getMessage()); } catch (SecurityException se) { discardPlayer(); midlet.alertError("SecurityException: " + se.getMessage()); } catch (Exception e) { discardPlayer(); midlet.alertError("Exception: " + e.getMessage()); } }
Create a method
for initializing the video player. The VideoControl
class
controls the display of video. A Player
which supports
the playback of video must provide a VideoControl
via
its getControl
and getControls
method.
The initDisplayMode
method initializes the mode on how
the video is displayed.
For
more information, see VideoControl
, getControl
, and initDisplayMode
in the MM API specification.
/** * Initializes the video player. * * Player is initialized only once to save the memory resources and to * increase performance. */ void initPlayer() { try { initDone = false; if (videoFile == null) { midlet.alertError("No video file specified"); return; } boolean fromHttp = videoFile.startsWith("http://"); InputStream is = fromHttp ? urlToStream(videoFile) : getClass() .getResourceAsStream(videoFile); player = Manager.createPlayer(is, "video/3gpp"); player.addPlayerListener(this); player.prefetch(); player.realize(); // get the video control and attach it to our canvas VideoControl videoControl = (VideoControl) (player .getControl("VideoControl")); if (videoControl == null) { midlet.alertError("VideoControl not supported"); } else { videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, this); videoControl.setVisible(true); } initDone = true; } catch (IOException ioe) { discardPlayer(); midlet.alertError("IOException: " + ioe.getMessage()); } catch (MediaException me) { discardPlayer(); midlet.alertError("MediaException: " + me.getMessage()); } catch (SecurityException se) { discardPlayer(); midlet.alertError("SecurityException: " + se.getMessage()); } catch (Exception ex) { discardPlayer(); midlet.alertError("Exception: " + ex.getMessage()); } }
Create methods for closing invalid players and updating players with new event data.
/** * Called in case of exception to make sure invalid players are closed */ void discardPlayer() { if (player != null) { controller.setStopped(); player.close(); player = null; Display.getDisplay(midlet).setCurrent(returnScreen); } } /** * Implemented javax.microedition.media.PlayerListener method. */ public void playerUpdate(final Player p, final String event, final Object eventData) { // queue a call to updateEvent in the user interface event queue Display display = Display.getDisplay(midlet); display.callSerially(new Runnable() { public void run() { VideoCanvas.this.updateEvent(p, event, eventData); } }); }
Create a method for handling update events for the player.
/** * Handles playerUpdate events of the Player. * * @param p * @param event * @param eventData */ void updateEvent(Player p, String event, Object eventData) { if (event == END_OF_MEDIA) { addCommand(replayCommand); removeCommand(stopCommand); } else if (event == CLOSED) { addCommand(replayCommand); removeCommand(stopCommand); } else if (event == STARTED) { removeCommand(replayCommand); addCommand(stopCommand); } else if (event.equals(ERROR)) { } }
Create a code
for calling the play and stop methods of the Player
.
This method is designed to separate the Player method calls from other event
threads.
/** * PlayerController calls the play and stop methods of the Player. The * purpose of this class is only to isolate Player method calls from the * event threads (such commandAction(...)) */ public class PlayerController extends Thread { private boolean running; // Lock object of this Thread private Object controllLock = new Object(); public PlayerController() { } // Activates the Player public void playVideo() { synchronized (controllLock) { controllLock.notify(); } } // Deactivates the player public void stopVideo() { synchronized (controllLock) { doStop(); } } // Terminates this thread public void setStopped() { running = false; synchronized (controllLock) { controllLock.notify(); } } public void run() { VideoCanvas.this.doPlay(); running = true; while (running) { try { synchronized (controllLock) { // Set this thread to wait for playVideo() method call. controllLock.wait(); if (!running) // Leave if controller is stopped. { break; } VideoCanvas.this.doPlay(); } } catch (Exception e) { e.printStackTrace(); } } } } }
Create the VideoSourceSelector
class
Import the
required classes and assign this class to the com.nokia.example.mmapi.mediasampler.viewer
package.
package com.nokia.example.mmapi.mediasampler.viewer; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Form; import javax.microedition.lcdui.List; import javax.microedition.lcdui.TextField; import com.nokia.example.mmapi.mediasampler.MediaSamplerMIDlet; import com.nokia.example.mmapi.mediasampler.data.MediaFactory;
Create the VideoSourceSelector
class
and set it to extend List
and implement CommandListener
.
Define the constants and create the constructor.
/** * List that allow user to select Video source. */ public class VideoSourceSelector extends List implements CommandListener { private MediaSamplerMIDlet midlet; private List returnList; private HTTPUrlForm urlForm; private Command backCommand = new Command("Back", Command.BACK, 1); public VideoSourceSelector(MediaSamplerMIDlet midlet, MediaList list) { super("Select Video Source", List.IMPLICIT); this.midlet = midlet; this.returnList = list; urlForm = new HTTPUrlForm(); append("From http", null); append("From jar", null); addCommand(backCommand); setCommandListener(this); }
Write code for monitoring commands.
public void commandAction(Command cmd, Displayable d) { if (cmd == SELECT_COMMAND) { int selection = getSelectedIndex(); if (selection == 0) // URL source selected { Display.getDisplay(midlet).setCurrent(urlForm); } else if (selection == 1) // JAR source selected { // File name returned by the MediaFactory refers to the // "Video-Clip" application property... String videoFile = MediaFactory.getDefaultVideo().getFile(); commitSelection(videoFile); } } else if (cmd == backCommand) { Display.getDisplay(midlet).setCurrent(returnList); } }
Create a method for initializing the video canvas with the selected video source and setting it visible.
/** * Initializes and set visible the video canvas with the selected video * source. * * @param input * String as video http url or file path. */ private void commitSelection(String url) { try { VideoCanvas canvas = new VideoCanvas(midlet, returnList, url); canvas.prepareToPlay(); Display.getDisplay(midlet).setCurrent(canvas); } catch (Exception e) { midlet.alertError("Cannot open connection: " + e.getMessage()); } }
Create a Form for the video URL input.
/** * Form for the video URL input. */ public class HTTPUrlForm extends Form implements CommandListener { TextField tf = new TextField("URL", "http://", 100, TextField.URL); Command cmdOK = new Command("OK", Command.OK, 1); Command cmdBack = new Command("Back", Command.BACK, 1); public HTTPUrlForm() { super("HTTP Address"); String defaultURL = VideoSourceSelector.this.midlet .getAppProperty("Video-URL"); if (defaultURL != null && defaultURL.length() > 0) { tf.setString(defaultURL); } append(tf); addCommand(cmdOK); addCommand(cmdBack); setCommandListener(this); } public void commandAction(Command cmd, Displayable d) { if (cmd == cmdOK) { String url = tf.getString(); commitSelection(url); } else { Display.getDisplay(midlet).setCurrent(VideoSourceSelector.this); } } } }