| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef MEDIA_CDM_PPAPI_EXTERNAL_CLEAR_KEY_CLEAR_KEY_CDM_H_ |
| #define MEDIA_CDM_PPAPI_EXTERNAL_CLEAR_KEY_CLEAR_KEY_CDM_H_ |
| |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/compiler_specific.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/synchronization/lock.h" |
| #include "media/base/cdm_key_information.h" |
| #include "media/cdm/aes_decryptor.h" |
| #include "media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h" |
| |
| // Enable this to use the fake decoder for testing. |
| // TODO(tomfinegan): Move fake audio decoder into a separate class. |
| #if 0 |
| #define CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER |
| #endif |
| |
| class GURL; |
| |
| namespace media { |
| class FileIOTestRunner; |
| class CdmVideoDecoder; |
| class DecoderBuffer; |
| class FFmpegCdmAudioDecoder; |
| |
| // Clear key implementation of the cdm::ContentDecryptionModule interface. |
| class ClearKeyCdm : public ClearKeyCdmInterface { |
| public: |
| ClearKeyCdm(Host* host, const std::string& key_system, const GURL& origin); |
| ~ClearKeyCdm() override; |
| |
| // ContentDecryptionModule implementation. |
| void Initialize(bool allow_distinctive_identifier, |
| bool allow_persistent_state) override; |
| void CreateSessionAndGenerateRequest(uint32_t promise_id, |
| cdm::SessionType session_type, |
| cdm::InitDataType init_data_type, |
| const uint8_t* init_data, |
| uint32_t init_data_size) override; |
| void LoadSession(uint32_t promise_id, |
| cdm::SessionType session_type, |
| const char* session_id, |
| uint32_t session_id_length) override; |
| void UpdateSession(uint32_t promise_id, |
| const char* session_id, |
| uint32_t session_id_length, |
| const uint8_t* response, |
| uint32_t response_size) override; |
| void CloseSession(uint32_t promise_id, |
| const char* session_id, |
| uint32_t session_id_length) override; |
| void RemoveSession(uint32_t promise_id, |
| const char* session_id, |
| uint32_t session_id_length) override; |
| void SetServerCertificate(uint32_t promise_id, |
| const uint8_t* server_certificate_data, |
| uint32_t server_certificate_data_size) override; |
| void TimerExpired(void* context) override; |
| cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer, |
| cdm::DecryptedBlock* decrypted_block) override; |
| cdm::Status InitializeAudioDecoder( |
| const cdm::AudioDecoderConfig& audio_decoder_config) override; |
| cdm::Status InitializeVideoDecoder( |
| const cdm::VideoDecoderConfig& video_decoder_config) override; |
| void DeinitializeDecoder(cdm::StreamType decoder_type) override; |
| void ResetDecoder(cdm::StreamType decoder_type) override; |
| cdm::Status DecryptAndDecodeFrame(const cdm::InputBuffer& encrypted_buffer, |
| cdm::VideoFrame* video_frame) override; |
| cdm::Status DecryptAndDecodeSamples(const cdm::InputBuffer& encrypted_buffer, |
| cdm::AudioFrames* audio_frames) override; |
| void Destroy() override; |
| void OnPlatformChallengeResponse( |
| const cdm::PlatformChallengeResponse& response) override; |
| void OnQueryOutputProtectionStatus(cdm::QueryResult result, |
| uint32_t link_mask, |
| uint32_t output_protection_mask) override; |
| |
| private: |
| // Emulates a session stored for |session_id_for_emulated_loadsession_|. This |
| // is necessary since aes_decryptor.cc does not support storing sessions. |
| void LoadLoadableSession(); |
| void OnLoadSessionUpdated(); |
| |
| // ContentDecryptionModule callbacks. |
| void OnSessionMessage(const std::string& session_id, |
| MediaKeys::MessageType message_type, |
| const std::vector<uint8_t>& message); |
| void OnSessionKeysChange(const std::string& session_id, |
| bool has_additional_usable_key, |
| CdmKeysInfo keys_info); |
| void OnSessionClosed(const std::string& session_id); |
| |
| // Handle the success/failure of a promise. These methods are responsible for |
| // calling |host_| to resolve or reject the promise. |
| void OnSessionCreated(uint32_t promise_id, const std::string& session_id); |
| void OnSessionLoaded(uint32_t promise_id, const std::string& session_id); |
| void OnPromiseResolved(uint32_t promise_id); |
| void OnPromiseFailed(uint32_t promise_id, |
| MediaKeys::Exception exception_code, |
| uint32_t system_code, |
| const std::string& error_message); |
| |
| // Prepares next renewal message and sets a timer for it. |
| void ScheduleNextRenewal(); |
| |
| // Decrypts the |encrypted_buffer| and puts the result in |decrypted_buffer|. |
| // Returns cdm::kSuccess if decryption succeeded. The decrypted result is |
| // put in |decrypted_buffer|. If |encrypted_buffer| is empty, the |
| // |decrypted_buffer| is set to an empty (EOS) buffer. |
| // Returns cdm::kNoKey if no decryption key was available. In this case |
| // |decrypted_buffer| should be ignored by the caller. |
| // Returns cdm::kDecryptError if any decryption error occurred. In this case |
| // |decrypted_buffer| should be ignored by the caller. |
| cdm::Status DecryptToMediaDecoderBuffer( |
| const cdm::InputBuffer& encrypted_buffer, |
| scoped_refptr<DecoderBuffer>* decrypted_buffer); |
| |
| #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) |
| int64_t CurrentTimeStampInMicroseconds() const; |
| |
| // Generates fake video frames with |duration_in_microseconds|. |
| // Returns the number of samples generated in the |audio_frames|. |
| int GenerateFakeAudioFramesFromDuration(int64_t duration_in_microseconds, |
| cdm::AudioFrames* audio_frames) const; |
| |
| // Generates fake video frames given |input_timestamp|. |
| // Returns cdm::kSuccess if any audio frame is successfully generated. |
| cdm::Status GenerateFakeAudioFrames(int64_t timestamp_in_microseconds, |
| cdm::AudioFrames* audio_frames); |
| #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER |
| |
| void OnUnitTestComplete(bool success); |
| |
| void StartFileIOTest(); |
| |
| // Callback for CDM File IO test. |
| void OnFileIOTestComplete(bool success); |
| |
| void StartOutputProtectionTest(); |
| |
| // Keep track of the last session created. |
| void SetSessionId(const std::string& session_id); |
| |
| scoped_refptr<AesDecryptor> decryptor_; |
| |
| ClearKeyCdmHost* host_; |
| |
| const std::string key_system_; |
| |
| std::string last_session_id_; |
| std::string next_renewal_message_; |
| |
| // In order to simulate LoadSession(), CreateSession() and then |
| // UpdateSession() will be called to create a session with known keys. |
| // |session_id_for_emulated_loadsession_| is used to keep track of the |
| // session_id allocated by aes_decryptor, as the session_id will be returned |
| // as |kLoadableSessionId|. Future requests for this simulated session |
| // need to use |session_id_for_emulated_loadsession_| for all calls |
| // to aes_decryptor. |
| // |promise_id_for_emulated_loadsession_| is used to keep track of the |
| // original LoadSession() promise, as it is not resolved until the |
| // UpdateSession() call succeeds. |
| // |has_received_keys_change_event_for_emulated_loadsession_| is used to keep |
| // track of whether a keyschange event has been received for the loadable |
| // session in case it happens before the emulated session is fully created. |
| // |keys_info_for_emulated_loadsession_| is used to keep track of the list |
| // of keys provided as a result of calling UpdateSession() if it happens, |
| // since they can't be forwarded on until the LoadSession() promise is |
| // resolved. |
| // TODO(xhwang): Extract testing code from main implementation. |
| // See http://crbug.com/341751 |
| // TODO(jrummell): Once the order of events is fixed, |
| // |has_received_keys_change_event_for_emulated_loadsession_| should be |
| // removed (the event should have either happened or never happened). |
| // |keys_info_for_emulated_loadsession_| may also go away if the event is |
| // not expected. See http://crbug.com/448225 |
| std::string session_id_for_emulated_loadsession_; |
| uint32_t promise_id_for_emulated_loadsession_; |
| bool has_received_keys_change_event_for_emulated_loadsession_; |
| CdmKeysInfo keys_info_for_emulated_loadsession_; |
| |
| // Timer delay in milliseconds for the next host_->SetTimer() call. |
| int64_t timer_delay_ms_; |
| |
| // Indicates whether a renewal timer has been set to prevent multiple timers |
| // from running. |
| bool renewal_timer_set_; |
| |
| #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) |
| int channel_count_; |
| int bits_per_channel_; |
| int samples_per_second_; |
| int64_t output_timestamp_base_in_microseconds_; |
| int total_samples_generated_; |
| #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER |
| |
| #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) |
| std::unique_ptr<FFmpegCdmAudioDecoder> audio_decoder_; |
| #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER |
| |
| std::unique_ptr<CdmVideoDecoder> video_decoder_; |
| |
| std::unique_ptr<FileIOTestRunner> file_io_test_runner_; |
| |
| bool is_running_output_protection_test_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ClearKeyCdm); |
| }; |
| |
| } // namespace media |
| |
| #endif // MEDIA_CDM_PPAPI_EXTERNAL_CLEAR_KEY_CLEAR_KEY_CDM_H_ |