blob: 2f068be746da7257e0bbf6efa1b5f5393219bea4 [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
38struct AMediaDrm {
39 sp<IDrm> mDrm;
40 sp<IDrmClient> mDrmClient;
41 AMediaDrmEventListener mListener;
42 List<idvec_t> mIds;
43 KeyedVector<String8, String8> mQueryResults;
44 Vector<uint8_t> mKeyRequest;
45 Vector<uint8_t> mProvisionRequest;
46 String8 mProvisionUrl;
47 String8 mPropertyString;
48 Vector<uint8_t> mPropertyByteArray;
49 List<Vector<uint8_t> > mSecureStops;
50};
51
52extern "C" {
53
Marco Nelissene419d7c2014-05-15 14:17:25 -070054static media_status_t translateStatus(status_t status) {
55 media_status_t result = AMEDIA_ERROR_UNKNOWN;
Jeff Tinker497ca092014-05-13 09:31:15 -070056 switch (status) {
57 case OK:
Marco Nelissene419d7c2014-05-15 14:17:25 -070058 result = AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -070059 break;
60 case android::ERROR_DRM_NOT_PROVISIONED:
Marco Nelissene419d7c2014-05-15 14:17:25 -070061 result = AMEDIA_DRM_NOT_PROVISIONED;
Jeff Tinker497ca092014-05-13 09:31:15 -070062 break;
63 case android::ERROR_DRM_RESOURCE_BUSY:
Marco Nelissene419d7c2014-05-15 14:17:25 -070064 result = AMEDIA_DRM_RESOURCE_BUSY;
Jeff Tinker497ca092014-05-13 09:31:15 -070065 break;
66 case android::ERROR_DRM_DEVICE_REVOKED:
Marco Nelissene419d7c2014-05-15 14:17:25 -070067 result = AMEDIA_DRM_DEVICE_REVOKED;
Jeff Tinker497ca092014-05-13 09:31:15 -070068 break;
69 case android::ERROR_DRM_CANNOT_HANDLE:
Marco Nelissene419d7c2014-05-15 14:17:25 -070070 result = AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -070071 break;
72 case android::ERROR_DRM_TAMPER_DETECTED:
Marco Nelissene419d7c2014-05-15 14:17:25 -070073 result = AMEDIA_DRM_TAMPER_DETECTED;
Jeff Tinker497ca092014-05-13 09:31:15 -070074 break;
75 case android::ERROR_DRM_SESSION_NOT_OPENED:
Marco Nelissene419d7c2014-05-15 14:17:25 -070076 result = AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -070077 break;
78 case android::ERROR_DRM_NO_LICENSE:
Marco Nelissene419d7c2014-05-15 14:17:25 -070079 result = AMEDIA_DRM_NEED_KEY;
Jeff Tinker497ca092014-05-13 09:31:15 -070080 break;
81 case android::ERROR_DRM_LICENSE_EXPIRED:
Marco Nelissene419d7c2014-05-15 14:17:25 -070082 result = AMEDIA_DRM_LICENSE_EXPIRED;
Jeff Tinker497ca092014-05-13 09:31:15 -070083 break;
84 default:
Jeff Tinker497ca092014-05-13 09:31:15 -070085 break;
86 }
87 return result;
88}
89
90static sp<IDrm> CreateDrm() {
91 sp<IServiceManager> sm = defaultServiceManager();
92
93 sp<IBinder> binder =
94 sm->getService(String16("media.player"));
95
96 sp<IMediaPlayerService> service =
97 interface_cast<IMediaPlayerService>(binder);
98
99 if (service == NULL) {
100 return NULL;
101 }
102
103 sp<IDrm> drm = service->makeDrm();
104
105 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
106 return NULL;
107 }
108
109 return drm;
110}
111
112
113static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
114 sp<IDrm> drm = CreateDrm();
115
116 if (drm == NULL) {
117 return NULL;
118 }
119
120 status_t err = drm->createPlugin(uuid);
121
122 if (err != OK) {
123 return NULL;
124 }
125
126 return drm;
127}
128
Marco Nelissen3425fd52014-05-14 11:12:46 -0700129EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700130bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
131 sp<IDrm> drm = CreateDrm();
132
133 if (drm == NULL) {
134 return false;
135 }
136
137 String8 mimeStr = mimeType ? String8(mimeType) : String8("");
138 return drm->isCryptoSchemeSupported(uuid, mimeStr);
139}
140
Marco Nelissen3425fd52014-05-14 11:12:46 -0700141EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700142AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
143 AMediaDrm *mObj = new AMediaDrm();
144 mObj->mDrm = CreateDrmFromUUID(uuid);
145 return mObj;
146}
147
Marco Nelissen3425fd52014-05-14 11:12:46 -0700148EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700149void AMediaDrm_release(AMediaDrm *mObj) {
150 if (mObj->mDrm != NULL) {
151 mObj->mDrm->setListener(NULL);
152 mObj->mDrm->destroyPlugin();
153 mObj->mDrm.clear();
154 }
155 delete mObj;
156}
157
158#if 0
159void AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
160 mObj->mListener = listener;
161}
162#endif
163
164
165static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
166 iter = mObj->mIds.begin();
167 while (iter != mObj->mIds.end()) {
168 if (iter->array() == id.ptr && iter->size() == id.length) {
169 return true;
170 }
171 }
172 return false;
173}
174
Marco Nelissen3425fd52014-05-14 11:12:46 -0700175EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700176media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700177 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700178 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700179 }
180 Vector<uint8_t> session;
181 status_t status = mObj->mDrm->openSession(session);
182 if (status == OK) {
183 mObj->mIds.push_front(session);
184 List<idvec_t>::iterator iter = mObj->mIds.begin();
185 sessionId.ptr = iter->array();
186 sessionId.length = iter->size();
187 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700188 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700189}
190
Marco Nelissen3425fd52014-05-14 11:12:46 -0700191EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700192media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700193 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700194 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700195 }
196
197 List<idvec_t>::iterator iter;
198 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700199 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700200 }
201 mObj->mDrm->closeSession(*iter);
202 mObj->mIds.erase(iter);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700203 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700204}
205
Marco Nelissen3425fd52014-05-14 11:12:46 -0700206EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700207media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope,
Jeff Tinker497ca092014-05-13 09:31:15 -0700208 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
209 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
210 const uint8_t *&keyRequest, size_t &keyRequestSize) {
211
212 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700213 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700214 }
215 if (!mimeType) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700216 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700217 }
218
219 List<idvec_t>::iterator iter;
220 if (!findId(mObj, scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700221 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700222 }
223
224 Vector<uint8_t> mdInit;
225 mdInit.appendArray(init, initSize);
226 DrmPlugin::KeyType mdKeyType;
227 switch (keyType) {
228 case KEY_TYPE_STREAMING:
229 mdKeyType = DrmPlugin::kKeyType_Streaming;
230 break;
231 case KEY_TYPE_OFFLINE:
232 mdKeyType = DrmPlugin::kKeyType_Offline;
233 break;
234 case KEY_TYPE_RELEASE:
235 mdKeyType = DrmPlugin::kKeyType_Release;
236 break;
237 default:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700238 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700239 }
240 KeyedVector<String8, String8> mdOptionalParameters;
241 for (size_t i = 0; i < numOptionalParameters; i++) {
242 mdOptionalParameters.add(String8(optionalParameters[i].mKey),
243 String8(optionalParameters[i].mValue));
244 }
245 String8 defaultUrl;
246 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
247 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl);
248 if (status != OK) {
249 return translateStatus(status);
250 } else {
251 keyRequest = mObj->mKeyRequest.array();
252 keyRequestSize = mObj->mKeyRequest.size();
253 }
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 Nelissene419d7c2014-05-15 14:17:25 -0700258media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope,
Jeff Tinker497ca092014-05-13 09:31:15 -0700259 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) {
260
261 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700262 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700263 }
264 if (!response || !responseSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700265 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700266 }
267
268 List<idvec_t>::iterator iter;
269 if (!findId(mObj, scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700270 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700271 }
272 Vector<uint8_t> mdResponse;
273 mdResponse.appendArray(response, responseSize);
274
275 Vector<uint8_t> mdKeySetId;
276 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
277 if (status == OK) {
278 mObj->mIds.push_front(mdKeySetId);
279 List<idvec_t>::iterator iter = mObj->mIds.begin();
280 keySetId.ptr = iter->array();
281 keySetId.length = iter->size();
282 } else {
283 keySetId.ptr = NULL;
284 keySetId.length = 0;
285 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700286 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700287}
288
Marco Nelissen3425fd52014-05-14 11:12:46 -0700289EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700290media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700291 const AMediaDrmKeySetId &keySetId) {
292
293 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700294 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700295 }
296 List<idvec_t>::iterator iter;
297 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700298 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700299 }
300 Vector<uint8_t> keySet;
301 keySet.appendArray(keySetId.ptr, keySetId.length);
302 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
303}
304
Marco Nelissen3425fd52014-05-14 11:12:46 -0700305EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700306media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700307 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700308 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700309 }
310 List<idvec_t>::iterator iter;
311 status_t status;
312 if (!findId(mObj, keySetId, iter)) {
313 Vector<uint8_t> keySet;
314 keySet.appendArray(keySetId.ptr, keySetId.length);
315 status = mObj->mDrm->removeKeys(keySet);
316 } else {
317 status = mObj->mDrm->removeKeys(*iter);
318 mObj->mIds.erase(iter);
319 }
320 return translateStatus(status);
321}
322
Marco Nelissen3425fd52014-05-14 11:12:46 -0700323EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700324media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700325 AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) {
326
327 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700328 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700329 }
330 List<idvec_t>::iterator iter;
331 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700332 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700333 }
334
335 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
336 if (status != OK) {
337 numPairs = 0;
338 return translateStatus(status);
339 }
340
341 if (mObj->mQueryResults.size() > numPairs) {
342 numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700343 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700344 }
345
346 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
347 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
348 keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
349 }
350 numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700351 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700352}
353
Marco Nelissen3425fd52014-05-14 11:12:46 -0700354EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700355media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest,
Jeff Tinker497ca092014-05-13 09:31:15 -0700356 size_t &provisionRequestSize, const char *&serverUrl) {
357 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700358 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700359 }
360 if (!provisionRequestSize || !serverUrl) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700361 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700362 }
363
364 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
365 mObj->mProvisionRequest, mObj->mProvisionUrl);
366 if (status != OK) {
367 return translateStatus(status);
368 } else {
369 provisionRequest = mObj->mProvisionRequest.array();
370 provisionRequestSize = mObj->mProvisionRequest.size();
371 serverUrl = mObj->mProvisionUrl.string();
372 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700373 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700374}
375
Marco Nelissen3425fd52014-05-14 11:12:46 -0700376EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700377media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700378 const uint8_t *response, size_t responseSize) {
379 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 }
382 if (!response || !responseSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700383 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700384 }
385
386 Vector<uint8_t> mdResponse;
387 mdResponse.appendArray(response, responseSize);
388
389 Vector<uint8_t> unused;
390 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
391}
392
Marco Nelissen3425fd52014-05-14 11:12:46 -0700393EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700394media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700395 AMediaDrmSecureStop *secureStops, size_t &numSecureStops) {
396
397 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700398 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700399 }
400 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
401 if (status != OK) {
402 numSecureStops = 0;
403 return translateStatus(status);
404 }
405 if (numSecureStops < mObj->mSecureStops.size()) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700406 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700407 }
408 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
409 size_t i = 0;
410 while (iter != mObj->mSecureStops.end()) {
411 secureStops[i].ptr = iter->array();
412 secureStops[i].length = iter->size();
413 ++iter;
414 ++i;
415 }
416 numSecureStops = mObj->mSecureStops.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700417 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700418}
419
Marco Nelissen3425fd52014-05-14 11:12:46 -0700420EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700421media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700422 const AMediaDrmSecureStop &ssRelease) {
423
424 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700425 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700426 }
427
428 Vector<uint8_t> release;
429 release.appendArray(ssRelease.ptr, ssRelease.length);
430 return translateStatus(mObj->mDrm->releaseSecureStops(release));
431}
432
433
Marco Nelissen3425fd52014-05-14 11:12:46 -0700434EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700435media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
Jeff Tinker497ca092014-05-13 09:31:15 -0700436 const char *&propertyValue) {
437
438 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700439 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700440 }
441
442 status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
443 mObj->mPropertyString);
444
445 if (status == OK) {
446 propertyValue = mObj->mPropertyString.string();
447 } else {
448 propertyValue = NULL;
449 }
450 return translateStatus(status);
451}
452
Marco Nelissen3425fd52014-05-14 11:12:46 -0700453EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700454media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700455 const char *propertyName, AMediaDrmByteArray &propertyValue) {
456 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700457 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700458 }
459
460 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
461 mObj->mPropertyByteArray);
462
463 if (status == OK) {
464 propertyValue.ptr = mObj->mPropertyByteArray.array();
465 propertyValue.length = mObj->mPropertyByteArray.size();
466 } else {
467 propertyValue.ptr = NULL;
468 propertyValue.length = 0;
469 }
470 return translateStatus(status);
471}
472
Marco Nelissen3425fd52014-05-14 11:12:46 -0700473EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700474media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700475 const char *propertyName, const char *value) {
476 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700477 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700478 }
479
480 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
481 String8(value)));
482}
483
Marco Nelissen3425fd52014-05-14 11:12:46 -0700484EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700485media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700486 const char *propertyName, const uint8_t *value, size_t valueSize) {
487
488 Vector<uint8_t> byteArray;
489 byteArray.appendArray(value, valueSize);
490
491 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
492 byteArray));
493}
494
495
Marco Nelissene419d7c2014-05-15 14:17:25 -0700496static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700497 const AMediaDrmSessionId &sessionId,
498 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
499 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
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 List<idvec_t>::iterator iter;
505 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700506 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700507 }
508
509 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
510 if (status != OK) {
511 return translateStatus(status);
512 }
513
514 Vector<uint8_t> keyIdVec;
515 const size_t kKeyIdSize = 16;
516 keyIdVec.appendArray(keyId, kKeyIdSize);
517
518 Vector<uint8_t> inputVec;
519 inputVec.appendArray(input, dataSize);
520
521 Vector<uint8_t> ivVec;
522 const size_t kIvSize = 16;
523 ivVec.appendArray(iv, kIvSize);
524
525 Vector<uint8_t> outputVec;
526 if (encrypt) {
527 status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
528 } else {
529 status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
530 }
531 if (status == OK) {
532 memcpy(output, outputVec.array(), outputVec.size());
533 }
534 return translateStatus(status);
535}
536
Marco Nelissen3425fd52014-05-14 11:12:46 -0700537EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700538media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700539 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
540 const uint8_t *input, uint8_t *output, size_t dataSize) {
541 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
542 input, output, dataSize, true);
543}
544
Marco Nelissen3425fd52014-05-14 11:12:46 -0700545EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700546media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700547 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
548 const uint8_t *input, uint8_t *output, size_t dataSize) {
549 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
550 input, output, dataSize, false);
551}
552
Marco Nelissen3425fd52014-05-14 11:12:46 -0700553EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700554media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700555 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
556 uint8_t *signature, size_t *signatureSize) {
557
558 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 }
561 List<idvec_t>::iterator iter;
562 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700563 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700564 }
565
566 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
567 if (status != OK) {
568 return translateStatus(status);
569 }
570
571 Vector<uint8_t> keyIdVec;
572 const size_t kKeyIdSize = 16;
573 keyIdVec.appendArray(keyId, kKeyIdSize);
574
575 Vector<uint8_t> messageVec;
576 messageVec.appendArray(message, messageSize);
577
578 Vector<uint8_t> signatureVec;
579 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
580 if (signatureVec.size() > *signatureSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700581 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700582 }
583 if (status == OK) {
584 memcpy(signature, signatureVec.array(), signatureVec.size());
585 }
586 return translateStatus(status);
587}
588
Marco Nelissen3425fd52014-05-14 11:12:46 -0700589EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700590media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700591 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
592 const uint8_t *signature, size_t signatureSize) {
593
594 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700595 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700596 }
597 List<idvec_t>::iterator iter;
598 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700599 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700600 }
601
602 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
603 if (status != OK) {
604 return translateStatus(status);
605 }
606
607 Vector<uint8_t> keyIdVec;
608 const size_t kKeyIdSize = 16;
609 keyIdVec.appendArray(keyId, kKeyIdSize);
610
611 Vector<uint8_t> messageVec;
612 messageVec.appendArray(message, messageSize);
613
614 Vector<uint8_t> signatureVec;
615 signatureVec.appendArray(signature, signatureSize);
616
617 bool match;
618 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
619 if (status == OK) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700620 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700621 }
622 return translateStatus(status);
623}
624
625} // extern "C"
626