diff options
Diffstat (limited to 'media')
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 |