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
3// found in the LICENSE file.
4
5#include "content/renderer/media/webcontentdecryptionmodulesession_impl.h"
6
7#include "base/bind.h"
8#include "base/callback_helpers.h"
9#include "base/logging.h"
10#include "base/strings/string_util.h"
11#include "base/strings/utf_string_conversions.h"
12#include "content/renderer/media/cdm_session_adapter.h"
13#include "media/base/cdm_promise.h"
14#include "third_party/WebKit/public/platform/WebURL.h"
15
16namespace content {
17
18WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl(
19    Client* client,
20    const scoped_refptr<CdmSessionAdapter>& adapter)
21    : adapter_(adapter),
22      client_(client),
23      is_closed_(false),
24      weak_ptr_factory_(this) {
25}
26
27WebContentDecryptionModuleSessionImpl::
28    ~WebContentDecryptionModuleSessionImpl() {
29  if (!web_session_id_.empty())
30    adapter_->RemoveSession(web_session_id_);
31}
32
33blink::WebString WebContentDecryptionModuleSessionImpl::sessionId() const {
34  return blink::WebString::fromUTF8(web_session_id_);
35}
36
37void WebContentDecryptionModuleSessionImpl::initializeNewSession(
38    const blink::WebString& init_data_type,
39    const uint8* init_data,
40    size_t init_data_length) {
41  // TODO(ddorwin): Guard against this in supported types check and remove this.
42  // Chromium only supports ASCII MIME types.
43  if (!base::IsStringASCII(init_data_type)) {
44    NOTREACHED();
45    OnSessionError(media::MediaKeys::NOT_SUPPORTED_ERROR,
46                   0,
47                   "The initialization data type " + init_data_type.utf8() +
48                       " is not supported by the key system.");
49    return;
50  }
51
52  std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type);
53  DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos)
54      << "init_data_type '" << init_data_type_as_ascii
55      << "' may be a MIME type";
56
57  scoped_ptr<media::NewSessionCdmPromise> promise(
58      new media::NewSessionCdmPromise(
59          base::Bind(&WebContentDecryptionModuleSessionImpl::SessionCreated,
60                     weak_ptr_factory_.GetWeakPtr()),
61          base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError,
62                     weak_ptr_factory_.GetWeakPtr())));
63  adapter_->InitializeNewSession(init_data_type_as_ascii,
64                                 init_data,
65                                 init_data_length,
66                                 media::MediaKeys::TEMPORARY_SESSION,
67                                 promise.Pass());
68}
69
70void WebContentDecryptionModuleSessionImpl::update(const uint8* response,
71                                                   size_t response_length) {
72  DCHECK(response);
73  scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
74      base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionReady,
75                 weak_ptr_factory_.GetWeakPtr()),
76      base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError,
77                 weak_ptr_factory_.GetWeakPtr())));
78  adapter_->UpdateSession(
79      web_session_id_, response, response_length, promise.Pass());
80}
81
82void WebContentDecryptionModuleSessionImpl::release() {
83  scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
84      base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionClosed,
85                 weak_ptr_factory_.GetWeakPtr()),
86      base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError,
87                 weak_ptr_factory_.GetWeakPtr())));
88  adapter_->ReleaseSession(web_session_id_, promise.Pass());
89}
90
91void WebContentDecryptionModuleSessionImpl::OnSessionMessage(
92    const std::vector<uint8>& message,
93    const GURL& destination_url) {
94  client_->message(
95      message.empty() ? NULL : &message[0], message.size(), destination_url);
96}
97
98void WebContentDecryptionModuleSessionImpl::OnSessionReady() {
99  client_->ready();
100}
101
102void WebContentDecryptionModuleSessionImpl::OnSessionClosed() {
103  if (!is_closed_) {
104    is_closed_ = true;
105    client_->close();
106  }
107}
108
109void WebContentDecryptionModuleSessionImpl::OnSessionError(
110    media::MediaKeys::Exception exception_code,
111    uint32 system_code,
112    const std::string& error_message) {
113  // Convert |exception_code| back to MediaKeyErrorCode if possible.
114  // TODO(jrummell): Update this conversion when promises flow
115  // back into blink:: (as blink:: will have its own error definition).
116  switch (exception_code) {
117    case media::MediaKeys::CLIENT_ERROR:
118      client_->error(Client::MediaKeyErrorCodeClient, system_code);
119      break;
120    default:
121      // This will include all other CDM4 errors and any error generated
122      // by CDM5 or later.
123      client_->error(Client::MediaKeyErrorCodeUnknown, system_code);
124      break;
125  }
126}
127
128void WebContentDecryptionModuleSessionImpl::SessionCreated(
129    const std::string& web_session_id) {
130  DCHECK(web_session_id_.empty()) << "Session ID may not be changed once set.";
131  web_session_id_ = web_session_id;
132  adapter_->RegisterSession(web_session_id_, weak_ptr_factory_.GetWeakPtr());
133}
134
135}  // namespace content
136