MediaPlayerBridge.java revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.media;
6
7import android.content.Context;
8import android.media.MediaPlayer;
9import android.net.Uri;
10import android.text.TextUtils;
11import android.util.Log;
12import android.view.Surface;
13
14import org.chromium.base.CalledByNative;
15import org.chromium.base.JNINamespace;
16
17import java.io.IOException;
18import java.io.Serializable;
19import java.lang.reflect.InvocationTargetException;
20import java.lang.reflect.Method;
21import java.util.HashMap;
22import java.util.Map;
23
24// A wrapper around android.media.MediaPlayer that allows the native code to use it.
25// See media/base/android/media_player_bridge.cc for the corresponding native code.
26@JNINamespace("media")
27public class MediaPlayerBridge {
28
29    private static final String TAG = "MediaPlayerBridge";
30
31    // Local player to forward this to. We don't initialize it here since the subclass might not
32    // want it.
33    private MediaPlayer mPlayer;
34
35    @CalledByNative
36    private static MediaPlayerBridge create() {
37        return new MediaPlayerBridge();
38    }
39
40    protected MediaPlayer getLocalPlayer() {
41        if (mPlayer == null) {
42            mPlayer = new MediaPlayer();
43        }
44        return mPlayer;
45    }
46
47    @CalledByNative
48    protected void setSurface(Surface surface) {
49        getLocalPlayer().setSurface(surface);
50    }
51
52    @CalledByNative
53    protected void prepareAsync() throws IllegalStateException {
54        getLocalPlayer().prepareAsync();
55    }
56
57    @CalledByNative
58    protected boolean isPlaying() {
59        return getLocalPlayer().isPlaying();
60    }
61
62    @CalledByNative
63    protected int getVideoWidth() {
64        return getLocalPlayer().getVideoWidth();
65    }
66
67    @CalledByNative
68    protected int getVideoHeight() {
69        return getLocalPlayer().getVideoHeight();
70    }
71
72    @CalledByNative
73    protected int getCurrentPosition() {
74        return getLocalPlayer().getCurrentPosition();
75    }
76
77    @CalledByNative
78    protected int getDuration() {
79        return getLocalPlayer().getDuration();
80    }
81
82    @CalledByNative
83    protected void release() {
84        getLocalPlayer().release();
85    }
86
87    @CalledByNative
88    protected void setVolume(double volume) {
89        getLocalPlayer().setVolume((float) volume, (float) volume);
90    }
91
92    @CalledByNative
93    protected void start() {
94        getLocalPlayer().start();
95    }
96
97    @CalledByNative
98    protected void pause() {
99        getLocalPlayer().pause();
100    }
101
102    @CalledByNative
103    protected void seekTo(int msec) throws IllegalStateException {
104        getLocalPlayer().seekTo(msec);
105    }
106
107    @CalledByNative
108    protected boolean setDataSource(
109            Context context, String url, String cookies, boolean hideUrlLog) {
110        Uri uri = Uri.parse(url);
111        HashMap<String, String> headersMap = new HashMap<String, String>();
112        if (hideUrlLog)
113            headersMap.put("x-hide-urls-from-log", "true");
114        if (!TextUtils.isEmpty(cookies))
115            headersMap.put("Cookie", cookies);
116        try {
117            getLocalPlayer().setDataSource(context, uri, headersMap);
118            return true;
119        } catch (Exception e) {
120            return false;
121        }
122    }
123
124    protected void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) {
125        getLocalPlayer().setOnBufferingUpdateListener(listener);
126    }
127
128    protected void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) {
129        getLocalPlayer().setOnCompletionListener(listener);
130    }
131
132    protected void setOnErrorListener(MediaPlayer.OnErrorListener listener) {
133        getLocalPlayer().setOnErrorListener(listener);
134    }
135
136    protected void setOnPreparedListener(MediaPlayer.OnPreparedListener listener) {
137        getLocalPlayer().setOnPreparedListener(listener);
138    }
139
140    protected void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener) {
141        getLocalPlayer().setOnSeekCompleteListener(listener);
142    }
143
144    protected void setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener) {
145        getLocalPlayer().setOnVideoSizeChangedListener(listener);
146    }
147
148    protected static class AllowedOperations {
149        private final boolean mCanPause;
150        private final boolean mCanSeekForward;
151        private final boolean mCanSeekBackward;
152
153        public AllowedOperations(boolean canPause, boolean canSeekForward,
154                boolean canSeekBackward) {
155            mCanPause = canPause;
156            mCanSeekForward = canSeekForward;
157            mCanSeekBackward = canSeekBackward;
158        }
159
160        @CalledByNative("AllowedOperations")
161        private boolean canPause() { return mCanPause; }
162
163        @CalledByNative("AllowedOperations")
164        private boolean canSeekForward() { return mCanSeekForward; }
165
166        @CalledByNative("AllowedOperations")
167        private boolean canSeekBackward() { return mCanSeekBackward; }
168    }
169
170    /**
171     * Returns an AllowedOperations object to show all the operations that are
172     * allowed on the media player.
173     */
174    @CalledByNative
175    protected AllowedOperations getAllowedOperations() {
176        MediaPlayer player = getLocalPlayer();
177        boolean canPause = true;
178        boolean canSeekForward = true;
179        boolean canSeekBackward = true;
180        try {
181            Method getMetadata = player.getClass().getDeclaredMethod(
182                    "getMetadata", boolean.class, boolean.class);
183            getMetadata.setAccessible(true);
184            Object data = getMetadata.invoke(player, false, false);
185            if (data != null) {
186                Class<?> metadataClass = data.getClass();
187                Method hasMethod = metadataClass.getDeclaredMethod("has", int.class);
188                Method getBooleanMethod = metadataClass.getDeclaredMethod("getBoolean", int.class);
189
190                int pause = (Integer) metadataClass.getField("PAUSE_AVAILABLE").get(null);
191                int seekForward =
192                    (Integer) metadataClass.getField("SEEK_FORWARD_AVAILABLE").get(null);
193                int seekBackward =
194                        (Integer) metadataClass.getField("SEEK_BACKWARD_AVAILABLE").get(null);
195                hasMethod.setAccessible(true);
196                getBooleanMethod.setAccessible(true);
197                canPause = !((Boolean) hasMethod.invoke(data, pause))
198                        || ((Boolean) getBooleanMethod.invoke(data, pause));
199                canSeekForward = !((Boolean) hasMethod.invoke(data, seekForward))
200                        || ((Boolean) getBooleanMethod.invoke(data, seekForward));
201                canSeekBackward = !((Boolean) hasMethod.invoke(data, seekBackward))
202                        || ((Boolean) getBooleanMethod.invoke(data, seekBackward));
203            }
204        } catch (NoSuchMethodException e) {
205            Log.e(TAG, "Cannot find getMetadata() method: " + e);
206        } catch (InvocationTargetException e) {
207            Log.e(TAG, "Cannot invoke MediaPlayer.getMetadata() method: " + e);
208        } catch (IllegalAccessException e) {
209            Log.e(TAG, "Cannot access metadata: " + e);
210        } catch (NoSuchFieldException e) {
211            Log.e(TAG, "Cannot find matching fields in Metadata class: " + e);
212        }
213        return new AllowedOperations(canPause, canSeekForward, canSeekBackward);
214    }
215}
216