blob: ea47d57fada1b9b095193dd4d82c4c32cfd44678 [file] [log] [blame]
Jeff Tinker497ca092014-05-13 09:31:15 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Marco Nelissenc7a11b22014-05-30 10:13:25 -070017//#define LOG_NDEBUG 0
Jeff Tinker497ca092014-05-13 09:31:15 -070018#define LOG_TAG "NdkMediaDrm"
19
20#include "NdkMediaDrm.h"
21
Jeff Tinkera69729d2016-02-12 08:47:00 -080022#include <cutils/properties.h>
Jeff Tinker497ca092014-05-13 09:31:15 -070023#include <utils/Log.h>
24#include <utils/StrongPointer.h>
25#include <gui/Surface.h>
26
27#include <media/IDrm.h>
28#include <media/IDrmClient.h>
29#include <media/stagefright/MediaErrors.h>
30#include <binder/IServiceManager.h>
Jeff Tinkera69729d2016-02-12 08:47:00 -080031#include <media/IMediaDrmService.h>
Jeff Tinker497ca092014-05-13 09:31:15 -070032#include <media/IMediaPlayerService.h>
33#include <ndk/NdkMediaCrypto.h>
34
35
36using namespace android;
37
38typedef Vector<uint8_t> idvec_t;
39
Jeff Tinker3305b992014-05-14 18:39:25 -070040struct DrmListener: virtual public BnDrmClient
41{
42private:
43 AMediaDrm *mObj;
44 AMediaDrmEventListener mListener;
45
46public:
47 DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {}
48 void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
49};
50
Jeff Tinker497ca092014-05-13 09:31:15 -070051struct AMediaDrm {
52 sp<IDrm> mDrm;
53 sp<IDrmClient> mDrmClient;
Jeff Tinker497ca092014-05-13 09:31:15 -070054 List<idvec_t> mIds;
55 KeyedVector<String8, String8> mQueryResults;
56 Vector<uint8_t> mKeyRequest;
57 Vector<uint8_t> mProvisionRequest;
58 String8 mProvisionUrl;
59 String8 mPropertyString;
60 Vector<uint8_t> mPropertyByteArray;
61 List<Vector<uint8_t> > mSecureStops;
Jeff Tinker3305b992014-05-14 18:39:25 -070062 sp<DrmListener> mListener;
Jeff Tinker497ca092014-05-13 09:31:15 -070063};
64
Jeff Tinker3305b992014-05-14 18:39:25 -070065void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
66 if (!mListener) {
67 return;
68 }
69
70 AMediaDrmSessionId sessionId = {NULL, 0};
71 int32_t sessionIdSize = obj->readInt32();
72 if (sessionIdSize) {
73 uint8_t *sessionIdData = new uint8_t[sessionIdSize];
74 sessionId.ptr = sessionIdData;
75 sessionId.length = sessionIdSize;
76 obj->read(sessionIdData, sessionId.length);
77 }
78
79 int32_t dataSize = obj->readInt32();
80 uint8_t *data = NULL;
81 if (dataSize) {
82 data = new uint8_t[dataSize];
83 obj->read(data, dataSize);
84 }
85
86 // translate DrmPlugin event types into their NDK equivalents
87 AMediaDrmEventType ndkEventType;
88 switch(eventType) {
89 case DrmPlugin::kDrmPluginEventProvisionRequired:
90 ndkEventType = EVENT_PROVISION_REQUIRED;
91 break;
92 case DrmPlugin::kDrmPluginEventKeyNeeded:
93 ndkEventType = EVENT_KEY_REQUIRED;
94 break;
95 case DrmPlugin::kDrmPluginEventKeyExpired:
96 ndkEventType = EVENT_KEY_EXPIRED;
97 break;
98 case DrmPlugin::kDrmPluginEventVendorDefined:
99 ndkEventType = EVENT_VENDOR_DEFINED;
100 break;
101 default:
102 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
103 return;
104 }
105
Marco Nelissen18a1b592014-05-20 08:45:18 -0700106 (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
Jeff Tinker3305b992014-05-14 18:39:25 -0700107
108 delete [] sessionId.ptr;
109 delete [] data;
110}
111
112
Jeff Tinker497ca092014-05-13 09:31:15 -0700113extern "C" {
114
Marco Nelissene419d7c2014-05-15 14:17:25 -0700115static media_status_t translateStatus(status_t status) {
116 media_status_t result = AMEDIA_ERROR_UNKNOWN;
Jeff Tinker497ca092014-05-13 09:31:15 -0700117 switch (status) {
118 case OK:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700119 result = AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700120 break;
121 case android::ERROR_DRM_NOT_PROVISIONED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700122 result = AMEDIA_DRM_NOT_PROVISIONED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700123 break;
124 case android::ERROR_DRM_RESOURCE_BUSY:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700125 result = AMEDIA_DRM_RESOURCE_BUSY;
Jeff Tinker497ca092014-05-13 09:31:15 -0700126 break;
127 case android::ERROR_DRM_DEVICE_REVOKED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700128 result = AMEDIA_DRM_DEVICE_REVOKED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700129 break;
130 case android::ERROR_DRM_CANNOT_HANDLE:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700131 result = AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700132 break;
133 case android::ERROR_DRM_TAMPER_DETECTED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700134 result = AMEDIA_DRM_TAMPER_DETECTED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700135 break;
136 case android::ERROR_DRM_SESSION_NOT_OPENED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700137 result = AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700138 break;
139 case android::ERROR_DRM_NO_LICENSE:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700140 result = AMEDIA_DRM_NEED_KEY;
Jeff Tinker497ca092014-05-13 09:31:15 -0700141 break;
142 case android::ERROR_DRM_LICENSE_EXPIRED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700143 result = AMEDIA_DRM_LICENSE_EXPIRED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700144 break;
145 default:
Jeff Tinker497ca092014-05-13 09:31:15 -0700146 break;
147 }
148 return result;
149}
150
151static sp<IDrm> CreateDrm() {
152 sp<IServiceManager> sm = defaultServiceManager();
Jeff Tinkera69729d2016-02-12 08:47:00 -0800153 sp<IDrm> drm;
Jeff Tinker497ca092014-05-13 09:31:15 -0700154
Jeff Tinkera69729d2016-02-12 08:47:00 -0800155 char value[PROPERTY_VALUE_MAX];
156 if (property_get("media.mediadrmservice.enable", value, NULL)
157 && (!strcmp("1", value) || !strcasecmp("true", value))) {
158 sp<IBinder> binder =
159 sm->getService(String16("media.drm"));
160 sp<IMediaDrmService> service =
161 interface_cast<IMediaDrmService>(binder);
162 if (service == NULL) {
163 return NULL;
164 }
165 drm = service->makeDrm();
166 } else {
167 sp<IBinder> binder =
168 sm->getService(String16("media.player"));
169 sp<IMediaPlayerService> service =
170 interface_cast<IMediaPlayerService>(binder);
171 if (service == NULL) {
172 return NULL;
173 }
174 drm = service->makeDrm();
Jeff Tinker497ca092014-05-13 09:31:15 -0700175 }
176
Jeff Tinker497ca092014-05-13 09:31:15 -0700177 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
178 return NULL;
179 }
180
181 return drm;
182}
183
184
185static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
186 sp<IDrm> drm = CreateDrm();
187
188 if (drm == NULL) {
189 return NULL;
190 }
191
192 status_t err = drm->createPlugin(uuid);
193
194 if (err != OK) {
195 return NULL;
196 }
197
198 return drm;
199}
200
Marco Nelissen3425fd52014-05-14 11:12:46 -0700201EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700202bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
203 sp<IDrm> drm = CreateDrm();
204
205 if (drm == NULL) {
206 return false;
207 }
208
209 String8 mimeStr = mimeType ? String8(mimeType) : String8("");
210 return drm->isCryptoSchemeSupported(uuid, mimeStr);
211}
212
Marco Nelissen3425fd52014-05-14 11:12:46 -0700213EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700214AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
215 AMediaDrm *mObj = new AMediaDrm();
216 mObj->mDrm = CreateDrmFromUUID(uuid);
217 return mObj;
218}
219
Marco Nelissen3425fd52014-05-14 11:12:46 -0700220EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700221void AMediaDrm_release(AMediaDrm *mObj) {
222 if (mObj->mDrm != NULL) {
223 mObj->mDrm->setListener(NULL);
224 mObj->mDrm->destroyPlugin();
225 mObj->mDrm.clear();
226 }
227 delete mObj;
228}
229
Jeff Tinker3305b992014-05-14 18:39:25 -0700230EXPORT
Marco Nelissen7c96d532014-05-15 15:26:14 -0700231media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
Jeff Tinker3305b992014-05-14 18:39:25 -0700232 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissen7c96d532014-05-15 15:26:14 -0700233 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker3305b992014-05-14 18:39:25 -0700234 }
235 mObj->mListener = new DrmListener(mObj, listener);
236 mObj->mDrm->setListener(mObj->mListener);
Marco Nelissen7c96d532014-05-15 15:26:14 -0700237 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700238}
Jeff Tinker497ca092014-05-13 09:31:15 -0700239
240
241static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
242 iter = mObj->mIds.begin();
243 while (iter != mObj->mIds.end()) {
244 if (iter->array() == id.ptr && iter->size() == id.length) {
245 return true;
246 }
247 }
248 return false;
249}
250
Marco Nelissen3425fd52014-05-14 11:12:46 -0700251EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700252media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId *sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700253 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700254 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700255 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700256 if (!sessionId) {
257 return AMEDIA_ERROR_INVALID_PARAMETER;
258 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700259 Vector<uint8_t> session;
260 status_t status = mObj->mDrm->openSession(session);
261 if (status == OK) {
262 mObj->mIds.push_front(session);
263 List<idvec_t>::iterator iter = mObj->mIds.begin();
Marco Nelissen18a1b592014-05-20 08:45:18 -0700264 sessionId->ptr = iter->array();
265 sessionId->length = iter->size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700266 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700267 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700268}
269
Marco Nelissen3425fd52014-05-14 11:12:46 -0700270EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700271media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700272 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700273 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700274 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700275 if (!sessionId) {
276 return AMEDIA_ERROR_INVALID_PARAMETER;
277 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700278
279 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700280 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700281 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700282 }
283 mObj->mDrm->closeSession(*iter);
284 mObj->mIds.erase(iter);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700285 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700286}
287
Marco Nelissen3425fd52014-05-14 11:12:46 -0700288EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700289media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope,
Jeff Tinker497ca092014-05-13 09:31:15 -0700290 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
291 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700292 const uint8_t **keyRequest, size_t *keyRequestSize) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700293
294 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700295 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700296 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700297 if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700298 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700299 }
300
301 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700302 if (!findId(mObj, *scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700303 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700304 }
305
306 Vector<uint8_t> mdInit;
307 mdInit.appendArray(init, initSize);
308 DrmPlugin::KeyType mdKeyType;
309 switch (keyType) {
310 case KEY_TYPE_STREAMING:
311 mdKeyType = DrmPlugin::kKeyType_Streaming;
312 break;
313 case KEY_TYPE_OFFLINE:
314 mdKeyType = DrmPlugin::kKeyType_Offline;
315 break;
316 case KEY_TYPE_RELEASE:
317 mdKeyType = DrmPlugin::kKeyType_Release;
318 break;
319 default:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700320 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700321 }
322 KeyedVector<String8, String8> mdOptionalParameters;
323 for (size_t i = 0; i < numOptionalParameters; i++) {
324 mdOptionalParameters.add(String8(optionalParameters[i].mKey),
325 String8(optionalParameters[i].mValue));
326 }
327 String8 defaultUrl;
Jeff Tinkerd072c902015-03-16 13:39:29 -0700328 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker497ca092014-05-13 09:31:15 -0700329 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
Jeff Tinkerd072c902015-03-16 13:39:29 -0700330 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
331 &keyRequestType);
Jeff Tinker497ca092014-05-13 09:31:15 -0700332 if (status != OK) {
333 return translateStatus(status);
334 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700335 *keyRequest = mObj->mKeyRequest.array();
336 *keyRequestSize = mObj->mKeyRequest.size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700337 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700338 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700339}
340
Marco Nelissen3425fd52014-05-14 11:12:46 -0700341EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700342media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
343 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700344
345 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700346 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700347 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700348 if (!scope || !response || !responseSize || !keySetId) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700349 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700350 }
351
352 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700353 if (!findId(mObj, *scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700354 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700355 }
356 Vector<uint8_t> mdResponse;
357 mdResponse.appendArray(response, responseSize);
358
359 Vector<uint8_t> mdKeySetId;
360 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
361 if (status == OK) {
362 mObj->mIds.push_front(mdKeySetId);
363 List<idvec_t>::iterator iter = mObj->mIds.begin();
Marco Nelissen18a1b592014-05-20 08:45:18 -0700364 keySetId->ptr = iter->array();
365 keySetId->length = iter->size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700366 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700367 keySetId->ptr = NULL;
368 keySetId->length = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700369 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700370 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700371}
372
Marco Nelissen3425fd52014-05-14 11:12:46 -0700373EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700374media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
375 const AMediaDrmKeySetId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700376
377 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700378 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700379 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700380 if (!sessionId || !keySetId) {
381 return AMEDIA_ERROR_INVALID_PARAMETER;
382 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700383 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700384 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700385 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700386 }
387 Vector<uint8_t> keySet;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700388 keySet.appendArray(keySetId->ptr, keySetId->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700389 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
390}
391
Marco Nelissen3425fd52014-05-14 11:12:46 -0700392EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700393media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700394 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700395 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700396 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700397 if (!keySetId) {
398 return AMEDIA_ERROR_INVALID_PARAMETER;
399 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700400 List<idvec_t>::iterator iter;
401 status_t status;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700402 if (!findId(mObj, *keySetId, iter)) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700403 Vector<uint8_t> keySet;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700404 keySet.appendArray(keySetId->ptr, keySetId->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700405 status = mObj->mDrm->removeKeys(keySet);
406 } else {
407 status = mObj->mDrm->removeKeys(*iter);
408 mObj->mIds.erase(iter);
409 }
410 return translateStatus(status);
411}
412
Marco Nelissen3425fd52014-05-14 11:12:46 -0700413EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700414media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
415 AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700416
417 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700418 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700419 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700420 if (!sessionId || !numPairs) {
421 return AMEDIA_ERROR_INVALID_PARAMETER;
422 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700423 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700424 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700425 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700426 }
427
428 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
429 if (status != OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700430 *numPairs = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700431 return translateStatus(status);
432 }
433
Marco Nelissen18a1b592014-05-20 08:45:18 -0700434 if (mObj->mQueryResults.size() > *numPairs) {
435 *numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700436 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700437 }
438
439 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
440 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
441 keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
442 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700443 *numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700444 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700445}
446
Marco Nelissen3425fd52014-05-14 11:12:46 -0700447EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700448media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
449 size_t *provisionRequestSize, const char **serverUrl) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700450 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700451 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700452 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700453 if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700454 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700455 }
456
457 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
458 mObj->mProvisionRequest, mObj->mProvisionUrl);
459 if (status != OK) {
460 return translateStatus(status);
461 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700462 *provisionRequest = mObj->mProvisionRequest.array();
463 *provisionRequestSize = mObj->mProvisionRequest.size();
464 *serverUrl = mObj->mProvisionUrl.string();
Jeff Tinker497ca092014-05-13 09:31:15 -0700465 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700466 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700467}
468
Marco Nelissen3425fd52014-05-14 11:12:46 -0700469EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700470media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700471 const uint8_t *response, size_t responseSize) {
472 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700473 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700474 }
475 if (!response || !responseSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700476 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700477 }
478
479 Vector<uint8_t> mdResponse;
480 mdResponse.appendArray(response, responseSize);
481
482 Vector<uint8_t> unused;
483 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
484}
485
Marco Nelissen3425fd52014-05-14 11:12:46 -0700486EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700487media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700488 AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700489
490 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700491 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700492 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700493 if (!numSecureStops) {
494 return AMEDIA_ERROR_INVALID_PARAMETER;
495 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700496 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
497 if (status != OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700498 *numSecureStops = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700499 return translateStatus(status);
500 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700501 if (*numSecureStops < mObj->mSecureStops.size()) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700502 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700503 }
504 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
505 size_t i = 0;
506 while (iter != mObj->mSecureStops.end()) {
507 secureStops[i].ptr = iter->array();
508 secureStops[i].length = iter->size();
509 ++iter;
510 ++i;
511 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700512 *numSecureStops = mObj->mSecureStops.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700513 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700514}
515
Marco Nelissen3425fd52014-05-14 11:12:46 -0700516EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700517media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700518 const AMediaDrmSecureStop *ssRelease) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700519
520 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700521 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700522 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700523 if (!ssRelease) {
524 return AMEDIA_ERROR_INVALID_PARAMETER;
525 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700526
527 Vector<uint8_t> release;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700528 release.appendArray(ssRelease->ptr, ssRelease->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700529 return translateStatus(mObj->mDrm->releaseSecureStops(release));
530}
531
532
Marco Nelissen3425fd52014-05-14 11:12:46 -0700533EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700534media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700535 const char **propertyValue) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700536
537 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700538 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700539 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700540 if (!propertyName || !propertyValue) {
541 return AMEDIA_ERROR_INVALID_PARAMETER;
542 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700543
544 status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
545 mObj->mPropertyString);
546
547 if (status == OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700548 *propertyValue = mObj->mPropertyString.string();
Jeff Tinker497ca092014-05-13 09:31:15 -0700549 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700550 *propertyValue = NULL;
Jeff Tinker497ca092014-05-13 09:31:15 -0700551 }
552 return translateStatus(status);
553}
554
Marco Nelissen3425fd52014-05-14 11:12:46 -0700555EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700556media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700557 const char *propertyName, AMediaDrmByteArray *propertyValue) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700558 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700559 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700560 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700561 if (!propertyName || !propertyValue) {
562 return AMEDIA_ERROR_INVALID_PARAMETER;
563 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700564
565 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
566 mObj->mPropertyByteArray);
567
568 if (status == OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700569 propertyValue->ptr = mObj->mPropertyByteArray.array();
570 propertyValue->length = mObj->mPropertyByteArray.size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700571 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700572 propertyValue->ptr = NULL;
573 propertyValue->length = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700574 }
575 return translateStatus(status);
576}
577
Marco Nelissen3425fd52014-05-14 11:12:46 -0700578EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700579media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700580 const char *propertyName, const char *value) {
581 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700582 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700583 }
584
585 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
586 String8(value)));
587}
588
Marco Nelissen3425fd52014-05-14 11:12:46 -0700589EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700590media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700591 const char *propertyName, const uint8_t *value, size_t valueSize) {
592
593 Vector<uint8_t> byteArray;
594 byteArray.appendArray(value, valueSize);
595
596 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
597 byteArray));
598}
599
600
Marco Nelissene419d7c2014-05-15 14:17:25 -0700601static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700602 const AMediaDrmSessionId &sessionId,
603 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
604 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
605
606 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700607 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700608 }
609 List<idvec_t>::iterator iter;
610 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700611 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700612 }
613
614 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
615 if (status != OK) {
616 return translateStatus(status);
617 }
618
619 Vector<uint8_t> keyIdVec;
620 const size_t kKeyIdSize = 16;
621 keyIdVec.appendArray(keyId, kKeyIdSize);
622
623 Vector<uint8_t> inputVec;
624 inputVec.appendArray(input, dataSize);
625
626 Vector<uint8_t> ivVec;
627 const size_t kIvSize = 16;
628 ivVec.appendArray(iv, kIvSize);
629
630 Vector<uint8_t> outputVec;
631 if (encrypt) {
632 status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
633 } else {
634 status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
635 }
636 if (status == OK) {
637 memcpy(output, outputVec.array(), outputVec.size());
638 }
639 return translateStatus(status);
640}
641
Marco Nelissen3425fd52014-05-14 11:12:46 -0700642EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700643media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700644 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
645 const uint8_t *input, uint8_t *output, size_t dataSize) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700646 if (!sessionId) {
647 return AMEDIA_ERROR_INVALID_PARAMETER;
648 }
649 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
Jeff Tinker497ca092014-05-13 09:31:15 -0700650 input, output, dataSize, true);
651}
652
Marco Nelissen3425fd52014-05-14 11:12:46 -0700653EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700654media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700655 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
656 const uint8_t *input, uint8_t *output, size_t dataSize) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700657 if (!sessionId) {
658 return AMEDIA_ERROR_INVALID_PARAMETER;
659 }
660 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
Jeff Tinker497ca092014-05-13 09:31:15 -0700661 input, output, dataSize, false);
662}
663
Marco Nelissen3425fd52014-05-14 11:12:46 -0700664EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700665media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700666 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
667 uint8_t *signature, size_t *signatureSize) {
668
669 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700670 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700671 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700672 if (!sessionId) {
673 return AMEDIA_ERROR_INVALID_PARAMETER;
674 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700675 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700676 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700677 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700678 }
679
680 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
681 if (status != OK) {
682 return translateStatus(status);
683 }
684
685 Vector<uint8_t> keyIdVec;
686 const size_t kKeyIdSize = 16;
687 keyIdVec.appendArray(keyId, kKeyIdSize);
688
689 Vector<uint8_t> messageVec;
690 messageVec.appendArray(message, messageSize);
691
692 Vector<uint8_t> signatureVec;
693 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
694 if (signatureVec.size() > *signatureSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700695 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700696 }
697 if (status == OK) {
698 memcpy(signature, signatureVec.array(), signatureVec.size());
699 }
700 return translateStatus(status);
701}
702
Marco Nelissen3425fd52014-05-14 11:12:46 -0700703EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700704media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700705 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
706 const uint8_t *signature, size_t signatureSize) {
707
708 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700709 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700710 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700711 if (!sessionId) {
712 return AMEDIA_ERROR_INVALID_PARAMETER;
713 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700714 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700715 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700716 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700717 }
718
719 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
720 if (status != OK) {
721 return translateStatus(status);
722 }
723
724 Vector<uint8_t> keyIdVec;
725 const size_t kKeyIdSize = 16;
726 keyIdVec.appendArray(keyId, kKeyIdSize);
727
728 Vector<uint8_t> messageVec;
729 messageVec.appendArray(message, messageSize);
730
731 Vector<uint8_t> signatureVec;
732 signatureVec.appendArray(signature, signatureSize);
733
734 bool match;
735 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
736 if (status == OK) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700737 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700738 }
739 return translateStatus(status);
740}
741
742} // extern "C"