namespace content {
+const char kCreateSessionUMAName[] = "CreateSession";
+
+// For backwards compatibility with blink not using
+// WebContentDecryptionModuleResult, reserve an index for |outstanding_results_|
+// that will not be used when adding a WebContentDecryptionModuleResult.
+// TODO(jrummell): Remove once blink always uses
+// WebContentDecryptionModuleResult.
+const uint32 kReservedIndex = 0;
+
+static blink::WebContentDecryptionModuleException ConvertException(
+ media::MediaKeys::Exception exception_code) {
+ switch (exception_code) {
+ case media::MediaKeys::NOT_SUPPORTED_ERROR:
+ return blink::WebContentDecryptionModuleExceptionNotSupportedError;
+ case media::MediaKeys::INVALID_STATE_ERROR:
+ return blink::WebContentDecryptionModuleExceptionInvalidStateError;
+ case media::MediaKeys::INVALID_ACCESS_ERROR:
+ return blink::WebContentDecryptionModuleExceptionInvalidAccessError;
+ case media::MediaKeys::QUOTA_EXCEEDED_ERROR:
+ return blink::WebContentDecryptionModuleExceptionQuotaExceededError;
+ case media::MediaKeys::UNKNOWN_ERROR:
+ return blink::WebContentDecryptionModuleExceptionUnknownError;
+ case media::MediaKeys::CLIENT_ERROR:
+ return blink::WebContentDecryptionModuleExceptionClientError;
+ case media::MediaKeys::OUTPUT_ERROR:
+ return blink::WebContentDecryptionModuleExceptionOutputError;
+ default:
+ NOTREACHED();
+ return blink::WebContentDecryptionModuleExceptionUnknownError;
+ }
+}
+
WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl(
- Client* client,
const scoped_refptr<CdmSessionAdapter>& adapter)
: adapter_(adapter),
- client_(client),
is_closed_(false),
+ next_available_result_index_(1),
weak_ptr_factory_(this) {
}
~WebContentDecryptionModuleSessionImpl() {
if (!web_session_id_.empty())
adapter_->RemoveSession(web_session_id_);
+
+ // Release any WebContentDecryptionModuleResult objects that are left. Their
+ // index will have been passed down via a CdmPromise, but it uses a WeakPtr.
+ DLOG_IF(WARNING, outstanding_results_.size() > 0)
+ << "Clearing " << outstanding_results_.size() << " results";
+ for (ResultMap::iterator it = outstanding_results_.begin();
+ it != outstanding_results_.end();
+ ++it) {
+ it->second.completeWithError(
+ blink::WebContentDecryptionModuleExceptionInvalidStateError,
+ 0,
+ "Outstanding request being cancelled.");
+ }
+ outstanding_results_.clear();
+}
+
+void WebContentDecryptionModuleSessionImpl::setClientInterface(Client* client) {
+ client_ = client;
}
blink::WebString WebContentDecryptionModuleSessionImpl::sessionId() const {
const blink::WebString& init_data_type,
const uint8* init_data,
size_t init_data_length) {
- // TODO(ddorwin): Guard against this in supported types check and remove this.
- // Chromium only supports ASCII MIME types.
- if (!base::IsStringASCII(init_data_type)) {
- NOTREACHED();
- OnSessionError(media::MediaKeys::NOT_SUPPORTED_ERROR,
- 0,
- "The initialization data type " + init_data_type.utf8() +
- " is not supported by the key system.");
- return;
- }
+ DCHECK(base::IsStringASCII(init_data_type));
std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type);
DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos)
<< "init_data_type '" << init_data_type_as_ascii
<< "' may be a MIME type";
+ // Attempt to translate content types.
+ // TODO(sandersd): Remove once tests stop using content types.
+ // http://crbug.com/385874
+ std::string content_type = base::StringToLowerASCII(init_data_type_as_ascii);
+ if (content_type == "audio/mp4" || content_type == "video/mp4") {
+ init_data_type_as_ascii = "cenc";
+ } else if (content_type == "audio/webm" || content_type == "video/webm") {
+ init_data_type_as_ascii = "webm";
+ }
+
scoped_ptr<media::NewSessionCdmPromise> promise(
new media::NewSessionCdmPromise(
base::Bind(&WebContentDecryptionModuleSessionImpl::SessionCreated,
- weak_ptr_factory_.GetWeakPtr()),
+ weak_ptr_factory_.GetWeakPtr(),
+ kReservedIndex),
base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError,
- weak_ptr_factory_.GetWeakPtr())));
+ weak_ptr_factory_.GetWeakPtr()),
+ adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName));
adapter_->InitializeNewSession(init_data_type_as_ascii,
init_data,
init_data_length,
adapter_->ReleaseSession(web_session_id_, promise.Pass());
}
+void WebContentDecryptionModuleSessionImpl::initializeNewSession(
+ const blink::WebString& init_data_type,
+ const uint8* init_data,
+ size_t init_data_length,
+ const blink::WebString& session_type,
+ blink::WebContentDecryptionModuleResult result) {
+ uint32 result_index = AddResult(result);
+
+ // TODO(ddorwin): Guard against this in supported types check and remove this.
+ // Chromium only supports ASCII MIME types.
+ if (!base::IsStringASCII(init_data_type)) {
+ NOTREACHED();
+ SessionError(result_index,
+ media::MediaKeys::NOT_SUPPORTED_ERROR,
+ 0,
+ "The initialization data type " + init_data_type.utf8() +
+ " is not supported by the key system.");
+ return;
+ }
+
+ std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type);
+ DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos)
+ << "init_data_type '" << init_data_type_as_ascii
+ << "' may be a MIME type";
+
+ scoped_ptr<media::NewSessionCdmPromise> promise(
+ new media::NewSessionCdmPromise(
+ base::Bind(&WebContentDecryptionModuleSessionImpl::SessionCreated,
+ weak_ptr_factory_.GetWeakPtr(),
+ result_index),
+ base::Bind(&WebContentDecryptionModuleSessionImpl::SessionError,
+ weak_ptr_factory_.GetWeakPtr(),
+ result_index),
+ adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName));
+ adapter_->InitializeNewSession(init_data_type_as_ascii,
+ init_data,
+ init_data_length,
+ media::MediaKeys::TEMPORARY_SESSION,
+ promise.Pass());
+}
+
+void WebContentDecryptionModuleSessionImpl::update(
+ const uint8* response,
+ size_t response_length,
+ blink::WebContentDecryptionModuleResult result) {
+ DCHECK(response);
+ uint32 result_index = AddResult(result);
+ scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
+ base::Bind(
+ &WebContentDecryptionModuleSessionImpl::SessionUpdatedOrReleased,
+ weak_ptr_factory_.GetWeakPtr(),
+ result_index),
+ base::Bind(&WebContentDecryptionModuleSessionImpl::SessionError,
+ weak_ptr_factory_.GetWeakPtr(),
+ result_index)));
+ adapter_->UpdateSession(
+ web_session_id_, response, response_length, promise.Pass());
+}
+
+void WebContentDecryptionModuleSessionImpl::release(
+ blink::WebContentDecryptionModuleResult result) {
+ uint32 result_index = AddResult(result);
+ scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
+ base::Bind(
+ &WebContentDecryptionModuleSessionImpl::SessionUpdatedOrReleased,
+ weak_ptr_factory_.GetWeakPtr(),
+ result_index),
+ base::Bind(&WebContentDecryptionModuleSessionImpl::SessionError,
+ weak_ptr_factory_.GetWeakPtr(),
+ result_index)));
+ adapter_->ReleaseSession(web_session_id_, promise.Pass());
+}
+
void WebContentDecryptionModuleSessionImpl::OnSessionMessage(
const std::vector<uint8>& message,
const GURL& destination_url) {
+ DCHECK(client_) << "Client not set before message event";
client_->message(
message.empty() ? NULL : &message[0], message.size(), destination_url);
}
}
void WebContentDecryptionModuleSessionImpl::SessionCreated(
+ uint32 result_index,
const std::string& web_session_id) {
- DCHECK(web_session_id_.empty()) << "Session ID may not be changed once set.";
- web_session_id_ = web_session_id;
- adapter_->RegisterSession(web_session_id_, weak_ptr_factory_.GetWeakPtr());
+ blink::WebContentDecryptionModuleResult::SessionStatus status;
+
+ // CDM will return NULL if the session to be loaded can't be found.
+ if (web_session_id.empty()) {
+ status = blink::WebContentDecryptionModuleResult::SessionNotFound;
+ } else {
+ DCHECK(web_session_id_.empty())
+ << "Session ID may not be changed once set.";
+ web_session_id_ = web_session_id;
+ status =
+ adapter_->RegisterSession(web_session_id_,
+ weak_ptr_factory_.GetWeakPtr())
+ ? blink::WebContentDecryptionModuleResult::NewSession
+ : blink::WebContentDecryptionModuleResult::SessionAlreadyExists;
+ }
+
+ ResultMap::iterator it = outstanding_results_.find(result_index);
+ if (it != outstanding_results_.end()) {
+ blink::WebContentDecryptionModuleResult& result = it->second;
+ result.completeWithSession(status);
+ outstanding_results_.erase(result_index);
+ }
+}
+
+void WebContentDecryptionModuleSessionImpl::SessionUpdatedOrReleased(
+ uint32 result_index) {
+ ResultMap::iterator it = outstanding_results_.find(result_index);
+ DCHECK(it != outstanding_results_.end());
+ blink::WebContentDecryptionModuleResult& result = it->second;
+ result.complete();
+ outstanding_results_.erase(it);
+}
+
+void WebContentDecryptionModuleSessionImpl::SessionError(
+ uint32 result_index,
+ media::MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message) {
+ ResultMap::iterator it = outstanding_results_.find(result_index);
+ DCHECK(it != outstanding_results_.end());
+ blink::WebContentDecryptionModuleResult& result = it->second;
+ result.completeWithError(ConvertException(exception_code),
+ system_code,
+ blink::WebString::fromUTF8(error_message));
+ outstanding_results_.erase(it);
+}
+
+uint32 WebContentDecryptionModuleSessionImpl::AddResult(
+ blink::WebContentDecryptionModuleResult result) {
+ uint32 result_index = next_available_result_index_++;
+ DCHECK(result_index != kReservedIndex);
+ outstanding_results_.insert(std::make_pair(result_index, result));
+ return result_index;
}
} // namespace content