blob: 166e6f1017767cb76378bcd52d1fdd9bf3a1f1ce [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 <ndk/NdkMediaCrypto.h>
33
34
35using namespace android;
36
37typedef Vector<uint8_t> idvec_t;
38
Jeff Tinker3305b992014-05-14 18:39:25 -070039struct DrmListener: virtual public BnDrmClient
40{
41private:
42 AMediaDrm *mObj;
43 AMediaDrmEventListener mListener;
44
45public:
46 DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {}
47 void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
48};
49
Jeff Tinker497ca092014-05-13 09:31:15 -070050struct AMediaDrm {
51 sp<IDrm> mDrm;
52 sp<IDrmClient> mDrmClient;
Jeff Tinker497ca092014-05-13 09:31:15 -070053 List<idvec_t> mIds;
54 KeyedVector<String8, String8> mQueryResults;
55 Vector<uint8_t> mKeyRequest;
56 Vector<uint8_t> mProvisionRequest;
57 String8 mProvisionUrl;
58 String8 mPropertyString;
59 Vector<uint8_t> mPropertyByteArray;
60 List<Vector<uint8_t> > mSecureStops;
Jeff Tinker3305b992014-05-14 18:39:25 -070061 sp<DrmListener> mListener;
Jeff Tinker497ca092014-05-13 09:31:15 -070062};
63
Jeff Tinker3305b992014-05-14 18:39:25 -070064void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
65 if (!mListener) {
66 return;
67 }
68
69 AMediaDrmSessionId sessionId = {NULL, 0};
70 int32_t sessionIdSize = obj->readInt32();
71 if (sessionIdSize) {
72 uint8_t *sessionIdData = new uint8_t[sessionIdSize];
73 sessionId.ptr = sessionIdData;
74 sessionId.length = sessionIdSize;
75 obj->read(sessionIdData, sessionId.length);
76 }
77
78 int32_t dataSize = obj->readInt32();
79 uint8_t *data = NULL;
80 if (dataSize) {
81 data = new uint8_t[dataSize];
82 obj->read(data, dataSize);
83 }
84
85 // translate DrmPlugin event types into their NDK equivalents
86 AMediaDrmEventType ndkEventType;
87 switch(eventType) {
88 case DrmPlugin::kDrmPluginEventProvisionRequired:
89 ndkEventType = EVENT_PROVISION_REQUIRED;
90 break;
91 case DrmPlugin::kDrmPluginEventKeyNeeded:
92 ndkEventType = EVENT_KEY_REQUIRED;
93 break;
94 case DrmPlugin::kDrmPluginEventKeyExpired:
95 ndkEventType = EVENT_KEY_EXPIRED;
96 break;
97 case DrmPlugin::kDrmPluginEventVendorDefined:
98 ndkEventType = EVENT_VENDOR_DEFINED;
99 break;
100 default:
101 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
102 return;
103 }
104
Marco Nelissen18a1b592014-05-20 08:45:18 -0700105 (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
Jeff Tinker3305b992014-05-14 18:39:25 -0700106
107 delete [] sessionId.ptr;
108 delete [] data;
109}
110
111
Jeff Tinker497ca092014-05-13 09:31:15 -0700112extern "C" {
113
Marco Nelissene419d7c2014-05-15 14:17:25 -0700114static media_status_t translateStatus(status_t status) {
115 media_status_t result = AMEDIA_ERROR_UNKNOWN;
Jeff Tinker497ca092014-05-13 09:31:15 -0700116 switch (status) {
117 case OK:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700118 result = AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700119 break;
120 case android::ERROR_DRM_NOT_PROVISIONED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700121 result = AMEDIA_DRM_NOT_PROVISIONED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700122 break;
123 case android::ERROR_DRM_RESOURCE_BUSY:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700124 result = AMEDIA_DRM_RESOURCE_BUSY;
Jeff Tinker497ca092014-05-13 09:31:15 -0700125 break;
126 case android::ERROR_DRM_DEVICE_REVOKED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700127 result = AMEDIA_DRM_DEVICE_REVOKED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700128 break;
129 case android::ERROR_DRM_CANNOT_HANDLE:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700130 result = AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700131 break;
132 case android::ERROR_DRM_TAMPER_DETECTED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700133 result = AMEDIA_DRM_TAMPER_DETECTED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700134 break;
135 case android::ERROR_DRM_SESSION_NOT_OPENED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700136 result = AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700137 break;
138 case android::ERROR_DRM_NO_LICENSE:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700139 result = AMEDIA_DRM_NEED_KEY;
Jeff Tinker497ca092014-05-13 09:31:15 -0700140 break;
141 case android::ERROR_DRM_LICENSE_EXPIRED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700142 result = AMEDIA_DRM_LICENSE_EXPIRED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700143 break;
144 default:
Jeff Tinker497ca092014-05-13 09:31:15 -0700145 break;
146 }
147 return result;
148}
149
150static sp<IDrm> CreateDrm() {
151 sp<IServiceManager> sm = defaultServiceManager();
Jeff Tinker30038072016-04-25 13:41:35 -0700152 sp<IBinder> binder = sm->getService(String16("media.drm"));
Jeff Tinker497ca092014-05-13 09:31:15 -0700153
Jeff Tinker30038072016-04-25 13:41:35 -0700154 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
155 if (service == NULL) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700156 return NULL;
157 }
158
Jeff Tinker30038072016-04-25 13:41:35 -0700159 sp<IDrm> drm = service->makeDrm();
160 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
161 return NULL;
162 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700163 return drm;
164}
165
166
167static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
168 sp<IDrm> drm = CreateDrm();
169
170 if (drm == NULL) {
171 return NULL;
172 }
173
174 status_t err = drm->createPlugin(uuid);
175
176 if (err != OK) {
177 return NULL;
178 }
179
180 return drm;
181}
182
Marco Nelissen3425fd52014-05-14 11:12:46 -0700183EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700184bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
185 sp<IDrm> drm = CreateDrm();
186
187 if (drm == NULL) {
188 return false;
189 }
190
191 String8 mimeStr = mimeType ? String8(mimeType) : String8("");
192 return drm->isCryptoSchemeSupported(uuid, mimeStr);
193}
194
Marco Nelissen3425fd52014-05-14 11:12:46 -0700195EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700196AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
197 AMediaDrm *mObj = new AMediaDrm();
198 mObj->mDrm = CreateDrmFromUUID(uuid);
199 return mObj;
200}
201
Marco Nelissen3425fd52014-05-14 11:12:46 -0700202EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700203void AMediaDrm_release(AMediaDrm *mObj) {
204 if (mObj->mDrm != NULL) {
205 mObj->mDrm->setListener(NULL);
206 mObj->mDrm->destroyPlugin();
207 mObj->mDrm.clear();
208 }
209 delete mObj;
210}
211
Jeff Tinker3305b992014-05-14 18:39:25 -0700212EXPORT
Marco Nelissen7c96d532014-05-15 15:26:14 -0700213media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
Jeff Tinker3305b992014-05-14 18:39:25 -0700214 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissen7c96d532014-05-15 15:26:14 -0700215 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker3305b992014-05-14 18:39:25 -0700216 }
217 mObj->mListener = new DrmListener(mObj, listener);
218 mObj->mDrm->setListener(mObj->mListener);
Marco Nelissen7c96d532014-05-15 15:26:14 -0700219 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700220}
Jeff Tinker497ca092014-05-13 09:31:15 -0700221
222
223static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
Edwin Wong8cc90e42016-11-02 18:32:49 -0700224 for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700225 if (iter->array() == id.ptr && iter->size() == id.length) {
226 return true;
227 }
228 }
229 return false;
230}
231
Marco Nelissen3425fd52014-05-14 11:12:46 -0700232EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700233media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId *sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700234 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700235 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700236 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700237 if (!sessionId) {
238 return AMEDIA_ERROR_INVALID_PARAMETER;
239 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700240 Vector<uint8_t> session;
241 status_t status = mObj->mDrm->openSession(session);
242 if (status == OK) {
243 mObj->mIds.push_front(session);
244 List<idvec_t>::iterator iter = mObj->mIds.begin();
Marco Nelissen18a1b592014-05-20 08:45:18 -0700245 sessionId->ptr = iter->array();
246 sessionId->length = iter->size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700247 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700248 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700249}
250
Marco Nelissen3425fd52014-05-14 11:12:46 -0700251EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700252media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const 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
260 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700261 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 Nelissen18a1b592014-05-20 08:45:18 -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,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700273 const uint8_t **keyRequest, size_t *keyRequestSize) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700274
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 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700278 if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
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;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700283 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;
Jeff Tinkerd072c902015-03-16 13:39:29 -0700309 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker497ca092014-05-13 09:31:15 -0700310 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
Jeff Tinkerd072c902015-03-16 13:39:29 -0700311 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
312 &keyRequestType);
Jeff Tinker497ca092014-05-13 09:31:15 -0700313 if (status != OK) {
314 return translateStatus(status);
315 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700316 *keyRequest = mObj->mKeyRequest.array();
317 *keyRequestSize = mObj->mKeyRequest.size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700318 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700319 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700320}
321
Marco Nelissen3425fd52014-05-14 11:12:46 -0700322EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700323media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
324 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700325
326 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700327 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700328 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700329 if (!scope || !response || !responseSize || !keySetId) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700330 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700331 }
332
333 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700334 if (!findId(mObj, *scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700335 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700336 }
337 Vector<uint8_t> mdResponse;
338 mdResponse.appendArray(response, responseSize);
339
340 Vector<uint8_t> mdKeySetId;
341 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
342 if (status == OK) {
343 mObj->mIds.push_front(mdKeySetId);
344 List<idvec_t>::iterator iter = mObj->mIds.begin();
Marco Nelissen18a1b592014-05-20 08:45:18 -0700345 keySetId->ptr = iter->array();
346 keySetId->length = iter->size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700347 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700348 keySetId->ptr = NULL;
349 keySetId->length = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700350 }
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 Nelissen18a1b592014-05-20 08:45:18 -0700355media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
356 const AMediaDrmKeySetId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700357
358 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700359 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700360 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700361 if (!sessionId || !keySetId) {
362 return AMEDIA_ERROR_INVALID_PARAMETER;
363 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700364 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700365 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700366 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700367 }
368 Vector<uint8_t> keySet;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700369 keySet.appendArray(keySetId->ptr, keySetId->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700370 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
371}
372
Marco Nelissen3425fd52014-05-14 11:12:46 -0700373EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700374media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700375 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700376 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700377 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700378 if (!keySetId) {
379 return AMEDIA_ERROR_INVALID_PARAMETER;
380 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700381 List<idvec_t>::iterator iter;
382 status_t status;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700383 if (!findId(mObj, *keySetId, iter)) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700384 Vector<uint8_t> keySet;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700385 keySet.appendArray(keySetId->ptr, keySetId->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700386 status = mObj->mDrm->removeKeys(keySet);
387 } else {
388 status = mObj->mDrm->removeKeys(*iter);
389 mObj->mIds.erase(iter);
390 }
391 return translateStatus(status);
392}
393
Marco Nelissen3425fd52014-05-14 11:12:46 -0700394EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700395media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
396 AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700397
398 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700399 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700400 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700401 if (!sessionId || !numPairs) {
402 return AMEDIA_ERROR_INVALID_PARAMETER;
403 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700404 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700405 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700406 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700407 }
408
409 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
410 if (status != OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700411 *numPairs = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700412 return translateStatus(status);
413 }
414
Marco Nelissen18a1b592014-05-20 08:45:18 -0700415 if (mObj->mQueryResults.size() > *numPairs) {
416 *numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700417 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700418 }
419
420 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
421 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
422 keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
423 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700424 *numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700425 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700426}
427
Marco Nelissen3425fd52014-05-14 11:12:46 -0700428EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700429media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
430 size_t *provisionRequestSize, const char **serverUrl) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700431 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700432 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700433 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700434 if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700435 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700436 }
437
438 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
439 mObj->mProvisionRequest, mObj->mProvisionUrl);
440 if (status != OK) {
441 return translateStatus(status);
442 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700443 *provisionRequest = mObj->mProvisionRequest.array();
444 *provisionRequestSize = mObj->mProvisionRequest.size();
445 *serverUrl = mObj->mProvisionUrl.string();
Jeff Tinker497ca092014-05-13 09:31:15 -0700446 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700447 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700448}
449
Marco Nelissen3425fd52014-05-14 11:12:46 -0700450EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700451media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700452 const uint8_t *response, size_t responseSize) {
453 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700454 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700455 }
456 if (!response || !responseSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700457 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700458 }
459
460 Vector<uint8_t> mdResponse;
461 mdResponse.appendArray(response, responseSize);
462
463 Vector<uint8_t> unused;
464 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
465}
466
Marco Nelissen3425fd52014-05-14 11:12:46 -0700467EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700468media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700469 AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700470
471 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700472 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700473 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700474 if (!numSecureStops) {
475 return AMEDIA_ERROR_INVALID_PARAMETER;
476 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700477 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
478 if (status != OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700479 *numSecureStops = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700480 return translateStatus(status);
481 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700482 if (*numSecureStops < mObj->mSecureStops.size()) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700483 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700484 }
485 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
486 size_t i = 0;
487 while (iter != mObj->mSecureStops.end()) {
488 secureStops[i].ptr = iter->array();
489 secureStops[i].length = iter->size();
490 ++iter;
491 ++i;
492 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700493 *numSecureStops = mObj->mSecureStops.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700494 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700495}
496
Marco Nelissen3425fd52014-05-14 11:12:46 -0700497EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700498media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700499 const AMediaDrmSecureStop *ssRelease) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700500
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 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700504 if (!ssRelease) {
505 return AMEDIA_ERROR_INVALID_PARAMETER;
506 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700507
508 Vector<uint8_t> release;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700509 release.appendArray(ssRelease->ptr, ssRelease->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700510 return translateStatus(mObj->mDrm->releaseSecureStops(release));
511}
512
513
Marco Nelissen3425fd52014-05-14 11:12:46 -0700514EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700515media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700516 const char **propertyValue) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700517
518 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700519 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700520 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700521 if (!propertyName || !propertyValue) {
522 return AMEDIA_ERROR_INVALID_PARAMETER;
523 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700524
525 status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
526 mObj->mPropertyString);
527
528 if (status == OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700529 *propertyValue = mObj->mPropertyString.string();
Jeff Tinker497ca092014-05-13 09:31:15 -0700530 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700531 *propertyValue = NULL;
Jeff Tinker497ca092014-05-13 09:31:15 -0700532 }
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_getPropertyByteArray(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700538 const char *propertyName, AMediaDrmByteArray *propertyValue) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700539 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 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700542 if (!propertyName || !propertyValue) {
543 return AMEDIA_ERROR_INVALID_PARAMETER;
544 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700545
546 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
547 mObj->mPropertyByteArray);
548
549 if (status == OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700550 propertyValue->ptr = mObj->mPropertyByteArray.array();
551 propertyValue->length = mObj->mPropertyByteArray.size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700552 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700553 propertyValue->ptr = NULL;
554 propertyValue->length = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700555 }
556 return translateStatus(status);
557}
558
Marco Nelissen3425fd52014-05-14 11:12:46 -0700559EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700560media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700561 const char *propertyName, const char *value) {
562 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700563 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700564 }
565
566 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
567 String8(value)));
568}
569
Marco Nelissen3425fd52014-05-14 11:12:46 -0700570EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700571media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700572 const char *propertyName, const uint8_t *value, size_t valueSize) {
573
574 Vector<uint8_t> byteArray;
575 byteArray.appendArray(value, valueSize);
576
577 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
578 byteArray));
579}
580
581
Marco Nelissene419d7c2014-05-15 14:17:25 -0700582static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700583 const AMediaDrmSessionId &sessionId,
584 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
585 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
586
587 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700588 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700589 }
590 List<idvec_t>::iterator iter;
591 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700592 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700593 }
594
595 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
596 if (status != OK) {
597 return translateStatus(status);
598 }
599
600 Vector<uint8_t> keyIdVec;
601 const size_t kKeyIdSize = 16;
602 keyIdVec.appendArray(keyId, kKeyIdSize);
603
604 Vector<uint8_t> inputVec;
605 inputVec.appendArray(input, dataSize);
606
607 Vector<uint8_t> ivVec;
608 const size_t kIvSize = 16;
609 ivVec.appendArray(iv, kIvSize);
610
611 Vector<uint8_t> outputVec;
612 if (encrypt) {
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800613 status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
Jeff Tinker497ca092014-05-13 09:31:15 -0700614 } else {
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800615 status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
Jeff Tinker497ca092014-05-13 09:31:15 -0700616 }
617 if (status == OK) {
618 memcpy(output, outputVec.array(), outputVec.size());
619 }
620 return translateStatus(status);
621}
622
Marco Nelissen3425fd52014-05-14 11:12:46 -0700623EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700624media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700625 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
626 const uint8_t *input, uint8_t *output, size_t dataSize) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700627 if (!sessionId) {
628 return AMEDIA_ERROR_INVALID_PARAMETER;
629 }
630 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
Jeff Tinker497ca092014-05-13 09:31:15 -0700631 input, output, dataSize, true);
632}
633
Marco Nelissen3425fd52014-05-14 11:12:46 -0700634EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700635media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700636 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
637 const uint8_t *input, uint8_t *output, size_t dataSize) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700638 if (!sessionId) {
639 return AMEDIA_ERROR_INVALID_PARAMETER;
640 }
641 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
Jeff Tinker497ca092014-05-13 09:31:15 -0700642 input, output, dataSize, false);
643}
644
Marco Nelissen3425fd52014-05-14 11:12:46 -0700645EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700646media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700647 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
648 uint8_t *signature, size_t *signatureSize) {
649
650 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700651 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700652 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700653 if (!sessionId) {
654 return AMEDIA_ERROR_INVALID_PARAMETER;
655 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700656 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700657 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700658 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700659 }
660
661 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
662 if (status != OK) {
663 return translateStatus(status);
664 }
665
666 Vector<uint8_t> keyIdVec;
667 const size_t kKeyIdSize = 16;
668 keyIdVec.appendArray(keyId, kKeyIdSize);
669
670 Vector<uint8_t> messageVec;
671 messageVec.appendArray(message, messageSize);
672
673 Vector<uint8_t> signatureVec;
674 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
675 if (signatureVec.size() > *signatureSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700676 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700677 }
678 if (status == OK) {
679 memcpy(signature, signatureVec.array(), signatureVec.size());
680 }
681 return translateStatus(status);
682}
683
Marco Nelissen3425fd52014-05-14 11:12:46 -0700684EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700685media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700686 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
687 const uint8_t *signature, size_t signatureSize) {
688
689 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700690 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700691 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700692 if (!sessionId) {
693 return AMEDIA_ERROR_INVALID_PARAMETER;
694 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700695 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700696 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700697 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700698 }
699
700 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
701 if (status != OK) {
702 return translateStatus(status);
703 }
704
705 Vector<uint8_t> keyIdVec;
706 const size_t kKeyIdSize = 16;
707 keyIdVec.appendArray(keyId, kKeyIdSize);
708
709 Vector<uint8_t> messageVec;
710 messageVec.appendArray(message, messageSize);
711
712 Vector<uint8_t> signatureVec;
713 signatureVec.appendArray(signature, signatureSize);
714
715 bool match;
716 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
717 if (status == OK) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700718 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700719 }
720 return translateStatus(status);
721}
722
723} // extern "C"