blob: ecf445853e8d2cb920ffd90dda6ff3e449310482 [file] [log] [blame]
// 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);
}
}