Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / media / base / android / media_drm_bridge.cc
blob0e31818d94875de7dc5e1e4a4796e9121de7df1b
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/base/android/media_drm_bridge.h"
7 #include <algorithm>
9 #include "base/android/build_info.h"
10 #include "base/android/jni_array.h"
11 #include "base/android/jni_string.h"
12 #include "base/callback_helpers.h"
13 #include "base/containers/hash_tables.h"
14 #include "base/lazy_instance.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/message_loop/message_loop_proxy.h"
18 #include "base/strings/string_util.h"
19 #include "base/sys_byteorder.h"
20 #include "base/sys_info.h"
21 #include "jni/MediaDrmBridge_jni.h"
22 #include "media/base/cdm_key_information.h"
24 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
26 using base::android::AttachCurrentThread;
27 using base::android::ConvertUTF8ToJavaString;
28 using base::android::ConvertJavaStringToUTF8;
29 using base::android::JavaByteArrayToByteVector;
30 using base::android::ScopedJavaLocalRef;
32 namespace media {
34 namespace {
36 // DrmBridge supports session expiration event but doesn't provide detailed
37 // status for each key ID, which is required by the EME spec. Use a dummy key ID
38 // here to report session expiration info.
39 const char kDummyKeyId[] = "Dummy Key Id";
41 uint32 ReadUint32(const uint8_t* data) {
42 uint32 value = 0;
43 for (int i = 0; i < 4; ++i)
44 value = (value << 8) | data[i];
45 return value;
48 uint64 ReadUint64(const uint8_t* data) {
49 uint64 value = 0;
50 for (int i = 0; i < 8; ++i)
51 value = (value << 8) | data[i];
52 return value;
55 // Returns string session ID from jbyteArray (byte[] in Java).
56 std::string GetSessionId(JNIEnv* env, jbyteArray j_session_id) {
57 std::vector<uint8> session_id_vector;
58 JavaByteArrayToByteVector(env, j_session_id, &session_id_vector);
59 return std::string(session_id_vector.begin(), session_id_vector.end());
62 // The structure of an ISO CENC Protection System Specific Header (PSSH) box is
63 // as follows. (See ISO/IEC FDIS 23001-7:2011(E).)
64 // Note: ISO boxes use big-endian values.
66 // PSSH {
67 // uint32 Size
68 // uint32 Type
69 // uint64 LargeSize # Field is only present if value(Size) == 1.
70 // uint32 VersionAndFlags
71 // uint8[16] SystemId
72 // uint32 DataSize
73 // uint8[DataSize] Data
74 // }
75 const int kBoxHeaderSize = 8; // Box's header contains Size and Type.
76 const int kBoxLargeSizeSize = 8;
77 const int kPsshVersionFlagSize = 4;
78 const int kPsshSystemIdSize = 16;
79 const int kPsshDataSizeSize = 4;
80 const uint32 kTencType = 0x74656e63;
81 const uint32 kPsshType = 0x70737368;
82 const uint8 kWidevineUuid[16] = {
83 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE,
84 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED };
86 typedef std::vector<uint8> UUID;
88 // Tries to find a PSSH box whose "SystemId" is |uuid| in |data|, parses the
89 // "Data" of the box and put it in |pssh_data|. Returns true if such a box is
90 // found and successfully parsed. Returns false otherwise.
91 // Notes:
92 // 1, If multiple PSSH boxes are found,the "Data" of the first matching PSSH box
93 // will be set in |pssh_data|.
94 // 2, Only PSSH and TENC boxes are allowed in |data|. TENC boxes are skipped.
95 bool GetPsshData(const uint8* data,
96 int data_size,
97 const UUID& uuid,
98 std::vector<uint8>* pssh_data) {
99 const uint8* cur = data;
100 const uint8* data_end = data + data_size;
101 int bytes_left = data_size;
103 while (bytes_left > 0) {
104 const uint8* box_head = cur;
106 if (bytes_left < kBoxHeaderSize)
107 return false;
109 uint64_t box_size = ReadUint32(cur);
110 uint32 type = ReadUint32(cur + 4);
111 cur += kBoxHeaderSize;
112 bytes_left -= kBoxHeaderSize;
114 if (box_size == 1) { // LargeSize is present.
115 if (bytes_left < kBoxLargeSizeSize)
116 return false;
118 box_size = ReadUint64(cur);
119 cur += kBoxLargeSizeSize;
120 bytes_left -= kBoxLargeSizeSize;
121 } else if (box_size == 0) {
122 box_size = bytes_left + kBoxHeaderSize;
125 const uint8* box_end = box_head + box_size;
126 if (data_end < box_end)
127 return false;
129 if (type == kTencType) {
130 // Skip 'tenc' box.
131 cur = box_end;
132 bytes_left = data_end - cur;
133 continue;
134 } else if (type != kPsshType) {
135 return false;
138 const int kPsshBoxMinimumSize =
139 kPsshVersionFlagSize + kPsshSystemIdSize + kPsshDataSizeSize;
140 if (box_end < cur + kPsshBoxMinimumSize)
141 return false;
143 uint32 version_and_flags = ReadUint32(cur);
144 cur += kPsshVersionFlagSize;
145 bytes_left -= kPsshVersionFlagSize;
146 if (version_and_flags != 0)
147 return false;
149 DCHECK_GE(bytes_left, kPsshSystemIdSize);
150 if (!std::equal(uuid.begin(), uuid.end(), cur)) {
151 cur = box_end;
152 bytes_left = data_end - cur;
153 continue;
156 cur += kPsshSystemIdSize;
157 bytes_left -= kPsshSystemIdSize;
159 uint32 data_size = ReadUint32(cur);
160 cur += kPsshDataSizeSize;
161 bytes_left -= kPsshDataSizeSize;
163 if (box_end < cur + data_size)
164 return false;
166 pssh_data->assign(cur, cur + data_size);
167 return true;
170 return false;
173 // Convert |init_data_type| to a string supported by MediaDRM.
174 // "audio"/"video" does not matter, so use "video".
175 std::string ConvertInitDataType(media::EmeInitDataType init_data_type) {
176 // TODO(jrummell): API level >=20 supports "webm" and "cenc", so switch
177 // to those strings.
178 switch (init_data_type) {
179 case media::EmeInitDataType::WEBM:
180 return "video/webm";
181 case media::EmeInitDataType::CENC:
182 return "video/mp4";
183 default:
184 NOTREACHED();
185 return "video/unknown";
189 class KeySystemUuidManager {
190 public:
191 KeySystemUuidManager();
192 UUID GetUUID(const std::string& key_system);
193 void AddMapping(const std::string& key_system, const UUID& uuid);
194 std::vector<std::string> GetPlatformKeySystemNames();
196 private:
197 typedef base::hash_map<std::string, UUID> KeySystemUuidMap;
199 KeySystemUuidMap key_system_uuid_map_;
201 DISALLOW_COPY_AND_ASSIGN(KeySystemUuidManager);
204 KeySystemUuidManager::KeySystemUuidManager() {
205 // Widevine is always supported in Android.
206 key_system_uuid_map_[kWidevineKeySystem] =
207 UUID(kWidevineUuid, kWidevineUuid + arraysize(kWidevineUuid));
210 UUID KeySystemUuidManager::GetUUID(const std::string& key_system) {
211 KeySystemUuidMap::iterator it = key_system_uuid_map_.find(key_system);
212 if (it == key_system_uuid_map_.end())
213 return UUID();
214 return it->second;
217 void KeySystemUuidManager::AddMapping(const std::string& key_system,
218 const UUID& uuid) {
219 KeySystemUuidMap::iterator it = key_system_uuid_map_.find(key_system);
220 DCHECK(it == key_system_uuid_map_.end())
221 << "Shouldn't overwrite an existing key system.";
222 if (it != key_system_uuid_map_.end())
223 return;
224 key_system_uuid_map_[key_system] = uuid;
227 std::vector<std::string> KeySystemUuidManager::GetPlatformKeySystemNames() {
228 std::vector<std::string> key_systems;
229 for (KeySystemUuidMap::iterator it = key_system_uuid_map_.begin();
230 it != key_system_uuid_map_.end(); ++it) {
231 // Rule out the key system handled by Chrome explicitly.
232 if (it->first != kWidevineKeySystem)
233 key_systems.push_back(it->first);
235 return key_systems;
238 base::LazyInstance<KeySystemUuidManager>::Leaky g_key_system_uuid_manager =
239 LAZY_INSTANCE_INITIALIZER;
241 // Checks whether |key_system| is supported with |container_mime_type|. Only
242 // checks |key_system| support if |container_mime_type| is empty.
243 // TODO(xhwang): The |container_mime_type| is not the same as contentType in
244 // the EME spec. Revisit this once the spec issue with initData type is
245 // resolved.
246 bool IsKeySystemSupportedWithTypeImpl(const std::string& key_system,
247 const std::string& container_mime_type) {
248 if (!MediaDrmBridge::IsAvailable())
249 return false;
251 UUID scheme_uuid = g_key_system_uuid_manager.Get().GetUUID(key_system);
252 if (scheme_uuid.empty())
253 return false;
255 JNIEnv* env = AttachCurrentThread();
256 ScopedJavaLocalRef<jbyteArray> j_scheme_uuid =
257 base::android::ToJavaByteArray(env, &scheme_uuid[0], scheme_uuid.size());
258 ScopedJavaLocalRef<jstring> j_container_mime_type =
259 ConvertUTF8ToJavaString(env, container_mime_type);
260 return Java_MediaDrmBridge_isCryptoSchemeSupported(
261 env, j_scheme_uuid.obj(), j_container_mime_type.obj());
264 MediaDrmBridge::SecurityLevel GetSecurityLevelFromString(
265 const std::string& security_level_str) {
266 if (0 == security_level_str.compare("L1"))
267 return MediaDrmBridge::SECURITY_LEVEL_1;
268 if (0 == security_level_str.compare("L3"))
269 return MediaDrmBridge::SECURITY_LEVEL_3;
270 DCHECK(security_level_str.empty());
271 return MediaDrmBridge::SECURITY_LEVEL_NONE;
274 std::string GetSecurityLevelString(
275 MediaDrmBridge::SecurityLevel security_level) {
276 switch (security_level) {
277 case MediaDrmBridge::SECURITY_LEVEL_NONE:
278 return "";
279 case MediaDrmBridge::SECURITY_LEVEL_1:
280 return "L1";
281 case MediaDrmBridge::SECURITY_LEVEL_3:
282 return "L3";
284 return "";
287 } // namespace
289 // Called by Java.
290 static void AddKeySystemUuidMapping(JNIEnv* env,
291 jclass clazz,
292 jstring j_key_system,
293 jobject j_buffer) {
294 std::string key_system = ConvertJavaStringToUTF8(env, j_key_system);
295 uint8* buffer = static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer));
296 UUID uuid(buffer, buffer + 16);
297 g_key_system_uuid_manager.Get().AddMapping(key_system, uuid);
300 // static
301 bool MediaDrmBridge::IsAvailable() {
302 if (base::android::BuildInfo::GetInstance()->sdk_int() < 19)
303 return false;
305 int32 os_major_version = 0;
306 int32 os_minor_version = 0;
307 int32 os_bugfix_version = 0;
308 base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
309 &os_minor_version,
310 &os_bugfix_version);
311 if (os_major_version == 4 && os_minor_version == 4 && os_bugfix_version == 0)
312 return false;
314 return true;
317 // TODO(ddorwin): This is specific to Widevine. http://crbug.com/459400
318 // static
319 bool MediaDrmBridge::IsSecureDecoderRequired(SecurityLevel security_level) {
320 DCHECK(IsAvailable());
321 return SECURITY_LEVEL_1 == security_level;
324 // static
325 std::vector<std::string> MediaDrmBridge::GetPlatformKeySystemNames() {
326 return g_key_system_uuid_manager.Get().GetPlatformKeySystemNames();
329 // static
330 bool MediaDrmBridge::IsKeySystemSupported(const std::string& key_system) {
331 DCHECK(!key_system.empty());
332 return IsKeySystemSupportedWithTypeImpl(key_system, "");
335 // static
336 bool MediaDrmBridge::IsKeySystemSupportedWithType(
337 const std::string& key_system,
338 const std::string& container_mime_type) {
339 DCHECK(!key_system.empty() && !container_mime_type.empty());
340 return IsKeySystemSupportedWithTypeImpl(key_system, container_mime_type);
343 bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv* env) {
344 return RegisterNativesImpl(env);
347 MediaDrmBridge::MediaDrmBridge(
348 const std::vector<uint8>& scheme_uuid,
349 const SessionMessageCB& session_message_cb,
350 const SessionClosedCB& session_closed_cb,
351 const LegacySessionErrorCB& legacy_session_error_cb,
352 const SessionKeysChangeCB& session_keys_change_cb)
353 : scheme_uuid_(scheme_uuid),
354 session_message_cb_(session_message_cb),
355 session_closed_cb_(session_closed_cb),
356 legacy_session_error_cb_(legacy_session_error_cb),
357 session_keys_change_cb_(session_keys_change_cb) {
358 JNIEnv* env = AttachCurrentThread();
359 CHECK(env);
361 ScopedJavaLocalRef<jbyteArray> j_scheme_uuid =
362 base::android::ToJavaByteArray(env, &scheme_uuid[0], scheme_uuid.size());
363 j_media_drm_.Reset(Java_MediaDrmBridge_create(
364 env, j_scheme_uuid.obj(), reinterpret_cast<intptr_t>(this)));
367 MediaDrmBridge::~MediaDrmBridge() {
368 JNIEnv* env = AttachCurrentThread();
369 player_tracker_.NotifyCdmUnset();
370 if (!j_media_drm_.is_null())
371 Java_MediaDrmBridge_destroy(env, j_media_drm_.obj());
374 // static
375 // TODO(xhwang): Enable SessionExpirationUpdateCB when it is supported.
376 scoped_ptr<MediaDrmBridge> MediaDrmBridge::Create(
377 const std::string& key_system,
378 const SessionMessageCB& session_message_cb,
379 const SessionClosedCB& session_closed_cb,
380 const LegacySessionErrorCB& legacy_session_error_cb,
381 const SessionKeysChangeCB& session_keys_change_cb,
382 const SessionExpirationUpdateCB& /* session_expiration_update_cb */) {
383 scoped_ptr<MediaDrmBridge> media_drm_bridge;
384 if (!IsAvailable())
385 return media_drm_bridge.Pass();
387 UUID scheme_uuid = g_key_system_uuid_manager.Get().GetUUID(key_system);
388 if (scheme_uuid.empty())
389 return media_drm_bridge.Pass();
391 media_drm_bridge.reset(
392 new MediaDrmBridge(scheme_uuid, session_message_cb, session_closed_cb,
393 legacy_session_error_cb, session_keys_change_cb));
395 if (media_drm_bridge->j_media_drm_.is_null())
396 media_drm_bridge.reset();
398 return media_drm_bridge.Pass();
401 // static
402 scoped_ptr<MediaDrmBridge> MediaDrmBridge::CreateWithoutSessionSupport(
403 const std::string& key_system) {
404 return MediaDrmBridge::Create(
405 key_system, SessionMessageCB(), SessionClosedCB(), LegacySessionErrorCB(),
406 SessionKeysChangeCB(), SessionExpirationUpdateCB());
409 bool MediaDrmBridge::SetSecurityLevel(SecurityLevel security_level) {
410 if (security_level != SECURITY_LEVEL_NONE &&
411 !std::equal(scheme_uuid_.begin(), scheme_uuid_.end(), kWidevineUuid)) {
412 NOTREACHED() << "Widevine security level " << security_level
413 << "used with another key system";
414 return false;
417 JNIEnv* env = AttachCurrentThread();
419 std::string security_level_str = GetSecurityLevelString(security_level);
420 if (security_level_str.empty())
421 return false;
423 ScopedJavaLocalRef<jstring> j_security_level =
424 ConvertUTF8ToJavaString(env, security_level_str);
425 return Java_MediaDrmBridge_setSecurityLevel(
426 env, j_media_drm_.obj(), j_security_level.obj());
429 void MediaDrmBridge::SetServerCertificate(
430 const uint8* certificate_data,
431 int certificate_data_length,
432 scoped_ptr<media::SimpleCdmPromise> promise) {
433 promise->reject(NOT_SUPPORTED_ERROR, 0,
434 "SetServerCertificate() is not supported.");
437 void MediaDrmBridge::CreateSessionAndGenerateRequest(
438 SessionType session_type,
439 media::EmeInitDataType init_data_type,
440 const uint8* init_data,
441 int init_data_length,
442 scoped_ptr<media::NewSessionCdmPromise> promise) {
443 DVLOG(1) << __FUNCTION__;
445 if (session_type != media::MediaKeys::TEMPORARY_SESSION) {
446 promise->reject(NOT_SUPPORTED_ERROR, 0,
447 "Only the temporary session type is supported.");
448 return;
451 JNIEnv* env = AttachCurrentThread();
452 ScopedJavaLocalRef<jbyteArray> j_init_data;
454 // Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as
455 // the init data when using MP4 container.
456 if (std::equal(scheme_uuid_.begin(), scheme_uuid_.end(), kWidevineUuid) &&
457 init_data_type == media::EmeInitDataType::CENC) {
458 std::vector<uint8> pssh_data;
459 if (!GetPsshData(init_data, init_data_length, scheme_uuid_, &pssh_data)) {
460 promise->reject(INVALID_ACCESS_ERROR, 0, "Invalid PSSH data.");
461 return;
463 j_init_data =
464 base::android::ToJavaByteArray(env, &pssh_data[0], pssh_data.size());
465 } else {
466 j_init_data =
467 base::android::ToJavaByteArray(env, init_data, init_data_length);
470 ScopedJavaLocalRef<jstring> j_mime =
471 ConvertUTF8ToJavaString(env, ConvertInitDataType(init_data_type));
472 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
473 Java_MediaDrmBridge_createSession(env, j_media_drm_.obj(), j_init_data.obj(),
474 j_mime.obj(), promise_id);
477 void MediaDrmBridge::LoadSession(
478 SessionType session_type,
479 const std::string& session_id,
480 scoped_ptr<media::NewSessionCdmPromise> promise) {
481 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported.");
484 void MediaDrmBridge::UpdateSession(
485 const std::string& session_id,
486 const uint8* response,
487 int response_length,
488 scoped_ptr<media::SimpleCdmPromise> promise) {
489 DVLOG(1) << __FUNCTION__;
491 JNIEnv* env = AttachCurrentThread();
492 ScopedJavaLocalRef<jbyteArray> j_response =
493 base::android::ToJavaByteArray(env, response, response_length);
494 ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray(
495 env, reinterpret_cast<const uint8_t*>(session_id.data()),
496 session_id.size());
497 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
498 Java_MediaDrmBridge_updateSession(env, j_media_drm_.obj(), j_session_id.obj(),
499 j_response.obj(), promise_id);
502 void MediaDrmBridge::CloseSession(const std::string& session_id,
503 scoped_ptr<media::SimpleCdmPromise> promise) {
504 DVLOG(1) << __FUNCTION__;
505 JNIEnv* env = AttachCurrentThread();
506 ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray(
507 env, reinterpret_cast<const uint8_t*>(session_id.data()),
508 session_id.size());
509 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
510 Java_MediaDrmBridge_closeSession(env, j_media_drm_.obj(), j_session_id.obj(),
511 promise_id);
514 void MediaDrmBridge::RemoveSession(
515 const std::string& session_id,
516 scoped_ptr<media::SimpleCdmPromise> promise) {
517 promise->reject(NOT_SUPPORTED_ERROR, 0, "RemoveSession() is not supported.");
520 CdmContext* MediaDrmBridge::GetCdmContext() {
521 NOTREACHED();
522 return nullptr;
525 int MediaDrmBridge::RegisterPlayer(const base::Closure& new_key_cb,
526 const base::Closure& cdm_unset_cb) {
527 return player_tracker_.RegisterPlayer(new_key_cb, cdm_unset_cb);
530 void MediaDrmBridge::UnregisterPlayer(int registration_id) {
531 player_tracker_.UnregisterPlayer(registration_id);
534 void MediaDrmBridge::SetMediaCryptoReadyCB(const base::Closure& closure) {
535 if (closure.is_null()) {
536 media_crypto_ready_cb_.Reset();
537 return;
540 DCHECK(media_crypto_ready_cb_.is_null());
542 if (!GetMediaCrypto().is_null()) {
543 base::MessageLoopProxy::current()->PostTask(FROM_HERE, closure);
544 return;
547 media_crypto_ready_cb_ = closure;
550 void MediaDrmBridge::OnMediaCryptoReady(JNIEnv* env, jobject) {
551 DCHECK(!GetMediaCrypto().is_null());
552 if (!media_crypto_ready_cb_.is_null())
553 base::ResetAndReturn(&media_crypto_ready_cb_).Run();
556 void MediaDrmBridge::OnPromiseResolved(JNIEnv* env,
557 jobject j_media_drm,
558 jint j_promise_id) {
559 cdm_promise_adapter_.ResolvePromise(j_promise_id);
562 void MediaDrmBridge::OnPromiseResolvedWithSession(JNIEnv* env,
563 jobject j_media_drm,
564 jint j_promise_id,
565 jbyteArray j_session_id) {
566 cdm_promise_adapter_.ResolvePromise(j_promise_id,
567 GetSessionId(env, j_session_id));
570 void MediaDrmBridge::OnPromiseRejected(JNIEnv* env,
571 jobject j_media_drm,
572 jint j_promise_id,
573 jstring j_error_message) {
574 std::string error_message = ConvertJavaStringToUTF8(env, j_error_message);
575 cdm_promise_adapter_.RejectPromise(j_promise_id, MediaKeys::UNKNOWN_ERROR, 0,
576 error_message);
579 void MediaDrmBridge::OnSessionMessage(JNIEnv* env,
580 jobject j_media_drm,
581 jbyteArray j_session_id,
582 jbyteArray j_message,
583 jstring j_legacy_destination_url) {
584 std::vector<uint8> message;
585 JavaByteArrayToByteVector(env, j_message, &message);
586 GURL legacy_destination_url =
587 GURL(ConvertJavaStringToUTF8(env, j_legacy_destination_url));
588 // Note: Message type is not supported in MediaDrm. Do our best guess here.
589 media::MediaKeys::MessageType message_type =
590 legacy_destination_url.is_empty() ? media::MediaKeys::LICENSE_REQUEST
591 : media::MediaKeys::LICENSE_RENEWAL;
593 session_message_cb_.Run(GetSessionId(env, j_session_id), message_type,
594 message, legacy_destination_url);
597 void MediaDrmBridge::OnSessionClosed(JNIEnv* env,
598 jobject j_media_drm,
599 jbyteArray j_session_id) {
600 session_closed_cb_.Run(GetSessionId(env, j_session_id));
603 void MediaDrmBridge::OnSessionKeysChange(JNIEnv* env,
604 jobject j_media_drm,
605 jbyteArray j_session_id,
606 bool has_additional_usable_key,
607 jint j_key_status) {
608 if (has_additional_usable_key)
609 player_tracker_.NotifyNewKey();
611 scoped_ptr<CdmKeyInformation> cdm_key_information(new CdmKeyInformation());
612 cdm_key_information->key_id.assign(kDummyKeyId,
613 kDummyKeyId + sizeof(kDummyKeyId));
614 cdm_key_information->status =
615 static_cast<CdmKeyInformation::KeyStatus>(j_key_status);
616 CdmKeysInfo cdm_keys_info;
617 cdm_keys_info.push_back(cdm_key_information.release());
619 session_keys_change_cb_.Run(GetSessionId(env, j_session_id),
620 has_additional_usable_key, cdm_keys_info.Pass());
623 void MediaDrmBridge::OnLegacySessionError(JNIEnv* env,
624 jobject j_media_drm,
625 jbyteArray j_session_id,
626 jstring j_error_message) {
627 std::string error_message = ConvertJavaStringToUTF8(env, j_error_message);
628 legacy_session_error_cb_.Run(GetSessionId(env, j_session_id),
629 MediaKeys::UNKNOWN_ERROR, 0, error_message);
632 ScopedJavaLocalRef<jobject> MediaDrmBridge::GetMediaCrypto() {
633 JNIEnv* env = AttachCurrentThread();
634 return Java_MediaDrmBridge_getMediaCrypto(env, j_media_drm_.obj());
637 MediaDrmBridge::SecurityLevel MediaDrmBridge::GetSecurityLevel() {
638 JNIEnv* env = AttachCurrentThread();
639 ScopedJavaLocalRef<jstring> j_security_level =
640 Java_MediaDrmBridge_getSecurityLevel(env, j_media_drm_.obj());
641 std::string security_level_str =
642 ConvertJavaStringToUTF8(env, j_security_level.obj());
643 return GetSecurityLevelFromString(security_level_str);
646 bool MediaDrmBridge::IsProtectedSurfaceRequired() {
647 // For Widevine, this depends on the security level.
648 if (std::equal(scheme_uuid_.begin(), scheme_uuid_.end(), kWidevineUuid))
649 return IsSecureDecoderRequired(GetSecurityLevel());
651 // For other key systems, assume true.
652 return true;
655 void MediaDrmBridge::ResetDeviceCredentials(
656 const ResetCredentialsCB& callback) {
657 DCHECK(reset_credentials_cb_.is_null());
658 reset_credentials_cb_ = callback;
659 JNIEnv* env = AttachCurrentThread();
660 Java_MediaDrmBridge_resetDeviceCredentials(env, j_media_drm_.obj());
663 void MediaDrmBridge::OnResetDeviceCredentialsCompleted(
664 JNIEnv* env, jobject, bool success) {
665 base::ResetAndReturn(&reset_credentials_cb_).Run(success);
668 } // namespace media