13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// found in the LICENSE file. 43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)package org.chromium.media; 63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.media.MediaCrypto; 83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.media.MediaDrm; 93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.os.AsyncTask; 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.os.Build; 113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.os.Handler; 123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.util.Log; 133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.apache.http.HttpResponse; 153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.apache.http.client.ClientProtocolException; 16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import org.apache.http.client.HttpClient; 17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import org.apache.http.client.methods.HttpPost; 183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.apache.http.impl.client.DefaultHttpClient; 193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.apache.http.util.EntityUtils; 203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.base.CalledByNative; 213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.base.JNINamespace; 223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.io.IOException; 24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import java.nio.ByteBuffer; 256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)import java.nio.ByteOrder; 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import java.util.ArrayDeque; 273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.util.HashMap; 283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.util.UUID; 293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)/** 313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * A wrapper of the android MediaDrm class. Each MediaDrmBridge manages multiple 323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * sessions for a single MediaSourcePlayer. 333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)@JNINamespace("media") 356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)public class MediaDrmBridge { 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Implementation Notes: 37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // - A media crypto session (mMediaCryptoSession) is opened after MediaDrm 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // is created. This session will be added to mSessionIds. 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // a) In multiple session mode, this session will only be used to create 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // the MediaCrypto object. It's associated mime type is always null and 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // it's session ID is always INVALID_SESSION_ID. 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // b) In single session mode, this session will be used to create the 43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // MediaCrypto object and will be used to call getKeyRequest() and 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // manage all keys. The session ID will always be the lastest session 45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // ID passed by the caller. 46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // - Each createSession() call creates a new session. All sessions are 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // managed in mSessionIds. 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // - Whenever NotProvisionedException is thrown, we will clean up the 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // current state and start the provisioning process. 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // - When provisioning is finished, we will try to resume suspended 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // operations: 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // a) Create the media crypto session if it's not created. 53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // b) Finish createSession() if previous createSession() was interrupted 54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // by a NotProvisionedException. 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // - Whenever an unexpected error occurred, we'll call release() to release 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // all resources and clear all states. In that case all calls to this 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // object will be no-op. All public APIs and callbacks should check 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // mMediaBridge to make sure release() hasn't been called. Also, we call 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // release() immediately after the error happens (e.g. after mMediaDrm) 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // calls. Indirect calls should not call release() again to avoid 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // duplication (even though it doesn't hurt to call release() twice). 623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private static final String TAG = "MediaDrmBridge"; 6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private static final String SECURITY_LEVEL = "securityLevel"; 6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private static final String PRIVACY_MODE = "privacyMode"; 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private static final String SESSION_SHARING = "sessionSharing"; 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private static final String ENABLE = "enable"; 68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private static final int INVALID_SESSION_ID = 0; 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private MediaDrm mMediaDrm; 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private long mNativeMediaDrmBridge; 723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private UUID mSchemeUUID; 73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) private Handler mHandler; 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // In this mode, we only open one session, i.e. mMediaCryptoSession. 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private boolean mSingleSessionMode; 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // A session only for the purpose of creating a MediaCrypto object. 79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // This session is opened when createSession() is called for the first 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // time. 81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // - In multiple session mode, all following createSession() calls 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // should create a new session and use it to call getKeyRequest(). No 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // getKeyRequest() should ever be called on this media crypto session. 84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // - In single session mode, all createSession() calls use the same 85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // media crypto session. When createSession() is called with a new 86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // initData, previously added keys may not be available anymore. 87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private ByteBuffer mMediaCryptoSession; 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private MediaCrypto mMediaCrypto; 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // The map of all opened sessions to their session reference IDs. 91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private HashMap<ByteBuffer, Integer> mSessionIds; 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The map of all opened sessions to their mime types. 93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private HashMap<ByteBuffer, String> mSessionMimeTypes; 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // The queue of all pending createSession() data. 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private ArrayDeque<PendingCreateSessionData> mPendingCreateSessionDataQueue; 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) private boolean mResetDeviceCredentialsPending; 993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // MediaDrmBridge is waiting for provisioning response from the server. 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Notes about NotProvisionedException: This exception can be thrown in a 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // lot of cases. To streamline implementation, we do not catch it in private 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // non-native methods and only catch it in public APIs. 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private boolean mProvisioningPending; 106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /** 108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * This class contains data needed to call createSession(). 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private static class PendingCreateSessionData { 111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private final int mSessionId; 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private final byte[] mInitData; 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private final String mMimeType; 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private PendingCreateSessionData(int sessionId, byte[] initData, String mimeType) { 116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mSessionId = sessionId; 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mInitData = initData; 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mMimeType = mimeType; 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private int sessionId() { return mSessionId; } 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private byte[] initData() { return mInitData; } 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private String mimeType() { return mMimeType; } 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private static UUID getUUIDFromBytes(byte[] data) { 1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (data.length != 16) { 1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return null; 1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) long mostSigBits = 0; 1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) long leastSigBits = 0; 1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) for (int i = 0; i < 8; i++) { 1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) mostSigBits = (mostSigBits << 8) | (data[i] & 0xff); 1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) for (int i = 8; i < 16; i++) { 1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) leastSigBits = (leastSigBits << 8) | (data[i] & 0xff); 1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return new UUID(mostSigBits, leastSigBits); 1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /** 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Gets session associated with the sessionId. 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @return session if sessionId maps a valid opened session. Returns null 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * otherwise. 146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) */ 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private ByteBuffer getSession(int sessionId) { 148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (ByteBuffer session : mSessionIds.keySet()) { 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (mSessionIds.get(session) == sessionId) { 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return session; 151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return null; 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private MediaDrmBridge(UUID schemeUUID, long nativeMediaDrmBridge, boolean singleSessionMode) 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) throws android.media.UnsupportedSchemeException { 15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) mSchemeUUID = schemeUUID; 15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) mMediaDrm = new MediaDrm(schemeUUID); 16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) mNativeMediaDrmBridge = nativeMediaDrmBridge; 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mHandler = new Handler(); 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mSingleSessionMode = singleSessionMode; 163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mSessionIds = new HashMap<ByteBuffer, Integer>(); 164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mSessionMimeTypes = new HashMap<ByteBuffer, String>(); 165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mPendingCreateSessionDataQueue = new ArrayDeque<PendingCreateSessionData>(); 16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) mResetDeviceCredentialsPending = false; 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mProvisioningPending = false; 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) mMediaDrm.setOnEventListener(new MediaDrmListener()); 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mMediaDrm.setPropertyString(PRIVACY_MODE, ENABLE); 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!mSingleSessionMode) { 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mMediaDrm.setPropertyString(SESSION_SHARING, ENABLE); 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // We could open a MediaCrypto session here to support faster start of 176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // clear lead (no need to wait for createSession()). But on 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Android, memory and battery resources are precious and we should 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // only create a session when we are sure we'll use it. 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(xhwang): Investigate other options to support fast start. 1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 1813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) /** 183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) * Create a MediaCrypto object. 184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) * 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @return whether a MediaCrypto object is successfully created. 186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) */ 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private boolean createMediaCrypto() throws android.media.NotProvisionedException { 188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mMediaDrm == null) { 189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert !mProvisioningPending; 192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaCryptoSession == null; 193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaCrypto == null; 194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Open media crypto session. 196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mMediaCryptoSession = openSession(); 197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (mMediaCryptoSession == null) { 198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Cannot create MediaCrypto Session."); 199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.d(TAG, "MediaCrypto Session created: " + mMediaCryptoSession); 202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Create MediaCrypto object. 204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) try { 205424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) { 206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) final byte[] mediaCryptoSession = mMediaCryptoSession.array(); 207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mMediaCrypto = new MediaCrypto(mSchemeUUID, mediaCryptoSession); 208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaCrypto != null; 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.d(TAG, "MediaCrypto successfully created!"); 210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mSessionIds.put(mMediaCryptoSession, INVALID_SESSION_ID); 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Notify the native code that MediaCrypto is ready. 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) nativeOnMediaCryptoReady(mNativeMediaDrmBridge); 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Cannot create MediaCrypto for unsupported scheme."); 216424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } catch (android.media.MediaCryptoException e) { 218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Cannot create MediaCrypto", e); 219424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 220424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) release(); 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 223424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 224424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 225424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) /** 226a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Open a new session.. 2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * 228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @return the session opened. Returns null if unexpected error happened. 2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 230a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private ByteBuffer openSession() throws android.media.NotProvisionedException { 231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaDrm != null; 232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) try { 233a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) byte[] session = mMediaDrm.openSession(); 234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // ByteBuffer.wrap() is backed by the byte[]. Make a clone here in 235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // case the underlying byte[] is modified. 236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return ByteBuffer.wrap(session.clone()); 237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } catch (java.lang.RuntimeException e) { // TODO(xhwang): Drop this? 238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Cannot open a new session", e); 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) release(); 240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return null; 2412f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles) } catch (android.media.NotProvisionedException e) { 2422f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles) // Throw NotProvisionedException so that we can startProvisioning(). 2432f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles) throw e; 2442f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles) } catch (android.media.MediaDrmException e) { 2452f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles) // Other MediaDrmExceptions (e.g. ResourceBusyException) are not 2462f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles) // recoverable. 2472f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles) Log.e(TAG, "Cannot open a new session", e); 2482f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles) release(); 2492f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles) return null; 250424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 252424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Close a session. 255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param session to be closed. 257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void closeSession(ByteBuffer session) { 259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaDrm != null; 260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mMediaDrm.closeSession(session.array()); 2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 263d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) /** 264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * Check whether the crypto scheme is supported for the given container. 265d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * If |containerMimeType| is an empty string, we just return whether 266d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * the crypto scheme is supported. 267d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * 268d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * @return true if the container and the crypto scheme is supported, or 269d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * false otherwise. 270d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) */ 27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) @CalledByNative 27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private static boolean isCryptoSchemeSupported(byte[] schemeUUID, String containerMimeType) { 27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) UUID cryptoScheme = getUUIDFromBytes(schemeUUID); 274c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 275c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (containerMimeType.isEmpty()) { 276c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return MediaDrm.isCryptoSchemeSupported(cryptoScheme); 277c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 278c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 279c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return MediaDrm.isCryptoSchemeSupported(cryptoScheme, containerMimeType); 28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) /** 2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * Create a new MediaDrmBridge from the crypto scheme UUID. 2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * 2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * @param schemeUUID Crypto scheme UUID. 28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * @param securityLevel Security level to be used. 2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * @param nativeMediaDrmBridge Native object of this class. 2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) @CalledByNative 290010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) private static MediaDrmBridge create(byte[] schemeUUID, long nativeMediaDrmBridge) { 2913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) UUID cryptoScheme = getUUIDFromBytes(schemeUUID); 29258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (cryptoScheme == null || !MediaDrm.isCryptoSchemeSupported(cryptoScheme)) { 29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return null; 2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 29558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) boolean singleSessionMode = false; 297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (Build.VERSION.RELEASE.equals("4.4")) { 298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) singleSessionMode = true; 299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.d(TAG, "MediaDrmBridge uses " + 301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) (singleSessionMode ? "single" : "multiple") + "-session mode."); 302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 303a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MediaDrmBridge mediaDrmBridge = null; 30458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) try { 305a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mediaDrmBridge = new MediaDrmBridge( 3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) cryptoScheme, nativeMediaDrmBridge, singleSessionMode); 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.d(TAG, "MediaDrmBridge successfully created."); 30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } catch (android.media.UnsupportedSchemeException e) { 309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Unsupported DRM scheme", e); 31058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } catch (java.lang.IllegalArgumentException e) { 311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Failed to create MediaDrmBridge", e); 31258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } catch (java.lang.IllegalStateException e) { 313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Failed to create MediaDrmBridge", e); 31458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return mediaDrmBridge; 3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 3183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 3193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) /** 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Set the security level that the MediaDrm object uses. 3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * This function should be called right after we construct MediaDrmBridge 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * and before we make any other calls. 3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @CalledByNative 3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private boolean setSecurityLevel(String securityLevel) { 3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (mMediaDrm == null || mMediaCrypto != null) { 3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) String currentSecurityLevel = mMediaDrm.getPropertyString(SECURITY_LEVEL); 3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.e(TAG, "Security level: current " + currentSecurityLevel + ", new " + securityLevel); 3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (securityLevel.equals(currentSecurityLevel)) { 3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // No need to set the same security level again. This is not just 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // a shortcut! Setting the same security level actually causes an 3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // exception in MediaDrm! 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) try { 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mMediaDrm.setPropertyString(SECURITY_LEVEL, securityLevel); 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } catch (java.lang.IllegalArgumentException e) { 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.e(TAG, "Failed to set security level " + securityLevel, e); 3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } catch (java.lang.IllegalStateException e) { 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.e(TAG, "Failed to set security level " + securityLevel, e); 3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Log.e(TAG, "Security level " + securityLevel + " not supported!"); 3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 353424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) * Return the MediaCrypto object if available. 3543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 3553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) @CalledByNative 3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private MediaCrypto getMediaCrypto() { 3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return mMediaCrypto; 3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 3593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 3603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) /** 36168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) * Reset the device DRM credentials. 36268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) */ 36368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) @CalledByNative 36468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) private void resetDeviceCredentials() { 36568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) mResetDeviceCredentialsPending = true; 36668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest(); 36768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) PostRequestTask postTask = new PostRequestTask(request.getData()); 36868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) postTask.execute(request.getDefaultUrl()); 36968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 37068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 37168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) /** 3723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * Release the MediaDrmBridge object. 3733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 3743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) @CalledByNative 3753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private void release() { 376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Do not reset mHandler and mNativeMediaDrmBridge so that we can still 377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // post KeyError back to native code. 378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mPendingCreateSessionDataQueue.clear(); 380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mPendingCreateSessionDataQueue = null; 381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (ByteBuffer session : mSessionIds.keySet()) { 383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) closeSession(session); 384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mSessionIds.clear(); 386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mSessionIds = null; 387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mSessionMimeTypes.clear(); 388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mSessionMimeTypes = null; 389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // This session was closed in the "for" loop above. 391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mMediaCryptoSession = null; 392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 3933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (mMediaCrypto != null) { 3943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) mMediaCrypto.release(); 39558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) mMediaCrypto = null; 3963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 39858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (mMediaDrm != null) { 39958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) mMediaDrm.release(); 40058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) mMediaDrm = null; 4013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 4023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 4033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 4043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) /** 405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Get a key request. 406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param session Session on which we need to get the key request. 408f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param data Data needed to get the key request. 409f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param mime Mime type to get the key request. 410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @return the key request. 412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private MediaDrm.KeyRequest getKeyRequest(ByteBuffer session, byte[] data, String mime) 414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) throws android.media.NotProvisionedException { 415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaDrm != null; 416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaCrypto != null; 417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert !mProvisioningPending; 418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HashMap<String, String> optionalParameters = new HashMap<String, String>(); 420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MediaDrm.KeyRequest request = mMediaDrm.getKeyRequest( 421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) session.array(), data, mime, MediaDrm.KEY_TYPE_STREAMING, optionalParameters); 422a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) String result = (request != null) ? "successed" : "failed"; 423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.d(TAG, "getKeyRequest " + result + "!"); 424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return request; 425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Save data to |mPendingCreateSessionDataQueue| so that we can resume the 429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * createSession() call later. 430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void savePendingCreateSessionData(int sessionId, byte[] initData, String mime) { 432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.d(TAG, "savePendingCreateSessionData()"); 433a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mPendingCreateSessionDataQueue.offer( 434a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new PendingCreateSessionData(sessionId, initData, mime)); 435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 437f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 438a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Process all pending createSession() calls synchronously. 439f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 440a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void processPendingCreateSessionData() { 441a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.d(TAG, "processPendingCreateSessionData()"); 442a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaDrm != null; 443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Check mMediaDrm != null because error may happen in createSession(). 445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Check !mProvisioningPending because NotProvisionedException may be 446a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // thrown in createSession(). 447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) while (mMediaDrm != null && !mProvisioningPending && 448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) !mPendingCreateSessionDataQueue.isEmpty()) { 449a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) PendingCreateSessionData pendingData = mPendingCreateSessionDataQueue.poll(); 450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int sessionId = pendingData.sessionId(); 451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) byte[] initData = pendingData.initData(); 452a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) String mime = pendingData.mimeType(); 453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) createSession(sessionId, initData, mime); 454f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Process pending operations asynchrnously. 459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private void resumePendingOperations() { 461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mHandler.post(new Runnable(){ 462a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) @Override 463f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public void run() { 464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) processPendingCreateSessionData(); 465f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 466f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) }); 467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 468f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 470a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Create a session with |sessionId|, |initData| and |mime|. 471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * In multiple session mode, a new session will be open. In single session 472a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * mode, the mMediaCryptoSession will be used. 4733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * 474a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param sessionId ID for the session to be created. 4753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * @param initData Data needed to generate the key request. 4763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * @param mime Mime type. 4773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 4783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) @CalledByNative 479a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void createSession(int sessionId, byte[] initData, String mime) { 480a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.d(TAG, "createSession()"); 481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mMediaDrm == null) { 482a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "createSession() called when MediaDrm is null."); 483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 485424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mProvisioningPending) { 487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaCrypto == null; 488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) savePendingCreateSessionData(sessionId, initData, mime); 4893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return; 4903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 491424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) boolean newSessionOpened = false; 493a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ByteBuffer session = null; 494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) try { 495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Create MediaCrypto if necessary. 496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mMediaCrypto == null && !createMediaCrypto()) { 497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionError(sessionId); 498a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 499424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 500a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaCrypto != null; 501a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mSessionIds.containsKey(mMediaCryptoSession); 502f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 503f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mSingleSessionMode) { 504a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) session = mMediaCryptoSession; 505a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (mSessionMimeTypes.get(session) != null && 506a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) !mSessionMimeTypes.get(session).equals(mime)) { 507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Only one mime type is supported in single session mode."); 508a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionError(sessionId); 509f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 512a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) session = openSession(); 513a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (session == null) { 514a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "Cannot open session in createSession()."); 515a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionError(sessionId); 516424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return; 517424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) newSessionOpened = true; 519a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert !mSessionIds.containsKey(session); 520f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 521424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MediaDrm.KeyRequest request = null; 523a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) request = getKeyRequest(session, initData, mime); 524a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (request == null) { 525a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (newSessionOpened) { 526a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) closeSession(session); 527a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 528a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionError(sessionId); 529424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return; 530424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 531424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 532a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionCreated(sessionId, getWebSessionId(session)); 533a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionMessage(sessionId, request); 534f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (newSessionOpened) { 535a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.d(TAG, "createSession(): Session " + getWebSessionId(session) + 536a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " (" + sessionId + ") created."); 537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 538a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 539a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mSessionIds.put(session, sessionId); 540a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mSessionMimeTypes.put(session, mime); 5413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } catch (android.media.NotProvisionedException e) { 542f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Device not provisioned", e); 543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (newSessionOpened) { 544a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) closeSession(session); 545f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 546a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) savePendingCreateSessionData(sessionId, initData, mime); 547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) startProvisioning(); 548f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 549f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 550f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 552f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Returns whether |sessionId| is a valid key session, excluding the media 553f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * crypto session in multi-session mode. 554f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param sessionId Crypto session Id. 556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 557a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private boolean sessionExists(ByteBuffer session) { 558a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (mMediaCryptoSession == null) { 559a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mSessionIds.isEmpty(); 560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Session doesn't exist because media crypto session is not created."); 561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 5623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 563a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mSessionIds.containsKey(mMediaCryptoSession); 564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mSingleSessionMode) { 566a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return mMediaCryptoSession.equals(session); 567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 569a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return !session.equals(mMediaCryptoSession) && mSessionIds.containsKey(session); 5703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 5713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 5723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) /** 5733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * Cancel a key request for a session Id. 5743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * 575a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param sessionId Reference ID of session to be released. 5763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 5773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) @CalledByNative 578a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void releaseSession(int sessionId) { 579a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.d(TAG, "releaseSession(): " + sessionId); 580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mMediaDrm == null) { 581a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "releaseSession() called when MediaDrm is null."); 582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 584f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 585a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ByteBuffer session = getSession(sessionId); 586a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (session == null) { 587a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "Invalid sessionId in releaseSession."); 588a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionError(sessionId); 5893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return; 5903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 591f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 592a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mMediaDrm.removeKeys(session.array()); 593f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 594f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // We don't close the media crypto session in single session mode. 595f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!mSingleSessionMode) { 596f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.d(TAG, "Session " + sessionId + "closed."); 597a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) closeSession(session); 598a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mSessionIds.remove(session); 599a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionClosed(sessionId); 6003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 6013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 6023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) /** 6043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * Add a key for a session Id. 6053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * 606a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param sessionId Reference ID of session to be updated. 6073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * @param key Response data from the server. 6083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 6093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) @CalledByNative 610a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void updateSession(int sessionId, byte[] key) { 611a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.d(TAG, "updateSession(): " + sessionId); 612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mMediaDrm == null) { 613a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "updateSession() called when MediaDrm is null."); 6143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return; 6153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 616f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 617f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(xhwang): We should be able to DCHECK this when WD EME is implemented. 618a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ByteBuffer session = getSession(sessionId); 619a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!sessionExists(session)) { 620a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "Invalid session in updateSession."); 621a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionError(sessionId); 622f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 623f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 624f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 6253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) try { 626424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) try { 627a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mMediaDrm.provideKeyResponse(session.array(), key); 628424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } catch (java.lang.IllegalStateException e) { 629424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // This is not really an exception. Some error code are incorrectly 630424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // reported as an exception. 631424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // TODO(qinmin): remove this exception catch when b/10495563 is fixed. 632f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "Exception intentionally caught when calling provideKeyResponse()", e); 633424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 634a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionReady(sessionId); 635f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.d(TAG, "Key successfully added for session " + sessionId); 6363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return; 6373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } catch (android.media.NotProvisionedException e) { 638a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // TODO(xhwang): Should we handle this? 639f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "failed to provide key response", e); 6403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } catch (android.media.DeniedByServerException e) { 641f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "failed to provide key response", e); 6423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 643a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionError(sessionId); 644f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) release(); 6453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 6463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) /** 648424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) * Return the security level of this DRM object. 649424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) */ 650424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) @CalledByNative 651424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) private String getSecurityLevel() { 652f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mMediaDrm == null) { 653f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "getSecurityLevel() called when MediaDrm is null."); 654f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return null; 655f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 656424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return mMediaDrm.getPropertyString("securityLevel"); 657424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 658424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 659f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private void startProvisioning() { 660f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.d(TAG, "startProvisioning"); 661a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mMediaDrm != null; 662a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert !mProvisioningPending; 663f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mProvisioningPending = true; 664f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest(); 665f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) PostRequestTask postTask = new PostRequestTask(request.getData()); 666f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) postTask.execute(request.getDefaultUrl()); 667f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 668f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 669424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) /** 6703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * Called when the provision response is received. 6713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * 6723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * @param response Response data from the provision server. 6733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 6743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private void onProvisionResponse(byte[] response) { 67558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Log.d(TAG, "onProvisionResponse()"); 676a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert mProvisioningPending; 677f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mProvisioningPending = false; 678424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 67968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // If |mMediaDrm| is released, there is no need to callback native. 68068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (mMediaDrm == null) { 68168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return; 68268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 68368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 68468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) boolean success = provideProvisionResponse(response); 685f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 68668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (mResetDeviceCredentialsPending) { 68768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) nativeOnResetDeviceCredentialsCompleted(mNativeMediaDrmBridge, success); 68868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) mResetDeviceCredentialsPending = false; 68968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 69068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 691f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (success) { 692f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) resumePendingOperations(); 69368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 69468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 69568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 69668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) /** 69768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) * Provide the provisioning response to MediaDrm. 69868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) * @returns false if the response is invalid or on error, true otherwise. 69968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) */ 70068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) boolean provideProvisionResponse(byte[] response) { 701424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (response == null || response.length == 0) { 702424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) Log.e(TAG, "Invalid provision response."); 70368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return false; 704424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 705424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 7063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) try { 7073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) mMediaDrm.provideProvisionResponse(response); 708f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 7093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } catch (android.media.DeniedByServerException e) { 710f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "failed to provide provision response", e); 71158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } catch (java.lang.IllegalStateException e) { 712f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.e(TAG, "failed to provide provision response", e); 713424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 714f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 715f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 716424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 717a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void onSessionCreated(final int sessionId, final String webSessionId) { 718f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mHandler.post(new Runnable(){ 719a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) @Override 720f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public void run() { 721a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) nativeOnSessionCreated(mNativeMediaDrmBridge, sessionId, webSessionId); 722f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 723f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) }); 724f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 725f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 726a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void onSessionMessage(final int sessionId, final MediaDrm.KeyRequest request) { 727a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mHandler.post(new Runnable(){ 728a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) @Override 729a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public void run() { 730a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) nativeOnSessionMessage(mNativeMediaDrmBridge, sessionId, 731a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) request.getData(), request.getDefaultUrl()); 732a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 733a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) }); 734a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 735a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 736a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void onSessionReady(final int sessionId) { 737f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mHandler.post(new Runnable() { 738a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) @Override 739f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public void run() { 740a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) nativeOnSessionReady(mNativeMediaDrmBridge, sessionId); 741f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 742f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) }); 7433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 7443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 745a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void onSessionClosed(final int sessionId) { 746a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mHandler.post(new Runnable() { 747a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) @Override 748a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public void run() { 749a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) nativeOnSessionClosed(mNativeMediaDrmBridge, sessionId); 750a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 751a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) }); 752a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 753a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 754a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private void onSessionError(final int sessionId) { 7553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // TODO(qinmin): pass the error code to native. 756424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) mHandler.post(new Runnable() { 757a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) @Override 7583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) public void run() { 759a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) nativeOnSessionError(mNativeMediaDrmBridge, sessionId); 7603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 7613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) }); 7623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 7633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 764a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private String getWebSessionId(ByteBuffer session) { 765a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) String webSessionId = null; 766f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) try { 767a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) webSessionId = new String(session.array(), "UTF-8"); 768f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } catch (java.io.UnsupportedEncodingException e) { 769a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "getWebSessionId failed", e); 770f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } catch (java.lang.NullPointerException e) { 771a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "getWebSessionId failed", e); 772f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 773a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return webSessionId; 774f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 775f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 7763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private class MediaDrmListener implements MediaDrm.OnEventListener { 7773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) @Override 778a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public void onEvent( 779a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MediaDrm mediaDrm, byte[] session_array, int event, int extra, byte[] data) { 780a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (session_array == null) { 781a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "MediaDrmListener: Null session."); 782a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 783a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 784a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ByteBuffer session = ByteBuffer.wrap(session_array); 785a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!sessionExists(session)) { 786a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "MediaDrmListener: Invalid session."); 787a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 788a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 789a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Integer sessionId = mSessionIds.get(session); 790a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (sessionId == null || sessionId == INVALID_SESSION_ID) { 791a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "MediaDrmListener: Invalid session ID."); 792a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 793a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 7943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) switch(event) { 7953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) case MediaDrm.EVENT_PROVISION_REQUIRED: 796f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.d(TAG, "MediaDrm.EVENT_PROVISION_REQUIRED"); 7973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) break; 7983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) case MediaDrm.EVENT_KEY_REQUIRED: 799f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.d(TAG, "MediaDrm.EVENT_KEY_REQUIRED"); 800a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (mProvisioningPending) { 801a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 802a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 803a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) String mime = mSessionMimeTypes.get(session); 804a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MediaDrm.KeyRequest request = null; 805a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) try { 806a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) request = getKeyRequest(session, data, mime); 807a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } catch (android.media.NotProvisionedException e) { 808a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "Device not provisioned", e); 809a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) startProvisioning(); 810a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 811a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 812a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (request != null) { 813a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionMessage(sessionId, request); 814a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else { 815a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionError(sessionId); 816f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 8173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) break; 8183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) case MediaDrm.EVENT_KEY_EXPIRED: 819f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.d(TAG, "MediaDrm.EVENT_KEY_EXPIRED"); 820a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) onSessionError(sessionId); 8213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) break; 8223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) case MediaDrm.EVENT_VENDOR_DEFINED: 823f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Log.d(TAG, "MediaDrm.EVENT_VENDOR_DEFINED"); 824a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert false; // Should never happen. 8253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) break; 8263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) default: 827a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Log.e(TAG, "Invalid DRM event " + event); 8283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return; 8293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private class PostRequestTask extends AsyncTask<String, Void, Void> { 8343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private static final String TAG = "PostRequestTask"; 8353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private byte[] mDrmRequest; 8373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private byte[] mResponseBody; 8383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) public PostRequestTask(byte[] drmRequest) { 8403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) mDrmRequest = drmRequest; 8413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) @Override 8443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) protected Void doInBackground(String... urls) { 8453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) mResponseBody = postRequest(urls[0], mDrmRequest); 8463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (mResponseBody != null) { 8473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) Log.d(TAG, "response length=" + mResponseBody.length); 8483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return null; 8503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private byte[] postRequest(String url, byte[] drmRequest) { 8533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) HttpClient httpClient = new DefaultHttpClient(); 8543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) HttpPost httpPost = new HttpPost(url + "&signedRequest=" + new String(drmRequest)); 8553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) Log.d(TAG, "PostRequest:" + httpPost.getRequestLine()); 8573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) try { 8583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // Add data 8593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) httpPost.setHeader("Accept", "*/*"); 8603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) httpPost.setHeader("User-Agent", "Widevine CDM v1.0"); 8613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) httpPost.setHeader("Content-Type", "application/json"); 8623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // Execute HTTP Post Request 8643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) HttpResponse response = httpClient.execute(httpPost); 8653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) byte[] responseBody; 8673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) int responseCode = response.getStatusLine().getStatusCode(); 8683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (responseCode == 200) { 8693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) responseBody = EntityUtils.toByteArray(response.getEntity()); 8703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } else { 8713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) Log.d(TAG, "Server returned HTTP error code " + responseCode); 8723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return null; 8733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return responseBody; 8753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } catch (ClientProtocolException e) { 8763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) e.printStackTrace(); 8773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } catch (IOException e) { 8783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) e.printStackTrace(); 8793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return null; 8813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) @Override 8843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) protected void onPostExecute(Void v) { 8853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) onProvisionResponse(mResponseBody); 8863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 8883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 8896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) public static void addKeySystemUuidMapping(String keySystem, UUID uuid) { 8906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ByteBuffer uuidBuffer = ByteBuffer.allocateDirect(16); 8916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // MSB (byte) should be positioned at the first element. 8926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) uuidBuffer.order(ByteOrder.BIG_ENDIAN); 8936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) uuidBuffer.putLong(uuid.getMostSignificantBits()); 8946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) uuidBuffer.putLong(uuid.getLeastSignificantBits()); 8956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) nativeAddKeySystemUuidMapping(keySystem, uuidBuffer); 8966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 8976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 898f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private native void nativeOnMediaCryptoReady(long nativeMediaDrmBridge); 899424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 900a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private native void nativeOnSessionCreated(long nativeMediaDrmBridge, int sessionId, 901a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) String webSessionId); 902a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 903a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private native void nativeOnSessionMessage(long nativeMediaDrmBridge, int sessionId, 904a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) byte[] message, String destinationUrl); 905a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 906a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private native void nativeOnSessionReady(long nativeMediaDrmBridge, int sessionId); 9073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 908a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private native void nativeOnSessionClosed(long nativeMediaDrmBridge, int sessionId); 9093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 910a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private native void nativeOnSessionError(long nativeMediaDrmBridge, int sessionId); 91168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 91268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) private native void nativeOnResetDeviceCredentialsCompleted( 913f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) long nativeMediaDrmBridge, boolean success); 9146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 9156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) private static native void nativeAddKeySystemUuidMapping(String keySystem, ByteBuffer uuid); 9163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 917