| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/android/media_drm_bridge.h" | 5 #include "media/base/android/media_drm_bridge.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 case RequestType::REQUEST_TYPE_RENEWAL: | 117 case RequestType::REQUEST_TYPE_RENEWAL: |
| 118 return ContentDecryptionModule::LICENSE_RENEWAL; | 118 return ContentDecryptionModule::LICENSE_RENEWAL; |
| 119 case RequestType::REQUEST_TYPE_RELEASE: | 119 case RequestType::REQUEST_TYPE_RELEASE: |
| 120 return ContentDecryptionModule::LICENSE_RELEASE; | 120 return ContentDecryptionModule::LICENSE_RELEASE; |
| 121 } | 121 } |
| 122 | 122 |
| 123 NOTREACHED(); | 123 NOTREACHED(); |
| 124 return ContentDecryptionModule::LICENSE_REQUEST; | 124 return ContentDecryptionModule::LICENSE_REQUEST; |
| 125 } | 125 } |
| 126 | 126 |
| 127 CdmKeyInformation::KeyStatus ConvertKeyStatus(KeyStatus key_status) { | 127 CdmKeyInformation::KeyStatus ConvertKeyStatus(KeyStatus key_status, |
| 128 bool is_key_release) { |
| 128 switch (key_status) { | 129 switch (key_status) { |
| 129 case KeyStatus::KEY_STATUS_USABLE: | 130 case KeyStatus::KEY_STATUS_USABLE: |
| 130 return CdmKeyInformation::USABLE; | 131 return CdmKeyInformation::USABLE; |
| 131 case KeyStatus::KEY_STATUS_EXPIRED: | 132 case KeyStatus::KEY_STATUS_EXPIRED: |
| 132 return CdmKeyInformation::EXPIRED; | 133 return is_key_release ? CdmKeyInformation::RELEASED |
| 134 : CdmKeyInformation::EXPIRED; |
| 133 case KeyStatus::KEY_STATUS_OUTPUT_NOT_ALLOWED: | 135 case KeyStatus::KEY_STATUS_OUTPUT_NOT_ALLOWED: |
| 134 return CdmKeyInformation::OUTPUT_RESTRICTED; | 136 return CdmKeyInformation::OUTPUT_RESTRICTED; |
| 135 case KeyStatus::KEY_STATUS_PENDING: | 137 case KeyStatus::KEY_STATUS_PENDING: |
| 136 // TODO(xhwang): This should probably be renamed to "PENDING". | 138 // TODO(xhwang): This should probably be renamed to "PENDING". |
| 137 return CdmKeyInformation::KEY_STATUS_PENDING; | 139 return CdmKeyInformation::KEY_STATUS_PENDING; |
| 138 case KeyStatus::KEY_STATUS_INTERNAL_ERROR: | 140 case KeyStatus::KEY_STATUS_INTERNAL_ERROR: |
| 139 return CdmKeyInformation::INTERNAL_ERROR; | 141 return CdmKeyInformation::INTERNAL_ERROR; |
| 140 } | 142 } |
| 141 | 143 |
| 142 NOTREACHED(); | 144 NOTREACHED(); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 int32_t os_minor_version = 0; | 251 int32_t os_minor_version = 0; |
| 250 int32_t os_bugfix_version = 0; | 252 int32_t os_bugfix_version = 0; |
| 251 base::SysInfo::OperatingSystemVersionNumbers( | 253 base::SysInfo::OperatingSystemVersionNumbers( |
| 252 &os_major_version, &os_minor_version, &os_bugfix_version); | 254 &os_major_version, &os_minor_version, &os_bugfix_version); |
| 253 if (os_major_version == 4 && os_minor_version == 4 && os_bugfix_version == 0) | 255 if (os_major_version == 4 && os_minor_version == 4 && os_bugfix_version == 0) |
| 254 return false; | 256 return false; |
| 255 | 257 |
| 256 return true; | 258 return true; |
| 257 } | 259 } |
| 258 | 260 |
| 261 bool IsPersistentLicenseTypeSupportedByMediaDrm() { |
| 262 return MediaDrmBridge::IsAvailable() && |
| 263 // In development. See http://crbug.com/493521 |
| 264 base::FeatureList::IsEnabled(kMediaDrmPersistentLicense) && |
| 265 base::android::BuildInfo::GetInstance()->sdk_int() >= 23; |
| 266 } |
| 267 |
| 259 } // namespace | 268 } // namespace |
| 260 | 269 |
| 261 // MediaDrm is not generally usable without MediaCodec. Thus, both the MediaDrm | 270 // MediaDrm is not generally usable without MediaCodec. Thus, both the MediaDrm |
| 262 // APIs and MediaCodec APIs must be enabled and not blacklisted. | 271 // APIs and MediaCodec APIs must be enabled and not blacklisted. |
| 263 // static | 272 // static |
| 264 bool MediaDrmBridge::IsAvailable() { | 273 bool MediaDrmBridge::IsAvailable() { |
| 265 return AreMediaDrmApisAvailable() && MediaCodecUtil::IsMediaCodecAvailable(); | 274 return AreMediaDrmApisAvailable() && MediaCodecUtil::IsMediaCodecAvailable(); |
| 266 } | 275 } |
| 267 | 276 |
| 268 // static | 277 // static |
| 269 bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv* env) { | 278 bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv* env) { |
| 270 return RegisterNativesImpl(env); | 279 return RegisterNativesImpl(env); |
| 271 } | 280 } |
| 272 | 281 |
| 273 // static | 282 // static |
| 274 bool MediaDrmBridge::IsKeySystemSupported(const std::string& key_system) { | 283 bool MediaDrmBridge::IsKeySystemSupported(const std::string& key_system) { |
| 275 if (!MediaDrmBridge::IsAvailable()) | 284 if (!MediaDrmBridge::IsAvailable()) |
| 276 return false; | 285 return false; |
| 277 | 286 |
| 278 return IsKeySystemSupportedWithTypeImpl(key_system, ""); | 287 return IsKeySystemSupportedWithTypeImpl(key_system, ""); |
| 279 } | 288 } |
| 280 | 289 |
| 281 // static | 290 // static |
| 282 bool MediaDrmBridge::IsPersistentLicenseTypeSupported( | 291 bool MediaDrmBridge::IsPersistentLicenseTypeSupported( |
| 283 const std::string& key_system) { | 292 const std::string& key_system) { |
| 284 if (!MediaDrmBridge::IsAvailable()) | 293 // TODO(yucliu): Check |key_system| if persistent license is supported by |
| 285 return false; | 294 // MediaDrm. |
| 286 | 295 return IsPersistentLicenseTypeSupportedByMediaDrm(); |
| 287 if (!base::FeatureList::IsEnabled(kMediaDrmPersistentLicense)) { | |
| 288 return false; | |
| 289 } | |
| 290 | |
| 291 NOTIMPLEMENTED() << "In development. See http://crbug.com/493521"; | |
| 292 return false; | |
| 293 } | 296 } |
| 294 | 297 |
| 295 // static | 298 // static |
| 296 bool MediaDrmBridge::IsKeySystemSupportedWithType( | 299 bool MediaDrmBridge::IsKeySystemSupportedWithType( |
| 297 const std::string& key_system, | 300 const std::string& key_system, |
| 298 const std::string& container_mime_type) { | 301 const std::string& container_mime_type) { |
| 299 DCHECK(!container_mime_type.empty()) << "Call IsKeySystemSupported instead"; | 302 DCHECK(!container_mime_type.empty()) << "Call IsKeySystemSupported instead"; |
| 300 | 303 |
| 301 if (!MediaDrmBridge::IsAvailable()) | 304 if (!MediaDrmBridge::IsAvailable()) |
| 302 return false; | 305 return false; |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 promise_id); | 456 promise_id); |
| 454 } | 457 } |
| 455 | 458 |
| 456 void MediaDrmBridge::LoadSession( | 459 void MediaDrmBridge::LoadSession( |
| 457 CdmSessionType session_type, | 460 CdmSessionType session_type, |
| 458 const std::string& session_id, | 461 const std::string& session_id, |
| 459 std::unique_ptr<media::NewSessionCdmPromise> promise) { | 462 std::unique_ptr<media::NewSessionCdmPromise> promise) { |
| 460 DCHECK(task_runner_->BelongsToCurrentThread()); | 463 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 461 DVLOG(2) << __func__; | 464 DVLOG(2) << __func__; |
| 462 | 465 |
| 463 DCHECK(base::FeatureList::IsEnabled(kMediaDrmPersistentLicense)); | 466 DCHECK(IsPersistentLicenseTypeSupportedByMediaDrm()); |
| 464 | 467 |
| 465 NOTIMPLEMENTED() << "EME persistent sessions not yet supported on Android."; | 468 if (session_type != CdmSessionType::PERSISTENT_LICENSE_SESSION) { |
| 466 promise->reject(CdmPromise::NOT_SUPPORTED_ERROR, 0, | 469 promise->reject( |
| 467 "LoadSession() is not supported."); | 470 CdmPromise::NOT_SUPPORTED_ERROR, 0, |
| 471 "LoadSession() is only supported for 'persistent-license'."); |
| 472 return; |
| 473 } |
| 474 |
| 475 JNIEnv* env = AttachCurrentThread(); |
| 476 ScopedJavaLocalRef<jbyteArray> j_session_id = |
| 477 StringToJavaBytes(env, session_id); |
| 478 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); |
| 479 Java_MediaDrmBridge_loadSession(env, j_media_drm_, j_session_id, promise_id); |
| 468 } | 480 } |
| 469 | 481 |
| 470 void MediaDrmBridge::UpdateSession( | 482 void MediaDrmBridge::UpdateSession( |
| 471 const std::string& session_id, | 483 const std::string& session_id, |
| 472 const std::vector<uint8_t>& response, | 484 const std::vector<uint8_t>& response, |
| 473 std::unique_ptr<media::SimpleCdmPromise> promise) { | 485 std::unique_ptr<media::SimpleCdmPromise> promise) { |
| 474 DCHECK(task_runner_->BelongsToCurrentThread()); | 486 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 475 DVLOG(2) << __func__; | 487 DVLOG(2) << __func__; |
| 476 | 488 |
| 477 JNIEnv* env = AttachCurrentThread(); | 489 JNIEnv* env = AttachCurrentThread(); |
| 478 ScopedJavaLocalRef<jbyteArray> j_response = | 490 ScopedJavaLocalRef<jbyteArray> j_response = |
| 479 base::android::ToJavaByteArray(env, response.data(), response.size()); | 491 base::android::ToJavaByteArray(env, response.data(), response.size()); |
| 480 ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray( | 492 ScopedJavaLocalRef<jbyteArray> j_session_id = |
| 481 env, reinterpret_cast<const uint8_t*>(session_id.data()), | 493 StringToJavaBytes(env, session_id); |
| 482 session_id.size()); | |
| 483 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); | 494 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); |
| 484 Java_MediaDrmBridge_updateSession(env, j_media_drm_, j_session_id, j_response, | 495 Java_MediaDrmBridge_updateSession(env, j_media_drm_, j_session_id, j_response, |
| 485 promise_id); | 496 promise_id); |
| 486 } | 497 } |
| 487 | 498 |
| 488 void MediaDrmBridge::CloseSession( | 499 void MediaDrmBridge::CloseSession( |
| 489 const std::string& session_id, | 500 const std::string& session_id, |
| 490 std::unique_ptr<media::SimpleCdmPromise> promise) { | 501 std::unique_ptr<media::SimpleCdmPromise> promise) { |
| 491 DCHECK(task_runner_->BelongsToCurrentThread()); | 502 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 492 DVLOG(2) << __func__; | 503 DVLOG(2) << __func__; |
| 493 | 504 |
| 494 JNIEnv* env = AttachCurrentThread(); | 505 JNIEnv* env = AttachCurrentThread(); |
| 495 ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray( | 506 ScopedJavaLocalRef<jbyteArray> j_session_id = |
| 496 env, reinterpret_cast<const uint8_t*>(session_id.data()), | 507 StringToJavaBytes(env, session_id); |
| 497 session_id.size()); | |
| 498 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); | 508 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); |
| 499 Java_MediaDrmBridge_closeSession(env, j_media_drm_, j_session_id, promise_id); | 509 Java_MediaDrmBridge_closeSession(env, j_media_drm_, j_session_id, promise_id); |
| 500 } | 510 } |
| 501 | 511 |
| 502 void MediaDrmBridge::RemoveSession( | 512 void MediaDrmBridge::RemoveSession( |
| 503 const std::string& session_id, | 513 const std::string& session_id, |
| 504 std::unique_ptr<media::SimpleCdmPromise> promise) { | 514 std::unique_ptr<media::SimpleCdmPromise> promise) { |
| 505 DCHECK(task_runner_->BelongsToCurrentThread()); | 515 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 506 DVLOG(2) << __func__; | 516 DVLOG(2) << __func__; |
| 507 | 517 |
| 508 NOTIMPLEMENTED() << "EME persistent sessions not yet supported on Android."; | 518 JNIEnv* env = AttachCurrentThread(); |
| 509 promise->reject(CdmPromise::NOT_SUPPORTED_ERROR, 0, | 519 ScopedJavaLocalRef<jbyteArray> j_session_id = |
| 510 "RemoveSession() is not supported."); | 520 StringToJavaBytes(env, session_id); |
| 521 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); |
| 522 Java_MediaDrmBridge_removeSession(env, j_media_drm_, j_session_id, |
| 523 promise_id); |
| 511 } | 524 } |
| 512 | 525 |
| 513 CdmContext* MediaDrmBridge::GetCdmContext() { | 526 CdmContext* MediaDrmBridge::GetCdmContext() { |
| 514 DVLOG(2) << __func__; | 527 DVLOG(2) << __func__; |
| 515 | 528 |
| 516 return &media_drm_bridge_cdm_context_; | 529 return &media_drm_bridge_cdm_context_; |
| 517 } | 530 } |
| 518 | 531 |
| 519 void MediaDrmBridge::DeleteOnCorrectThread() const { | 532 void MediaDrmBridge::DeleteOnCorrectThread() const { |
| 520 DVLOG(1) << __func__; | 533 DVLOG(1) << __func__; |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 DVLOG(2) << __func__; | 704 DVLOG(2) << __func__; |
| 692 std::string session_id = JavaBytesToString(env, j_session_id); | 705 std::string session_id = JavaBytesToString(env, j_session_id); |
| 693 task_runner_->PostTask(FROM_HERE, base::Bind(session_closed_cb_, session_id)); | 706 task_runner_->PostTask(FROM_HERE, base::Bind(session_closed_cb_, session_id)); |
| 694 } | 707 } |
| 695 | 708 |
| 696 void MediaDrmBridge::OnSessionKeysChange( | 709 void MediaDrmBridge::OnSessionKeysChange( |
| 697 JNIEnv* env, | 710 JNIEnv* env, |
| 698 const JavaParamRef<jobject>& j_media_drm, | 711 const JavaParamRef<jobject>& j_media_drm, |
| 699 const JavaParamRef<jbyteArray>& j_session_id, | 712 const JavaParamRef<jbyteArray>& j_session_id, |
| 700 const JavaParamRef<jobjectArray>& j_keys_info, | 713 const JavaParamRef<jobjectArray>& j_keys_info, |
| 701 bool has_additional_usable_key) { | 714 bool has_additional_usable_key, |
| 715 bool is_key_release) { |
| 702 DVLOG(2) << __func__; | 716 DVLOG(2) << __func__; |
| 703 | 717 |
| 704 CdmKeysInfo cdm_keys_info; | 718 CdmKeysInfo cdm_keys_info; |
| 705 | 719 |
| 706 size_t size = env->GetArrayLength(j_keys_info); | 720 size_t size = env->GetArrayLength(j_keys_info); |
| 707 DCHECK_GT(size, 0u); | 721 DCHECK_GT(size, 0u); |
| 708 | 722 |
| 709 for (size_t i = 0; i < size; ++i) { | 723 for (size_t i = 0; i < size; ++i) { |
| 710 ScopedJavaLocalRef<jobject> j_key_status( | 724 ScopedJavaLocalRef<jobject> j_key_status( |
| 711 env, env->GetObjectArrayElement(j_keys_info, i)); | 725 env, env->GetObjectArrayElement(j_keys_info, i)); |
| 712 | 726 |
| 713 ScopedJavaLocalRef<jbyteArray> j_key_id = | 727 ScopedJavaLocalRef<jbyteArray> j_key_id = |
| 714 Java_KeyStatus_getKeyId(env, j_key_status); | 728 Java_KeyStatus_getKeyId(env, j_key_status); |
| 715 std::vector<uint8_t> key_id; | 729 std::vector<uint8_t> key_id; |
| 716 JavaByteArrayToByteVector(env, j_key_id.obj(), &key_id); | 730 JavaByteArrayToByteVector(env, j_key_id.obj(), &key_id); |
| 717 DCHECK(!key_id.empty()); | 731 DCHECK(!key_id.empty()); |
| 718 | 732 |
| 719 jint j_status_code = Java_KeyStatus_getStatusCode(env, j_key_status); | 733 jint j_status_code = Java_KeyStatus_getStatusCode(env, j_key_status); |
| 720 CdmKeyInformation::KeyStatus key_status = | 734 CdmKeyInformation::KeyStatus key_status = |
| 721 ConvertKeyStatus(static_cast<KeyStatus>(j_status_code)); | 735 ConvertKeyStatus(static_cast<KeyStatus>(j_status_code), is_key_release); |
| 722 | 736 |
| 723 DVLOG(2) << __func__ << "Key status change: " | 737 DVLOG(2) << __func__ << "Key status change: " |
| 724 << base::HexEncode(&key_id[0], key_id.size()) << ", " | 738 << base::HexEncode(&key_id[0], key_id.size()) << ", " |
| 725 << key_status; | 739 << key_status; |
| 726 | 740 |
| 727 cdm_keys_info.push_back(new CdmKeyInformation(key_id, key_status, 0)); | 741 cdm_keys_info.push_back(new CdmKeyInformation(key_id, key_status, 0)); |
| 728 } | 742 } |
| 729 | 743 |
| 730 task_runner_->PostTask( | 744 task_runner_->PostTask( |
| 731 FROM_HERE, | 745 FROM_HERE, |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 909 DVLOG(1) << __func__; | 923 DVLOG(1) << __func__; |
| 910 | 924 |
| 911 DCHECK(provision_fetcher_) << "No provision request pending."; | 925 DCHECK(provision_fetcher_) << "No provision request pending."; |
| 912 provision_fetcher_.reset(); | 926 provision_fetcher_.reset(); |
| 913 | 927 |
| 914 if (!success) | 928 if (!success) |
| 915 VLOG(1) << "Device provision failure: can't get server response"; | 929 VLOG(1) << "Device provision failure: can't get server response"; |
| 916 | 930 |
| 917 JNIEnv* env = AttachCurrentThread(); | 931 JNIEnv* env = AttachCurrentThread(); |
| 918 | 932 |
| 919 ScopedJavaLocalRef<jbyteArray> j_response = base::android::ToJavaByteArray( | 933 ScopedJavaLocalRef<jbyteArray> j_response = StringToJavaBytes(env, response); |
| 920 env, reinterpret_cast<const uint8_t*>(response.data()), response.size()); | |
| 921 | 934 |
| 922 Java_MediaDrmBridge_processProvisionResponse(env, j_media_drm_, success, | 935 Java_MediaDrmBridge_processProvisionResponse(env, j_media_drm_, success, |
| 923 j_response); | 936 j_response); |
| 924 } | 937 } |
| 925 | 938 |
| 926 void MediaDrmBridge::OnHasAdditionalUsableKey() { | 939 void MediaDrmBridge::OnHasAdditionalUsableKey() { |
| 927 DCHECK(task_runner_->BelongsToCurrentThread()); | 940 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 928 DVLOG(1) << __func__; | 941 DVLOG(1) << __func__; |
| 929 | 942 |
| 930 player_tracker_.NotifyNewKey(); | 943 player_tracker_.NotifyNewKey(); |
| 931 } | 944 } |
| 932 | 945 |
| 933 } // namespace media | 946 } // namespace media |
| OLD | NEW |