OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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/cdm/ppapi/external_clear_key/clear_key_cdm.h" | 5 #include "media/cdm/ppapi/external_clear_key/clear_key_cdm.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cstring> | 8 #include <cstring> |
9 #include <sstream> | 9 #include <sstream> |
10 #include <utility> | 10 #include <utility> |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 static bool InitializeFFmpegLibraries() { | 51 static bool InitializeFFmpegLibraries() { |
52 media::InitializeMediaLibrary(); | 52 media::InitializeMediaLibrary(); |
53 return true; | 53 return true; |
54 } | 54 } |
55 static bool g_ffmpeg_lib_initialized = InitializeFFmpegLibraries(); | 55 static bool g_ffmpeg_lib_initialized = InitializeFFmpegLibraries(); |
56 | 56 |
57 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER | 57 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER |
58 | 58 |
59 const char kClearKeyCdmVersion[] = "0.1.0.1"; | 59 const char kClearKeyCdmVersion[] = "0.1.0.1"; |
60 const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey"; | 60 const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey"; |
61 | |
62 // Variants of External Clear Key key system to test different scenarios. | |
63 const char kExternalClearKeyDecryptOnlyKeySystem[] = | 61 const char kExternalClearKeyDecryptOnlyKeySystem[] = |
64 "org.chromium.externalclearkey.decryptonly"; | 62 "org.chromium.externalclearkey.decryptonly"; |
65 const char kExternalClearKeyFileIOTestKeySystem[] = | 63 const char kExternalClearKeyFileIOTestKeySystem[] = |
66 "org.chromium.externalclearkey.fileiotest"; | 64 "org.chromium.externalclearkey.fileiotest"; |
67 const char kExternalClearKeyOutputProtectionTestKeySystem[] = | |
68 "org.chromium.externalclearkey.outputprotectiontest"; | |
69 const char kExternalClearKeyCrashKeySystem[] = | 65 const char kExternalClearKeyCrashKeySystem[] = |
70 "org.chromium.externalclearkey.crash"; | 66 "org.chromium.externalclearkey.crash"; |
71 | 67 |
72 // Constants for the enumalted session that can be loaded by LoadSession(). | 68 // Constants for the enumalted session that can be loaded by LoadSession(). |
73 // These constants need to be in sync with | 69 // These constants need to be in sync with |
74 // chrome/test/data/media/encrypted_media_utils.js | 70 // chrome/test/data/media/encrypted_media_utils.js |
75 const char kLoadableSessionId[] = "LoadableSession"; | 71 const char kLoadableSessionId[] = "LoadableSession"; |
76 const uint8_t kLoadableSessionKeyId[] = "0123456789012345"; | 72 const uint8_t kLoadableSessionKeyId[] = "0123456789012345"; |
77 const uint8_t kLoadableSessionKey[] = {0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, | 73 const uint8_t kLoadableSessionKey[] = {0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, |
78 0xd2, 0x7b, 0x68, 0xef, 0x12, 0x2a, | 74 0xd2, 0x7b, 0x68, 0xef, 0x12, 0x2a, |
79 0xfc, 0xe4, 0xae, 0x3c}; | 75 0xfc, 0xe4, 0xae, 0x3c}; |
80 | 76 |
81 const int64_t kSecondsPerMinute = 60; | 77 const int64_t kSecondsPerMinute = 60; |
82 const int64_t kMsPerSecond = 1000; | 78 const int64_t kMsPerSecond = 1000; |
83 const int64_t kInitialTimerDelayMs = 200; | 79 const int64_t kInitialTimerDelayMs = 200; |
84 const int64_t kMaxTimerDelayMs = 1 * kSecondsPerMinute * kMsPerSecond; | 80 const int64_t kMaxTimerDelayMs = 1 * kSecondsPerMinute * kMsPerSecond; |
85 // Renewal message header. For prefixed EME, if a key message starts with | 81 // Renewal message header. For prefixed EME, if a key message starts with |
86 // |kRenewalHeader|, it's a renewal message. Otherwise, it's a key request. | 82 // |kRenewalHeader|, it's a renewal message. Otherwise, it's a key request. |
87 // FIXME(jrummell): Remove this once prefixed EME goes away. | 83 // FIXME(jrummell): Remove this once prefixed EME goes away. |
88 const char kRenewalHeader[] = "RENEWAL"; | 84 const char kRenewalHeader[] = "RENEWAL"; |
89 | 85 // CDM file IO test result header. |
90 // CDM unit test result header. Must be in sync with UNIT_TEST_RESULT_HEADER in | 86 const char kFileIOTestResultHeader[] = "FILEIOTESTRESULT"; |
91 // media/test/data/eme_player_js/globals.js. | |
92 const char kUnitTestResultHeader[] = "UNIT_TEST_RESULT"; | |
93 | 87 |
94 // Copies |input_buffer| into a media::DecoderBuffer. If the |input_buffer| is | 88 // Copies |input_buffer| into a media::DecoderBuffer. If the |input_buffer| is |
95 // empty, an empty (end-of-stream) media::DecoderBuffer is returned. | 89 // empty, an empty (end-of-stream) media::DecoderBuffer is returned. |
96 static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom( | 90 static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom( |
97 const cdm::InputBuffer& input_buffer) { | 91 const cdm::InputBuffer& input_buffer) { |
98 if (!input_buffer.data) { | 92 if (!input_buffer.data) { |
99 DCHECK(!input_buffer.data_size); | 93 DCHECK(!input_buffer.data_size); |
100 return media::DecoderBuffer::CreateEOSBuffer(); | 94 return media::DecoderBuffer::CreateEOSBuffer(); |
101 } | 95 } |
102 | 96 |
(...skipping 15 matching lines...) Expand all Loading... |
118 input_buffer.iv_size), | 112 input_buffer.iv_size), |
119 subsamples)); | 113 subsamples)); |
120 | 114 |
121 output_buffer->set_decrypt_config(std::move(decrypt_config)); | 115 output_buffer->set_decrypt_config(std::move(decrypt_config)); |
122 output_buffer->set_timestamp( | 116 output_buffer->set_timestamp( |
123 base::TimeDelta::FromMicroseconds(input_buffer.timestamp)); | 117 base::TimeDelta::FromMicroseconds(input_buffer.timestamp)); |
124 | 118 |
125 return output_buffer; | 119 return output_buffer; |
126 } | 120 } |
127 | 121 |
128 static std::string GetUnitTestResultMessage(bool success) { | 122 static std::string GetFileIOTestResultMessage(bool success) { |
129 std::string message(kUnitTestResultHeader); | 123 std::string message(kFileIOTestResultHeader); |
130 message += success ? '1' : '0'; | 124 message += success ? '1' : '0'; |
131 return message; | 125 return message; |
132 } | 126 } |
133 | 127 |
134 static cdm::Error ConvertException(media::MediaKeys::Exception exception_code) { | 128 static cdm::Error ConvertException(media::MediaKeys::Exception exception_code) { |
135 switch (exception_code) { | 129 switch (exception_code) { |
136 case media::MediaKeys::NOT_SUPPORTED_ERROR: | 130 case media::MediaKeys::NOT_SUPPORTED_ERROR: |
137 return cdm::kNotSupportedError; | 131 return cdm::kNotSupportedError; |
138 case media::MediaKeys::INVALID_STATE_ERROR: | 132 case media::MediaKeys::INVALID_STATE_ERROR: |
139 return cdm::kInvalidStateError; | 133 return cdm::kInvalidStateError; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 void* CreateCdmInstance(int cdm_interface_version, | 225 void* CreateCdmInstance(int cdm_interface_version, |
232 const char* key_system, uint32_t key_system_size, | 226 const char* key_system, uint32_t key_system_size, |
233 GetCdmHostFunc get_cdm_host_func, | 227 GetCdmHostFunc get_cdm_host_func, |
234 void* user_data) { | 228 void* user_data) { |
235 DVLOG(1) << "CreateCdmInstance()"; | 229 DVLOG(1) << "CreateCdmInstance()"; |
236 | 230 |
237 std::string key_system_string(key_system, key_system_size); | 231 std::string key_system_string(key_system, key_system_size); |
238 if (key_system_string != kExternalClearKeyKeySystem && | 232 if (key_system_string != kExternalClearKeyKeySystem && |
239 key_system_string != kExternalClearKeyDecryptOnlyKeySystem && | 233 key_system_string != kExternalClearKeyDecryptOnlyKeySystem && |
240 key_system_string != kExternalClearKeyFileIOTestKeySystem && | 234 key_system_string != kExternalClearKeyFileIOTestKeySystem && |
241 key_system_string != kExternalClearKeyOutputProtectionTestKeySystem && | |
242 key_system_string != kExternalClearKeyCrashKeySystem) { | 235 key_system_string != kExternalClearKeyCrashKeySystem) { |
243 DVLOG(1) << "Unsupported key system:" << key_system_string; | 236 DVLOG(1) << "Unsupported key system:" << key_system_string; |
244 return NULL; | 237 return NULL; |
245 } | 238 } |
246 | 239 |
247 if (cdm_interface_version != media::ClearKeyCdmInterface::kVersion) | 240 if (cdm_interface_version != media::ClearKeyCdmInterface::kVersion) |
248 return NULL; | 241 return NULL; |
249 | 242 |
250 media::ClearKeyCdmHost* host = static_cast<media::ClearKeyCdmHost*>( | 243 media::ClearKeyCdmHost* host = static_cast<media::ClearKeyCdmHost*>( |
251 get_cdm_host_func(media::ClearKeyCdmHost::kVersion, user_data)); | 244 get_cdm_host_func(media::ClearKeyCdmHost::kVersion, user_data)); |
(...skipping 17 matching lines...) Expand all Loading... |
269 : decryptor_(new AesDecryptor( | 262 : decryptor_(new AesDecryptor( |
270 origin, | 263 origin, |
271 base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)), | 264 base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)), |
272 base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)), | 265 base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)), |
273 base::Bind(&ClearKeyCdm::OnSessionKeysChange, | 266 base::Bind(&ClearKeyCdm::OnSessionKeysChange, |
274 base::Unretained(this)))), | 267 base::Unretained(this)))), |
275 host_(host), | 268 host_(host), |
276 key_system_(key_system), | 269 key_system_(key_system), |
277 has_received_keys_change_event_for_emulated_loadsession_(false), | 270 has_received_keys_change_event_for_emulated_loadsession_(false), |
278 timer_delay_ms_(kInitialTimerDelayMs), | 271 timer_delay_ms_(kInitialTimerDelayMs), |
279 renewal_timer_set_(false), | 272 renewal_timer_set_(false) { |
280 is_running_output_protection_test_(false) { | |
281 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) | 273 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) |
282 channel_count_ = 0; | 274 channel_count_ = 0; |
283 bits_per_channel_ = 0; | 275 bits_per_channel_ = 0; |
284 samples_per_second_ = 0; | 276 samples_per_second_ = 0; |
285 output_timestamp_base_in_microseconds_ = kNoTimestamp; | 277 output_timestamp_base_in_microseconds_ = kNoTimestamp; |
286 total_samples_generated_ = 0; | 278 total_samples_generated_ = 0; |
287 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER | 279 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER |
288 } | 280 } |
289 | 281 |
290 ClearKeyCdm::~ClearKeyCdm() {} | 282 ClearKeyCdm::~ClearKeyCdm() {} |
(...skipping 16 matching lines...) Expand all Loading... |
307 new media::CdmCallbackPromise<std::string>( | 299 new media::CdmCallbackPromise<std::string>( |
308 base::Bind(&ClearKeyCdm::OnSessionCreated, base::Unretained(this), | 300 base::Bind(&ClearKeyCdm::OnSessionCreated, base::Unretained(this), |
309 promise_id), | 301 promise_id), |
310 base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), | 302 base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), |
311 promise_id))); | 303 promise_id))); |
312 decryptor_->CreateSessionAndGenerateRequest( | 304 decryptor_->CreateSessionAndGenerateRequest( |
313 ConvertSessionType(session_type), ConvertInitDataType(init_data_type), | 305 ConvertSessionType(session_type), ConvertInitDataType(init_data_type), |
314 std::vector<uint8_t>(init_data, init_data + init_data_size), | 306 std::vector<uint8_t>(init_data, init_data + init_data_size), |
315 std::move(promise)); | 307 std::move(promise)); |
316 | 308 |
317 if (key_system_ == kExternalClearKeyFileIOTestKeySystem) { | 309 if (key_system_ == kExternalClearKeyFileIOTestKeySystem) |
318 StartFileIOTest(); | 310 StartFileIOTest(); |
319 } else if (key_system_ == kExternalClearKeyOutputProtectionTestKeySystem) { | |
320 StartOutputProtectionTest(); | |
321 } | |
322 } | 311 } |
323 | 312 |
324 // Loads a emulated stored session. Currently only |kLoadableSessionId| | 313 // Loads a emulated stored session. Currently only |kLoadableSessionId| |
325 // (containing a |kLoadableSessionKey| for |kLoadableSessionKeyId|) is | 314 // (containing a |kLoadableSessionKey| for |kLoadableSessionKeyId|) is |
326 // supported. | 315 // supported. |
327 void ClearKeyCdm::LoadSession(uint32_t promise_id, | 316 void ClearKeyCdm::LoadSession(uint32_t promise_id, |
328 cdm::SessionType session_type, | 317 cdm::SessionType session_type, |
329 const char* session_id, | 318 const char* session_id, |
330 uint32_t session_id_length) { | 319 uint32_t session_id_length) { |
331 DVLOG(1) << __FUNCTION__; | 320 DVLOG(1) << __FUNCTION__; |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 | 687 |
699 void ClearKeyCdm::OnPlatformChallengeResponse( | 688 void ClearKeyCdm::OnPlatformChallengeResponse( |
700 const cdm::PlatformChallengeResponse& response) { | 689 const cdm::PlatformChallengeResponse& response) { |
701 NOTIMPLEMENTED(); | 690 NOTIMPLEMENTED(); |
702 } | 691 } |
703 | 692 |
704 void ClearKeyCdm::OnQueryOutputProtectionStatus( | 693 void ClearKeyCdm::OnQueryOutputProtectionStatus( |
705 cdm::QueryResult result, | 694 cdm::QueryResult result, |
706 uint32_t link_mask, | 695 uint32_t link_mask, |
707 uint32_t output_protection_mask) { | 696 uint32_t output_protection_mask) { |
708 if (!is_running_output_protection_test_) { | 697 NOTIMPLEMENTED(); |
709 NOTREACHED() << "OnQueryOutputProtectionStatus() called unexpectedly."; | |
710 return; | |
711 } | |
712 | |
713 is_running_output_protection_test_ = false; | |
714 | |
715 // On Chrome OS, status query will fail on Linux Chrome OS build. So we ignore | |
716 // the query result. On all other platforms, status query should succeed. | |
717 // TODO(xhwang): Improve the check on Chrome OS builds. For example, use | |
718 // base::SysInfo::IsRunningOnChromeOS() to differentiate between real Chrome OS | |
719 // build and Linux Chrome OS build. | |
720 #if !defined(OS_CHROMEOS) | |
721 if (result != cdm::kQuerySucceeded || link_mask != 0) { | |
722 OnUnitTestComplete(false); | |
723 return; | |
724 } | |
725 #endif | |
726 OnUnitTestComplete(true); | |
727 }; | 698 }; |
728 | 699 |
729 void ClearKeyCdm::LoadLoadableSession() { | 700 void ClearKeyCdm::LoadLoadableSession() { |
730 std::string jwk_set = GenerateJWKSet(kLoadableSessionKey, | 701 std::string jwk_set = GenerateJWKSet(kLoadableSessionKey, |
731 sizeof(kLoadableSessionKey), | 702 sizeof(kLoadableSessionKey), |
732 kLoadableSessionKeyId, | 703 kLoadableSessionKeyId, |
733 sizeof(kLoadableSessionKeyId) - 1); | 704 sizeof(kLoadableSessionKeyId) - 1); |
734 std::unique_ptr<media::SimpleCdmPromise> promise( | 705 std::unique_ptr<media::SimpleCdmPromise> promise( |
735 new media::CdmCallbackPromise<>( | 706 new media::CdmCallbackPromise<>( |
736 base::Bind(&ClearKeyCdm::OnLoadSessionUpdated, | 707 base::Bind(&ClearKeyCdm::OnLoadSessionUpdated, |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
925 | 896 |
926 int samples_generated = GenerateFakeAudioFramesFromDuration( | 897 int samples_generated = GenerateFakeAudioFramesFromDuration( |
927 timestamp_in_microseconds - CurrentTimeStampInMicroseconds(), | 898 timestamp_in_microseconds - CurrentTimeStampInMicroseconds(), |
928 audio_frames); | 899 audio_frames); |
929 total_samples_generated_ += samples_generated; | 900 total_samples_generated_ += samples_generated; |
930 | 901 |
931 return samples_generated == 0 ? cdm::kNeedMoreData : cdm::kSuccess; | 902 return samples_generated == 0 ? cdm::kNeedMoreData : cdm::kSuccess; |
932 } | 903 } |
933 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER | 904 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER |
934 | 905 |
935 void ClearKeyCdm::OnUnitTestComplete(bool success) { | |
936 std::string message = GetUnitTestResultMessage(success); | |
937 host_->OnSessionMessage(last_session_id_.data(), last_session_id_.length(), | |
938 cdm::kLicenseRequest, message.data(), | |
939 message.length(), NULL, 0); | |
940 } | |
941 | |
942 void ClearKeyCdm::StartFileIOTest() { | 906 void ClearKeyCdm::StartFileIOTest() { |
943 file_io_test_runner_.reset(new FileIOTestRunner( | 907 file_io_test_runner_.reset(new FileIOTestRunner( |
944 base::Bind(&ClearKeyCdmHost::CreateFileIO, base::Unretained(host_)))); | 908 base::Bind(&ClearKeyCdmHost::CreateFileIO, base::Unretained(host_)))); |
945 file_io_test_runner_->RunAllTests( | 909 file_io_test_runner_->RunAllTests( |
946 base::Bind(&ClearKeyCdm::OnFileIOTestComplete, base::Unretained(this))); | 910 base::Bind(&ClearKeyCdm::OnFileIOTestComplete, base::Unretained(this))); |
947 } | 911 } |
948 | 912 |
949 void ClearKeyCdm::OnFileIOTestComplete(bool success) { | 913 void ClearKeyCdm::OnFileIOTestComplete(bool success) { |
950 DVLOG(1) << __FUNCTION__ << ": " << success; | 914 DVLOG(1) << __FUNCTION__ << ": " << success; |
951 OnUnitTestComplete(success); | 915 std::string message = GetFileIOTestResultMessage(success); |
| 916 host_->OnSessionMessage(last_session_id_.data(), last_session_id_.length(), |
| 917 cdm::kLicenseRequest, message.data(), |
| 918 message.length(), NULL, 0); |
952 file_io_test_runner_.reset(); | 919 file_io_test_runner_.reset(); |
953 } | 920 } |
954 | 921 |
955 void ClearKeyCdm::StartOutputProtectionTest() { | |
956 is_running_output_protection_test_ = true; | |
957 host_->QueryOutputProtectionStatus(); | |
958 } | |
959 | |
960 } // namespace media | 922 } // namespace media |
OLD | NEW |