• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.googlecode.android_scripting.facade.media;
18 
19 import android.app.Service;
20 import android.media.MediaPlayer;
21 import android.net.Uri;
22 
23 import com.googlecode.android_scripting.facade.EventFacade;
24 import com.googlecode.android_scripting.facade.FacadeManager;
25 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
26 import com.googlecode.android_scripting.rpc.Rpc;
27 import com.googlecode.android_scripting.rpc.RpcDefault;
28 import com.googlecode.android_scripting.rpc.RpcParameter;
29 
30 import java.util.HashMap;
31 import java.util.Hashtable;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.Map.Entry;
35 
36 /**
37  * This facade exposes basic mediaPlayer functionality. <br>
38  * <br>
39  * <b>Usage Notes:</b><br>
40  * mediaPlayerFacade maintains a list of media streams, identified by a user supplied tag. If the
41  * tag is null or blank, this tag defaults to "default"<br>
42  * Basic operation is: mediaPlayOpen("file:///sdcard/MP3/sample.mp3","mytag",true)<br>
43  * This will look for a media file at /sdcard/MP3/sample.mp3. Other urls should work. If the file
44  * exists and is playable, this will return a true otherwise it will return a false. <br>
45  * If play=true, then the media file will play immediately, otherwise it will wait for a
46  * {@link #mediaPlayStart mediaPlayerStart} command. <br>
47  * When done with the resource, use {@link #mediaPlayClose mediaPlayClose} <br>
48  * You can get information about the loaded media with {@link #mediaPlayInfo mediaPlayInfo} This
49  * returns a map with the following elements:
50  * <ul>
51  * <li>"tag" - user supplied tag identifying this mediaPlayer.
52  * <li>"loaded" - true if loaded, false if not. If false, no other elements are returned.
53  * <li>"duration" - length of the media in milliseconds.
54  * <li>"position" - current position of playback in milliseconds. Controlled by
55  * {@link #mediaPlaySeek mediaPlaySeek}
56  * <li>"isplaying" - shows whether media is playing. Controlled by {@link #mediaPlayPause
57  * mediaPlayPause} and {@link #mediaPlayStart mediaPlayStart}
58  * <li>"url" - the url used to open this media.
59  * <li>"looping" - whether media will loop. Controlled by {@link #mediaPlaySetLooping
60  * mediaPlaySetLooping}
61  * </ul>
62  * <br>
63  * You can use {@link #mediaPlayList mediaPlayList} to get a list of the loaded tags. <br>
64  * {@link #mediaIsPlaying mediaIsPlaying} will return true if the media is playing.<br>
65  * <b>Events:</b><br>
66  * A playing media will throw a <b>"media"</b> event on completion. NB: In remote mode, a media file
67  * will continue playing after the script has finished unless an explicit {@link #mediaPlayClose
68  * mediaPlayClose} event is called.
69  *
70  */
71 
72 public class MediaPlayerFacade extends RpcReceiver implements MediaPlayer.OnCompletionListener {
73 
74     private final Service mService;
75     static private final Map<String, MediaPlayer> mPlayers = new Hashtable<String, MediaPlayer>();
76     static private final Map<String, String> mUrls = new Hashtable<String, String>();
77 
78     private final EventFacade mEventFacade;
79 
MediaPlayerFacade(FacadeManager manager)80     public MediaPlayerFacade(FacadeManager manager) {
81         super(manager);
82         mService = manager.getService();
83         mEventFacade = manager.getReceiver(EventFacade.class);
84     }
85 
getDefault(String tag)86     private String getDefault(String tag) {
87         return (tag == null || tag.equals("")) ? "default" : tag;
88     }
89 
getPlayer(String tag)90     private MediaPlayer getPlayer(String tag) {
91         tag = getDefault(tag);
92         return mPlayers.get(tag);
93     }
94 
getUrl(String tag)95     private String getUrl(String tag) {
96         tag = getDefault(tag);
97         return mUrls.get(tag);
98     }
99 
putMp(String tag, MediaPlayer player, String url)100     private void putMp(String tag, MediaPlayer player, String url) {
101         tag = getDefault(tag);
102         mPlayers.put(tag, player);
103         mUrls.put(tag, url);
104     }
105 
removeMp(String tag)106     private void removeMp(String tag) {
107         tag = getDefault(tag);
108         MediaPlayer player = mPlayers.get(tag);
109         if (player != null) {
110             player.stop();
111             player.release();
112         }
113         mPlayers.remove(tag);
114         mUrls.remove(tag);
115     }
116 
117     @Rpc(description = "Open a media file", returns = "true if play successful")
mediaPlayOpen(@pcParametername = "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)118     public synchronized boolean mediaPlayOpen(@RpcParameter(name = "url",
119                                                             description = "url of media resource")
120     String url, @RpcParameter(name = "tag", description = "string identifying resource")
121     @RpcDefault(value = "default")
122     String tag, @RpcParameter(name = "play", description = "start playing immediately")
123     @RpcDefault(value = "true")
124     Boolean play) {
125         removeMp(tag);
126         MediaPlayer player = getPlayer(tag);
127         player = MediaPlayer.create(mService, Uri.parse(url));
128         if (player != null) {
129             putMp(tag, player, url);
130             player.setOnCompletionListener(this);
131             if (play) {
132                 player.start();
133             }
134         }
135         return player != null;
136     }
137 
138     @Rpc(description = "pause playing media file", returns = "true if successful")
mediaPlayPause( @pcParametername = "tag", description = "string identifying resource") @pcDefaultvalue = "default") String tag)139     public synchronized boolean mediaPlayPause(
140             @RpcParameter(name = "tag", description = "string identifying resource")
141             @RpcDefault(value = "default")
142             String tag) {
143         MediaPlayer player = getPlayer(tag);
144         if (player == null) {
145             return false;
146         }
147         player.pause();
148         return true;
149     }
150 
151     @Rpc(description = "Start playing media file.", returns = "true if successful")
mediaPlayStart( @pcParametername = "tag", description = "string identifying resource") @pcDefaultvalue = "default") String tag)152     public synchronized boolean mediaPlayStart(
153             @RpcParameter(name = "tag", description = "string identifying resource")
154             @RpcDefault(value = "default")
155             String tag) {
156         MediaPlayer player = getPlayer(tag);
157         if (player == null) {
158             return false;
159         }
160         player.start();
161         return mediaIsPlaying(tag);
162     }
163 
164     @Rpc(description = "Stop playing media file.", returns = "true if successful")
mediaPlayStop( @pcParametername = "tag", description = "string identifying resource") @pcDefaultvalue = "default") String tag)165     public synchronized boolean mediaPlayStop(
166             @RpcParameter(name = "tag", description = "string identifying resource")
167             @RpcDefault(value = "default")
168             String tag) {
169         MediaPlayer player = getPlayer(tag);
170         if (player == null) {
171             return false;
172         }
173         player.stop();
174         return !mediaIsPlaying(tag) && player.getCurrentPosition() == 0;
175     }
176 
177     @Rpc(description = "Stop all players.")
mediaPlayStopAll()178     public synchronized void mediaPlayStopAll() {
179         for (MediaPlayer p : mPlayers.values()) {
180             p.stop();
181         }
182     }
183 
184     @Rpc(description = "Seek To Position", returns = "New Position (in ms)")
mediaPlaySeek(@pcParametername = "msec", description = "Position in millseconds") Integer msec, @RpcParameter(name = "tag", description = "string identifying resource") @RpcDefault(value = "default") String tag)185     public synchronized int mediaPlaySeek(@RpcParameter(name = "msec",
186                                                         description = "Position in millseconds")
187     Integer msec, @RpcParameter(name = "tag", description = "string identifying resource")
188     @RpcDefault(value = "default")
189     String tag) {
190         MediaPlayer player = getPlayer(tag);
191         if (player == null) {
192             return 0;
193         }
194         player.seekTo(msec);
195         return player.getCurrentPosition();
196     }
197 
198     @Rpc(description = "Close media file", returns = "true if successful")
mediaPlayClose( @pcParametername = "tag", description = "string identifying resource") @pcDefaultvalue = "default") String tag)199     public synchronized boolean mediaPlayClose(
200             @RpcParameter(name = "tag", description = "string identifying resource")
201             @RpcDefault(value = "default")
202             String tag) throws Exception {
203         if (!mPlayers.containsKey(tag)) {
204             return false;
205         }
206         removeMp(tag);
207         return true;
208     }
209 
210     @Rpc(description = "Checks if media file is playing.", returns = "true if playing")
mediaIsPlaying( @pcParametername = "tag", description = "string identifying resource") @pcDefaultvalue = "default") String tag)211     public synchronized boolean mediaIsPlaying(
212             @RpcParameter(name = "tag", description = "string identifying resource")
213             @RpcDefault(value = "default")
214             String tag) {
215         MediaPlayer player = getPlayer(tag);
216         return (player == null) ? false : player.isPlaying();
217     }
218 
219     @Rpc(description = "Information on current media", returns = "Media Information")
mediaPlayGetInfo( @pcParametername = "tag", description = "string identifying resource") @pcDefaultvalue = "default") String tag)220     public synchronized Map<String, Object> mediaPlayGetInfo(
221             @RpcParameter(name = "tag", description = "string identifying resource")
222             @RpcDefault(value = "default")
223             String tag) {
224         Map<String, Object> result = new HashMap<String, Object>();
225         MediaPlayer player = getPlayer(tag);
226         result.put("tag", getDefault(tag));
227         if (player == null) {
228             result.put("loaded", false);
229         } else {
230             result.put("loaded", true);
231             result.put("duration", player.getDuration());
232             result.put("position", player.getCurrentPosition());
233             result.put("isplaying", player.isPlaying());
234             result.put("url", getUrl(tag));
235             result.put("looping", player.isLooping());
236         }
237         return result;
238     }
239 
240     @Rpc(description = "Lists currently loaded media", returns = "List of Media Tags")
mediaPlayList()241     public Set<String> mediaPlayList() {
242         return mPlayers.keySet();
243     }
244 
245     @Rpc(description = "Set Looping", returns = "True if successful")
mediaPlaySetLooping(@pcParametername = "enabled") @pcDefaultvalue = "true") Boolean enabled, @RpcParameter(name = "tag", description = "string identifying resource") @RpcDefault(value = "default") String tag)246     public synchronized boolean mediaPlaySetLooping(@RpcParameter(name = "enabled")
247     @RpcDefault(value = "true")
248     Boolean enabled, @RpcParameter(name = "tag", description = "string identifying resource")
249     @RpcDefault(value = "default")
250     String tag) {
251         MediaPlayer player = getPlayer(tag);
252         if (player == null) {
253             return false;
254         }
255         player.setLooping(enabled);
256         return true;
257     }
258 
259     @Rpc(description = "Checks if media file is playing.", returns = "true if playing")
mediaSetNext( @pcParametername = "tag", description = "string identifying resource") @pcDefaultvalue = "default") String tag, @RpcParameter(name = "next", description = "tag of the next track to play.") String next)260     public synchronized void mediaSetNext(
261             @RpcParameter(name = "tag", description = "string identifying resource")
262             @RpcDefault(value = "default")
263             String tag,
264             @RpcParameter(name = "next", description = "tag of the next track to play.")
265             String next) {
266         MediaPlayer player = getPlayer(tag);
267         MediaPlayer nPlayer = getPlayer(next);
268         if (player == null) {
269             throw new NullPointerException("Non-existent player tag " + tag);
270         }
271         if (nPlayer == null) {
272             throw new NullPointerException("Non-existent player tag " + next);
273         }
274         player.setNextMediaPlayer(nPlayer);
275     }
276 
277     @Override
shutdown()278     public synchronized void shutdown() {
279         for (String key : mPlayers.keySet()) {
280             MediaPlayer player = mPlayers.get(key);
281             if (player != null) {
282                 player.stop();
283                 player.release();
284                 player = null;
285             }
286         }
287         mPlayers.clear();
288         mUrls.clear();
289     }
290 
291     @Override
onCompletion(MediaPlayer player)292     public void onCompletion(MediaPlayer player) {
293         String tag = getTag(player);
294         if (tag != null) {
295             Map<String, Object> data = new HashMap<String, Object>();
296             data.put("action", "complete");
297             data.put("tag", tag);
298             mEventFacade.postEvent("media", data);
299         }
300     }
301 
getTag(MediaPlayer player)302     private String getTag(MediaPlayer player) {
303         for (Entry<String, MediaPlayer> m : mPlayers.entrySet()) {
304             if (m.getValue() == player) {
305                 return m.getKey();
306             }
307         }
308         return null;
309     }
310 }
311