#include "media/cdm/ppapi/external_clear_key/clear_key_cdm.h"
#include <algorithm>
+#include <cstring>
#include <sstream>
#include <string>
#include <vector>
#include "base/time/time.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
+#include "media/cdm/json_web_key.h"
#include "media/cdm/ppapi/cdm_file_io_test.h"
#include "media/cdm/ppapi/external_clear_key/cdm_video_decoder.h"
const char kExternalClearKeyCrashKeySystem[] =
"org.chromium.externalclearkey.crash";
+// Constants for the enumalted session that can be loaded by LoadSession().
+// These constants need to be in sync with
+// chrome/test/data/media/encrypted_media_utils.js
+const char kLoadableWebSessionId[] = "LoadableSession";
+const char kLoadableSessionContentType[] = "video/webm";
+const uint8 kLoadableSessionKeyId[] = "0123456789012345";
+const uint8 kLoadableSessionKey[] =
+ {0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
+ 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c};
+
const int64 kSecondsPerMinute = 60;
const int64 kMsPerSecond = 1000;
const int64 kInitialTimerDelayMs = 200;
host_(host),
key_system_(key_system),
last_session_id_(MediaKeys::kInvalidSessionId),
+ session_id_for_emulated_loadsession_(MediaKeys::kInvalidSessionId),
timer_delay_ms_(kInitialTimerDelayMs),
- timer_set_(false) {
+ heartbeat_timer_set_(false) {
#if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
channel_count_ = 0;
bits_per_channel_ = 0;
StartFileIOTest();
}
+// Loads a emulated stored session. Currently only |kLoadableWebSessionId|
+// (containing a |kLoadableSessionKey| for |kLoadableSessionKeyId|) is
+// supported.
+void ClearKeyCdm::LoadSession(uint32_t session_id,
+ const char* web_session_id,
+ uint32_t web_session_id_length) {
+ DVLOG(1) << __FUNCTION__;
+
+ if (std::string(kLoadableWebSessionId) !=
+ std::string(web_session_id, web_session_id_length)) {
+ // TODO(xhwang): Report "NotFoundError" when we support DOMError style.
+ OnSessionError(session_id, MediaKeys::kUnknownError, 0);
+ return;
+ }
+
+ session_id_for_emulated_loadsession_ = session_id;
+
+ decryptor_.CreateSession(session_id, kLoadableSessionContentType, NULL, 0);
+}
+
void ClearKeyCdm::UpdateSession(uint32 session_id,
const uint8* response,
uint32 response_size) {
DVLOG(1) << __FUNCTION__;
decryptor_.UpdateSession(session_id, response, response_size);
- if (!timer_set_) {
+ if (!heartbeat_timer_set_) {
ScheduleNextHeartBeat();
- timer_set_ = true;
+ heartbeat_timer_set_ = true;
}
}
}
void ClearKeyCdm::TimerExpired(void* context) {
+ if (context == &session_id_for_emulated_loadsession_) {
+ LoadLoadableSession();
+ return;
+ }
+
+ DCHECK(heartbeat_timer_set_);
std::string heartbeat_message;
if (!next_heartbeat_message_.empty() &&
context == &next_heartbeat_message_[0]) {
NOTIMPLEMENTED();
};
+void ClearKeyCdm::LoadLoadableSession() {
+ std::string jwk_set = GenerateJWKSet(kLoadableSessionKey,
+ sizeof(kLoadableSessionKey),
+ kLoadableSessionKeyId,
+ sizeof(kLoadableSessionKeyId) - 1);
+ // TODO(xhwang): This triggers OnSessionUpdated(). For prefixed EME support,
+ // this is okay. Check WD EME support.
+ decryptor_.UpdateSession(session_id_for_emulated_loadsession_,
+ reinterpret_cast<const uint8*>(jwk_set.data()),
+ jwk_set.size());
+}
+
void ClearKeyCdm::OnSessionCreated(uint32 session_id,
const std::string& web_session_id) {
+ std::string new_web_session_id = web_session_id;
+
+ if (session_id == session_id_for_emulated_loadsession_) {
+ // Delay LoadLoadableSession() to test the case where Decrypt*() calls are
+ // made before the session is fully loaded.
+ const int64 kDelayToLoadSessionMs = 500;
+ // Use the address of |session_id_for_emulated_loadsession_| as the timer
+ // context so that we can call LoadLoadableSession() when the timer expires.
+ host_->SetTimer(kDelayToLoadSessionMs,
+ &session_id_for_emulated_loadsession_);
+ // Defer OnSessionCreated() until the session is loaded.
+ return;
+ }
+
host_->OnSessionCreated(
session_id, web_session_id.data(), web_session_id.size());
}
void ClearKeyCdm::OnSessionMessage(uint32 session_id,
const std::vector<uint8>& message,
const std::string& destination_url) {
+ DVLOG(1) << "OnSessionMessage: " << message.size();
+
+ // Ignore the message when we are waiting to update the loadable session.
+ if (session_id == session_id_for_emulated_loadsession_)
+ return;
+
host_->OnSessionMessage(session_id,
reinterpret_cast<const char*>(message.data()),
message.size(),
}
void ClearKeyCdm::OnSessionReady(uint32 session_id) {
+ if (session_id == session_id_for_emulated_loadsession_) {
+ session_id_for_emulated_loadsession_ = MediaKeys::kInvalidSessionId;
+ host_->OnSessionCreated(
+ session_id, kLoadableWebSessionId, strlen(kLoadableWebSessionId));
+ }
+
host_->OnSessionReady(session_id);
}