| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.media; |
| |
| import android.content.Context; |
| import android.media.MediaPlayer; |
| import android.net.Uri; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.view.Surface; |
| |
| import org.chromium.base.CalledByNative; |
| import org.chromium.base.JNINamespace; |
| |
| import java.io.IOException; |
| import java.io.Serializable; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| // A wrapper around android.media.MediaPlayer that allows the native code to use it. |
| // See media/base/android/media_player_bridge.cc for the corresponding native code. |
| @JNINamespace("media") |
| public class MediaPlayerBridge { |
| |
| private static final String TAG = "MediaPlayerBridge"; |
| |
| // Local player to forward this to. We don't initialize it here since the subclass might not |
| // want it. |
| private MediaPlayer mPlayer; |
| |
| @CalledByNative |
| private static MediaPlayerBridge create() { |
| return new MediaPlayerBridge(); |
| } |
| |
| protected MediaPlayer getLocalPlayer() { |
| if (mPlayer == null) { |
| mPlayer = new MediaPlayer(); |
| } |
| return mPlayer; |
| } |
| |
| @CalledByNative |
| protected void setSurface(Surface surface) { |
| getLocalPlayer().setSurface(surface); |
| } |
| |
| @CalledByNative |
| protected void prepareAsync() throws IllegalStateException { |
| getLocalPlayer().prepareAsync(); |
| } |
| |
| @CalledByNative |
| protected boolean isPlaying() { |
| return getLocalPlayer().isPlaying(); |
| } |
| |
| @CalledByNative |
| protected int getVideoWidth() { |
| return getLocalPlayer().getVideoWidth(); |
| } |
| |
| @CalledByNative |
| protected int getVideoHeight() { |
| return getLocalPlayer().getVideoHeight(); |
| } |
| |
| @CalledByNative |
| protected int getCurrentPosition() { |
| return getLocalPlayer().getCurrentPosition(); |
| } |
| |
| @CalledByNative |
| protected int getDuration() { |
| return getLocalPlayer().getDuration(); |
| } |
| |
| @CalledByNative |
| protected void release() { |
| getLocalPlayer().release(); |
| } |
| |
| @CalledByNative |
| protected void setVolume(double volume) { |
| getLocalPlayer().setVolume((float) volume, (float) volume); |
| } |
| |
| @CalledByNative |
| protected void start() { |
| getLocalPlayer().start(); |
| } |
| |
| @CalledByNative |
| protected void pause() { |
| getLocalPlayer().pause(); |
| } |
| |
| @CalledByNative |
| protected void seekTo(int msec) throws IllegalStateException { |
| getLocalPlayer().seekTo(msec); |
| } |
| |
| @CalledByNative |
| protected boolean setDataSource( |
| Context context, String url, String cookies, boolean hideUrlLog) { |
| Uri uri = Uri.parse(url); |
| HashMap<String, String> headersMap = new HashMap<String, String>(); |
| if (hideUrlLog) |
| headersMap.put("x-hide-urls-from-log", "true"); |
| if (!TextUtils.isEmpty(cookies)) |
| headersMap.put("Cookie", cookies); |
| try { |
| getLocalPlayer().setDataSource(context, uri, headersMap); |
| return true; |
| } catch (Exception e) { |
| return false; |
| } |
| } |
| |
| protected void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) { |
| getLocalPlayer().setOnBufferingUpdateListener(listener); |
| } |
| |
| protected void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) { |
| getLocalPlayer().setOnCompletionListener(listener); |
| } |
| |
| protected void setOnErrorListener(MediaPlayer.OnErrorListener listener) { |
| getLocalPlayer().setOnErrorListener(listener); |
| } |
| |
| protected void setOnPreparedListener(MediaPlayer.OnPreparedListener listener) { |
| getLocalPlayer().setOnPreparedListener(listener); |
| } |
| |
| protected void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener) { |
| getLocalPlayer().setOnSeekCompleteListener(listener); |
| } |
| |
| protected void setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener) { |
| getLocalPlayer().setOnVideoSizeChangedListener(listener); |
| } |
| |
| protected static class AllowedOperations { |
| private final boolean mCanPause; |
| private final boolean mCanSeekForward; |
| private final boolean mCanSeekBackward; |
| |
| public AllowedOperations(boolean canPause, boolean canSeekForward, |
| boolean canSeekBackward) { |
| mCanPause = canPause; |
| mCanSeekForward = canSeekForward; |
| mCanSeekBackward = canSeekBackward; |
| } |
| |
| @CalledByNative("AllowedOperations") |
| private boolean canPause() { return mCanPause; } |
| |
| @CalledByNative("AllowedOperations") |
| private boolean canSeekForward() { return mCanSeekForward; } |
| |
| @CalledByNative("AllowedOperations") |
| private boolean canSeekBackward() { return mCanSeekBackward; } |
| } |
| |
| /** |
| * Returns an AllowedOperations object to show all the operations that are |
| * allowed on the media player. |
| */ |
| @CalledByNative |
| protected AllowedOperations getAllowedOperations() { |
| MediaPlayer player = getLocalPlayer(); |
| boolean canPause = true; |
| boolean canSeekForward = true; |
| boolean canSeekBackward = true; |
| try { |
| Method getMetadata = player.getClass().getDeclaredMethod( |
| "getMetadata", boolean.class, boolean.class); |
| getMetadata.setAccessible(true); |
| Object data = getMetadata.invoke(player, false, false); |
| if (data != null) { |
| Class<?> metadataClass = data.getClass(); |
| Method hasMethod = metadataClass.getDeclaredMethod("has", int.class); |
| Method getBooleanMethod = metadataClass.getDeclaredMethod("getBoolean", int.class); |
| |
| int pause = (Integer) metadataClass.getField("PAUSE_AVAILABLE").get(null); |
| int seekForward = |
| (Integer) metadataClass.getField("SEEK_FORWARD_AVAILABLE").get(null); |
| int seekBackward = |
| (Integer) metadataClass.getField("SEEK_BACKWARD_AVAILABLE").get(null); |
| hasMethod.setAccessible(true); |
| getBooleanMethod.setAccessible(true); |
| canPause = !((Boolean) hasMethod.invoke(data, pause)) |
| || ((Boolean) getBooleanMethod.invoke(data, pause)); |
| canSeekForward = !((Boolean) hasMethod.invoke(data, seekForward)) |
| || ((Boolean) getBooleanMethod.invoke(data, seekForward)); |
| canSeekBackward = !((Boolean) hasMethod.invoke(data, seekBackward)) |
| || ((Boolean) getBooleanMethod.invoke(data, seekBackward)); |
| } |
| } catch (NoSuchMethodException e) { |
| Log.e(TAG, "Cannot find getMetadata() method: " + e); |
| } catch (InvocationTargetException e) { |
| Log.e(TAG, "Cannot invoke MediaPlayer.getMetadata() method: " + e); |
| } catch (IllegalAccessException e) { |
| Log.e(TAG, "Cannot access metadata: " + e); |
| } catch (NoSuchFieldException e) { |
| Log.e(TAG, "Cannot find matching fields in Metadata class: " + e); |
| } |
| return new AllowedOperations(canPause, canSeekForward, canSeekBackward); |
| } |
| } |