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