19f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li/*
2f04335f899f2cce69f843692a3cb9cec229683c2tturney * Copyright (C) 2017 The Android Open Source Project
39f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
4f04335f899f2cce69f843692a3cb9cec229683c2tturney * Licensed under the Apache License, Version 2.0 (the "License");
5f04335f899f2cce69f843692a3cb9cec229683c2tturney * you may not use this file except in compliance with the License.
6f04335f899f2cce69f843692a3cb9cec229683c2tturney * You may obtain a copy of the License at
79f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
8f04335f899f2cce69f843692a3cb9cec229683c2tturney *      http://www.apache.org/licenses/LICENSE-2.0
99f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Unless required by applicable law or agreed to in writing, software
11f04335f899f2cce69f843692a3cb9cec229683c2tturney * distributed under the License is distributed on an "AS IS" BASIS,
12f04335f899f2cce69f843692a3cb9cec229683c2tturney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f04335f899f2cce69f843692a3cb9cec229683c2tturney * See the License for the specific language governing permissions and
14f04335f899f2cce69f843692a3cb9cec229683c2tturney * limitations under the License.
159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */
169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipackage com.googlecode.android_scripting.facade.media;
189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.app.Service;
209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.media.MediaPlayer;
219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.net.Uri;
229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.facade.EventFacade;
249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.facade.FacadeManager;
259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.jsonrpc.RpcReceiver;
269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.rpc.Rpc;
279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.rpc.RpcDefault;
289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.rpc.RpcParameter;
299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.HashMap;
319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.Hashtable;
329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.Map;
339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.Set;
349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.Map.Entry;
359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li/**
379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * This facade exposes basic mediaPlayer functionality. <br>
389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <br>
399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <b>Usage Notes:</b><br>
409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * mediaPlayerFacade maintains a list of media streams, identified by a user supplied tag. If the
419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * tag is null or blank, this tag defaults to "default"<br>
429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Basic operation is: mediaPlayOpen("file:///sdcard/MP3/sample.mp3","mytag",true)<br>
439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * This will look for a media file at /sdcard/MP3/sample.mp3. Other urls should work. If the file
449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * exists and is playable, this will return a true otherwise it will return a false. <br>
459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * If play=true, then the media file will play immediately, otherwise it will wait for a
469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * {@link #mediaPlayStart mediaPlayerStart} command. <br>
479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * When done with the resource, use {@link #mediaPlayClose mediaPlayClose} <br>
489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * You can get information about the loaded media with {@link #mediaPlayInfo mediaPlayInfo} This
499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * returns a map with the following elements:
509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <ul>
519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <li>"tag" - user supplied tag identifying this mediaPlayer.
529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <li>"loaded" - true if loaded, false if not. If false, no other elements are returned.
539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <li>"duration" - length of the media in milliseconds.
549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <li>"position" - current position of playback in milliseconds. Controlled by
559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * {@link #mediaPlaySeek mediaPlaySeek}
569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <li>"isplaying" - shows whether media is playing. Controlled by {@link #mediaPlayPause
579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * mediaPlayPause} and {@link #mediaPlayStart mediaPlayStart}
589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <li>"url" - the url used to open this media.
599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <li>"looping" - whether media will loop. Controlled by {@link #mediaPlaySetLooping
609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * mediaPlaySetLooping}
619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * </ul>
629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <br>
639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * You can use {@link #mediaPlayList mediaPlayList} to get a list of the loaded tags. <br>
649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * {@link #mediaIsPlaying mediaIsPlaying} will return true if the media is playing.<br>
659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * <b>Events:</b><br>
669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * A playing media will throw a <b>"media"</b> event on completion. NB: In remote mode, a media file
679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * will continue playing after the script has finished unless an explicit {@link #mediaPlayClose
689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * mediaPlayClose} event is called.
699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */
719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipublic class MediaPlayerFacade extends RpcReceiver implements MediaPlayer.OnCompletionListener {
739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final Service mService;
759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    static private final Map<String, MediaPlayer> mPlayers = new Hashtable<String, MediaPlayer>();
769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    static private final Map<String, String> mUrls = new Hashtable<String, String>();
779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final EventFacade mEventFacade;
799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public MediaPlayerFacade(FacadeManager manager) {
819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        super(manager);
829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService = manager.getService();
839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mEventFacade = manager.getReceiver(EventFacade.class);
849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private String getDefault(String tag) {
879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return (tag == null || tag.equals("")) ? "default" : tag;
889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private MediaPlayer getPlayer(String tag) {
919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        tag = getDefault(tag);
929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mPlayers.get(tag);
939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private String getUrl(String tag) {
969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        tag = getDefault(tag);
979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mUrls.get(tag);
989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private void putMp(String tag, MediaPlayer player, String url) {
1019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        tag = getDefault(tag);
1029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mPlayers.put(tag, player);
1039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mUrls.put(tag, url);
1049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private void removeMp(String tag) {
1079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        tag = getDefault(tag);
1089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = mPlayers.get(tag);
1099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (player != null) {
1109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            player.stop();
1119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            player.release();
1129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mPlayers.remove(tag);
1149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mUrls.remove(tag);
1159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Open a media file", returns = "true if play successful")
1189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized boolean mediaPlayOpen(@RpcParameter(name = "url",
1199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                                                            description = "url of media resource")
1209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    String url, @RpcParameter(name = "tag", description = "string identifying resource")
1219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @RpcDefault(value = "default")
1229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    String tag, @RpcParameter(name = "play", description = "start playing immediately")
1239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @RpcDefault(value = "true")
1249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    Boolean play) {
1259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        removeMp(tag);
1269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = getPlayer(tag);
1279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        player = MediaPlayer.create(mService, Uri.parse(url));
1289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (player != null) {
1299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            putMp(tag, player, url);
1309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            player.setOnCompletionListener(this);
1319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (play) {
1329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                player.start();
1339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
1349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return player != null;
1369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "pause playing media file", returns = "true if successful")
1399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized boolean mediaPlayPause(
1409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "tag", description = "string identifying resource")
1419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcDefault(value = "default")
1429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String tag) {
1439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = getPlayer(tag);
1449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (player == null) {
1459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return false;
1469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        player.pause();
1489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return true;
1499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Start playing media file.", returns = "true if successful")
1529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized boolean mediaPlayStart(
1539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "tag", description = "string identifying resource")
1549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcDefault(value = "default")
1559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String tag) {
1569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = getPlayer(tag);
1579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (player == null) {
1589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return false;
1599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        player.start();
1619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mediaIsPlaying(tag);
1629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Stop playing media file.", returns = "true if successful")
1659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized boolean mediaPlayStop(
1669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "tag", description = "string identifying resource")
1679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcDefault(value = "default")
1689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String tag) {
1699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = getPlayer(tag);
1709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (player == null) {
1719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return false;
1729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        player.stop();
1749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return !mediaIsPlaying(tag) && player.getCurrentPosition() == 0;
1759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Stop all players.")
1789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized void mediaPlayStopAll() {
1799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        for (MediaPlayer p : mPlayers.values()) {
1809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            p.stop();
1819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Seek To Position", returns = "New Position (in ms)")
1859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized int mediaPlaySeek(@RpcParameter(name = "msec",
1869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                                                        description = "Position in millseconds")
1879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    Integer msec, @RpcParameter(name = "tag", description = "string identifying resource")
1889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @RpcDefault(value = "default")
1899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    String tag) {
1909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = getPlayer(tag);
1919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (player == null) {
1929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return 0;
1939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        player.seekTo(msec);
1959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return player.getCurrentPosition();
1969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Close media file", returns = "true if successful")
1999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized boolean mediaPlayClose(
2009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "tag", description = "string identifying resource")
2019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcDefault(value = "default")
2029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String tag) throws Exception {
2039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (!mPlayers.containsKey(tag)) {
2049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return false;
2059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        removeMp(tag);
2079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return true;
2089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Checks if media file is playing.", returns = "true if playing")
2119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized boolean mediaIsPlaying(
2129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "tag", description = "string identifying resource")
2139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcDefault(value = "default")
2149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String tag) {
2159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = getPlayer(tag);
2169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return (player == null) ? false : player.isPlaying();
2179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Information on current media", returns = "Media Information")
2209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized Map<String, Object> mediaPlayGetInfo(
2219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "tag", description = "string identifying resource")
2229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcDefault(value = "default")
2239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String tag) {
2249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        Map<String, Object> result = new HashMap<String, Object>();
2259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = getPlayer(tag);
2269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        result.put("tag", getDefault(tag));
2279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (player == null) {
2289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            result.put("loaded", false);
2299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        } else {
2309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            result.put("loaded", true);
2319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            result.put("duration", player.getDuration());
2329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            result.put("position", player.getCurrentPosition());
2339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            result.put("isplaying", player.isPlaying());
2349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            result.put("url", getUrl(tag));
2359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            result.put("looping", player.isLooping());
2369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return result;
2389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Lists currently loaded media", returns = "List of Media Tags")
2419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public Set<String> mediaPlayList() {
2429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mPlayers.keySet();
2439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Set Looping", returns = "True if successful")
2469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized boolean mediaPlaySetLooping(@RpcParameter(name = "enabled")
2479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @RpcDefault(value = "true")
2489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    Boolean enabled, @RpcParameter(name = "tag", description = "string identifying resource")
2499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @RpcDefault(value = "default")
2509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    String tag) {
2519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = getPlayer(tag);
2529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (player == null) {
2539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return false;
2549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        player.setLooping(enabled);
2569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return true;
2579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Checks if media file is playing.", returns = "true if playing")
2609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized void mediaSetNext(
2619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "tag", description = "string identifying resource")
2629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcDefault(value = "default")
2639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String tag,
2649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "next", description = "tag of the next track to play.")
2659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String next) {
2669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer player = getPlayer(tag);
2679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        MediaPlayer nPlayer = getPlayer(next);
2689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (player == null) {
2699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            throw new NullPointerException("Non-existent player tag " + tag);
2709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (nPlayer == null) {
2729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            throw new NullPointerException("Non-existent player tag " + next);
2739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        player.setNextMediaPlayer(nPlayer);
2759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Override
2789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public synchronized void shutdown() {
2799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        for (String key : mPlayers.keySet()) {
2809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            MediaPlayer player = mPlayers.get(key);
2819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (player != null) {
2829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                player.stop();
2839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                player.release();
2849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                player = null;
2859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
2869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mPlayers.clear();
2889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mUrls.clear();
2899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Override
2929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public void onCompletion(MediaPlayer player) {
2939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        String tag = getTag(player);
2949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (tag != null) {
2959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            Map<String, Object> data = new HashMap<String, Object>();
2969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            data.put("action", "complete");
2979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            data.put("tag", tag);
2989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mEventFacade.postEvent("media", data);
2999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
3009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
3019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
3029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private String getTag(MediaPlayer player) {
3039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        for (Entry<String, MediaPlayer> m : mPlayers.entrySet()) {
3049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (m.getValue() == player) {
3059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                return m.getKey();
3069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
3079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
3089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return null;
3099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
3109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li}
311