blob: a0cbb7022573fa4408868ac4b85b1e5e0f020507 [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
Marco Nelissen18a1b592014-05-20 08:45:18 -0700104 (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
Jeff Tinker3305b992014-05-14 18:39:25 -0700105
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 Nelissen18a1b592014-05-20 08:45:18 -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 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700243 if (!sessionId) {
244 return AMEDIA_ERROR_INVALID_PARAMETER;
245 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700246 Vector<uint8_t> session;
247 status_t status = mObj->mDrm->openSession(session);
248 if (status == OK) {
249 mObj->mIds.push_front(session);
250 List<idvec_t>::iterator iter = mObj->mIds.begin();
Marco Nelissen18a1b592014-05-20 08:45:18 -0700251 sessionId->ptr = iter->array();
252 sessionId->length = iter->size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700253 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700254 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700255}
256
Marco Nelissen3425fd52014-05-14 11:12:46 -0700257EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700258media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700259 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700260 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700261 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700262 if (!sessionId) {
263 return AMEDIA_ERROR_INVALID_PARAMETER;
264 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700265
266 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700267 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700268 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700269 }
270 mObj->mDrm->closeSession(*iter);
271 mObj->mIds.erase(iter);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700272 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700273}
274
Marco Nelissen3425fd52014-05-14 11:12:46 -0700275EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700276media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope,
Jeff Tinker497ca092014-05-13 09:31:15 -0700277 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
278 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700279 const uint8_t **keyRequest, size_t *keyRequestSize) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700280
281 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700282 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700283 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700284 if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700285 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700286 }
287
288 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700289 if (!findId(mObj, *scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700290 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700291 }
292
293 Vector<uint8_t> mdInit;
294 mdInit.appendArray(init, initSize);
295 DrmPlugin::KeyType mdKeyType;
296 switch (keyType) {
297 case KEY_TYPE_STREAMING:
298 mdKeyType = DrmPlugin::kKeyType_Streaming;
299 break;
300 case KEY_TYPE_OFFLINE:
301 mdKeyType = DrmPlugin::kKeyType_Offline;
302 break;
303 case KEY_TYPE_RELEASE:
304 mdKeyType = DrmPlugin::kKeyType_Release;
305 break;
306 default:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700307 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700308 }
309 KeyedVector<String8, String8> mdOptionalParameters;
310 for (size_t i = 0; i < numOptionalParameters; i++) {
311 mdOptionalParameters.add(String8(optionalParameters[i].mKey),
312 String8(optionalParameters[i].mValue));
313 }
314 String8 defaultUrl;
315 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
316 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl);
317 if (status != OK) {
318 return translateStatus(status);
319 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700320 *keyRequest = mObj->mKeyRequest.array();
321 *keyRequestSize = mObj->mKeyRequest.size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700322 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700323 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700324}
325
Marco Nelissen3425fd52014-05-14 11:12:46 -0700326EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700327media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
328 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700329
330 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700331 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700332 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700333 if (!scope || !response || !responseSize || !keySetId) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700334 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700335 }
336
337 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700338 if (!findId(mObj, *scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700339 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700340 }
341 Vector<uint8_t> mdResponse;
342 mdResponse.appendArray(response, responseSize);
343
344 Vector<uint8_t> mdKeySetId;
345 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
346 if (status == OK) {
347 mObj->mIds.push_front(mdKeySetId);
348 List<idvec_t>::iterator iter = mObj->mIds.begin();
Marco Nelissen18a1b592014-05-20 08:45:18 -0700349 keySetId->ptr = iter->array();
350 keySetId->length = iter->size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700351 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700352 keySetId->ptr = NULL;
353 keySetId->length = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700354 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700355 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700356}
357
Marco Nelissen3425fd52014-05-14 11:12:46 -0700358EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700359media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
360 const AMediaDrmKeySetId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700361
362 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700363 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700364 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700365 if (!sessionId || !keySetId) {
366 return AMEDIA_ERROR_INVALID_PARAMETER;
367 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700368 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700369 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700370 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700371 }
372 Vector<uint8_t> keySet;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700373 keySet.appendArray(keySetId->ptr, keySetId->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700374 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
375}
376
Marco Nelissen3425fd52014-05-14 11:12:46 -0700377EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700378media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700379 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700380 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700381 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700382 if (!keySetId) {
383 return AMEDIA_ERROR_INVALID_PARAMETER;
384 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700385 List<idvec_t>::iterator iter;
386 status_t status;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700387 if (!findId(mObj, *keySetId, iter)) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700388 Vector<uint8_t> keySet;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700389 keySet.appendArray(keySetId->ptr, keySetId->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700390 status = mObj->mDrm->removeKeys(keySet);
391 } else {
392 status = mObj->mDrm->removeKeys(*iter);
393 mObj->mIds.erase(iter);
394 }
395 return translateStatus(status);
396}
397
Marco Nelissen3425fd52014-05-14 11:12:46 -0700398EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700399media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
400 AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700401
402 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700403 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700404 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700405 if (!sessionId || !numPairs) {
406 return AMEDIA_ERROR_INVALID_PARAMETER;
407 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700408 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700409 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700410 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700411 }
412
413 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
414 if (status != OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700415 *numPairs = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700416 return translateStatus(status);
417 }
418
Marco Nelissen18a1b592014-05-20 08:45:18 -0700419 if (mObj->mQueryResults.size() > *numPairs) {
420 *numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700421 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700422 }
423
424 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
425 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
426 keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
427 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700428 *numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700429 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700430}
431
Marco Nelissen3425fd52014-05-14 11:12:46 -0700432EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700433media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
434 size_t *provisionRequestSize, const char **serverUrl) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700435 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700436 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700437 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700438 if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700439 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700440 }
441
442 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
443 mObj->mProvisionRequest, mObj->mProvisionUrl);
444 if (status != OK) {
445 return translateStatus(status);
446 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700447 *provisionRequest = mObj->mProvisionRequest.array();
448 *provisionRequestSize = mObj->mProvisionRequest.size();
449 *serverUrl = mObj->mProvisionUrl.string();
Jeff Tinker497ca092014-05-13 09:31:15 -0700450 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700451 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700452}
453
Marco Nelissen3425fd52014-05-14 11:12:46 -0700454EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700455media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700456 const uint8_t *response, size_t responseSize) {
457 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700458 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700459 }
460 if (!response || !responseSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700461 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700462 }
463
464 Vector<uint8_t> mdResponse;
465 mdResponse.appendArray(response, responseSize);
466
467 Vector<uint8_t> unused;
468 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
469}
470
Marco Nelissen3425fd52014-05-14 11:12:46 -0700471EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700472media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700473 AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700474
475 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700476 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700477 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700478 if (!numSecureStops) {
479 return AMEDIA_ERROR_INVALID_PARAMETER;
480 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700481 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
482 if (status != OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700483 *numSecureStops = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700484 return translateStatus(status);
485 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700486 if (*numSecureStops < mObj->mSecureStops.size()) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700487 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700488 }
489 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
490 size_t i = 0;
491 while (iter != mObj->mSecureStops.end()) {
492 secureStops[i].ptr = iter->array();
493 secureStops[i].length = iter->size();
494 ++iter;
495 ++i;
496 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700497 *numSecureStops = mObj->mSecureStops.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700498 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700499}
500
Marco Nelissen3425fd52014-05-14 11:12:46 -0700501EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700502media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700503 const AMediaDrmSecureStop *ssRelease) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700504
505 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700506 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700507 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700508 if (!ssRelease) {
509 return AMEDIA_ERROR_INVALID_PARAMETER;
510 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700511
512 Vector<uint8_t> release;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700513 release.appendArray(ssRelease->ptr, ssRelease->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700514 return translateStatus(mObj->mDrm->releaseSecureStops(release));
515}
516
517
Marco Nelissen3425fd52014-05-14 11:12:46 -0700518EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700519media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700520 const char **propertyValue) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700521
522 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700523 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700524 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700525 if (!propertyName || !propertyValue) {
526 return AMEDIA_ERROR_INVALID_PARAMETER;
527 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700528
529 status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
530 mObj->mPropertyString);
531
532 if (status == OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700533 *propertyValue = mObj->mPropertyString.string();
Jeff Tinker497ca092014-05-13 09:31:15 -0700534 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700535 *propertyValue = NULL;
Jeff Tinker497ca092014-05-13 09:31:15 -0700536 }
537 return translateStatus(status);
538}
539
Marco Nelissen3425fd52014-05-14 11:12:46 -0700540EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700541media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700542 const char *propertyName, AMediaDrmByteArray *propertyValue) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700543 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700544 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700545 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700546 if (!propertyName || !propertyValue) {
547 return AMEDIA_ERROR_INVALID_PARAMETER;
548 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700549
550 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
551 mObj->mPropertyByteArray);
552
553 if (status == OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700554 propertyValue->ptr = mObj->mPropertyByteArray.array();
555 propertyValue->length = mObj->mPropertyByteArray.size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700556 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700557 propertyValue->ptr = NULL;
558 propertyValue->length = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700559 }
560 return translateStatus(status);
561}
562
Marco Nelissen3425fd52014-05-14 11:12:46 -0700563EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700564media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700565 const char *propertyName, const char *value) {
566 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700567 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700568 }
569
570 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
571 String8(value)));
572}
573
Marco Nelissen3425fd52014-05-14 11:12:46 -0700574EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700575media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700576 const char *propertyName, const uint8_t *value, size_t valueSize) {
577
578 Vector<uint8_t> byteArray;
579 byteArray.appendArray(value, valueSize);
580
581 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
582 byteArray));
583}
584
585
Marco Nelissene419d7c2014-05-15 14:17:25 -0700586static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700587 const AMediaDrmSessionId &sessionId,
588 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
589 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
590
591 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700592 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700593 }
594 List<idvec_t>::iterator iter;
595 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700596 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700597 }
598
599 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
600 if (status != OK) {
601 return translateStatus(status);
602 }
603
604 Vector<uint8_t> keyIdVec;
605 const size_t kKeyIdSize = 16;
606 keyIdVec.appendArray(keyId, kKeyIdSize);
607
608 Vector<uint8_t> inputVec;
609 inputVec.appendArray(input, dataSize);
610
611 Vector<uint8_t> ivVec;
612 const size_t kIvSize = 16;
613 ivVec.appendArray(iv, kIvSize);
614
615 Vector<uint8_t> outputVec;
616 if (encrypt) {
617 status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
618 } else {
619 status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
620 }
621 if (status == OK) {
622 memcpy(output, outputVec.array(), outputVec.size());
623 }
624 return translateStatus(status);
625}
626
Marco Nelissen3425fd52014-05-14 11:12:46 -0700627EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700628media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700629 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
630 const uint8_t *input, uint8_t *output, size_t dataSize) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700631 if (!sessionId) {
632 return AMEDIA_ERROR_INVALID_PARAMETER;
633 }
634 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
Jeff Tinker497ca092014-05-13 09:31:15 -0700635 input, output, dataSize, true);
636}
637
Marco Nelissen3425fd52014-05-14 11:12:46 -0700638EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700639media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700640 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
641 const uint8_t *input, uint8_t *output, size_t dataSize) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700642 if (!sessionId) {
643 return AMEDIA_ERROR_INVALID_PARAMETER;
644 }
645 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
Jeff Tinker497ca092014-05-13 09:31:15 -0700646 input, output, dataSize, false);
647}
648
Marco Nelissen3425fd52014-05-14 11:12:46 -0700649EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700650media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700651 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
652 uint8_t *signature, size_t *signatureSize) {
653
654 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700655 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700656 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700657 if (!sessionId) {
658 return AMEDIA_ERROR_INVALID_PARAMETER;
659 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700660 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700661 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 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
679 if (signatureVec.size() > *signatureSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700680 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700681 }
682 if (status == OK) {
683 memcpy(signature, signatureVec.array(), signatureVec.size());
684 }
685 return translateStatus(status);
686}
687
Marco Nelissen3425fd52014-05-14 11:12:46 -0700688EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700689media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700690 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
691 const uint8_t *signature, size_t signatureSize) {
692
693 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700694 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700695 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700696 if (!sessionId) {
697 return AMEDIA_ERROR_INVALID_PARAMETER;
698 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700699 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700700 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700701 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700702 }
703
704 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
705 if (status != OK) {
706 return translateStatus(status);
707 }
708
709 Vector<uint8_t> keyIdVec;
710 const size_t kKeyIdSize = 16;
711 keyIdVec.appendArray(keyId, kKeyIdSize);
712
713 Vector<uint8_t> messageVec;
714 messageVec.appendArray(message, messageSize);
715
716 Vector<uint8_t> signatureVec;
717 signatureVec.appendArray(signature, signatureSize);
718
719 bool match;
720 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
721 if (status == OK) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700722 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700723 }
724 return translateStatus(status);
725}
726
727} // extern "C"
728