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/single_thread_task_runner.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/sys_byteorder.h"
22 #include "base/sys_info.h"
23 #include "base/thread_task_runner_handle.h"
24 #include "jni/MediaDrmBridge_jni.h"
25 #include "media/base/android/media_client_android.h"
26 #include "media/base/android/media_drm_bridge_delegate.h"
27 #include "media/base/cdm_key_information.h"
29 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
31 using base::android::AttachCurrentThread
;
32 using base::android::ConvertUTF8ToJavaString
;
33 using base::android::ConvertJavaStringToUTF8
;
34 using base::android::JavaByteArrayToByteVector
;
35 using base::android::ScopedJavaLocalRef
;
41 // These must be in sync with Android MediaDrm REQUEST_TYPE_XXX constants!
42 // https://developer.android.com/reference/android/media/MediaDrm.KeyRequest.html
43 enum class RequestType
{
44 REQUEST_TYPE_INITIAL
= 0,
45 REQUEST_TYPE_RENEWAL
= 1,
46 REQUEST_TYPE_RELEASE
= 2,
49 // These must be in sync with Android MediaDrm KEY_STATUS_XXX constants:
50 // https://developer.android.com/reference/android/media/MediaDrm.KeyStatus.html
51 enum class KeyStatus
{
52 KEY_STATUS_USABLE
= 0,
53 KEY_STATUS_EXPIRED
= 1,
54 KEY_STATUS_OUTPUT_NOT_ALLOWED
= 2,
55 KEY_STATUS_PENDING
= 3,
56 KEY_STATUS_INTERNAL_ERROR
= 4,
59 // Returns string session ID from jbyteArray (byte[] in Java).
60 std::string
GetSessionId(JNIEnv
* env
, jbyteArray j_session_id
) {
61 std::vector
<uint8
> session_id_vector
;
62 JavaByteArrayToByteVector(env
, j_session_id
, &session_id_vector
);
63 return std::string(session_id_vector
.begin(), session_id_vector
.end());
66 const uint8 kWidevineUuid
[16] = {
67 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE,
68 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED };
70 // Convert |init_data_type| to a string supported by MediaDRM.
71 // "audio"/"video" does not matter, so use "video".
72 std::string
ConvertInitDataType(media::EmeInitDataType init_data_type
) {
73 // TODO(jrummell/xhwang): EME init data types like "webm" and "cenc" are
74 // supported in API level >=21 for Widevine key system. Switch to use those
75 // strings when they are officially supported in Android for all key systems.
76 switch (init_data_type
) {
77 case media::EmeInitDataType::WEBM
:
79 case media::EmeInitDataType::CENC
:
81 case media::EmeInitDataType::KEYIDS
:
89 MediaKeys::MessageType
GetMessageType(RequestType request_type
) {
90 switch (request_type
) {
91 case RequestType::REQUEST_TYPE_INITIAL
:
92 return MediaKeys::LICENSE_REQUEST
;
93 case RequestType::REQUEST_TYPE_RENEWAL
:
94 return MediaKeys::LICENSE_RENEWAL
;
95 case RequestType::REQUEST_TYPE_RELEASE
:
96 return MediaKeys::LICENSE_RELEASE
;
100 return MediaKeys::LICENSE_REQUEST
;
103 CdmKeyInformation::KeyStatus
ConvertKeyStatus(KeyStatus key_status
) {
104 switch (key_status
) {
105 case KeyStatus::KEY_STATUS_USABLE
:
106 return CdmKeyInformation::USABLE
;
107 case KeyStatus::KEY_STATUS_EXPIRED
:
108 return CdmKeyInformation::EXPIRED
;
109 case KeyStatus::KEY_STATUS_OUTPUT_NOT_ALLOWED
:
110 return CdmKeyInformation::OUTPUT_RESTRICTED
;
111 case KeyStatus::KEY_STATUS_PENDING
:
112 // TODO(xhwang): This should probably be renamed to "PENDING".
113 return CdmKeyInformation::KEY_STATUS_PENDING
;
114 case KeyStatus::KEY_STATUS_INTERNAL_ERROR
:
115 return CdmKeyInformation::INTERNAL_ERROR
;
119 return CdmKeyInformation::INTERNAL_ERROR
;
122 class KeySystemManager
{
125 UUID
GetUUID(const std::string
& key_system
);
126 std::vector
<std::string
> GetPlatformKeySystemNames();
129 using KeySystemUuidMap
= MediaClientAndroid::KeySystemUuidMap
;
131 KeySystemUuidMap key_system_uuid_map_
;
133 DISALLOW_COPY_AND_ASSIGN(KeySystemManager
);
136 KeySystemManager::KeySystemManager() {
137 // Widevine is always supported in Android.
138 key_system_uuid_map_
[kWidevineKeySystem
] =
139 UUID(kWidevineUuid
, kWidevineUuid
+ arraysize(kWidevineUuid
));
140 MediaClientAndroid
* client
= GetMediaClientAndroid();
142 client
->AddKeySystemUUIDMappings(&key_system_uuid_map_
);
145 UUID
KeySystemManager::GetUUID(const std::string
& key_system
) {
146 KeySystemUuidMap::iterator it
= key_system_uuid_map_
.find(key_system
);
147 if (it
== key_system_uuid_map_
.end())
152 std::vector
<std::string
> KeySystemManager::GetPlatformKeySystemNames() {
153 std::vector
<std::string
> key_systems
;
154 for (KeySystemUuidMap::iterator it
= key_system_uuid_map_
.begin();
155 it
!= key_system_uuid_map_
.end(); ++it
) {
156 // Rule out the key system handled by Chrome explicitly.
157 if (it
->first
!= kWidevineKeySystem
)
158 key_systems
.push_back(it
->first
);
163 base::LazyInstance
<KeySystemManager
>::Leaky g_key_system_manager
=
164 LAZY_INSTANCE_INITIALIZER
;
166 // Checks whether |key_system| is supported with |container_mime_type|. Only
167 // checks |key_system| support if |container_mime_type| is empty.
168 // TODO(xhwang): The |container_mime_type| is not the same as contentType in
169 // the EME spec. Revisit this once the spec issue with initData type is
171 bool IsKeySystemSupportedWithTypeImpl(const std::string
& key_system
,
172 const std::string
& container_mime_type
) {
173 if (!MediaDrmBridge::IsAvailable())
176 UUID scheme_uuid
= g_key_system_manager
.Get().GetUUID(key_system
);
177 if (scheme_uuid
.empty())
180 JNIEnv
* env
= AttachCurrentThread();
181 ScopedJavaLocalRef
<jbyteArray
> j_scheme_uuid
=
182 base::android::ToJavaByteArray(env
, &scheme_uuid
[0], scheme_uuid
.size());
183 ScopedJavaLocalRef
<jstring
> j_container_mime_type
=
184 ConvertUTF8ToJavaString(env
, container_mime_type
);
185 return Java_MediaDrmBridge_isCryptoSchemeSupported(
186 env
, j_scheme_uuid
.obj(), j_container_mime_type
.obj());
189 MediaDrmBridge::SecurityLevel
GetSecurityLevelFromString(
190 const std::string
& security_level_str
) {
191 if (0 == security_level_str
.compare("L1"))
192 return MediaDrmBridge::SECURITY_LEVEL_1
;
193 if (0 == security_level_str
.compare("L3"))
194 return MediaDrmBridge::SECURITY_LEVEL_3
;
195 DCHECK(security_level_str
.empty());
196 return MediaDrmBridge::SECURITY_LEVEL_NONE
;
199 std::string
GetSecurityLevelString(
200 MediaDrmBridge::SecurityLevel security_level
) {
201 switch (security_level
) {
202 case MediaDrmBridge::SECURITY_LEVEL_NONE
:
204 case MediaDrmBridge::SECURITY_LEVEL_1
:
206 case MediaDrmBridge::SECURITY_LEVEL_3
:
215 bool MediaDrmBridge::IsAvailable() {
216 if (base::android::BuildInfo::GetInstance()->sdk_int() < 19)
219 int32 os_major_version
= 0;
220 int32 os_minor_version
= 0;
221 int32 os_bugfix_version
= 0;
222 base::SysInfo::OperatingSystemVersionNumbers(&os_major_version
,
225 if (os_major_version
== 4 && os_minor_version
== 4 && os_bugfix_version
== 0)
231 // TODO(ddorwin): This is specific to Widevine. http://crbug.com/459400
233 bool MediaDrmBridge::IsSecureDecoderRequired(SecurityLevel security_level
) {
234 DCHECK(IsAvailable());
235 return SECURITY_LEVEL_1
== security_level
;
239 std::vector
<std::string
> MediaDrmBridge::GetPlatformKeySystemNames() {
240 return g_key_system_manager
.Get().GetPlatformKeySystemNames();
244 bool MediaDrmBridge::IsKeySystemSupported(const std::string
& key_system
) {
245 DCHECK(!key_system
.empty());
246 return IsKeySystemSupportedWithTypeImpl(key_system
, "");
250 bool MediaDrmBridge::IsKeySystemSupportedWithType(
251 const std::string
& key_system
,
252 const std::string
& container_mime_type
) {
253 DCHECK(!key_system
.empty() && !container_mime_type
.empty());
254 return IsKeySystemSupportedWithTypeImpl(key_system
, container_mime_type
);
257 bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv
* env
) {
258 return RegisterNativesImpl(env
);
261 MediaDrmBridge::MediaDrmBridge(
262 const std::vector
<uint8
>& scheme_uuid
,
263 const SessionMessageCB
& session_message_cb
,
264 const SessionClosedCB
& session_closed_cb
,
265 const LegacySessionErrorCB
& legacy_session_error_cb
,
266 const SessionKeysChangeCB
& session_keys_change_cb
,
267 const SessionExpirationUpdateCB
& session_expiration_update_cb
)
268 : scheme_uuid_(scheme_uuid
),
269 session_message_cb_(session_message_cb
),
270 session_closed_cb_(session_closed_cb
),
271 legacy_session_error_cb_(legacy_session_error_cb
),
272 session_keys_change_cb_(session_keys_change_cb
),
273 session_expiration_update_cb_(session_expiration_update_cb
) {
274 JNIEnv
* env
= AttachCurrentThread();
277 ScopedJavaLocalRef
<jbyteArray
> j_scheme_uuid
=
278 base::android::ToJavaByteArray(env
, &scheme_uuid
[0], scheme_uuid
.size());
279 j_media_drm_
.Reset(Java_MediaDrmBridge_create(
280 env
, j_scheme_uuid
.obj(), reinterpret_cast<intptr_t>(this)));
283 MediaDrmBridge::~MediaDrmBridge() {
284 JNIEnv
* env
= AttachCurrentThread();
285 player_tracker_
.NotifyCdmUnset();
286 if (!j_media_drm_
.is_null())
287 Java_MediaDrmBridge_destroy(env
, j_media_drm_
.obj());
291 scoped_ptr
<MediaDrmBridge
> MediaDrmBridge::Create(
292 const std::string
& key_system
,
293 const SessionMessageCB
& session_message_cb
,
294 const SessionClosedCB
& session_closed_cb
,
295 const LegacySessionErrorCB
& legacy_session_error_cb
,
296 const SessionKeysChangeCB
& session_keys_change_cb
,
297 const SessionExpirationUpdateCB
& session_expiration_update_cb
) {
298 scoped_ptr
<MediaDrmBridge
> media_drm_bridge
;
300 return media_drm_bridge
.Pass();
302 UUID scheme_uuid
= g_key_system_manager
.Get().GetUUID(key_system
);
303 if (scheme_uuid
.empty())
304 return media_drm_bridge
.Pass();
306 media_drm_bridge
.reset(
307 new MediaDrmBridge(scheme_uuid
, session_message_cb
, session_closed_cb
,
308 legacy_session_error_cb
, session_keys_change_cb
,
309 session_expiration_update_cb
));
311 if (media_drm_bridge
->j_media_drm_
.is_null())
312 media_drm_bridge
.reset();
314 return media_drm_bridge
.Pass();
318 scoped_ptr
<MediaDrmBridge
> MediaDrmBridge::CreateWithoutSessionSupport(
319 const std::string
& key_system
) {
320 return MediaDrmBridge::Create(
321 key_system
, SessionMessageCB(), SessionClosedCB(), LegacySessionErrorCB(),
322 SessionKeysChangeCB(), SessionExpirationUpdateCB());
325 bool MediaDrmBridge::SetSecurityLevel(SecurityLevel security_level
) {
326 if (security_level
!= SECURITY_LEVEL_NONE
&&
327 !std::equal(scheme_uuid_
.begin(), scheme_uuid_
.end(), kWidevineUuid
)) {
328 NOTREACHED() << "Widevine security level " << security_level
329 << "used with another key system";
333 JNIEnv
* env
= AttachCurrentThread();
335 std::string security_level_str
= GetSecurityLevelString(security_level
);
336 if (security_level_str
.empty())
339 ScopedJavaLocalRef
<jstring
> j_security_level
=
340 ConvertUTF8ToJavaString(env
, security_level_str
);
341 return Java_MediaDrmBridge_setSecurityLevel(
342 env
, j_media_drm_
.obj(), j_security_level
.obj());
345 void MediaDrmBridge::SetServerCertificate(
346 const std::vector
<uint8_t>& certificate
,
347 scoped_ptr
<media::SimpleCdmPromise
> promise
) {
348 DCHECK(!certificate
.empty());
350 JNIEnv
* env
= AttachCurrentThread();
351 ScopedJavaLocalRef
<jbyteArray
> j_certificate
;
352 if (Java_MediaDrmBridge_setServerCertificate(env
, j_media_drm_
.obj(),
353 j_certificate
.obj())) {
356 promise
->reject(INVALID_ACCESS_ERROR
, 0, "Set server certificate failed.");
360 void MediaDrmBridge::CreateSessionAndGenerateRequest(
361 SessionType session_type
,
362 media::EmeInitDataType init_data_type
,
363 const std::vector
<uint8_t>& init_data
,
364 scoped_ptr
<media::NewSessionCdmPromise
> promise
) {
365 DVLOG(1) << __FUNCTION__
;
367 if (session_type
!= media::MediaKeys::TEMPORARY_SESSION
) {
368 NOTIMPLEMENTED() << "EME persistent sessions not yet supported on Android.";
369 promise
->reject(NOT_SUPPORTED_ERROR
, 0,
370 "Only the temporary session type is supported.");
374 JNIEnv
* env
= AttachCurrentThread();
375 ScopedJavaLocalRef
<jbyteArray
> j_init_data
;
376 ScopedJavaLocalRef
<jobjectArray
> j_optional_parameters
;
378 MediaClientAndroid
* client
= GetMediaClientAndroid();
380 MediaDrmBridgeDelegate
* delegate
=
381 client
->GetMediaDrmBridgeDelegate(scheme_uuid_
);
383 std::vector
<uint8
> init_data_from_delegate
;
384 std::vector
<std::string
> optional_parameters_from_delegate
;
385 if (!delegate
->OnCreateSession(init_data_type
, init_data
,
386 &init_data_from_delegate
,
387 &optional_parameters_from_delegate
)) {
388 promise
->reject(INVALID_ACCESS_ERROR
, 0, "Invalid init data.");
390 if (!init_data_from_delegate
.empty()) {
391 j_init_data
= base::android::ToJavaByteArray(
392 env
, vector_as_array(&init_data_from_delegate
),
393 init_data_from_delegate
.size());
395 if (!optional_parameters_from_delegate
.empty()) {
396 j_optional_parameters
= base::android::ToJavaArrayOfStrings(
397 env
, optional_parameters_from_delegate
);
402 if (j_init_data
.is_null()) {
403 j_init_data
= base::android::ToJavaByteArray(
404 env
, vector_as_array(&init_data
), init_data
.size());
407 ScopedJavaLocalRef
<jstring
> j_mime
=
408 ConvertUTF8ToJavaString(env
, ConvertInitDataType(init_data_type
));
409 uint32_t promise_id
= cdm_promise_adapter_
.SavePromise(promise
.Pass());
410 Java_MediaDrmBridge_createSessionFromNative(env
, j_media_drm_
.obj(),
411 j_init_data
.obj(), j_mime
.obj(),
412 j_optional_parameters
.obj(),
416 void MediaDrmBridge::LoadSession(
417 SessionType session_type
,
418 const std::string
& session_id
,
419 scoped_ptr
<media::NewSessionCdmPromise
> promise
) {
420 NOTIMPLEMENTED() << "EME persistent sessions not yet supported on Android.";
421 promise
->reject(NOT_SUPPORTED_ERROR
, 0, "LoadSession() is not supported.");
424 void MediaDrmBridge::UpdateSession(
425 const std::string
& session_id
,
426 const std::vector
<uint8_t>& response
,
427 scoped_ptr
<media::SimpleCdmPromise
> promise
) {
428 DVLOG(1) << __FUNCTION__
;
430 JNIEnv
* env
= AttachCurrentThread();
431 ScopedJavaLocalRef
<jbyteArray
> j_response
= base::android::ToJavaByteArray(
432 env
, vector_as_array(&response
), response
.size());
433 ScopedJavaLocalRef
<jbyteArray
> j_session_id
= base::android::ToJavaByteArray(
434 env
, reinterpret_cast<const uint8_t*>(session_id
.data()),
436 uint32_t promise_id
= cdm_promise_adapter_
.SavePromise(promise
.Pass());
437 Java_MediaDrmBridge_updateSession(env
, j_media_drm_
.obj(), j_session_id
.obj(),
438 j_response
.obj(), promise_id
);
441 void MediaDrmBridge::CloseSession(const std::string
& session_id
,
442 scoped_ptr
<media::SimpleCdmPromise
> promise
) {
443 DVLOG(1) << __FUNCTION__
;
444 JNIEnv
* env
= AttachCurrentThread();
445 ScopedJavaLocalRef
<jbyteArray
> j_session_id
= base::android::ToJavaByteArray(
446 env
, reinterpret_cast<const uint8_t*>(session_id
.data()),
448 uint32_t promise_id
= cdm_promise_adapter_
.SavePromise(promise
.Pass());
449 Java_MediaDrmBridge_closeSession(env
, j_media_drm_
.obj(), j_session_id
.obj(),
453 void MediaDrmBridge::RemoveSession(
454 const std::string
& session_id
,
455 scoped_ptr
<media::SimpleCdmPromise
> promise
) {
456 NOTIMPLEMENTED() << "EME persistent sessions not yet supported on Android.";
457 promise
->reject(NOT_SUPPORTED_ERROR
, 0, "RemoveSession() is not supported.");
460 CdmContext
* MediaDrmBridge::GetCdmContext() {
465 int MediaDrmBridge::RegisterPlayer(const base::Closure
& new_key_cb
,
466 const base::Closure
& cdm_unset_cb
) {
467 return player_tracker_
.RegisterPlayer(new_key_cb
, cdm_unset_cb
);
470 void MediaDrmBridge::UnregisterPlayer(int registration_id
) {
471 player_tracker_
.UnregisterPlayer(registration_id
);
474 void MediaDrmBridge::SetMediaCryptoReadyCB(const base::Closure
& closure
) {
475 if (closure
.is_null()) {
476 media_crypto_ready_cb_
.Reset();
480 DCHECK(media_crypto_ready_cb_
.is_null());
482 if (!GetMediaCrypto().is_null()) {
483 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, closure
);
487 media_crypto_ready_cb_
= closure
;
490 void MediaDrmBridge::OnMediaCryptoReady(JNIEnv
* env
, jobject
) {
491 DCHECK(!GetMediaCrypto().is_null());
492 if (!media_crypto_ready_cb_
.is_null())
493 base::ResetAndReturn(&media_crypto_ready_cb_
).Run();
496 void MediaDrmBridge::OnPromiseResolved(JNIEnv
* env
,
499 cdm_promise_adapter_
.ResolvePromise(j_promise_id
);
502 void MediaDrmBridge::OnPromiseResolvedWithSession(JNIEnv
* env
,
505 jbyteArray j_session_id
) {
506 cdm_promise_adapter_
.ResolvePromise(j_promise_id
,
507 GetSessionId(env
, j_session_id
));
510 void MediaDrmBridge::OnPromiseRejected(JNIEnv
* env
,
513 jstring j_error_message
) {
514 std::string error_message
= ConvertJavaStringToUTF8(env
, j_error_message
);
515 cdm_promise_adapter_
.RejectPromise(j_promise_id
, MediaKeys::UNKNOWN_ERROR
, 0,
519 void MediaDrmBridge::OnSessionMessage(JNIEnv
* env
,
521 jbyteArray j_session_id
,
523 jbyteArray j_message
,
524 jstring j_legacy_destination_url
) {
525 std::vector
<uint8
> message
;
526 JavaByteArrayToByteVector(env
, j_message
, &message
);
527 GURL legacy_destination_url
=
528 GURL(ConvertJavaStringToUTF8(env
, j_legacy_destination_url
));
529 MediaKeys::MessageType message_type
=
530 GetMessageType(static_cast<RequestType
>(j_message_type
));
532 session_message_cb_
.Run(GetSessionId(env
, j_session_id
), message_type
,
533 message
, legacy_destination_url
);
536 void MediaDrmBridge::OnSessionClosed(JNIEnv
* env
,
538 jbyteArray j_session_id
) {
539 session_closed_cb_
.Run(GetSessionId(env
, j_session_id
));
542 void MediaDrmBridge::OnSessionKeysChange(JNIEnv
* env
,
544 jbyteArray j_session_id
,
545 jobjectArray j_keys_info
,
546 bool has_additional_usable_key
) {
547 if (has_additional_usable_key
)
548 player_tracker_
.NotifyNewKey();
550 CdmKeysInfo cdm_keys_info
;
552 size_t size
= env
->GetArrayLength(j_keys_info
);
555 for (size_t i
= 0; i
< size
; ++i
) {
556 ScopedJavaLocalRef
<jobject
> j_key_status(
557 env
, env
->GetObjectArrayElement(j_keys_info
, i
));
559 ScopedJavaLocalRef
<jbyteArray
> j_key_id
=
560 Java_KeyStatus_getKeyId(env
, j_key_status
.obj());
561 std::vector
<uint8
> key_id
;
562 JavaByteArrayToByteVector(env
, j_key_id
.obj(), &key_id
);
563 DCHECK(!key_id
.empty());
566 Java_KeyStatus_getStatusCode(env
, j_key_status
.obj());
567 CdmKeyInformation::KeyStatus key_status
=
568 ConvertKeyStatus(static_cast<KeyStatus
>(j_status_code
));
570 DVLOG(2) << __FUNCTION__
<< "Key status change: "
571 << base::HexEncode(&key_id
[0], key_id
.size()) << ", "
574 // TODO(xhwang): Update CdmKeyInformation to take key_id and status in the
576 scoped_ptr
<CdmKeyInformation
> cdm_key_information(new CdmKeyInformation());
577 cdm_key_information
->key_id
= key_id
;
578 cdm_key_information
->status
= key_status
;
579 cdm_keys_info
.push_back(cdm_key_information
.release());
582 session_keys_change_cb_
.Run(GetSessionId(env
, j_session_id
),
583 has_additional_usable_key
, cdm_keys_info
.Pass());
586 // According to MeidaDrm documentation [1], zero |expiry_time_ms| means the keys
587 // will never expire. This will be translated into a NULL base::Time() [2],
588 // which will then be mapped to a zero Java time [3]. The zero Java time is
589 // passed to Blink which will then be translated to NaN [4], which is what the
590 // spec uses to indicate that the license will never expire [5].
591 // [1] http://developer.android.com/reference/android/media/MediaDrm.OnExpirationUpdateListener.html
592 // [2] See base::Time::FromDoubleT()
593 // [3] See base::Time::ToJavaTime()
594 // [4] See MediaKeySession::expirationChanged()
595 // [5] https://github.com/w3c/encrypted-media/issues/58
596 void MediaDrmBridge::OnSessionExpirationUpdate(JNIEnv
* env
,
598 jbyteArray j_session_id
,
599 jlong expiry_time_ms
) {
600 DVLOG(2) << __FUNCTION__
<< ": " << expiry_time_ms
<< " ms";
601 session_expiration_update_cb_
.Run(
602 GetSessionId(env
, j_session_id
),
603 base::Time::FromDoubleT(expiry_time_ms
/ 1000.0));
606 void MediaDrmBridge::OnLegacySessionError(JNIEnv
* env
,
608 jbyteArray j_session_id
,
609 jstring j_error_message
) {
610 std::string error_message
= ConvertJavaStringToUTF8(env
, j_error_message
);
611 legacy_session_error_cb_
.Run(GetSessionId(env
, j_session_id
),
612 MediaKeys::UNKNOWN_ERROR
, 0, error_message
);
615 ScopedJavaLocalRef
<jobject
> MediaDrmBridge::GetMediaCrypto() {
616 JNIEnv
* env
= AttachCurrentThread();
617 return Java_MediaDrmBridge_getMediaCrypto(env
, j_media_drm_
.obj());
620 MediaDrmBridge::SecurityLevel
MediaDrmBridge::GetSecurityLevel() {
621 JNIEnv
* env
= AttachCurrentThread();
622 ScopedJavaLocalRef
<jstring
> j_security_level
=
623 Java_MediaDrmBridge_getSecurityLevel(env
, j_media_drm_
.obj());
624 std::string security_level_str
=
625 ConvertJavaStringToUTF8(env
, j_security_level
.obj());
626 return GetSecurityLevelFromString(security_level_str
);
629 bool MediaDrmBridge::IsProtectedSurfaceRequired() {
630 // For Widevine, this depends on the security level.
631 if (std::equal(scheme_uuid_
.begin(), scheme_uuid_
.end(), kWidevineUuid
))
632 return IsSecureDecoderRequired(GetSecurityLevel());
634 // For other key systems, assume true.
638 void MediaDrmBridge::ResetDeviceCredentials(
639 const ResetCredentialsCB
& callback
) {
640 DCHECK(reset_credentials_cb_
.is_null());
641 reset_credentials_cb_
= callback
;
642 JNIEnv
* env
= AttachCurrentThread();
643 Java_MediaDrmBridge_resetDeviceCredentials(env
, j_media_drm_
.obj());
646 void MediaDrmBridge::OnResetDeviceCredentialsCompleted(
647 JNIEnv
* env
, jobject
, bool success
) {
648 base::ResetAndReturn(&reset_credentials_cb_
).Run(success
);