Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Side by Side Diff: webkit/media/crypto/content_decryptor.cc

Issue 10545036: Add PPAPI decryptor interfaces. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Changes in response to dmichael's comments/xhwang's testing. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 <cassert>
6 #include <string>
7
8 #include "base/basictypes.h"
9 #include "base/string_number_conversions.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "ppapi/c/pp_errors.h"
12 #include "ppapi/cpp/completion_callback.h"
13 #include "ppapi/cpp/core.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/module.h"
16 #include "ppapi/cpp/pass_ref.h"
17 #include "ppapi/cpp/resource.h"
18 #include "ppapi/cpp/var.h"
19 #include "ppapi/cpp/var_array_buffer.h"
20 #include "ppapi/cpp/dev/buffer_dev.h"
21 #include "ppapi/cpp/dev/content_decryptor_dev.h"
22 #include "ppapi/utility/completion_callback_factory.h"
23
24 namespace {
25
26 struct DecryptorMessage {
27 DecryptorMessage() : media_error(0), system_error(0) {}
28 std::string key_system;
29 std::string session_id;
30 std::string default_url;
31 std::string message_data;
32 uint16 media_error;
33 uint16 system_error;
34 };
35
36 struct DecryptedBlock {
37 DecryptedBlock() : callback(PP_MakeCompletionCallback(NULL, NULL)) {}
38 PP_CompletionCallback callback;
39 std::string data;
40 };
41
42 bool IsMainThread() {
43 return pp::Module::Get()->core()->IsMainThread();
44 }
45
46 void CallOnMain(pp::CompletionCallback cb) {
47 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
48 }
49
50 } // namespace
51
52
53 // A wrapper class responsible for managing interaction between the browser and
54 // a Content Decryption Module (CDM).
55 class CDMWrapper : public pp::Instance,
56 public pp::ContentDecryptor_Dev {
57 public:
58 CDMWrapper(PP_Instance instance, pp::Module* module);
59 virtual ~CDMWrapper() {}
60
61 // PPP_ContentDecryptor_Dev methods
62 virtual bool GenerateKeyRequest(PP_Var key_system, PP_Var init_data) OVERRIDE;
63 virtual bool AddKey(PP_Var session_id, PP_Var key) OVERRIDE;
64 virtual bool CancelKeyRequest(PP_Var session_id) OVERRIDE;
65 virtual bool Decrypt(PP_Resource encrypted_block,
66 PP_CompletionCallback callback) OVERRIDE;
67
68 virtual bool DecryptAndDecode(PP_Resource encrypted_block,
69 PP_CompletionCallback callback) OVERRIDE {
70 return false;
71 }
72
73 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
74 return true;
75 }
76
77 private:
78 PP_Resource StringToBufferResource(const std::string& str);
79
80 // <code>PPB_ContentDecryptor_Dev</code> dispatchers. These are passed to
81 // <code>callback_factory_</code> to ensure that calls into
82 // <code>PPP_ContentDecryptor_Dev</code> are asynchronous.
83 void NeedKey(int32 result, const DecryptorMessage& decryptor_message);
84 void KeyAdded(int32 result, const DecryptorMessage& decryptor_message);
85 void KeyMessage(int32 result, const DecryptorMessage& decryptor_message);
86 void KeyError(int32 result, const DecryptorMessage& decryptor_message);
87 void DeliverBlock(int32 result, const DecryptedBlock& decrypted_block);
88
89 pp::CompletionCallbackFactory<CDMWrapper> callback_factory_;
90
91 virtual bool IsValidSessionId(std::string session_id) {
92 // TODO(tomfinegan): The CDM MUST handle multiple session IDs. This simple
93 // implementation exists for testing purposes.
94 return (!session_id_.empty() && session_id == session_id_);
95 }
96
97 // TODO(tomfinegan): This needs to be mappable to init data (key IDs in the
98 // WebM case). For WebM it most likely will be 1 key ID and 1 session per
99 // stream. For now we'll just use a random number.
100 uint32 next_session_id_;
101 std::string session_id_;
102
103 // Key ID obtained from init data passed to <code>GenerateKeyRequest</code>.
104 // As-is: WebM video specific; Inadequate for WebM with encrypted audio (A/V
105 // will not have same key ID/key/session ID). Probably inadequate for ISO.
106 std::string key_id_;
107
108 // TODO(tomfinegan): Should these be multimaps of session_id:key_system and
109 // session_id:key? Or am I completely confused? :)
110 std::string key_;
111 std::string key_system_;
112 };
113
114 CDMWrapper::CDMWrapper(PP_Instance instance,
115 pp::Module* module)
116 : pp::Instance(instance),
117 pp::ContentDecryptor_Dev(this),
118 next_session_id_(0) {
119 callback_factory_.Initialize(this);
120 }
121
122 bool CDMWrapper::GenerateKeyRequest(PP_Var key_system_arg,
123 PP_Var init_data_arg) {
124
125 pp::Var init_data(pp::PASS_REF, init_data_arg);
126
127 // TODO(tomfinegan): Testing only implementation; init data will not always
128 // be the key ID.
129 pp::Var key_system_var(pp::PASS_REF, key_system_arg);
130
131 // TODO(tomfinegan): confirm support for the key system.
132
133 DecryptorMessage decryptor_message;
134 key_system_ = key_system_var.AsString();
135 decryptor_message.key_system = key_system_;
136 session_id_ = base::UintToString(next_session_id_++);
137 decryptor_message.session_id = session_id_;
138 decryptor_message.default_url = "http://www.google.com";
139 decryptor_message.message_data = "key request";
140
141 CallOnMain(callback_factory_.NewCallback(&CDMWrapper::KeyMessage,
142 decryptor_message));
143 return true;
144 }
145
146 bool CDMWrapper::AddKey(PP_Var session_id_var, PP_Var key_arg) {
147 pp::Var session_id(pp::PASS_REF, session_id_var);
148 if (!IsValidSessionId(session_id.AsString()))
149 return false;
150
151 pp::VarArrayBuffer key(pp::Var(pp::PASS_REF, key_arg));
152 if (!key.is_array_buffer())
153 return false;
154
155 key_.assign(reinterpret_cast<char*>(key.Map()), key.ByteLength());
156
157 DecryptorMessage decryptor_message;
158 decryptor_message.key_system = key_system_;
159 decryptor_message.session_id = session_id_;
160 CallOnMain(callback_factory_.NewCallback(&CDMWrapper::KeyAdded,
161 decryptor_message));
162 return true;
163 }
164
165 bool CDMWrapper::CancelKeyRequest(PP_Var session_id_arg) {
166 pp::Var session_id_var(pp::PASS_REF, session_id_arg);
167
168 if (!IsValidSessionId(session_id_var.AsString()))
169 return false;
170
171 // TODO(tomfinegan): cancel pending key request in CDM.
172
173 return true;
174 }
175
176 bool CDMWrapper::Decrypt(PP_Resource encrypted_block,
177 PP_CompletionCallback callback) {
178 pp::Buffer_Dev block_buffer(encrypted_block);
179 if (!block_buffer.data() || !callback.func) {
180 return false;
181 }
182
183 DecryptedBlock decrypted_block;
184 decrypted_block.callback = callback;
185 decrypted_block.data = "Pretend I'm decrypted data!";
186 CallOnMain(callback_factory_.NewCallback(&CDMWrapper::DeliverBlock,
187 decrypted_block));
188 return true;
189 }
190
191 PP_Resource CDMWrapper::StringToBufferResource(const std::string& str) {
192 if (str.empty())
193 return 0;
194
195 pp::Buffer_Dev buffer(this, str.size());
196 if (!buffer.data())
197 return 0;
198
199 memcpy(buffer.data(), str.data(), str.size());
200 return buffer.detach();
201 }
202
203 void CDMWrapper::NeedKey(int32 result,
204 const DecryptorMessage& decryptor_message) {
205 pp::Var key_system(decryptor_message.key_system);
206 pp::Var session_id(decryptor_message.session_id);
207 pp::Var init_data(decryptor_message.message_data);
208 pp::ContentDecryptor_Dev::NeedKey(key_system.pp_var(),
209 session_id.pp_var(),
210 init_data.pp_var());
211 }
212
213 void CDMWrapper::KeyAdded(int32 result,
214 const DecryptorMessage& decryptor_message) {
215 PP_Var key_system = pp::Var(decryptor_message.key_system).pp_var();
216 PP_Var session_id = pp::Var(decryptor_message.session_id).pp_var();
217 pp::ContentDecryptor_Dev::KeyAdded(key_system, session_id);
218 }
219
220 void CDMWrapper::KeyMessage(int32 result,
221 const DecryptorMessage& decryptor_message) {
222 PP_Var key_system = pp::Var(decryptor_message.key_system).pp_var();
223 PP_Var session_id = pp::Var(decryptor_message.session_id).pp_var();
224 PP_Resource message =
225 StringToBufferResource(decryptor_message.message_data);
226 PP_Var default_url = pp::Var(decryptor_message.default_url).pp_var();
227 pp::ContentDecryptor_Dev::KeyMessage(key_system,
228 session_id,
229 message,
230 default_url);
231 }
232
233 void CDMWrapper::KeyError(int32 result,
234 const DecryptorMessage& decryptor_message) {
235 PP_Var key_system = pp::Var(decryptor_message.key_system).pp_var();
236 PP_Var session_id = pp::Var(decryptor_message.session_id).pp_var();
237 pp::ContentDecryptor_Dev::KeyError(key_system,
238 session_id,
239 decryptor_message.media_error,
240 decryptor_message.system_error);
241 }
242
243 void CDMWrapper::DeliverBlock(int32 result,
244 const DecryptedBlock& decrypted_block) {
245 PP_Resource decrypted_resource = StringToBufferResource(
246 decrypted_block.data);
247 if (decrypted_resource) {
248 pp::ContentDecryptor_Dev::DeliverBlock(decrypted_resource,
249 decrypted_block.callback);
250 }
251 }
252
253 // This object is the global object representing this plugin library as long
254 // as it is loaded.
255 class MyModule : public pp::Module {
256 public:
257 MyModule() : pp::Module() {}
258 virtual ~MyModule() {}
259
260 virtual pp::Instance* CreateInstance(PP_Instance instance) {
261 return new CDMWrapper(instance, this);
262 }
263 };
264
265 namespace pp {
266
267 // Factory function for your specialization of the Module object.
268 Module* CreateModule() {
269 return new MyModule();
270 }
271
272 } // namespace pp
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698