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"
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
;
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
) {
43 for (int i
= 0; i
< 4; ++i
)
44 value
= (value
<< 8) | data
[i
];
48 uint64
ReadUint64(const uint8_t* data
) {
50 for (int i
= 0; i
< 8; ++i
)
51 value
= (value
<< 8) | data
[i
];
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.
69 // uint64 LargeSize # Field is only present if value(Size) == 1.
70 // uint32 VersionAndFlags
73 // uint8[DataSize] Data
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.
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
,
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
)
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
)
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
)
129 if (type
== kTencType
) {
132 bytes_left
= data_end
- cur
;
134 } else if (type
!= kPsshType
) {
138 const int kPsshBoxMinimumSize
=
139 kPsshVersionFlagSize
+ kPsshSystemIdSize
+ kPsshDataSizeSize
;
140 if (box_end
< cur
+ kPsshBoxMinimumSize
)
143 uint32 version_and_flags
= ReadUint32(cur
);
144 cur
+= kPsshVersionFlagSize
;
145 bytes_left
-= kPsshVersionFlagSize
;
146 if (version_and_flags
!= 0)
149 DCHECK_GE(bytes_left
, kPsshSystemIdSize
);
150 if (!std::equal(uuid
.begin(), uuid
.end(), cur
)) {
152 bytes_left
= data_end
- cur
;
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
)
166 pssh_data
->assign(cur
, cur
+ data_size
);
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
178 switch (init_data_type
) {
179 case media::EmeInitDataType::WEBM
:
181 case media::EmeInitDataType::CENC
:
185 return "video/unknown";
189 class KeySystemUuidManager
{
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();
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())
217 void KeySystemUuidManager::AddMapping(const std::string
& key_system
,
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())
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
);
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
246 bool IsKeySystemSupportedWithTypeImpl(const std::string
& key_system
,
247 const std::string
& container_mime_type
) {
248 if (!MediaDrmBridge::IsAvailable())
251 UUID scheme_uuid
= g_key_system_uuid_manager
.Get().GetUUID(key_system
);
252 if (scheme_uuid
.empty())
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
:
279 case MediaDrmBridge::SECURITY_LEVEL_1
:
281 case MediaDrmBridge::SECURITY_LEVEL_3
:
290 static void AddKeySystemUuidMapping(JNIEnv
* env
,
292 jstring j_key_system
,
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
);
301 bool MediaDrmBridge::IsAvailable() {
302 if (base::android::BuildInfo::GetInstance()->sdk_int() < 19)
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
,
311 if (os_major_version
== 4 && os_minor_version
== 4 && os_bugfix_version
== 0)
317 // TODO(ddorwin): This is specific to Widevine. http://crbug.com/459400
319 bool MediaDrmBridge::IsSecureDecoderRequired(SecurityLevel security_level
) {
320 DCHECK(IsAvailable());
321 return SECURITY_LEVEL_1
== security_level
;
325 std::vector
<std::string
> MediaDrmBridge::GetPlatformKeySystemNames() {
326 return g_key_system_uuid_manager
.Get().GetPlatformKeySystemNames();
330 bool MediaDrmBridge::IsKeySystemSupported(const std::string
& key_system
) {
331 DCHECK(!key_system
.empty());
332 return IsKeySystemSupportedWithTypeImpl(key_system
, "");
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();
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());
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
;
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();
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";
417 JNIEnv
* env
= AttachCurrentThread();
419 std::string security_level_str
= GetSecurityLevelString(security_level
);
420 if (security_level_str
.empty())
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.");
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.");
464 base::android::ToJavaByteArray(env
, &pssh_data
[0], pssh_data
.size());
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
,
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()),
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()),
509 uint32_t promise_id
= cdm_promise_adapter_
.SavePromise(promise
.Pass());
510 Java_MediaDrmBridge_closeSession(env
, j_media_drm_
.obj(), j_session_id
.obj(),
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() {
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();
540 DCHECK(media_crypto_ready_cb_
.is_null());
542 if (!GetMediaCrypto().is_null()) {
543 base::MessageLoopProxy::current()->PostTask(FROM_HERE
, closure
);
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
,
559 cdm_promise_adapter_
.ResolvePromise(j_promise_id
);
562 void MediaDrmBridge::OnPromiseResolvedWithSession(JNIEnv
* env
,
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
,
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,
579 void MediaDrmBridge::OnSessionMessage(JNIEnv
* env
,
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
,
599 jbyteArray j_session_id
) {
600 session_closed_cb_
.Run(GetSessionId(env
, j_session_id
));
603 void MediaDrmBridge::OnSessionKeysChange(JNIEnv
* env
,
605 jbyteArray j_session_id
,
606 bool has_additional_usable_key
,
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
,
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.
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
);