Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / media / cdm / browser_cdm_manager.cc
bloba71bfafbd5f64f6a3726f9a81e08fed301183ae7
1 // Copyright 2014 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.
5 #include "content/browser/media/cdm/browser_cdm_manager.h"
7 #include "base/command_line.h"
8 #include "content/common/media/cdm_messages.h"
9 #include "content/public/browser/content_browser_client.h"
10 #include "content/public/browser/render_frame_host.h"
11 #include "content/public/browser/render_process_host.h"
12 #include "content/public/browser/render_view_host.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/public/common/content_switches.h"
15 #include "media/base/browser_cdm.h"
16 #include "media/base/browser_cdm_factory.h"
17 #include "media/base/media_switches.h"
19 namespace content {
21 using media::BrowserCdm;
22 using media::MediaKeys;
24 // Maximum lengths for various EME API parameters. These are checks to
25 // prevent unnecessarily large parameters from being passed around, and the
26 // lengths are somewhat arbitrary as the EME spec doesn't specify any limits.
27 const size_t kMaxInitDataLength = 64 * 1024; // 64 KB
28 const size_t kMaxSessionResponseLength = 64 * 1024; // 64 KB
29 const size_t kMaxKeySystemLength = 256;
31 // static
32 BrowserCdmManager* BrowserCdmManager::Create(RenderFrameHost* rfh) {
33 return new BrowserCdmManager(rfh);
36 BrowserCdmManager::BrowserCdmManager(RenderFrameHost* render_frame_host)
37 : render_frame_host_(render_frame_host),
38 web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
39 weak_ptr_factory_(this) {
42 BrowserCdmManager::~BrowserCdmManager() {
43 // During the tear down process, OnDestroyCdm() may or may not be called
44 // (e.g. WebContents may be destroyed before the render process is killed). So
45 // we cannot DCHECK(cdm_map_.empty()) here. Instead, all CDMs in |cdm_map_|
46 // will be destroyed here because they are owned by BrowserCdmManager.
49 BrowserCdm* BrowserCdmManager::GetCdm(int cdm_id) {
50 return cdm_map_.get(cdm_id);
53 void BrowserCdmManager::OnSessionCreated(
54 int cdm_id,
55 uint32 session_id,
56 const std::string& web_session_id) {
57 Send(new CdmMsg_SessionCreated(
58 RoutingID(), cdm_id, session_id, web_session_id));
61 void BrowserCdmManager::OnSessionMessage(
62 int cdm_id,
63 uint32 session_id,
64 const std::vector<uint8>& message,
65 const GURL& destination_url) {
66 GURL verified_gurl = destination_url;
67 if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
68 DLOG(WARNING) << "SessionMessage destination_url is invalid : "
69 << destination_url.possibly_invalid_spec();
70 verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url.
73 Send(new CdmMsg_SessionMessage(
74 RoutingID(), cdm_id, session_id, message, verified_gurl));
77 void BrowserCdmManager::OnSessionReady(int cdm_id, uint32 session_id) {
78 Send(new CdmMsg_SessionReady(RoutingID(), cdm_id, session_id));
81 void BrowserCdmManager::OnSessionClosed(int cdm_id, uint32 session_id) {
82 Send(new CdmMsg_SessionClosed(RoutingID(), cdm_id, session_id));
85 void BrowserCdmManager::OnSessionError(int cdm_id,
86 uint32 session_id,
87 MediaKeys::KeyError error_code,
88 uint32 system_code) {
89 Send(new CdmMsg_SessionError(
90 RoutingID(), cdm_id, session_id, error_code, system_code));
93 void BrowserCdmManager::OnInitializeCdm(int cdm_id,
94 const std::string& key_system,
95 const GURL& security_origin) {
96 if (key_system.size() > kMaxKeySystemLength) {
97 // This failure will be discovered and reported by OnCreateSession()
98 // as GetCdm() will return null.
99 NOTREACHED() << "Invalid key system: " << key_system;
100 return;
103 AddCdm(cdm_id, key_system, security_origin);
106 void BrowserCdmManager::OnCreateSession(
107 int cdm_id,
108 uint32 session_id,
109 CdmHostMsg_CreateSession_ContentType content_type,
110 const std::vector<uint8>& init_data) {
111 if (init_data.size() > kMaxInitDataLength) {
112 LOG(WARNING) << "InitData for ID: " << cdm_id
113 << " too long: " << init_data.size();
114 OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
115 return;
118 // Convert the session content type into a MIME type. "audio" and "video"
119 // don't matter, so using "video" for the MIME type.
120 // Ref:
121 // https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-createsession
122 std::string mime_type;
123 switch (content_type) {
124 case CREATE_SESSION_TYPE_WEBM:
125 mime_type = "video/webm";
126 break;
127 case CREATE_SESSION_TYPE_MP4:
128 mime_type = "video/mp4";
129 break;
130 default:
131 NOTREACHED();
132 return;
135 #if defined(OS_ANDROID)
136 if (CommandLine::ForCurrentProcess()
137 ->HasSwitch(switches::kDisableInfobarForProtectedMediaIdentifier)) {
138 CreateSessionIfPermitted(cdm_id, session_id, mime_type, init_data, true);
139 return;
141 #endif
143 BrowserCdm* cdm = GetCdm(cdm_id);
144 if (!cdm) {
145 DLOG(WARNING) << "No CDM for ID " << cdm_id << " found";
146 OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
147 return;
150 std::map<int, GURL>::const_iterator iter =
151 cdm_security_origin_map_.find(cdm_id);
152 if (iter == cdm_security_origin_map_.end()) {
153 NOTREACHED();
154 OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
155 return;
158 base::Closure cancel_callback;
159 GetContentClient()->browser()->RequestProtectedMediaIdentifierPermission(
160 web_contents_,
161 iter->second,
162 base::Bind(&BrowserCdmManager::CreateSessionIfPermitted,
163 weak_ptr_factory_.GetWeakPtr(),
164 cdm_id,
165 session_id,
166 mime_type,
167 init_data),
168 &cancel_callback);
169 if (!cancel_callback.is_null())
170 cdm_cancel_permision_map_[cdm_id] = cancel_callback;
173 void BrowserCdmManager::OnUpdateSession(
174 int cdm_id,
175 uint32 session_id,
176 const std::vector<uint8>& response) {
177 BrowserCdm* cdm = GetCdm(cdm_id);
178 if (!cdm) {
179 DLOG(WARNING) << "No CDM for ID " << cdm_id << " found";
180 OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
181 return;
184 if (response.size() > kMaxSessionResponseLength) {
185 LOG(WARNING) << "Response for ID " << cdm_id
186 << " is too long: " << response.size();
187 OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
188 return;
191 cdm->UpdateSession(session_id, &response[0], response.size());
194 void BrowserCdmManager::OnReleaseSession(int cdm_id, uint32 session_id) {
195 BrowserCdm* cdm = GetCdm(cdm_id);
196 if (!cdm) {
197 DLOG(WARNING) << "No CDM for ID " << cdm_id << " found";
198 OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
199 return;
202 cdm->ReleaseSession(session_id);
205 void BrowserCdmManager::OnDestroyCdm(int cdm_id) {
206 BrowserCdm* cdm = GetCdm(cdm_id);
207 if (!cdm)
208 return;
210 CancelAllPendingSessionCreations(cdm_id);
211 RemoveCdm(cdm_id);
214 void BrowserCdmManager::CancelAllPendingSessionCreations(int cdm_id) {
215 if (cdm_cancel_permision_map_.count(cdm_id)) {
216 cdm_cancel_permision_map_[cdm_id].Run();
217 cdm_cancel_permision_map_.erase(cdm_id);
221 void BrowserCdmManager::AddCdm(int cdm_id,
222 const std::string& key_system,
223 const GURL& security_origin) {
224 DCHECK(!GetCdm(cdm_id));
225 base::WeakPtr<BrowserCdmManager> weak_this = weak_ptr_factory_.GetWeakPtr();
226 scoped_ptr<BrowserCdm> cdm(media::CreateBrowserCdm(
227 key_system,
228 base::Bind(&BrowserCdmManager::OnSessionCreated, weak_this, cdm_id),
229 base::Bind(&BrowserCdmManager::OnSessionMessage, weak_this, cdm_id),
230 base::Bind(&BrowserCdmManager::OnSessionReady, weak_this, cdm_id),
231 base::Bind(&BrowserCdmManager::OnSessionClosed, weak_this, cdm_id),
232 base::Bind(&BrowserCdmManager::OnSessionError, weak_this, cdm_id)));
234 if (!cdm) {
235 // This failure will be discovered and reported by OnCreateSession()
236 // as GetCdm() will return null.
237 DVLOG(1) << "failed to create CDM.";
238 return;
241 cdm_map_.add(cdm_id, cdm.Pass());
242 cdm_security_origin_map_[cdm_id] = security_origin;
245 void BrowserCdmManager::RemoveCdm(int cdm_id) {
246 // TODO(xhwang): Detach CDM from the player it's set to. In prefixed
247 // EME implementation the current code is fine because we always destroy the
248 // player before we destroy the DrmBridge. This will not always be the case
249 // in unprefixed EME implementation.
250 cdm_map_.erase(cdm_id);
251 cdm_security_origin_map_.erase(cdm_id);
252 cdm_cancel_permision_map_.erase(cdm_id);
255 int BrowserCdmManager::RoutingID() {
256 return render_frame_host_->GetRoutingID();
259 bool BrowserCdmManager::Send(IPC::Message* msg) {
260 return render_frame_host_->Send(msg);
263 void BrowserCdmManager::CreateSessionIfPermitted(
264 int cdm_id,
265 uint32 session_id,
266 const std::string& content_type,
267 const std::vector<uint8>& init_data,
268 bool permitted) {
269 cdm_cancel_permision_map_.erase(cdm_id);
270 if (!permitted) {
271 OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
272 return;
275 BrowserCdm* cdm = GetCdm(cdm_id);
276 if (!cdm) {
277 DLOG(WARNING) << "No CDM for ID: " << cdm_id << " found";
278 OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
279 return;
282 // This could fail, in which case a SessionError will be fired.
283 cdm->CreateSession(session_id, content_type, &init_data[0], init_data.size());
286 } // namespace content