Update V8 to version 4.7.56.
[chromium-blink-merge.git] / media / base / android / media_drm_bridge.cc
blob14bdbda03f0ac81e2f32ea958d02103f3b91e3d1
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/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;
37 namespace media {
39 namespace {
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:
78 return "video/webm";
79 case media::EmeInitDataType::CENC:
80 return "video/mp4";
81 case media::EmeInitDataType::KEYIDS:
82 return "keyids";
83 default:
84 NOTREACHED();
85 return "unknown";
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;
99 NOTREACHED();
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;
118 NOTREACHED();
119 return CdmKeyInformation::INTERNAL_ERROR;
122 class KeySystemManager {
123 public:
124 KeySystemManager();
125 UUID GetUUID(const std::string& key_system);
126 std::vector<std::string> GetPlatformKeySystemNames();
128 private:
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();
141 if (client)
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())
148 return UUID();
149 return it->second;
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);
160 return key_systems;
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
170 // resolved.
171 bool IsKeySystemSupportedWithTypeImpl(const std::string& key_system,
172 const std::string& container_mime_type) {
173 if (!MediaDrmBridge::IsAvailable())
174 return false;
176 UUID scheme_uuid = g_key_system_manager.Get().GetUUID(key_system);
177 if (scheme_uuid.empty())
178 return false;
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:
203 return "";
204 case MediaDrmBridge::SECURITY_LEVEL_1:
205 return "L1";
206 case MediaDrmBridge::SECURITY_LEVEL_3:
207 return "L3";
209 return "";
212 } // namespace
214 // static
215 bool MediaDrmBridge::IsAvailable() {
216 if (base::android::BuildInfo::GetInstance()->sdk_int() < 19)
217 return false;
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,
223 &os_minor_version,
224 &os_bugfix_version);
225 if (os_major_version == 4 && os_minor_version == 4 && os_bugfix_version == 0)
226 return false;
228 return true;
231 // TODO(ddorwin): This is specific to Widevine. http://crbug.com/459400
232 // static
233 bool MediaDrmBridge::IsSecureDecoderRequired(SecurityLevel security_level) {
234 DCHECK(IsAvailable());
235 return SECURITY_LEVEL_1 == security_level;
238 // static
239 std::vector<std::string> MediaDrmBridge::GetPlatformKeySystemNames() {
240 return g_key_system_manager.Get().GetPlatformKeySystemNames();
243 // static
244 bool MediaDrmBridge::IsKeySystemSupported(const std::string& key_system) {
245 DCHECK(!key_system.empty());
246 return IsKeySystemSupportedWithTypeImpl(key_system, "");
249 // static
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();
275 CHECK(env);
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());
290 // static
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;
299 if (!IsAvailable())
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();
317 // static
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";
330 return false;
333 JNIEnv* env = AttachCurrentThread();
335 std::string security_level_str = GetSecurityLevelString(security_level);
336 if (security_level_str.empty())
337 return false;
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())) {
354 promise->resolve();
355 } else {
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.");
371 return;
374 JNIEnv* env = AttachCurrentThread();
375 ScopedJavaLocalRef<jbyteArray> j_init_data;
376 ScopedJavaLocalRef<jobjectArray> j_optional_parameters;
378 MediaClientAndroid* client = GetMediaClientAndroid();
379 if (client) {
380 MediaDrmBridgeDelegate* delegate =
381 client->GetMediaDrmBridgeDelegate(scheme_uuid_);
382 if (delegate) {
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(),
413 promise_id);
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()),
435 session_id.size());
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()),
447 session_id.size());
448 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
449 Java_MediaDrmBridge_closeSession(env, j_media_drm_.obj(), j_session_id.obj(),
450 promise_id);
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() {
461 NOTREACHED();
462 return nullptr;
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();
477 return;
480 DCHECK(media_crypto_ready_cb_.is_null());
482 if (!GetMediaCrypto().is_null()) {
483 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure);
484 return;
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,
497 jobject j_media_drm,
498 jint j_promise_id) {
499 cdm_promise_adapter_.ResolvePromise(j_promise_id);
502 void MediaDrmBridge::OnPromiseResolvedWithSession(JNIEnv* env,
503 jobject j_media_drm,
504 jint j_promise_id,
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,
511 jobject j_media_drm,
512 jint j_promise_id,
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,
516 error_message);
519 void MediaDrmBridge::OnSessionMessage(JNIEnv* env,
520 jobject j_media_drm,
521 jbyteArray j_session_id,
522 jint j_message_type,
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,
537 jobject j_media_drm,
538 jbyteArray j_session_id) {
539 session_closed_cb_.Run(GetSessionId(env, j_session_id));
542 void MediaDrmBridge::OnSessionKeysChange(JNIEnv* env,
543 jobject j_media_drm,
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);
553 DCHECK_GT(size, 0u);
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());
565 jint j_status_code =
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()) << ", "
572 << key_status;
574 // TODO(xhwang): Update CdmKeyInformation to take key_id and status in the
575 // constructor.
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,
597 jobject j_media_drm,
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,
607 jobject j_media_drm,
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.
635 return 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);
651 } // namespace media