Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / webcontentdecryptionmodulesession_impl.cc
index 50ebcd0..527720f 100644 (file)
 
 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) {
 }
 
@@ -28,6 +59,24 @@ WebContentDecryptionModuleSessionImpl::
     ~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 {
@@ -38,28 +87,31 @@ void WebContentDecryptionModuleSessionImpl::initializeNewSession(
     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,
@@ -88,9 +140,83 @@ void WebContentDecryptionModuleSessionImpl::release() {
   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);
 }
@@ -126,10 +252,61 @@ void WebContentDecryptionModuleSessionImpl::OnSessionError(
 }
 
 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