summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioManager.java4
-rw-r--r--media/java/android/media/AudioService.java107
-rw-r--r--media/java/android/media/AudioTrack.java2
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--media/java/android/media/MediaCodec.java22
-rw-r--r--media/java/android/media/MediaDrm.java60
-rw-r--r--media/java/android/media/MediaExtractor.java48
-rw-r--r--media/java/android/media/MediaMuxer.java6
-rw-r--r--media/java/android/media/MediaPlayer.java3
-rw-r--r--media/java/android/media/MediaRouter.java17
-rw-r--r--media/java/android/media/RemoteControlClient.java38
-rw-r--r--media/jni/Android.mk1
-rw-r--r--media/jni/android_media_MediaCodec.cpp6
-rw-r--r--media/jni/android_media_MediaDrm.cpp145
-rw-r--r--media/jni/android_media_MediaDrm.h19
-rw-r--r--media/jni/android_media_MediaExtractor.cpp35
-rw-r--r--media/jni/android_media_MediaExtractor.h2
-rw-r--r--media/jni/audioeffect/Android.mk1
-rw-r--r--media/jni/mediaeditor/Android.mk1
-rw-r--r--media/jni/soundpool/Android.mk1
-rw-r--r--media/libdrm/mobile1/Android.mk6
-rw-r--r--media/mca/filterfw/Android.mk3
-rw-r--r--media/mca/filterpacks/Android.mk4
-rw-r--r--media/tests/omxjpegdecoder/Android.mk1
-rw-r--r--media/tests/players/Android.mk3
25 files changed, 435 insertions, 102 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b80a166..917a47d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -50,6 +50,7 @@ public class AudioManager {
private long mVolumeKeyUpTime;
private final boolean mUseMasterVolume;
private final boolean mUseVolumeKeySounds;
+ private final Binder mToken = new Binder();
private static String TAG = "AudioManager";
/**
@@ -2075,7 +2076,8 @@ public class AudioManager {
IAudioService service = getService();
try {
// pi != null
- service.registerMediaButtonIntent(pi, eventReceiver);
+ service.registerMediaButtonIntent(pi, eventReceiver,
+ eventReceiver == null ? mToken : null);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index fd71d79..637ac85 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -357,7 +357,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
private static final int SCO_STATE_INACTIVE = 0;
// SCO audio activation request waiting for headset service to connect
private static final int SCO_STATE_ACTIVATE_REQ = 1;
- // SCO audio state is active or starting due to a local request to start a virtual call
+ // SCO audio state is active or starting due to a request from AudioManager API
private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
// SCO audio deactivation request waiting for headset service to connect
private static final int SCO_STATE_DEACTIVATE_REQ = 5;
@@ -530,6 +530,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
// Register for package removal intent broadcasts for media button receiver persistence
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
pkgFilter.addDataScheme("package");
context.registerReceiver(mReceiver, pkgFilter);
@@ -2053,8 +2056,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
if (mScoAudioState == SCO_STATE_INACTIVE) {
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
- if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
- mBluetoothHeadsetDevice)) {
+ if (mBluetoothHeadset.connectAudio()) {
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
} else {
broadcastScoConnectionState(
@@ -2076,8 +2078,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
- if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
- mBluetoothHeadsetDevice)) {
+ if (!mBluetoothHeadset.disconnectAudio()) {
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
@@ -2250,12 +2251,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
switch (mScoAudioState) {
case SCO_STATE_ACTIVATE_REQ:
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
- mBluetoothHeadsetDevice);
+ status = mBluetoothHeadset.connectAudio();
break;
case SCO_STATE_DEACTIVATE_REQ:
- status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
- mBluetoothHeadsetDevice);
+ status = mBluetoothHeadset.disconnectAudio();
break;
case SCO_STATE_DEACTIVATE_EXT_REQ:
status = mBluetoothHeadset.stopVoiceRecognition(
@@ -3535,6 +3534,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
onNewPlaybackStateForRcc(msg.arg1 /* rccId */, msg.arg2 /* state */,
(RccPlaybackState)msg.obj /* newState */);
break;
+ case MSG_RCC_SEEK_REQUEST:
+ onSetRemoteControlClientPlaybackPosition(msg.arg1 /* generationId */,
+ ((Long)msg.obj).longValue() /* timeMs */);
case MSG_SET_RSX_CONNECTION_STATE:
onSetRsxConnectionState(msg.arg1/*available*/, msg.arg2/*address*/);
@@ -4037,14 +4039,21 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
0,
null,
SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
- } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
+ } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
+ || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
// a package is being removed, not replaced
String packageName = intent.getData().getSchemeSpecificPart();
if (packageName != null) {
- removeMediaButtonReceiverForPackage(packageName);
+ cleanupMediaButtonReceiverForPackage(packageName, true);
}
}
+ } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
+ || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
+ String packageName = intent.getData().getSchemeSpecificPart();
+ if (packageName != null) {
+ cleanupMediaButtonReceiverForPackage(packageName, false);
+ }
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
AudioSystem.setParameters("screen_state=on");
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
@@ -4851,8 +4860,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
}
- private static class RemoteControlStackEntry {
+ private static class RemoteControlStackEntry implements DeathRecipient {
public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+ final public AudioService mService;
/**
* The target for the ACTION_MEDIA_BUTTON events.
* Always non null.
@@ -4863,6 +4873,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
* Always non null.
*/
final public ComponentName mReceiverComponent;
+ public IBinder mToken;
public String mCallingPackageName;
public int mCallingUid;
/**
@@ -4893,9 +4904,12 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
/** precondition: mediaIntent != null */
- public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) {
+ public RemoteControlStackEntry(AudioService service, PendingIntent mediaIntent,
+ ComponentName eventReceiver, IBinder token) {
+ mService = service;
mMediaIntent = mediaIntent;
mReceiverComponent = eventReceiver;
+ mToken = token;
mCallingUid = -1;
mRcClient = null;
mRccId = ++sLastRccId;
@@ -4905,6 +4919,17 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
RemoteControlClient.PLAYBACK_SPEED_1X);
resetPlaybackInfo();
+ if (mToken != null) {
+ try {
+ mToken.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ mService.mAudioHandler.post(new Runnable() {
+ @Override public void run() {
+ mService.unregisterMediaButtonIntent(mMediaIntent);
+ }
+ });
+ }
+ }
}
public void unlinkToRcClientDeath() {
@@ -4920,9 +4945,22 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
}
+ public void destroy() {
+ unlinkToRcClientDeath();
+ if (mToken != null) {
+ mToken.unlinkToDeath(this, 0);
+ mToken = null;
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ mService.unregisterMediaButtonIntent(mMediaIntent);
+ }
+
@Override
protected void finalize() throws Throwable {
- unlinkToRcClientDeath();// unlink exception handled inside method
+ destroy(); // unlink exception handled inside method
super.finalize();
}
}
@@ -5021,11 +5059,12 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
* Remove any entry in the remote control stack that has the same package name as packageName
* Pre-condition: packageName != null
*/
- private void removeMediaButtonReceiverForPackage(String packageName) {
+ private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) {
synchronized(mRCStack) {
if (mRCStack.empty()) {
return;
} else {
+ final PackageManager pm = mContext.getPackageManager();
RemoteControlStackEntry oldTop = mRCStack.peek();
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
// iterate over the stack entries
@@ -5033,10 +5072,19 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
// evaluated it, traversal order doesn't matter here)
while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
- if (packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
+ if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
// a stack entry is from the package being removed, remove it from the stack
stackIterator.remove();
- rcse.unlinkToRcClientDeath();
+ rcse.destroy();
+ } else if (rcse.mReceiverComponent != null) {
+ try {
+ // Check to see if this receiver still exists.
+ pm.getReceiverInfo(rcse.mReceiverComponent, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Not found -- remove it!
+ stackIterator.remove();
+ rcse.destroy();
+ }
}
}
if (mRCStack.empty()) {
@@ -5079,7 +5127,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
mediaButtonIntent.setComponent(eventReceiver);
PendingIntent pi = PendingIntent.getBroadcast(mContext,
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
- registerMediaButtonIntent(pi, eventReceiver);
+ registerMediaButtonIntent(pi, eventReceiver, null);
}
}
@@ -5089,7 +5137,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
* Called synchronized on mAudioFocusLock, then mRCStack
* precondition: mediaIntent != null
*/
- private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target) {
+ private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target,
+ IBinder token) {
// already at top of stack?
if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
return;
@@ -5111,7 +5160,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
}
if (!wasInsideStack) {
- rcse = new RemoteControlStackEntry(mediaIntent, target);
+ rcse = new RemoteControlStackEntry(this, mediaIntent, target, token);
}
mRCStack.push(rcse); // rcse is never null
@@ -5133,7 +5182,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
for (int index = mRCStack.size()-1; index >= 0; index--) {
final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
if (rcse.mMediaIntent.equals(pi)) {
- rcse.unlinkToRcClientDeath();
+ rcse.destroy();
// ok to remove element while traversing the stack since we're leaving the loop
mRCStack.removeElementAt(index);
break;
@@ -5421,12 +5470,13 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
* see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
* precondition: mediaIntent != null
*/
- public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) {
+ public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
+ IBinder token) {
Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent);
synchronized(mAudioFocusLock) {
synchronized(mRCStack) {
- pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver);
+ pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token);
// new RC client, assume every type of information shall be queried
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
@@ -5820,7 +5870,16 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
- sendMsg(mAudioHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_QUEUE, generationId /* arg1 */,
+ // ignore position change requests if invalid generation ID
+ synchronized(mRCStack) {
+ synchronized(mCurrentRcLock) {
+ if (mCurrentRcClientGen != generationId) {
+ return;
+ }
+ }
+ }
+ // discard any unprocessed seek request in the message queue, and replace with latest
+ sendMsg(mAudioHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */,
0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */);
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index cd50de4..399eb7b 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -791,7 +791,7 @@ public class AudioTrack
* {@link #ERROR_INVALID_OPERATION}
*/
public int setPlaybackRate(int sampleRateInHz) {
- if (mState == STATE_UNINITIALIZED) {
+ if (mState != STATE_INITIALIZED) {
return ERROR_INVALID_OPERATION;
}
if (sampleRateInHz <= 0) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 25aae8f..13f6c02 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -120,7 +120,7 @@ interface IAudioService {
oneway void dispatchMediaKeyEvent(in KeyEvent keyEvent);
void dispatchMediaKeyEventUnderWakelock(in KeyEvent keyEvent);
- void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c);
+ void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c, IBinder token);
oneway void unregisterMediaButtonIntent(in PendingIntent pi);
oneway void registerMediaButtonEventReceiverForCalls(in ComponentName c);
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index b6b49a2..45a8b99 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -22,6 +22,7 @@ import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.view.Surface;
import java.nio.ByteBuffer;
+import java.util.Arrays;
import java.util.Map;
/**
@@ -395,6 +396,27 @@ final public class MediaCodec {
* see {@link #CRYPTO_MODE_UNENCRYPTED} and {@link #CRYPTO_MODE_AES_CTR}.
*/
public int mode;
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(numSubSamples + " subsamples, key [");
+ String hexdigits = "0123456789abcdef";
+ for (int i = 0; i < key.length; i++) {
+ builder.append(hexdigits.charAt((key[i] & 0xf0) >> 4));
+ builder.append(hexdigits.charAt(key[i] & 0x0f));
+ }
+ builder.append("], iv [");
+ for (int i = 0; i < key.length; i++) {
+ builder.append(hexdigits.charAt((iv[i] & 0xf0) >> 4));
+ builder.append(hexdigits.charAt(iv[i] & 0x0f));
+ }
+ builder.append("], clear ");
+ builder.append(Arrays.toString(numBytesOfClearData));
+ builder.append(", encrypted ");
+ builder.append(Arrays.toString(numBytesOfEncryptedData));
+ return builder.toString();
+ }
};
/**
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 3cdf261..6872278 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Bundle;
+import android.os.Parcel;
import android.util.Log;
/**
@@ -136,10 +137,8 @@ public final class MediaDrm {
public static final int MEDIA_DRM_EVENT_KEY_EXPIRED = 3;
public static final int MEDIA_DRM_EVENT_VENDOR_DEFINED = 4;
- /* Do not change these values without updating their counterparts
- * in include/media/mediadrm.h!
- */
private static final int DRM_EVENT = 200;
+
private class EventHandler extends Handler
{
private MediaDrm mMediaDrm;
@@ -161,10 +160,18 @@ public final class MediaDrm {
Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
if (mOnEventListener != null) {
- Bundle bundle = msg.getData();
- byte[] sessionId = bundle.getByteArray("sessionId");
- byte[] data = bundle.getByteArray("data");
- mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
+ if (msg.obj != null && msg.obj instanceof Parcel) {
+ Parcel parcel = (Parcel)msg.obj;
+ byte[] sessionId = parcel.createByteArray();
+ if (sessionId.length == 0) {
+ sessionId = null;
+ }
+ byte[] data = parcel.createByteArray();
+ if (data.length == 0) {
+ data = null;
+ }
+ mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
+ }
}
return;
@@ -183,14 +190,14 @@ public final class MediaDrm {
* the cookie passed to native_setup().)
*/
private static void postEventFromNative(Object mediadrm_ref,
- int what, int arg1, int arg2, Object obj)
+ int eventType, int extra, Object obj)
{
MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
if (md == null) {
return;
}
if (md.mEventHandler != null) {
- Message m = md.mEventHandler.obtainMessage(what, arg1, arg2, obj);
+ Message m = md.mEventHandler.obtainMessage(DRM_EVENT, eventType, extra, obj);
md.mEventHandler.sendMessage(m);
}
}
@@ -208,6 +215,7 @@ public final class MediaDrm {
public static final int MEDIA_DRM_KEY_TYPE_STREAMING = 1;
public static final int MEDIA_DRM_KEY_TYPE_OFFLINE = 2;
+ public static final int MEDIA_DRM_KEY_TYPE_RELEASE = 3;
public final class KeyRequest {
public KeyRequest() {}
@@ -216,28 +224,36 @@ public final class MediaDrm {
};
/**
- * A key request/response exchange occurs between the app and a license
- * server to obtain the keys to decrypt encrypted content. getKeyRequest()
- * is used to obtain an opaque key request byte array that is delivered to the
- * license server. The opaque key request byte array is returned in
- * KeyRequest.data. The recommended URL to deliver the key request to is
+ * A key request/response exchange occurs between the app and a license server
+ * to obtain or release keys used to decrypt encrypted content.
+ * getKeyRequest() is used to obtain an opaque key request byte array that is
+ * delivered to the license server. The opaque key request byte array is returned
+ * in KeyRequest.data. The recommended URL to deliver the key request to is
* returned in KeyRequest.defaultUrl.
*
* After the app has received the key request response from the server,
* it should deliver to the response to the DRM engine plugin using the method
* {@link #provideKeyResponse}.
*
- * @param sessonId the session ID for the drm session
+ * @param scope may be a sessionId or a keySetId, depending on the specified keyType.
+ * When the keyType is MEDIA_DRM_KEY_TYPE_STREAMING or MEDIA_DRM_KEY_TYPE_OFFLINE,
+ * scope should be set to the sessionId the keys will be provided to. When the keyType
+ * is MEDIA_DRM_KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
+ * being released. Releasing keys from a device invalidates them for all sessions.
* @param init container-specific data, its meaning is interpreted based on the
* mime type provided in the mimeType parameter. It could contain, for example,
* the content ID, key ID or other data obtained from the content metadata that is
- * required in generating the key request.
+ * required in generating the key request. init may be null when keyType is
+ * MEDIA_DRM_KEY_TYPE_RELEASE.
* @param mimeType identifies the mime type of the content
- * @param keyType specifes if the request is for streaming or offline content
+ * @param keyType specifes the type of the request. The request may be to acquire
+ * keys for streaming or offline content, or to release previously acquired
+ * keys, which are identified by a keySetId.
+
* @param optionalParameters are included in the key request message to
* allow a client application to provide additional message parameters to the server.
*/
- public native KeyRequest getKeyRequest(byte[] sessionId, byte[] init,
+ public native KeyRequest getKeyRequest(byte[] scope, byte[] init,
String mimeType, int keyType,
HashMap<String, String> optionalParameters)
throws MediaDrmException;
@@ -265,13 +281,11 @@ public final class MediaDrm {
throws MediaDrmException;
/**
- * Remove the persisted keys associated with an offline license. Keys are persisted
- * when {@link provideKeyResponse} is called with keys obtained from the method
- * {@link getKeyRequest} using keyType = MEDIA_DRM_KEY_TYPE_OFFLINE.
+ * Remove the current keys from a session.
*
- * @param keySetId identifies the saved key set to remove
+ * @param sessionId the session ID for the DRM session
*/
- public native void removeKeys(byte[] keySetId) throws MediaDrmException;
+ public native void removeKeys(byte[] sessionId) throws MediaDrmException;
/**
* Request an informative description of the key status for the session. The status is
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 749ef12..cf159f0 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -26,7 +26,10 @@ import android.net.Uri;
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.HashMap;
import java.util.Map;
+import java.util.UUID;
/**
* MediaExtractor facilitates extraction of demuxed, typically encoded, media data
@@ -64,7 +67,7 @@ final public class MediaExtractor {
* Sets the DataSource object to be used as the data source for this extractor
* {@hide}
*/
- public native final void setDataSource(DataSource source);
+ public native final void setDataSource(DataSource source) throws IOException;
/**
* Sets the data source as a content Uri.
@@ -118,7 +121,8 @@ final public class MediaExtractor {
* @param path the path of the file, or the http URL
* @param headers the headers associated with the http request for the stream you want to play
*/
- public final void setDataSource(String path, Map<String, String> headers) {
+ public final void setDataSource(String path, Map<String, String> headers)
+ throws IOException {
String[] keys = null;
String[] values = null;
@@ -137,7 +141,7 @@ final public class MediaExtractor {
}
private native final void setDataSource(
- String path, String[] keys, String[] values);
+ String path, String[] keys, String[] values) throws IOException;
/**
* Sets the data source (file-path or http URL) to use.
@@ -151,7 +155,7 @@ final public class MediaExtractor {
* As an alternative, the application could first open the file for reading,
* and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
*/
- public final void setDataSource(String path) {
+ public final void setDataSource(String path) throws IOException {
setDataSource(path, null, null);
}
@@ -161,7 +165,7 @@ final public class MediaExtractor {
*
* @param fd the FileDescriptor for the file you want to extract from.
*/
- public final void setDataSource(FileDescriptor fd) {
+ public final void setDataSource(FileDescriptor fd) throws IOException {
setDataSource(fd, 0, 0x7ffffffffffffffL);
}
@@ -175,7 +179,7 @@ final public class MediaExtractor {
* @param length the length in bytes of the data to be extracted
*/
public native final void setDataSource(
- FileDescriptor fd, long offset, long length);
+ FileDescriptor fd, long offset, long length) throws IOException;
@Override
protected void finalize() {
@@ -195,6 +199,38 @@ final public class MediaExtractor {
public native final int getTrackCount();
/**
+ * Get the PSSH info if present. This returns a map of uuid-to-bytes, with the uuid specifying
+ * the crypto scheme, and the bytes being the data specific to that scheme.
+ * {@hide}
+ */
+ public Map<UUID, byte[]> getPsshInfo() {
+ Map<UUID, byte[]> psshMap = null;
+ Map<String, Object> formatMap = getFileFormatNative();
+ if (formatMap != null && formatMap.containsKey("pssh")) {
+ ByteBuffer rawpssh = (ByteBuffer) formatMap.get("pssh");
+ rawpssh.order(ByteOrder.nativeOrder());
+ rawpssh.rewind();
+ formatMap.remove("pssh");
+ // parse the flat pssh bytebuffer into something more manageable
+ psshMap = new HashMap<UUID, byte[]>();
+ while (rawpssh.remaining() > 0) {
+ rawpssh.order(ByteOrder.BIG_ENDIAN);
+ long msb = rawpssh.getLong();
+ long lsb = rawpssh.getLong();
+ UUID uuid = new UUID(msb, lsb);
+ rawpssh.order(ByteOrder.nativeOrder());
+ int datalen = rawpssh.getInt();
+ byte [] psshdata = new byte[datalen];
+ rawpssh.get(psshdata);
+ psshMap.put(uuid, psshdata);
+ }
+ }
+ return psshMap;
+ }
+
+ private native Map<String, Object> getFileFormatNative();
+
+ /**
* Get the track format at the specified index.
* More detail on the representation can be found at {@link android.media.MediaCodec}
*/
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 1f5ca35..c0fbd2e 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -257,8 +257,10 @@ final public class MediaMuxer {
}
/**
- * Writes an encoded sample into the muxer. The application needs to make
- * sure that the samples are written into the right tracks.
+ * Writes an encoded sample into the muxer.
+ * <p>The application needs to make sure that the samples are written into
+ * the right tracks. Also, it needs to make sure the samples for each track
+ * are written in chronological order.</p>
* @param byteBuf The encoded sample.
* @param trackIndex The track index for this sample.
* @param bufferInfo The buffer information related to this sample.
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 85a32ca..f745163 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1181,7 +1181,8 @@ public class MediaPlayer
/**
* Gets the duration of the file.
*
- * @return the duration in milliseconds
+ * @return the duration in milliseconds, if no duration is available
+ * (for example, if streaming live content), -1 is returned.
*/
public native int getDuration();
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 795c3c2..61c55a5 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -767,10 +767,19 @@ public class MediaRouter {
boolean wantScan = false;
boolean blockScan = false;
WifiDisplay[] oldDisplays = oldStatus != null ?
- oldStatus.getRememberedDisplays() : new WifiDisplay[0];
- WifiDisplay[] newDisplays = newStatus.getRememberedDisplays();
- WifiDisplay[] availableDisplays = newStatus.getAvailableDisplays();
- WifiDisplay activeDisplay = newStatus.getActiveDisplay();
+ oldStatus.getRememberedDisplays() : WifiDisplay.EMPTY_ARRAY;
+ WifiDisplay[] newDisplays;
+ WifiDisplay[] availableDisplays;
+ WifiDisplay activeDisplay;
+
+ if (newStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
+ newDisplays = newStatus.getRememberedDisplays();
+ availableDisplays = newStatus.getAvailableDisplays();
+ activeDisplay = newStatus.getActiveDisplay();
+ } else {
+ newDisplays = availableDisplays = WifiDisplay.EMPTY_ARRAY;
+ activeDisplay = null;
+ }
for (int i = 0; i < newDisplays.length; i++) {
final WifiDisplay d = newDisplays[i];
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index e076ef0..4a5e82e 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -277,14 +277,12 @@ public class RemoteControlClient
*/
public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
/**
- * @hide
- * TODO un-hide and add in javadoc of setTransportControlFlags(int)
* Flag indicating a RemoteControlClient can receive changes in the media playback position
- * through the {@link #OnPlaybackPositionUpdateListener} interface. This flag must be set
+ * through the {@link OnPlaybackPositionUpdateListener} interface. This flag must be set
* in order for components that display the RemoteControlClient information, to display and
* let the user control media playback position.
* @see #setTransportControlFlags(int)
- * @see #setPlaybackPositionProvider(PlaybackPositionProvider)
+ * @see #setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener)
* @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
*/
public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
@@ -607,8 +605,6 @@ public class RemoteControlClient
}
/**
- * @hide
- * TODO un-hide
* Sets the current playback state and the matching media position for the current playback
* speed.
* @param state The current playback state, one of the following values:
@@ -660,7 +656,8 @@ public class RemoteControlClient
* {@link #FLAG_KEY_MEDIA_PAUSE},
* {@link #FLAG_KEY_MEDIA_STOP},
* {@link #FLAG_KEY_MEDIA_FAST_FORWARD},
- * {@link #FLAG_KEY_MEDIA_NEXT}
+ * {@link #FLAG_KEY_MEDIA_NEXT},
+ * {@link #FLAG_KEY_MEDIA_POSITION_UPDATE}
*/
public void setTransportControlFlags(int transportControlFlags) {
synchronized(mCacheLock) {
@@ -673,8 +670,6 @@ public class RemoteControlClient
}
/**
- * @hide
- * TODO un-hide
* Interface definition for a callback to be invoked when the media playback position is
* requested to be updated.
* @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
@@ -683,39 +678,38 @@ public class RemoteControlClient
/**
* Called on the implementer to notify it that the playback head should be set at the given
* position. If the position can be changed from its current value, the implementor of
- * the interface should also update the playback position using
- * {@link RemoteControlClient#setPlaybackState(int, long, int)} to reflect the actual new
+ * the interface must also update the playback position using
+ * {@link #setPlaybackState(int, long, float)} to reflect the actual new
* position being used, regardless of whether it differs from the requested position.
+ * Failure to do so would cause the system to not know the new actual playback position,
+ * and user interface components would fail to show the user where playback resumed after
+ * the position was updated.
* @param newPositionMs the new requested position in the current media, expressed in ms.
*/
void onPlaybackPositionUpdate(long newPositionMs);
}
/**
- * @hide
- * TODO un-hide
* Interface definition for a callback to be invoked when the media playback position is
* queried.
* @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
*/
- public interface PlaybackPositionProvider {
+ public interface OnGetPlaybackPositionListener {
/**
* Called on the implementer of the interface to query the current playback position.
* @return a negative value if the current playback position (or the last valid playback
* position) is not known, or a zero or positive value expressed in ms indicating the
* current position, or the last valid known position.
*/
- long getPlaybackPosition();
+ long onGetPlaybackPosition();
}
/**
- * @hide
- * TODO un-hide
* Sets the listener to be called whenever the media playback position is requested
* to be updated.
* Notifications will be received in the same thread as the one in which RemoteControlClient
* was created.
- * @param l
+ * @param l the position update listener to be called
*/
public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
synchronized(mCacheLock) {
@@ -734,14 +728,12 @@ public class RemoteControlClient
}
/**
- * @hide
- * TODO un-hide
* Sets the listener to be called whenever the media current playback position is needed.
* Queries will be received in the same thread as the one in which RemoteControlClient
* was created.
- * @param l
+ * @param l the listener to be called to retrieve the playback position
*/
- public void setPlaybackPositionProvider(PlaybackPositionProvider l) {
+ public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) {
synchronized(mCacheLock) {
int oldCapa = mPlaybackPositionCapabilities;
if (l != null) {
@@ -939,7 +931,7 @@ public class RemoteControlClient
/**
* Provider registered by user of RemoteControlClient to provide the current playback position.
*/
- private PlaybackPositionProvider mPositionProvider;
+ private OnGetPlaybackPositionListener mPositionProvider;
/**
* The current remote control client generation ID across the system, as known by this object
*/
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 6873060..416a2a1 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -28,6 +28,7 @@ LOCAL_SHARED_LIBRARIES := \
libmedia \
libskia \
libui \
+ liblog \
libcutils \
libgui \
libstagefright \
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 3a42db2..cd1d9ce 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -372,7 +372,7 @@ static jint throwExceptionAsNecessary(
default:
{
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException", msg);
break;
}
}
@@ -455,13 +455,13 @@ static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException", "no codec found");
return;
}
status_t err = codec->start();
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, "start failed");
}
static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 1618edf..c32ba9d 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -21,10 +21,12 @@
#include "android_media_MediaDrm.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_os_Parcel.h"
#include "jni.h"
#include "JNIHelp.h"
#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
#include <media/IDrm.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -43,6 +45,15 @@ namespace android {
var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find method " fieldName);
+#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find static method " fieldName);
+
+
struct RequestFields {
jfieldID data;
jfieldID defaultUrl;
@@ -74,8 +85,16 @@ struct EntryFields {
jmethodID getValue;
};
+struct EventTypes {
+ int kEventProvisionRequired;
+ int kEventKeyRequired;
+ int kEventKeyExpired;
+ int kEventVendorDefined;
+} gEventTypes;
+
struct fields_t {
jfieldID context;
+ jmethodID post_event;
RequestFields keyRequest;
RequestFields provisionRequest;
ArrayListFields arraylist;
@@ -87,6 +106,88 @@ struct fields_t {
static fields_t gFields;
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class JNIDrmListener: public DrmListener
+{
+public:
+ JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
+ ~JNIDrmListener();
+ virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
+private:
+ JNIDrmListener();
+ jclass mClass; // Reference to MediaDrm class
+ jobject mObject; // Weak ref to MediaDrm Java object to call on
+};
+
+JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
+{
+ // Hold onto the MediaDrm class for use in calling the static method
+ // that posts events to the application thread.
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ ALOGE("Can't find android/media/MediaDrm");
+ jniThrowException(env, "java/lang/Exception", NULL);
+ return;
+ }
+ mClass = (jclass)env->NewGlobalRef(clazz);
+
+ // We use a weak reference so the MediaDrm object can be garbage collected.
+ // The reference is only used as a proxy for callbacks.
+ mObject = env->NewGlobalRef(weak_thiz);
+}
+
+JNIDrmListener::~JNIDrmListener()
+{
+ // remove global references
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mObject);
+ env->DeleteGlobalRef(mClass);
+}
+
+void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
+ const Parcel *obj)
+{
+ jint jeventType;
+
+ // translate DrmPlugin event types into their java equivalents
+ switch(eventType) {
+ case DrmPlugin::kDrmPluginEventProvisionRequired:
+ jeventType = gEventTypes.kEventProvisionRequired;
+ break;
+ case DrmPlugin::kDrmPluginEventKeyNeeded:
+ jeventType = gEventTypes.kEventKeyRequired;
+ break;
+ case DrmPlugin::kDrmPluginEventKeyExpired:
+ jeventType = gEventTypes.kEventKeyExpired;
+ break;
+ case DrmPlugin::kDrmPluginEventVendorDefined:
+ jeventType = gEventTypes.kEventVendorDefined;
+ break;
+ default:
+ ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
+ return;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (obj && obj->dataSize() > 0) {
+ jobject jParcel = createJavaParcelObject(env);
+ if (jParcel != NULL) {
+ Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
+ nativeParcel->setData(obj->data(), obj->dataSize());
+ env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
+ jeventType, extra, jParcel);
+ }
+ }
+
+ if (env->ExceptionCheck()) {
+ ALOGW("An exception occurred while notifying an event.");
+ LOGW_EX(env);
+ env->ExceptionClear();
+ }
+}
+
+
static bool throwExceptionAsNecessary(
JNIEnv *env, status_t err, const char *msg = NULL) {
@@ -109,6 +210,9 @@ JDrm::JDrm(
JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
mObject = env->NewWeakGlobalRef(thiz);
mDrm = MakeDrm(uuid);
+ if (mDrm != NULL) {
+ mDrm->setListener(this);
+ }
}
JDrm::~JDrm() {
@@ -160,6 +264,25 @@ sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
return drm;
}
+status_t JDrm::setListener(const sp<DrmListener>& listener) {
+ Mutex::Autolock lock(mLock);
+ mListener = listener;
+ return OK;
+}
+
+void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
+ sp<DrmListener> listener;
+ mLock.lock();
+ listener = mListener;
+ mLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->notify(eventType, extra, obj);
+ }
+}
+
+
// static
bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
sp<IDrm> drm = MakeDrm();
@@ -194,10 +317,9 @@ static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector)
}
static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
- jboolean isCopy;
String8 result;
- const char *s = env->GetStringUTFChars(jstr, &isCopy);
+ const char *s = env->GetStringUTFChars(jstr, NULL);
if (s) {
result = s;
env->ReleaseStringUTFChars(jstr, s);
@@ -322,13 +444,28 @@ static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jse
}
static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
- setDrm(env, thiz, NULL);
+ sp<JDrm> drm = setDrm(env, thiz, NULL);
+ if (drm != NULL) {
+ drm->setListener(NULL);
+ }
}
static void android_media_MediaDrm_native_init(JNIEnv *env) {
jclass clazz;
FIND_CLASS(clazz, "android/media/MediaDrm");
GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
+ GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
+ "(Ljava/lang/Object;IILjava/lang/Object;)V");
+
+ jfieldID field;
+ GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_PROVISION_REQUIRED", "I");
+ gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_REQUIRED", "I");
+ gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_EXPIRED", "I");
+ gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_VENDOR_DEFINED", "I");
+ gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B");
@@ -389,6 +526,8 @@ static void android_media_MediaDrm_native_setup(
return;
}
+ sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
+ drm->setListener(listener);
setDrm(env, thiz, drm);
}
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index 01067c4..9b3917f 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -20,6 +20,8 @@
#include "jni.h"
#include <media/stagefright/foundation/ABase.h>
+#include <media/IDrm.h>
+#include <media/IDrmClient.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -27,15 +29,24 @@ namespace android {
struct IDrm;
-struct JDrm : public RefBase {
+class DrmListener: virtual public RefBase
+{
+public:
+ virtual void notify(DrmPlugin::EventType eventType, int extra,
+ const Parcel *obj) = 0;
+};
+
+struct JDrm : public BnDrmClient {
static bool IsCryptoSchemeSupported(const uint8_t uuid[16]);
JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16]);
status_t initCheck() const;
-
sp<IDrm> getDrm() { return mDrm; }
+ void notify(DrmPlugin::EventType, int extra, const Parcel *obj);
+ status_t setListener(const sp<DrmListener>& listener);
+
protected:
virtual ~JDrm();
@@ -43,6 +54,10 @@ private:
jweak mObject;
sp<IDrm> mDrm;
+ sp<DrmListener> mListener;
+ Mutex mNotifyLock;
+ Mutex mLock;
+
static sp<IDrm> MakeDrm();
static sp<IDrm> MakeDrm(const uint8_t uuid[16]);
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 23949fa..1704d5c 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -162,6 +162,18 @@ status_t JMediaExtractor::getTrackFormat(size_t index, jobject *format) const {
return ConvertMessageToMap(env, msg, format);
}
+status_t JMediaExtractor::getFileFormat(jobject *format) const {
+ sp<AMessage> msg;
+ status_t err;
+ if ((err = mImpl->getFileFormat(&msg)) != OK) {
+ return err;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ return ConvertMessageToMap(env, msg, format);
+}
+
status_t JMediaExtractor::selectTrack(size_t index) {
return mImpl->selectTrack(index);
}
@@ -339,6 +351,26 @@ static jobject android_media_MediaExtractor_getTrackFormatNative(
return format;
}
+static jobject android_media_MediaExtractor_getFileFormatNative(
+ JNIEnv *env, jobject thiz) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ jobject format;
+ status_t err = extractor->getFileFormat(&format);
+
+ if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return NULL;
+ }
+
+ return format;
+}
+
static void android_media_MediaExtractor_selectTrack(
JNIEnv *env, jobject thiz, jint index) {
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -768,6 +800,9 @@ static JNINativeMethod gMethods[] = {
{ "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount },
+ { "getFileFormatNative", "()Ljava/util/Map;",
+ (void *)android_media_MediaExtractor_getFileFormatNative },
+
{ "getTrackFormatNative", "(I)Ljava/util/Map;",
(void *)android_media_MediaExtractor_getTrackFormatNative },
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 03900db..ccbad8c 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -45,6 +45,8 @@ struct JMediaExtractor : public RefBase {
size_t countTracks() const;
status_t getTrackFormat(size_t index, jobject *format) const;
+ status_t getFileFormat(jobject *format) const;
+
status_t selectTrack(size_t index);
status_t unselectTrack(size_t index);
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
index b5d8b7b..3b1fb19 100644
--- a/media/jni/audioeffect/Android.mk
+++ b/media/jni/audioeffect/Android.mk
@@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \
android_media_Visualizer.cpp
LOCAL_SHARED_LIBRARIES := \
+ liblog \
libcutils \
libutils \
libandroid_runtime \
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 040d2ab..6be7fdd 100644
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -52,6 +52,7 @@ LOCAL_SHARED_LIBRARIES := \
libaudioutils \
libbinder \
libcutils \
+ liblog \
libdl \
libgui \
libmedia \
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 9b11bfa..5835b9f 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \
android_media_SoundPool.cpp
LOCAL_SHARED_LIBRARIES := \
+ liblog \
libcutils \
libutils \
libandroid_runtime \
diff --git a/media/libdrm/mobile1/Android.mk b/media/libdrm/mobile1/Android.mk
index b07d91c..7356f46 100644
--- a/media/libdrm/mobile1/Android.mk
+++ b/media/libdrm/mobile1/Android.mk
@@ -44,6 +44,7 @@ LOCAL_CFLAGS := $(LOCAL_DRM_CFLAG)
LOCAL_SHARED_LIBRARIES := \
libutils \
libcutils \
+ liblog \
libcrypto
LOCAL_MODULE := libdrm1
@@ -69,12 +70,13 @@ LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include/parser \
$(JNI_H_INCLUDE) \
$(call include-path-for, system-core)/cutils
-
+
LOCAL_SHARED_LIBRARIES := libdrm1 \
libnativehelper \
libutils \
- libcutils
+ libcutils \
+ liblog
LOCAL_MODULE := libdrm1_jni
diff --git a/media/mca/filterfw/Android.mk b/media/mca/filterfw/Android.mk
index 1d69799..2a9448d 100644
--- a/media/mca/filterfw/Android.mk
+++ b/media/mca/filterfw/Android.mk
@@ -37,6 +37,7 @@ LOCAL_SHARED_LIBRARIES := libstlport \
libdl \
libcutils \
libutils \
+ liblog \
libandroid \
libjnigraphics \
libmedia
@@ -48,5 +49,3 @@ LOCAL_SHARED_LIBRARIES := libstlport \
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
-
-
diff --git a/media/mca/filterpacks/Android.mk b/media/mca/filterpacks/Android.mk
index 6166b1e..6e54f60 100644
--- a/media/mca/filterpacks/Android.mk
+++ b/media/mca/filterpacks/Android.mk
@@ -46,10 +46,8 @@ LOCAL_SRC_FILES += native/imageproc/brightness.c \
native/imageproc/invert.c \
native/imageproc/to_rgba.c
-LOCAL_SHARED_LIBRARIES := libutils libfilterfw
+LOCAL_SHARED_LIBRARIES := liblog libutils libfilterfw
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
-
-
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 9dcc7ba..ad874c8 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -29,6 +29,7 @@ LOCAL_SHARED_LIBRARIES := \
libstagefright_foundation \
libbinder \
libutils \
+ liblog \
libjpeg
LOCAL_C_INCLUDES := \
diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk
index c655ae6..adf0d30 100644
--- a/media/tests/players/Android.mk
+++ b/media/tests/players/Android.mk
@@ -20,7 +20,8 @@ LOCAL_SRC_FILES:= invoke_mock_media_player.cpp
LOCAL_SHARED_LIBRARIES:= \
libbinder \
- libutils
+ libutils \
+ liblog
LOCAL_MODULE:= invoke_mock_media_player
LOCAL_MODULE_TAGS := tests eng