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