package com.googlecode.android_scripting.facade.media; | |
import android.app.Service; | |
import android.media.MediaPlayer; | |
import android.net.Uri; | |
import com.googlecode.android_scripting.facade.EventFacade; | |
import com.googlecode.android_scripting.facade.FacadeManager; | |
import com.googlecode.android_scripting.jsonrpc.RpcReceiver; | |
import com.googlecode.android_scripting.rpc.Rpc; | |
import com.googlecode.android_scripting.rpc.RpcDefault; | |
import com.googlecode.android_scripting.rpc.RpcParameter; | |
import java.util.HashMap; | |
import java.util.Hashtable; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.Map.Entry; | |
/** | |
* This facade exposes basic mediaPlayer functionality. <br> | |
* <br> | |
* <b>Usage Notes:</b><br> | |
* mediaPlayerFacade maintains a list of media streams, identified by a user supplied tag. If the | |
* tag is null or blank, this tag defaults to "default"<br> | |
* Basic operation is: mediaPlayOpen("file:///sdcard/MP3/sample.mp3","mytag",true)<br> | |
* This will look for a media file at /sdcard/MP3/sample.mp3. Other urls should work. If the file | |
* exists and is playable, this will return a true otherwise it will return a false. <br> | |
* If play=true, then the media file will play immediately, otherwise it will wait for a | |
* {@link #mediaPlayStart mediaPlayerStart} command. <br> | |
* When done with the resource, use {@link #mediaPlayClose mediaPlayClose} <br> | |
* You can get information about the loaded media with {@link #mediaPlayInfo mediaPlayInfo} This | |
* returns a map with the following elements: | |
* <ul> | |
* <li>"tag" - user supplied tag identifying this mediaPlayer. | |
* <li>"loaded" - true if loaded, false if not. If false, no other elements are returned. | |
* <li>"duration" - length of the media in milliseconds. | |
* <li>"position" - current position of playback in milliseconds. Controlled by | |
* {@link #mediaPlaySeek mediaPlaySeek} | |
* <li>"isplaying" - shows whether media is playing. Controlled by {@link #mediaPlayPause | |
* mediaPlayPause} and {@link #mediaPlayStart mediaPlayStart} | |
* <li>"url" - the url used to open this media. | |
* <li>"looping" - whether media will loop. Controlled by {@link #mediaPlaySetLooping | |
* mediaPlaySetLooping} | |
* </ul> | |
* <br> | |
* You can use {@link #mediaPlayList mediaPlayList} to get a list of the loaded tags. <br> | |
* {@link #mediaIsPlaying mediaIsPlaying} will return true if the media is playing.<br> | |
* <b>Events:</b><br> | |
* A playing media will throw a <b>"media"</b> event on completion. NB: In remote mode, a media file | |
* will continue playing after the script has finished unless an explicit {@link #mediaPlayClose | |
* mediaPlayClose} event is called. | |
* | |
* @author Robbie Matthews (rjmatthews62@gmail.com) | |
*/ | |
public class MediaPlayerFacade extends RpcReceiver implements MediaPlayer.OnCompletionListener { | |
private final Service mService; | |
static private final Map<String, MediaPlayer> mPlayers = new Hashtable<String, MediaPlayer>(); | |
static private final Map<String, String> mUrls = new Hashtable<String, String>(); | |
private final EventFacade mEventFacade; | |
public MediaPlayerFacade(FacadeManager manager) { | |
super(manager); | |
mService = manager.getService(); | |
mEventFacade = manager.getReceiver(EventFacade.class); | |
} | |
private String getDefault(String tag) { | |
return (tag == null || tag.equals("")) ? "default" : tag; | |
} | |
private MediaPlayer getPlayer(String tag) { | |
tag = getDefault(tag); | |
return mPlayers.get(tag); | |
} | |
private String getUrl(String tag) { | |
tag = getDefault(tag); | |
return mUrls.get(tag); | |
} | |
private void putMp(String tag, MediaPlayer player, String url) { | |
tag = getDefault(tag); | |
mPlayers.put(tag, player); | |
mUrls.put(tag, url); | |
} | |
private void removeMp(String tag) { | |
tag = getDefault(tag); | |
MediaPlayer player = mPlayers.get(tag); | |
if (player != null) { | |
player.stop(); | |
player.release(); | |
} | |
mPlayers.remove(tag); | |
mUrls.remove(tag); | |
} | |
@Rpc(description = "Open a media file", returns = "true if play successful") | |
public synchronized boolean mediaPlayOpen(@RpcParameter(name = "url", | |
description = "url of media resource") | |
String url, @RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag, @RpcParameter(name = "play", description = "start playing immediately") | |
@RpcDefault(value = "true") | |
Boolean play) { | |
removeMp(tag); | |
MediaPlayer player = getPlayer(tag); | |
player = MediaPlayer.create(mService, Uri.parse(url)); | |
if (player != null) { | |
putMp(tag, player, url); | |
player.setOnCompletionListener(this); | |
if (play) { | |
player.start(); | |
} | |
} | |
return player != null; | |
} | |
@Rpc(description = "pause playing media file", returns = "true if successful") | |
public synchronized boolean mediaPlayPause( | |
@RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag) { | |
MediaPlayer player = getPlayer(tag); | |
if (player == null) { | |
return false; | |
} | |
player.pause(); | |
return true; | |
} | |
@Rpc(description = "Start playing media file.", returns = "true if successful") | |
public synchronized boolean mediaPlayStart( | |
@RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag) { | |
MediaPlayer player = getPlayer(tag); | |
if (player == null) { | |
return false; | |
} | |
player.start(); | |
return mediaIsPlaying(tag); | |
} | |
@Rpc(description = "Stop playing media file.", returns = "true if successful") | |
public synchronized boolean mediaPlayStop( | |
@RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag) { | |
MediaPlayer player = getPlayer(tag); | |
if (player == null) { | |
return false; | |
} | |
player.stop(); | |
return !mediaIsPlaying(tag) && player.getCurrentPosition() == 0; | |
} | |
@Rpc(description = "Stop all players.") | |
public synchronized void mediaPlayStopAll() { | |
for (MediaPlayer p : mPlayers.values()) { | |
p.stop(); | |
} | |
} | |
@Rpc(description = "Seek To Position", returns = "New Position (in ms)") | |
public synchronized int mediaPlaySeek(@RpcParameter(name = "msec", | |
description = "Position in millseconds") | |
Integer msec, @RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag) { | |
MediaPlayer player = getPlayer(tag); | |
if (player == null) { | |
return 0; | |
} | |
player.seekTo(msec); | |
return player.getCurrentPosition(); | |
} | |
@Rpc(description = "Close media file", returns = "true if successful") | |
public synchronized boolean mediaPlayClose( | |
@RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag) throws Exception { | |
if (!mPlayers.containsKey(tag)) { | |
return false; | |
} | |
removeMp(tag); | |
return true; | |
} | |
@Rpc(description = "Checks if media file is playing.", returns = "true if playing") | |
public synchronized boolean mediaIsPlaying( | |
@RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag) { | |
MediaPlayer player = getPlayer(tag); | |
return (player == null) ? false : player.isPlaying(); | |
} | |
@Rpc(description = "Information on current media", returns = "Media Information") | |
public synchronized Map<String, Object> mediaPlayGetInfo( | |
@RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag) { | |
Map<String, Object> result = new HashMap<String, Object>(); | |
MediaPlayer player = getPlayer(tag); | |
result.put("tag", getDefault(tag)); | |
if (player == null) { | |
result.put("loaded", false); | |
} else { | |
result.put("loaded", true); | |
result.put("duration", player.getDuration()); | |
result.put("position", player.getCurrentPosition()); | |
result.put("isplaying", player.isPlaying()); | |
result.put("url", getUrl(tag)); | |
result.put("looping", player.isLooping()); | |
} | |
return result; | |
} | |
@Rpc(description = "Lists currently loaded media", returns = "List of Media Tags") | |
public Set<String> mediaPlayList() { | |
return mPlayers.keySet(); | |
} | |
@Rpc(description = "Set Looping", returns = "True if successful") | |
public synchronized boolean mediaPlaySetLooping(@RpcParameter(name = "enabled") | |
@RpcDefault(value = "true") | |
Boolean enabled, @RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag) { | |
MediaPlayer player = getPlayer(tag); | |
if (player == null) { | |
return false; | |
} | |
player.setLooping(enabled); | |
return true; | |
} | |
@Rpc(description = "Checks if media file is playing.", returns = "true if playing") | |
public synchronized void mediaSetNext( | |
@RpcParameter(name = "tag", description = "string identifying resource") | |
@RpcDefault(value = "default") | |
String tag, | |
@RpcParameter(name = "next", description = "tag of the next track to play.") | |
String next) { | |
MediaPlayer player = getPlayer(tag); | |
MediaPlayer nPlayer = getPlayer(next); | |
if (player == null) { | |
throw new NullPointerException("Non-existent player tag " + tag); | |
} | |
if (nPlayer == null) { | |
throw new NullPointerException("Non-existent player tag " + next); | |
} | |
player.setNextMediaPlayer(nPlayer); | |
} | |
@Override | |
public synchronized void shutdown() { | |
for (String key : mPlayers.keySet()) { | |
MediaPlayer player = mPlayers.get(key); | |
if (player != null) { | |
player.stop(); | |
player.release(); | |
player = null; | |
} | |
} | |
mPlayers.clear(); | |
mUrls.clear(); | |
} | |
@Override | |
public void onCompletion(MediaPlayer player) { | |
String tag = getTag(player); | |
if (tag != null) { | |
Map<String, Object> data = new HashMap<String, Object>(); | |
data.put("action", "complete"); | |
data.put("tag", tag); | |
mEventFacade.postEvent("media", data); | |
} | |
} | |
private String getTag(MediaPlayer player) { | |
for (Entry<String, MediaPlayer> m : mPlayers.entrySet()) { | |
if (m.getValue() == player) { | |
return m.getKey(); | |
} | |
} | |
return null; | |
} | |
} |