mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1306196-[P2] Provide RemoteMediaDrmBridge & corresponding stub to underlying GeckoMediaDrmBridge implementation. r=cpearce,jchen
MozReview-Commit-ID: K49zWmuJOpt --HG-- extra : rebase_source : cc721396185cc4730a6c081f385f0d8cebbd4c7b
This commit is contained in:
parent
998d263f00
commit
f0150be625
@ -25,7 +25,7 @@ public final class MediaManager extends Service {
|
||||
public IMediaDrmBridge createRemoteMediaDrmBridge(String keySystem,
|
||||
String stubId)
|
||||
throws RemoteException {
|
||||
return null;
|
||||
return new RemoteMediaDrmBridgeStub(keySystem, stubId);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -144,6 +144,23 @@ public final class RemoteManager implements IBinder.DeathRecipient {
|
||||
private void reportDecodingProcessCrash() {
|
||||
Telemetry.addToHistogram(MEDIA_DECODING_PROCESS_CRASH, 1);
|
||||
}
|
||||
|
||||
public synchronized IMediaDrmBridge createRemoteMediaDrmBridge(String keySystem,
|
||||
String stubId) {
|
||||
if (mRemote == null) {
|
||||
if (DEBUG) Log.d(LOGTAG, "createRemoteMediaDrmBridge failed due to not initialize");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
IMediaDrmBridge remoteBridge =
|
||||
mRemote.createRemoteMediaDrmBridge(keySystem, stubId);
|
||||
return remoteBridge;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "Got exception during createRemoteMediaDrmBridge().", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
Log.e(LOGTAG, "remote codec is dead");
|
||||
|
@ -0,0 +1,152 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.media;
|
||||
|
||||
import android.media.MediaCrypto;
|
||||
import android.util.Log;
|
||||
|
||||
final class RemoteMediaDrmBridge implements GeckoMediaDrm {
|
||||
private static final String LOGTAG = "GeckoRemoteMediaDrmBridge";
|
||||
private static final boolean DEBUG = false;
|
||||
private CallbacksForwarder mCallbacksFwd;
|
||||
private IMediaDrmBridge mRemote;
|
||||
|
||||
// Forward callbacks from remote bridge stub to MediaDrmProxy.
|
||||
private static class CallbacksForwarder extends IMediaDrmBridgeCallbacks.Stub {
|
||||
private final GeckoMediaDrm.Callbacks mProxyCallbacks;
|
||||
CallbacksForwarder(Callbacks callbacks) {
|
||||
assertTrue(callbacks != null);
|
||||
mProxyCallbacks = callbacks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionCreated(int createSessionToken,
|
||||
int promiseId,
|
||||
byte[] sessionId,
|
||||
byte[] request) {
|
||||
mProxyCallbacks.onSessionCreated(createSessionToken,
|
||||
promiseId,
|
||||
sessionId,
|
||||
request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionUpdated(int promiseId, byte[] sessionId) {
|
||||
mProxyCallbacks.onSessionUpdated(promiseId, sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionClosed(int promiseId, byte[] sessionId) {
|
||||
mProxyCallbacks.onSessionClosed(promiseId, sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionMessage(byte[] sessionId,
|
||||
int sessionMessageType,
|
||||
byte[] request) {
|
||||
mProxyCallbacks.onSessionMessage(sessionId, sessionMessageType, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionError(byte[] sessionId, String message) {
|
||||
mProxyCallbacks.onSessionError(sessionId, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionBatchedKeyChanged(byte[] sessionId,
|
||||
SessionKeyInfo[] keyInfos) {
|
||||
mProxyCallbacks.onSessionBatchedKeyChanged(sessionId, keyInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRejectPromise(int promiseId, String message) {
|
||||
mProxyCallbacks.onRejectPromise(promiseId, message);
|
||||
}
|
||||
} // CallbacksForwarder
|
||||
|
||||
/* package-private */ static void assertTrue(boolean condition) {
|
||||
if (DEBUG && !condition) {
|
||||
throw new AssertionError("Expected condition to be true");
|
||||
}
|
||||
}
|
||||
|
||||
public RemoteMediaDrmBridge(IMediaDrmBridge remoteBridge) {
|
||||
assertTrue(remoteBridge != null);
|
||||
mRemote = remoteBridge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setCallbacks(Callbacks callbacks) {
|
||||
if (DEBUG) Log.d(LOGTAG, "setCallbacks()");
|
||||
assertTrue(callbacks != null);
|
||||
assertTrue(mRemote != null);
|
||||
|
||||
mCallbacksFwd = new CallbacksForwarder(callbacks);
|
||||
try {
|
||||
mRemote.setCallbacks(mCallbacksFwd);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Got exception during setCallbacks", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void createSession(int createSessionToken,
|
||||
int promiseId,
|
||||
String initDataType,
|
||||
byte[] initData) {
|
||||
if (DEBUG) Log.d(LOGTAG, "createSession()");
|
||||
|
||||
try {
|
||||
mRemote.createSession(createSessionToken, promiseId, initDataType, initData);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Got exception while creating remote session.", e);
|
||||
mCallbacksFwd.onRejectPromise(promiseId, "Failed to create session.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateSession(int promiseId, String sessionId, byte[] response) {
|
||||
if (DEBUG) Log.d(LOGTAG, "updateSession()");
|
||||
|
||||
try {
|
||||
mRemote.updateSession(promiseId, sessionId, response);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Got exception while updating remote session.", e);
|
||||
mCallbacksFwd.onRejectPromise(promiseId, "Failed to update session.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeSession(int promiseId, String sessionId) {
|
||||
if (DEBUG) Log.d(LOGTAG, "closeSession()");
|
||||
|
||||
try {
|
||||
mRemote.closeSession(promiseId, sessionId);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Got exception while closing remote session.", e);
|
||||
mCallbacksFwd.onRejectPromise(promiseId, "Failed to close session.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void release() {
|
||||
if (DEBUG) Log.d(LOGTAG, "release()");
|
||||
|
||||
try {
|
||||
mRemote.release();
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Got exception while releasing RemoteDrmBridge.", e);
|
||||
}
|
||||
mRemote = null;
|
||||
mCallbacksFwd = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized MediaCrypto getMediaCrypto() {
|
||||
if (DEBUG) Log.d(LOGTAG, "getMediaCrypto(), should not enter here!");
|
||||
assertTrue(false);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,247 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.media;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.media.MediaCrypto;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
final class RemoteMediaDrmBridgeStub extends IMediaDrmBridge.Stub implements IBinder.DeathRecipient {
|
||||
private static final String LOGTAG = "GeckoRemoteMediaDrmBridgeStub";
|
||||
private static final boolean DEBUG = false;
|
||||
private volatile IMediaDrmBridgeCallbacks mCallbacks = null;
|
||||
|
||||
// Underlying bridge implmenetaion, i.e. GeckoMediaDrmBrdigeV21.
|
||||
private GeckoMediaDrm mBridge = null;
|
||||
|
||||
// mStubId is initialized during stub construction. It should be a unique
|
||||
// string which is generated in MediaDrmProxy in Fennec App process and is
|
||||
// used for Codec to obtain corresponding MediaCrypto as input to achieve
|
||||
// decryption.
|
||||
// The generated stubId will be delivered to Codec via a code path starting
|
||||
// from MediaDrmProxy -> MediaDrmCDMProxy -> RemoteDataDecoder => IPC => Codec.
|
||||
private String mStubId = "";
|
||||
|
||||
public static ArrayList<RemoteMediaDrmBridgeStub> mBridgeStubs =
|
||||
new ArrayList<RemoteMediaDrmBridgeStub>();
|
||||
|
||||
private String getId() {
|
||||
return mStubId;
|
||||
}
|
||||
|
||||
private MediaCrypto getMediaCryptoFromBridge() {
|
||||
return mBridge != null ? mBridge.getMediaCrypto() : null;
|
||||
}
|
||||
|
||||
public static synchronized MediaCrypto getMediaCrypto(String stubId) {
|
||||
if (DEBUG) Log.d(LOGTAG, "getMediaCrypto()");
|
||||
|
||||
for (int i = 0; i < mBridgeStubs.size(); i++) {
|
||||
if (mBridgeStubs.get(i) != null &&
|
||||
mBridgeStubs.get(i).getId().equals(stubId)) {
|
||||
return mBridgeStubs.get(i).getMediaCryptoFromBridge();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Callback to RemoteMediaDrmBridge.
|
||||
private final class Callbacks implements GeckoMediaDrm.Callbacks {
|
||||
private IMediaDrmBridgeCallbacks mRemoteCallbacks;
|
||||
|
||||
public Callbacks(IMediaDrmBridgeCallbacks remote) {
|
||||
mRemoteCallbacks = remote;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionCreated(int createSessionToken,
|
||||
int promiseId,
|
||||
byte[] sessionId,
|
||||
byte[] request) {
|
||||
if (DEBUG) Log.d(LOGTAG, "onSessionCreated()");
|
||||
try {
|
||||
mRemoteCallbacks.onSessionCreated(createSessionToken,
|
||||
promiseId,
|
||||
sessionId,
|
||||
request);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "Exception ! Dead recipient !!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionUpdated(int promiseId, byte[] sessionId) {
|
||||
if (DEBUG) Log.d(LOGTAG, "onSessionUpdated()");
|
||||
try {
|
||||
mRemoteCallbacks.onSessionUpdated(promiseId, sessionId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "Exception ! Dead recipient !!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionClosed(int promiseId, byte[] sessionId) {
|
||||
if (DEBUG) Log.d(LOGTAG, "onSessionClosed()");
|
||||
try {
|
||||
mRemoteCallbacks.onSessionClosed(promiseId, sessionId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "Exception ! Dead recipient !!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionMessage(byte[] sessionId,
|
||||
int sessionMessageType,
|
||||
byte[] request) {
|
||||
if (DEBUG) Log.d(LOGTAG, "onSessionMessage()");
|
||||
try {
|
||||
mRemoteCallbacks.onSessionMessage(sessionId, sessionMessageType, request);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "Exception ! Dead recipient !!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionError(byte[] sessionId, String message) {
|
||||
if (DEBUG) Log.d(LOGTAG, "onSessionError()");
|
||||
try {
|
||||
mRemoteCallbacks.onSessionError(sessionId, message);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "Exception ! Dead recipient !!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionBatchedKeyChanged(byte[] sessionId,
|
||||
SessionKeyInfo[] keyInfos) {
|
||||
if (DEBUG) Log.d(LOGTAG, "onSessionBatchedKeyChanged()");
|
||||
try {
|
||||
mRemoteCallbacks.onSessionBatchedKeyChanged(sessionId, keyInfos);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "Exception ! Dead recipient !!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRejectPromise(int promiseId, String message) {
|
||||
if (DEBUG) Log.d(LOGTAG, "onRejectPromise()");
|
||||
try {
|
||||
mRemoteCallbacks.onRejectPromise(promiseId, message);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "Exception ! Dead recipient !!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* package-private */ void assertTrue(boolean condition) {
|
||||
if (DEBUG && !condition) {
|
||||
throw new AssertionError("Expected condition to be true");
|
||||
}
|
||||
}
|
||||
|
||||
RemoteMediaDrmBridgeStub(String keySystem, String stubId) throws RemoteException {
|
||||
if (AppConstants.Versions.preLollipop) {
|
||||
Log.e(LOGTAG, "Pre-Lollipop should never enter here!!");
|
||||
throw new RemoteException("Error, unsupported version!");
|
||||
}
|
||||
try {
|
||||
if (AppConstants.Versions.feature21Plus &&
|
||||
AppConstants.Versions.preMarshmallow) {
|
||||
mBridge = new GeckoMediaDrmBridgeV21(keySystem);
|
||||
} else {
|
||||
mBridge = new GeckoMediaDrmBridgeV23(keySystem);
|
||||
}
|
||||
mStubId = stubId;
|
||||
mBridgeStubs.add(this);
|
||||
} catch (Exception e) {
|
||||
throw new RemoteException("RemoteMediaDrmBridgeStub cannot create bridge implementation.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setCallbacks(IMediaDrmBridgeCallbacks callbacks) throws RemoteException {
|
||||
if (DEBUG) Log.d(LOGTAG, "setCallbacks()");
|
||||
assertTrue(mBridge != null);
|
||||
assertTrue(callbacks != null);
|
||||
mCallbacks = callbacks;
|
||||
callbacks.asBinder().linkToDeath(this, 0);
|
||||
mBridge.setCallbacks(new Callbacks(mCallbacks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void createSession(int createSessionToken,
|
||||
int promiseId,
|
||||
String initDataType,
|
||||
byte[] initData) throws RemoteException {
|
||||
if (DEBUG) Log.d(LOGTAG, "createSession()");
|
||||
try {
|
||||
assertTrue(mCallbacks != null);
|
||||
assertTrue(mBridge != null);
|
||||
mBridge.createSession(createSessionToken,
|
||||
promiseId,
|
||||
initDataType,
|
||||
initData);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Failed to createSession.", e);
|
||||
mCallbacks.onRejectPromise(promiseId, "Failed to createSession.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateSession(int promiseId,
|
||||
String sessionId,
|
||||
byte[] response) throws RemoteException {
|
||||
if (DEBUG) Log.d(LOGTAG, "updateSession()");
|
||||
try {
|
||||
assertTrue(mCallbacks != null);
|
||||
assertTrue(mBridge != null);
|
||||
mBridge.updateSession(promiseId, sessionId, response);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Failed to updateSession.", e);
|
||||
mCallbacks.onRejectPromise(promiseId, "Failed to updateSession.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeSession(int promiseId, String sessionId) throws RemoteException {
|
||||
if (DEBUG) Log.d(LOGTAG, "closeSession()");
|
||||
try {
|
||||
assertTrue(mCallbacks != null);
|
||||
assertTrue(mBridge != null);
|
||||
mBridge.closeSession(promiseId, sessionId);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Failed to closeSession.", e);
|
||||
mCallbacks.onRejectPromise(promiseId, "Failed to closeSession.");
|
||||
}
|
||||
}
|
||||
|
||||
// IBinder.DeathRecipient
|
||||
@Override
|
||||
public synchronized void binderDied() {
|
||||
Log.e(LOGTAG, "Binder died !!");
|
||||
try {
|
||||
release();
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Exception ! Dead recipient !!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void release() {
|
||||
if (DEBUG) Log.d(LOGTAG, "release()");
|
||||
mBridgeStubs.remove(this);
|
||||
if (mBridge != null) {
|
||||
mBridge.release();
|
||||
mBridge = null;
|
||||
}
|
||||
mCallbacks.asBinder().unlinkToDeath(this, 0);
|
||||
mCallbacks = null;
|
||||
mStubId = "";
|
||||
}
|
||||
}
|
@ -564,6 +564,8 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||
'media/MediaDrmProxy.java',
|
||||
'media/MediaManager.java',
|
||||
'media/RemoteManager.java',
|
||||
'media/RemoteMediaDrmBridge.java',
|
||||
'media/RemoteMediaDrmBridgeStub.java',
|
||||
'media/Sample.java',
|
||||
'media/SamplePool.java',
|
||||
'media/SessionKeyInfo.java',
|
||||
|
Loading…
Reference in New Issue
Block a user