PlayerPool.java
/*
* Copyright © 2012 Nokia Corporation. All rights reserved.
* Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation.
* Oracle and Java are trademarks or registered trademarks of Oracle and/or its
* affiliates. Other product and company names mentioned herein may be trademarks
* or trade names of their respective owners.
* See LICENSE.TXT for license information.
*/
package com.nokia.example.mmapi.mediasampler.model;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.StopTimeControl;
import javax.microedition.media.control.ToneControl;
import javax.microedition.media.control.VolumeControl;
import com.nokia.example.mmapi.mediasampler.MediaSamplerMIDlet;
import com.nokia.example.mmapi.mediasampler.data.Media;
/**
* PlayerPool enables multiple realized / prefetched players.
*/
public class PlayerPool implements PlayerListener {
protected Vector players;
protected Vector medias;
protected MediaSamplerMIDlet midlet;
protected int latency;
boolean supportMultiPlayer = true;
private int actualVolume = 0;
private int globalVolume = 0;
private int midletVolume = 100;
private long stopTime = StopTimeControl.RESET;
private int realizedSoundIndex;
public PlayerPool(MediaSamplerMIDlet midlet, int latency) {
this.midlet = midlet;
this.latency = latency;
players = new Vector();
medias = new Vector();
}
/**
* PlayerListener interface's method.
*/
public void playerUpdate(Player player, String event, Object eventData) {
if (event.equals(PlayerListener.VOLUME_CHANGED)) { // Gauge is adjusted
actualVolume = (int) (((float) globalVolume / 100) * (float) midletVolume);
} else if (event.equals("com.nokia.external.volume.event")) {
// External volumes keys are pressed
globalVolume = Integer.parseInt(eventData.toString());
actualVolume = (int) (((float) globalVolume / 100) * (float) midletVolume);
}
midlet.actualVolume = actualVolume;
midlet.globalVolume = globalVolume;
midlet.midletVolume = midletVolume;
midlet.eventString = event;
midlet.updateVolume();
}
/**
* Returns boolean indication is media mimetype supported by the Device.
*
* @param mimeType
* String as media mime-type
* @return boolean is supported
*/
public boolean isMediaSupported(String mimeType) {
String[] types = Manager.getSupportedContentTypes(null);
for (int i = 0; i < types.length; i++) {
if (mimeType.toLowerCase().equals(types[i].toLowerCase())) {
return true;
}
}
return false;
}
/**
* Add media to pool.
*
* @param media -
* Media to add
*/
public void addMedia(Media media) throws MediaException {
String mimeType = media.getType();
if (!isMediaSupported(mimeType)) {
throw new MediaException("Type " + mimeType + " is not supported!");
}
addSoundObject(media);
}
/**
* Return true if device supports multiple simultaneous players.
*
* @return a boolean indication are multiple players supported.
*/
public boolean supportsMulplePlayers() {
return supportMultiPlayer;
}
/**
* Adds Tone Sequence to this
*
* @param sequence
* @throws MediaException -
* if tone sequence is not supported
*/
public void addToneSequence(byte[] sequence) throws MediaException {
if (!isMediaSupported("audio/x-tone-seq")) {
throw new MediaException("Tone (audio/x-tone-seq) is not supported!");
}
addSoundObject(sequence);
}
/**
* Creates and initializes the Player
*
* @param sequence -
* tone sequence data in byte array
* @return realized tone sequence Player
* @throws MediaException
* thrown by the system while creating the player
* @throws IOException
* thrown by the system while creating the player
*/
private Player createTonePlayer(byte[] sequence) throws MediaException, IOException {
Player player = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
player.addPlayerListener(this);
player.realize();
ToneControl tc = (ToneControl) (player.getControl("ToneControl"));
tc.setSequence(sequence);
return player;
}
/**
* Creates and initializes the Player.
*
* @param media -
* Media datatype that represents the data
* @return realized Player
* @throws MediaException
* occured while creating the player
* @throws IOException
* occured while creating the player
*/
private Player createPlayer(Object media) throws MediaException, IOException {
if (media instanceof byte[]) {
return createTonePlayer((byte[]) media);
}
return createPlayer((Media) media);
}
/**
* Creates and initializes the Player.
*
* @param media -
* Media datatype that represents the data
* @return realized Player
* @throws MediaException
* occured while creating the player
* @throws IOException
* occured while creating the player
*/
private Player createPlayer(Media media) throws MediaException, IOException {
InputStream is = media.getInputStream();
String mediaType = media.getType();
Player player = Manager.createPlayer(is, mediaType);
player.addPlayerListener(this);
player.realize();
player.prefetch();
return player;
}
/**
* Closes the players and removes all references.
*/
public void releaseResources() {
discardAll();
players.removeAllElements();
medias.removeAllElements();
}
/**
* Set the volume level of players.
*
* @param volume
* int as volume level in range 0-100.
*/
public void setVolumeLevel(int volume) {
midletVolume = volume;
updateVolumeLevel();
}
/**
* Set the stop time of players.
*
* @param time
* long as stop time in millis
*/
public void setStopTime(long time) {
this.stopTime = time;
updateStopTime();
}
/**
* Plays the specified sound.
*
* @param index
* int as sound index to play
*/
public void playSound(int index) throws MediaException {
if (supportMultiPlayer) {
if (index >= 0 && index < players.size()) {
Player player = (Player) players.elementAt(index);
startPlayer(player);
}
} else {
// use old player if already exists (has been previously played)
if (index == realizedSoundIndex) {
Player player = (Player) players.elementAt(0);
startPlayer(player);
return;
}
// otherwise close old player and create a new one.
discardAll();
players.removeAllElements();
try {
Object obj = medias.elementAt(index);
Player player = createPlayer(obj);
players.addElement(player);
updateStopTime();
updateVolumeLevel();
realizedSoundIndex = index;
startPlayer(player);
} catch (IOException ioe) {
midlet.alertError("IOException: " + ioe.getMessage());
}
}
}
private void startPlayer(Player player) {
try {
if (player != null) {
if (player.getState() == Player.UNREALIZED) {
player.prefetch();
player.realize();
}
if (player.getState() != Player.CLOSED) {
Thread.sleep(latency);
player.start();
}
}
Thread.sleep(latency);
} catch (InterruptedException e) {
} catch (MediaException e) {
discardPlayer(player);
midlet.alertError("MediaException: " + e.getMessage());
}
}
public void discardPlayer(Player player) {
if (player != null) {
player.close();
}
}
public void discardAll() {
for (int i = 0; i < players.size(); i++) {
Player player = (Player) players.elementAt(i);
discardPlayer(player);
}
}
/**
* Set volume level to existing players.
*/
private void updateVolumeLevel() {
int size = players.size();
for (int i = 0; i < size; i++) { // Set the same volume level for all players
Player player = (Player) players.elementAt(i);
VolumeControl control = (VolumeControl) player.getControl("VolumeControl");
actualVolume = (int) (((float) globalVolume / 100) * (float) midletVolume);
control.setLevel(midletVolume);
}
}
/**
* Set current stop-time to existing players.
*/
private void updateStopTime() {
int size = players.size();
for (int i = 0; i < size; i++) { // Set the same stop time for all players
Player player = (Player) players.elementAt(i);
StopTimeControl control = (StopTimeControl) player.getControl("StopTimeControl");
control.setStopTime(stopTime);
}
}
private void addSoundObject(Object sndObject) throws MediaException {
if (!supportMultiPlayer) {
medias.addElement(sndObject);
} else {
try {
Player player = createPlayer(sndObject);
players.addElement(player);
medias.addElement(sndObject);
} catch (MediaException se) {
// Let's assume that second player creation failes even media
// type should be supported.
if (supportMultiPlayer && players.size() == 1) {
Player failedPlayer = (Player) players.elementAt(0);
discardPlayer(failedPlayer);
players.removeElementAt(0);
try {
Player player = createPlayer(sndObject);
// Assuming that Player creation works if there is not other
// instances, we let the pool work in single Player instance mode.
supportMultiPlayer = false;
medias.addElement(sndObject);
// Update player vector to contain only current.
players.removeAllElements();
players.addElement(player);
realizedSoundIndex = medias.size() - 1;
} catch (MediaException me) {
// Cannot create player.
throw me;
} catch (IOException ioe) {
midlet.alertError("IOException: " + ioe.getMessage());
}
} else {
// Reject this media and route Exception to method caller.
throw se;
}
} catch (IOException ioe) {
midlet.alertError("IOException: " + ioe.getMessage());
}
}
}
}