blob: f982275cd8a5adea01653e28c2437975ef669612 [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
17#define LOG_NDEBUG 0
18#define LOG_TAG "NdkMediaDrm"
19
20#include "NdkMediaDrm.h"
21
22#include <utils/Log.h>
23#include <utils/StrongPointer.h>
24#include <gui/Surface.h>
25
26#include <media/IDrm.h>
27#include <media/IDrmClient.h>
28#include <media/stagefright/MediaErrors.h>
29#include <binder/IServiceManager.h>
30#include <media/IMediaPlayerService.h>
31#include <ndk/NdkMediaCrypto.h>
32
33
34using namespace android;
35
36typedef Vector<uint8_t> idvec_t;
37
Jeff Tinker3305b992014-05-14 18:39:25 -070038struct DrmListener: virtual public BnDrmClient
39{
40private:
41 AMediaDrm *mObj;
42 AMediaDrmEventListener mListener;
43
44public:
45 DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {}
46 void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
47};
48
Jeff Tinker497ca092014-05-13 09:31:15 -070049struct AMediaDrm {
50 sp<IDrm> mDrm;
51 sp<IDrmClient> mDrmClient;
Jeff Tinker497ca092014-05-13 09:31:15 -070052 List<idvec_t> mIds;
53 KeyedVector<String8, String8> mQueryResults;
54 Vector<uint8_t> mKeyRequest;
55 Vector<uint8_t> mProvisionRequest;
56 String8 mProvisionUrl;
57 String8 mPropertyString;
58 Vector<uint8_t> mPropertyByteArray;
59 List<Vector<uint8_t> > mSecureStops;
Jeff Tinker3305b992014-05-14 18:39:25 -070060 sp<DrmListener> mListener;
Jeff Tinker497ca092014-05-13 09:31:15 -070061};
62
Jeff Tinker3305b992014-05-14 18:39:25 -070063void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
64 if (!mListener) {
65 return;
66 }
67
68 AMediaDrmSessionId sessionId = {NULL, 0};
69 int32_t sessionIdSize = obj->readInt32();
70 if (sessionIdSize) {
71 uint8_t *sessionIdData = new uint8_t[sessionIdSize];
72 sessionId.ptr = sessionIdData;
73 sessionId.length = sessionIdSize;
74 obj->read(sessionIdData, sessionId.length);
75 }
76
77 int32_t dataSize = obj->readInt32();
78 uint8_t *data = NULL;
79 if (dataSize) {
80 data = new uint8_t[dataSize];
81 obj->read(data, dataSize);
82 }
83
84 // translate DrmPlugin event types into their NDK equivalents
85 AMediaDrmEventType ndkEventType;
86 switch(eventType) {
87 case DrmPlugin::kDrmPluginEventProvisionRequired:
88 ndkEventType = EVENT_PROVISION_REQUIRED;
89 break;
90 case DrmPlugin::kDrmPluginEventKeyNeeded:
91 ndkEventType = EVENT_KEY_REQUIRED;
92 break;
93 case DrmPlugin::kDrmPluginEventKeyExpired:
94 ndkEventType = EVENT_KEY_EXPIRED;
95 break;
96 case DrmPlugin::kDrmPluginEventVendorDefined:
97 ndkEventType = EVENT_VENDOR_DEFINED;
98 break;
99 default:
100 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
101 return;
102 }
103
104 (*mListener)(mObj, sessionId, ndkEventType, extra, data, dataSize);
105
106 delete [] sessionId.ptr;
107 delete [] data;
108}
109
110
Jeff Tinker497ca092014-05-13 09:31:15 -0700111extern "C" {
112
Marco Nelissene419d7c2014-05-15 14:17:25 -0700113static media_status_t translateStatus(status_t status) {
114 media_status_t result = AMEDIA_ERROR_UNKNOWN;
Jeff Tinker497ca092014-05-13 09:31:15 -0700115 switch (status) {
116 case OK:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700117 result = AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700118 break;
119 case android::ERROR_DRM_NOT_PROVISIONED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700120 result = AMEDIA_DRM_NOT_PROVISIONED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700121 break;
122 case android::ERROR_DRM_RESOURCE_BUSY:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700123 result = AMEDIA_DRM_RESOURCE_BUSY;
Jeff Tinker497ca092014-05-13 09:31:15 -0700124 break;
125 case android::ERROR_DRM_DEVICE_REVOKED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700126 result = AMEDIA_DRM_DEVICE_REVOKED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700127 break;
128 case android::ERROR_DRM_CANNOT_HANDLE:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700129 result = AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700130 break;
131 case android::ERROR_DRM_TAMPER_DETECTED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700132 result = AMEDIA_DRM_TAMPER_DETECTED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700133 break;
134 case android::ERROR_DRM_SESSION_NOT_OPENED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700135 result = AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700136 break;
137 case android::ERROR_DRM_NO_LICENSE:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700138 result = AMEDIA_DRM_NEED_KEY;
Jeff Tinker497ca092014-05-13 09:31:15 -0700139 break;
140 case android::ERROR_DRM_LICENSE_EXPIRED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700141 result = AMEDIA_DRM_LICENSE_EXPIRED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700142 break;
143 default:
Jeff Tinker497ca092014-05-13 09:31:15 -0700144 break;
145 }
146 return result;
147}
148
149static sp<IDrm> CreateDrm() {
150 sp<IServiceManager> sm = defaultServiceManager();
151
152 sp<IBinder> binder =
153 sm->getService(String16("media.player"));
154
155 sp<IMediaPlayerService> service =
156 interface_cast<IMediaPlayerService>(binder);
157
158 if (service == NULL) {
159 return NULL;
160 }
161
162 sp<IDrm> drm = service->makeDrm();
163
164 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
165 return NULL;
166 }
167
168 return drm;
169}
170
171
172static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
173 sp<IDrm> drm = CreateDrm();
174
175 if (drm == NULL) {
176 return NULL;
177 }
178
179 status_t err = drm->createPlugin(uuid);
180
181 if (err != OK) {
182 return NULL;
183 }
184
185 return drm;
186}
187
Marco Nelissen3425fd52014-05-14 11:12:46 -0700188EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700189bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
190 sp<IDrm> drm = CreateDrm();
191
192 if (drm == NULL) {
193 return false;
194 }
195
196 String8 mimeStr = mimeType ? String8(mimeType) : String8("");
197 return drm->isCryptoSchemeSupported(uuid, mimeStr);
198}
199
Marco Nelissen3425fd52014-05-14 11:12:46 -0700200EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700201AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
202 AMediaDrm *mObj = new AMediaDrm();
203 mObj->mDrm = CreateDrmFromUUID(uuid);
204 return mObj;
205}
206
Marco Nelissen3425fd52014-05-14 11:12:46 -0700207EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700208void AMediaDrm_release(AMediaDrm *mObj) {
209 if (mObj->mDrm != NULL) {
210 mObj->mDrm->setListener(NULL);
211 mObj->mDrm->destroyPlugin();
212 mObj->mDrm.clear();
213 }
214 delete mObj;
215}
216
Jeff Tinker3305b992014-05-14 18:39:25 -0700217EXPORT
Marco Nelissen7c96d532014-05-15 15:26:14 -0700218media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
Jeff Tinker3305b992014-05-14 18:39:25 -0700219 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissen7c96d532014-05-15 15:26:14 -0700220 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker3305b992014-05-14 18:39:25 -0700221 }
222 mObj->mListener = new DrmListener(mObj, listener);
223 mObj->mDrm->setListener(mObj->mListener);
Marco Nelissen7c96d532014-05-15 15:26:14 -0700224 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700225}
Jeff Tinker497ca092014-05-13 09:31:15 -0700226
227
228static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
229 iter = mObj->mIds.begin();
230 while (iter != mObj->mIds.end()) {
231 if (iter->array() == id.ptr && iter->size() == id.length) {
232 return true;
233 }
234 }
235 return false;
236}
237
Marco Nelissen3425fd52014-05-14 11:12:46 -0700238EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700239media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700240 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700241 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700242 }
243 Vector<uint8_t> session;
244 status_t status = mObj->mDrm->openSession(session);
245 if (status == OK) {
246 mObj->mIds.push_front(session);
247 List<idvec_t>::iterator iter = mObj->mIds.begin();
248 sessionId.ptr = iter->array();
249 sessionId.length = iter->size();
250 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700251 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700252}
253
Marco Nelissen3425fd52014-05-14 11:12:46 -0700254EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700255media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700256 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700257 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700258 }
259
260 List<idvec_t>::iterator iter;
261 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700262 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700263 }
264 mObj->mDrm->closeSession(*iter);
265 mObj->mIds.erase(iter);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700266 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700267}
268
Marco Nelissen3425fd52014-05-14 11:12:46 -0700269EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700270media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope,
Jeff Tinker497ca092014-05-13 09:31:15 -0700271 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
272 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
273 const uint8_t *&keyRequest, size_t &keyRequestSize) {
274
275 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700276 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700277 }
278 if (!mimeType) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700279 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700280 }
281
282 List<idvec_t>::iterator iter;
283 if (!findId(mObj, scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700284 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700285 }
286
287 Vector<uint8_t> mdInit;
288 mdInit.appendArray(init, initSize);
289 DrmPlugin::KeyType mdKeyType;
290 switch (keyType) {
291 case KEY_TYPE_STREAMING:
292 mdKeyType = DrmPlugin::kKeyType_Streaming;
293 break;
294 case KEY_TYPE_OFFLINE:
295 mdKeyType = DrmPlugin::kKeyType_Offline;
296 break;
297 case KEY_TYPE_RELEASE:
298 mdKeyType = DrmPlugin::kKeyType_Release;
299 break;
300 default:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700301 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700302 }
303 KeyedVector<String8, String8> mdOptionalParameters;
304 for (size_t i = 0; i < numOptionalParameters; i++) {
305 mdOptionalParameters.add(String8(optionalParameters[i].mKey),
306 String8(optionalParameters[i].mValue));
307 }
308 String8 defaultUrl;
309 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
310 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl);
311 if (status != OK) {
312 return translateStatus(status);
313 } else {
314 keyRequest = mObj->mKeyRequest.array();
315 keyRequestSize = mObj->mKeyRequest.size();
316 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700317 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700318}
319
Marco Nelissen3425fd52014-05-14 11:12:46 -0700320EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700321media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope,
Jeff Tinker497ca092014-05-13 09:31:15 -0700322 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) {
323
324 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700325 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700326 }
327 if (!response || !responseSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700328 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700329 }
330
331 List<idvec_t>::iterator iter;
332 if (!findId(mObj, scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700333 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700334 }
335 Vector<uint8_t> mdResponse;
336 mdResponse.appendArray(response, responseSize);
337
338 Vector<uint8_t> mdKeySetId;
339 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
340 if (status == OK) {
341 mObj->mIds.push_front(mdKeySetId);
342 List<idvec_t>::iterator iter = mObj->mIds.begin();
343 keySetId.ptr = iter->array();
344 keySetId.length = iter->size();
345 } else {
346 keySetId.ptr = NULL;
347 keySetId.length = 0;
348 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700349 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700350}
351
Marco Nelissen3425fd52014-05-14 11:12:46 -0700352EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700353media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700354 const AMediaDrmKeySetId &keySetId) {
355
356 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700357 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700358 }
359 List<idvec_t>::iterator iter;
360 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700361 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700362 }
363 Vector<uint8_t> keySet;
364 keySet.appendArray(keySetId.ptr, keySetId.length);
365 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
366}
367
Marco Nelissen3425fd52014-05-14 11:12:46 -0700368EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700369media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700370 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700371 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700372 }
373 List<idvec_t>::iterator iter;
374 status_t status;
375 if (!findId(mObj, keySetId, iter)) {
376 Vector<uint8_t> keySet;
377 keySet.appendArray(keySetId.ptr, keySetId.length);
378 status = mObj->mDrm->removeKeys(keySet);
379 } else {
380 status = mObj->mDrm->removeKeys(*iter);
381 mObj->mIds.erase(iter);
382 }
383 return translateStatus(status);
384}
385
Marco Nelissen3425fd52014-05-14 11:12:46 -0700386EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700387media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700388 AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) {
389
390 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700391 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700392 }
393 List<idvec_t>::iterator iter;
394 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700395 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700396 }
397
398 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
399 if (status != OK) {
400 numPairs = 0;
401 return translateStatus(status);
402 }
403
404 if (mObj->mQueryResults.size() > numPairs) {
405 numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700406 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700407 }
408
409 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
410 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
411 keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
412 }
413 numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700414 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700415}
416
Marco Nelissen3425fd52014-05-14 11:12:46 -0700417EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700418media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest,
Jeff Tinker497ca092014-05-13 09:31:15 -0700419 size_t &provisionRequestSize, const char *&serverUrl) {
420 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700421 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700422 }
423 if (!provisionRequestSize || !serverUrl) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700424 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700425 }
426
427 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
428 mObj->mProvisionRequest, mObj->mProvisionUrl);
429 if (status != OK) {
430 return translateStatus(status);
431 } else {
432 provisionRequest = mObj->mProvisionRequest.array();
433 provisionRequestSize = mObj->mProvisionRequest.size();
434 serverUrl = mObj->mProvisionUrl.string();
435 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700436 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700437}
438
Marco Nelissen3425fd52014-05-14 11:12:46 -0700439EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700440media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700441 const uint8_t *response, size_t responseSize) {
442 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700443 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700444 }
445 if (!response || !responseSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700446 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700447 }
448
449 Vector<uint8_t> mdResponse;
450 mdResponse.appendArray(response, responseSize);
451
452 Vector<uint8_t> unused;
453 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
454}
455
Marco Nelissen3425fd52014-05-14 11:12:46 -0700456EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700457media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700458 AMediaDrmSecureStop *secureStops, size_t &numSecureStops) {
459
460 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700461 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700462 }
463 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
464 if (status != OK) {
465 numSecureStops = 0;
466 return translateStatus(status);
467 }
468 if (numSecureStops < mObj->mSecureStops.size()) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700469 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700470 }
471 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
472 size_t i = 0;
473 while (iter != mObj->mSecureStops.end()) {
474 secureStops[i].ptr = iter->array();
475 secureStops[i].length = iter->size();
476 ++iter;
477 ++i;
478 }
479 numSecureStops = mObj->mSecureStops.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700480 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700481}
482
Marco Nelissen3425fd52014-05-14 11:12:46 -0700483EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700484media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700485 const AMediaDrmSecureStop &ssRelease) {
486
487 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700488 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700489 }
490
491 Vector<uint8_t> release;
492 release.appendArray(ssRelease.ptr, ssRelease.length);
493 return translateStatus(mObj->mDrm->releaseSecureStops(release));
494}
495
496
Marco Nelissen3425fd52014-05-14 11:12:46 -0700497EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700498media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
Jeff Tinker497ca092014-05-13 09:31:15 -0700499 const char *&propertyValue) {
500
501 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700502 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700503 }
504
505 status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
506 mObj->mPropertyString);
507
508 if (status == OK) {
509 propertyValue = mObj->mPropertyString.string();
510 } else {
511 propertyValue = NULL;
512 }
513 return translateStatus(status);
514}
515
Marco Nelissen3425fd52014-05-14 11:12:46 -0700516EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700517media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700518 const char *propertyName, AMediaDrmByteArray &propertyValue) {
519 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700520 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700521 }
522
523 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
524 mObj->mPropertyByteArray);
525
526 if (status == OK) {
527 propertyValue.ptr = mObj->mPropertyByteArray.array();
528 propertyValue.length = mObj->mPropertyByteArray.size();
529 } else {
530 propertyValue.ptr = NULL;
531 propertyValue.length = 0;
532 }
533 return translateStatus(status);
534}
535
Marco Nelissen3425fd52014-05-14 11:12:46 -0700536EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700537media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700538 const char *propertyName, const char *value) {
539 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700540 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700541 }
542
543 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
544 String8(value)));
545}
546
Marco Nelissen3425fd52014-05-14 11:12:46 -0700547EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700548media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700549 const char *propertyName, const uint8_t *value, size_t valueSize) {
550
551 Vector<uint8_t> byteArray;
552 byteArray.appendArray(value, valueSize);
553
554 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
555 byteArray));
556}
557
558
Marco Nelissene419d7c2014-05-15 14:17:25 -0700559static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700560 const AMediaDrmSessionId &sessionId,
561 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
562 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
563
564 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700565 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700566 }
567 List<idvec_t>::iterator iter;
568 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700569 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700570 }
571
572 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
573 if (status != OK) {
574 return translateStatus(status);
575 }
576
577 Vector<uint8_t> keyIdVec;
578 const size_t kKeyIdSize = 16;
579 keyIdVec.appendArray(keyId, kKeyIdSize);
580
581 Vector<uint8_t> inputVec;
582 inputVec.appendArray(input, dataSize);
583
584 Vector<uint8_t> ivVec;
585 const size_t kIvSize = 16;
586 ivVec.appendArray(iv, kIvSize);
587
588 Vector<uint8_t> outputVec;
589 if (encrypt) {
590 status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
591 } else {
592 status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
593 }
594 if (status == OK) {
595 memcpy(output, outputVec.array(), outputVec.size());
596 }
597 return translateStatus(status);
598}
599
Marco Nelissen3425fd52014-05-14 11:12:46 -0700600EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700601media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700602 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
603 const uint8_t *input, uint8_t *output, size_t dataSize) {
604 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
605 input, output, dataSize, true);
606}
607
Marco Nelissen3425fd52014-05-14 11:12:46 -0700608EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700609media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700610 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
611 const uint8_t *input, uint8_t *output, size_t dataSize) {
612 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
613 input, output, dataSize, false);
614}
615
Marco Nelissen3425fd52014-05-14 11:12:46 -0700616EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700617media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700618 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
619 uint8_t *signature, size_t *signatureSize) {
620
621 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700622 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700623 }
624 List<idvec_t>::iterator iter;
625 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700626 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700627 }
628
629 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
630 if (status != OK) {
631 return translateStatus(status);
632 }
633
634 Vector<uint8_t> keyIdVec;
635 const size_t kKeyIdSize = 16;
636 keyIdVec.appendArray(keyId, kKeyIdSize);
637
638 Vector<uint8_t> messageVec;
639 messageVec.appendArray(message, messageSize);
640
641 Vector<uint8_t> signatureVec;
642 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
643 if (signatureVec.size() > *signatureSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700644 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700645 }
646 if (status == OK) {
647 memcpy(signature, signatureVec.array(), signatureVec.size());
648 }
649 return translateStatus(status);
650}
651
Marco Nelissen3425fd52014-05-14 11:12:46 -0700652EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700653media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700654 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
655 const uint8_t *signature, size_t signatureSize) {
656
657 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700658 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700659 }
660 List<idvec_t>::iterator iter;
661 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700662 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700663 }
664
665 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
666 if (status != OK) {
667 return translateStatus(status);
668 }
669
670 Vector<uint8_t> keyIdVec;
671 const size_t kKeyIdSize = 16;
672 keyIdVec.appendArray(keyId, kKeyIdSize);
673
674 Vector<uint8_t> messageVec;
675 messageVec.appendArray(message, messageSize);
676
677 Vector<uint8_t> signatureVec;
678 signatureVec.appendArray(signature, signatureSize);
679
680 bool match;
681 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
682 if (status == OK) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700683 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700684 }
685 return translateStatus(status);
686}
687
688} // extern "C"
689