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

Side by Side Diff: media/cdm/ppapi/cdm_file_io_impl.cc

Issue 93243003: Add CDM FileIO tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years 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 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 "media/cdm/ppapi/cdm_file_io_impl.h"
6
7 #include <algorithm>
8 #include <sstream>
9
10 #include "base/logging.h"
11 #include "ppapi/c/pp_errors.h"
12
13 namespace media {
14
15 const int kReadSize = 1024; // Arbitrary choice.
16
17 // Call func_call and check the result. If the result is not
18 // PP_OK_COMPLETIONPENDING, print out logs, call OnError() and return.
19 #define CHECK_PP_OK_COMPLETIONPENDING(func_call, error_type) \
20 do { \
21 int32_t result = func_call; \
ddorwin 2013/12/04 05:27:08 PP_DCHECK(result != PP_OK)?
xhwang 2013/12/10 01:24:25 Done.
22 if (result != PP_OK_COMPLETIONPENDING) { \
23 std::ostringstream error_message; \
24 error_message << #func_call << " failed with result: " << result; \
ddorwin 2013/12/04 05:27:08 All these strings will get included in prod binari
xhwang 2013/12/10 01:24:25 Done.
25 OnError((error_type), (error_message).str()); \
26 return; \
27 } \
28 } while (0)
29
30 // PPAPI calls should only be made on the main thread. In this file, main thread
31 // checking is only performed in public APIs and the completion callback
32 // (HandleCompletedTask). This ensures all functions are running on the main
33 // thread since internal methods are called either by the public APIs or by the
34 // completion callback.
35 static bool IsMainThread() {
36 return pp::Module::Get()->core()->IsMainThread();
37 }
38
39 // Posts a task to run |cb| on the main thread. The task is posted even if the
40 // current thread is the main thread.
41 static void PostOnMain(pp::CompletionCallback cb) {
42 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
43 }
44
45 CdmFileIOImpl::CdmFileIOImpl(cdm::CdmFileIOClient* client,
46 PP_Instance pp_instance)
ddorwin 2013/12/04 05:27:08 fits?
xhwang 2013/12/10 01:24:25 Done.
47 : state_(FILE_CLOSED),
ddorwin 2013/12/04 05:27:08 Kind of odd to start out in closed, esp. since the
xhwang 2013/12/10 01:24:25 Done. Added FILE_UNOPENED.
48 client_(client),
49 pp_instance_handle_(pp_instance),
50 callback_factory_(this),
51 file_offset_(0) {
52 PP_DCHECK(pp_instance); // 0 indicates a "NULL handle".
53 }
54
55 CdmFileIOImpl::~CdmFileIOImpl() {
56 if (state_ != FILE_CLOSED)
57 CloseFile();
58 }
59
60 // Call sequence: Open() -> OpenFileSystem() -> OpenFile() -> FILE_OPENED.
61 void CdmFileIOImpl::Open(const char* file_name, uint32_t file_name_size) {
62 DVLOG(3) << __FUNCTION__;
63 PP_DCHECK(IsMainThread());
64
65 if (state_ != FILE_CLOSED) {
66 OnError(OPEN_ERROR, "Open() called in an invalid state.");
67 return;
68 }
69
70 state_ = OPENING_FILE_SYSTEM;
71
72 // File name should not contain any path separators.
73 std::string file_name_str(file_name, file_name_size);
74 if (file_name_str.find('/') != std::string::npos ||
75 file_name_str.find('\\') != std::string::npos) {
76 OnError(OPEN_ERROR, "Invalid file name.");
77 return;
78 }
79
80 // pp::FileRef only accepts path that begins with a '/' character.
81 file_name_ = '/';
82 file_name_ += file_name_str;
ddorwin 2013/12/04 05:27:08 Can we merge with above line?
xhwang 2013/12/10 01:24:25 Done.
83
84 OpenFileSystem();
85 }
86
87 // Call sequence:
88 // finished
89 // Read() -> ReadFile() -> OnFileRead() ----------> Done.
90 // ^ |
91 // | | not finished
ddorwin 2013/12/04 05:27:08 This is a bit confusing. I guess because of the di
xhwang 2013/12/10 01:24:25 Done.
92 // |--------------|
93 void CdmFileIOImpl::Read() {
94 DVLOG(3) << __FUNCTION__;
95 PP_DCHECK(IsMainThread());
96
97 if (state_ != FILE_OPENED) {
98 OnError(READ_ERROR, "Read() called in an invalid state.");
99 return;
100 }
101
102 PP_DCHECK(buffer_.empty());
103 PP_DCHECK(read_buffer_.empty());
104
105 buffer_.resize(kReadSize);
106 file_offset_ = 0;
107
108 state_ = READING_FILE;
109 ReadFile();
110 }
111
112 // Call sequence:
113 // finished
114 // Write() -> WriteFile() -> OnFileWritten() ----------> Done.
115 // ^ |
116 // | | not finished
117 // |------------------|
118 void CdmFileIOImpl::Write(const uint8_t* data, uint32_t data_size) {
119 DVLOG(3) << __FUNCTION__;
120 PP_DCHECK(IsMainThread());
121
122 if (state_ != FILE_OPENED) {
123 OnError(WRITE_ERROR, "Write() called in an invalid state.");
124 return;
125 }
126
127 PP_DCHECK(state_ == FILE_OPENED);
ddorwin 2013/12/04 05:27:08 duplicate with 122?
xhwang 2013/12/10 01:24:25 Done.
128 // TODO(xhwang): Support NULL |data|.
129 PP_DCHECK(data);
130
131 buffer_.assign(data, data + data_size);
132 file_offset_ = 0;
133
134 state_ = WRITING_FILE;
135 WriteFile();
136 }
137
138 void CdmFileIOImpl::Close() {
139 if (state_ != FILE_CLOSED)
140 CloseFile();
141 delete this;
142 }
143
144 void CdmFileIOImpl::OpenFileSystem() {
145 DVLOG(3) << __FUNCTION__;
146 PP_DCHECK(state_ == OPENING_FILE_SYSTEM);
147
148 pp::CompletionCallbackWithOutput<pp::FileSystem> cb =
149 callback_factory_.NewCallbackWithOutput(&CdmFileIOImpl::OnFileSystemOpen);
150 pp::IsolatedFileSystemPrivate isolated_file_system(
151 pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE);
152
153 CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system.Open(cb), OPEN_ERROR);
ddorwin 2013/12/04 05:27:08 Is it okay that isolated_file_system will go out o
xhwang 2013/12/10 01:24:25 Done.
154 }
155
156 void CdmFileIOImpl::OnFileSystemOpen(int32_t result,
157 pp::FileSystem file_system) {
ddorwin 2013/12/04 05:27:08 fits
xhwang 2013/12/10 01:24:25 doesn't fit now
158 DVLOG(3) << __FUNCTION__;
ddorwin 2013/12/04 05:27:08 PP_DCHECK(IsMainThread());? Need to check callback
xhwang 2013/12/10 01:24:25 Done.
159 PP_DCHECK(state_ == OPENING_FILE_SYSTEM);
160 if (result != PP_OK) {
161 OnError(OPEN_ERROR, "File system open failed asynchronously.");
162 return;
163 }
164
165 file_system_ = file_system;
166 state_ = OPENING_FILE;
167 OpenFile();
168 }
169
170 void CdmFileIOImpl::OpenFile() {
171 DVLOG(3) << __FUNCTION__;
172 PP_DCHECK(state_ == OPENING_FILE);
173
174 file_io_ = pp::FileIO(pp_instance_handle_);
175 file_ref_ = pp::FileRef(file_system_, file_name_.c_str());
176 // TODO(xhwang): This is not safe when we have multiple instances trying to
ddorwin 2013/12/11 21:16:16 What did you do that made this safe in the new pat
177 // access the same file.
178 int32_t file_open_flag = PP_FILEOPENFLAG_READ |
179 PP_FILEOPENFLAG_WRITE |
180 PP_FILEOPENFLAG_CREATE;
181 pp::CompletionCallback cb =
182 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpen);
183 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb),
184 OPEN_ERROR);
185 }
186
187 void CdmFileIOImpl::OnFileOpen(int32_t result) {
188 PP_DCHECK(IsMainThread());
189 PP_DCHECK(state_ == OPENING_FILE);
190
191 if (result != PP_OK) {
192 OnError(OPEN_ERROR, "File open failed.");
193 return;
194 }
195
196 state_ = FILE_OPENED;
197 client_->OnOpenComplete(cdm::CdmFileIOClient::kSuccess);
198 }
199
200 void CdmFileIOImpl::ReadFile() {
201 PP_DCHECK(state_ == READING_FILE);
202 PP_DCHECK(!buffer_.empty());
203
204 pp::CompletionCallback cb =
205 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead);
206 CHECK_PP_OK_COMPLETIONPENDING(
207 file_io_.Read(file_offset_, &buffer_[0], buffer_.size(), cb), READ_ERROR);
208 }
209
210 void CdmFileIOImpl::OnFileRead(int32_t bytes_read) {
211 PP_DCHECK(state_ == READING_FILE);
ddorwin 2013/12/04 05:27:08 PP_DCHECK(IsMainThread());?
xhwang 2013/12/10 01:24:25 Done.
212
213 // 0 |bytes_read| indicates end-of-file reached.
214 if (bytes_read < PP_OK) {
ddorwin 2013/12/04 05:27:08 |bytes_read| is a |result|?
xhwang 2013/12/10 01:24:25 yes
215 OnError(READ_ERROR, "Read file failed.");
216 return;
217 }
218
219 PP_DCHECK(!buffer_.empty());
ddorwin 2013/12/04 05:27:08 This could be at 212, right? Might be unnecessary
xhwang 2013/12/10 01:24:25 Done.
220 PP_DCHECK(static_cast<size_t>(bytes_read) <= buffer_.size());
221 // Append |bytes_read| in |buffer_| to the end of |read_buffer_|.
222 read_buffer_.insert(read_buffer_.end(),
223 buffer_.begin(), buffer_.begin() + bytes_read);
224
225 buffer_.erase(buffer_.begin(), buffer_.begin() + bytes_read);
ddorwin 2013/12/04 05:27:08 This seems unnecessarily inefficient. Can we just
xhwang 2013/12/10 01:24:25 Done. Reuse the read buffer and this is not needed
226 file_offset_ += bytes_read;
227
228 // Still have data to read and we have not received end-of-file yet.
ddorwin 2013/12/04 05:27:08 With all the complexity, we should probably includ
xhwang 2013/12/10 01:24:25 I'll add more tests later.
229 if (!buffer_.empty() && bytes_read > 0) {
ddorwin 2013/12/04 05:27:08 Why wouldn't buffer_ be empty here? Shouldn't it b
xhwang 2013/12/10 01:24:25 For example, we ask to read 100 bytes, the only 50
230 ReadFile();
231 return;
232 }
233
234 // All requested data read or we hit end-of-file. Return read data to the
235 // client.
236 buffer_.clear();
237 file_offset_ = 0;
238 // Clear |read_buffer_| in case OnReadComplete() calls Read() or Write().
239 std::vector<char> local_buffer;
240 std::swap(read_buffer_, local_buffer);
241
242 state_ = FILE_OPENED;
243 client_->OnReadComplete(cdm::CdmFileIOClient::kSuccess,
244 reinterpret_cast<const uint8_t*>(&local_buffer[0]),
245 local_buffer.size());
246 }
247
248 void CdmFileIOImpl::WriteFile() {
249 PP_DCHECK(state_ == WRITING_FILE);
250 PP_DCHECK(!buffer_.empty());
251
252 pp::CompletionCallback cb =
253 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileWritten);
254 CHECK_PP_OK_COMPLETIONPENDING(
255 file_io_.Write(file_offset_, &buffer_[0], buffer_.size(), cb),
256 WRITE_ERROR);
257 }
258
259 void CdmFileIOImpl::OnFileWritten(int32_t bytes_written) {
260 PP_DCHECK(state_ == WRITING_FILE);
ddorwin 2013/12/04 05:27:08 PP_DCHECK(IsMainThread());?
xhwang 2013/12/10 01:24:25 Done.
261
262 if (bytes_written <= PP_OK) {
263 OnError(READ_ERROR, "Write file failed.");
264 return;
265 }
266
267 PP_DCHECK(!buffer_.empty());
268 PP_DCHECK(static_cast<size_t>(bytes_written) <= buffer_.size());
269 buffer_.erase(buffer_.begin(), buffer_.begin() + bytes_written);
ddorwin 2013/12/04 05:27:08 Same issues as read. Wouldn't it be easier to just
xhwang 2013/12/10 01:24:25 Done.
270 file_offset_ += bytes_written;
271
272 if (!buffer_.empty()) {
273 WriteFile();
ddorwin 2013/12/04 05:27:08 Just to be clear, this probably won't happen, righ
xhwang 2013/12/10 01:24:25 This happens when only part of the data were writt
274 return;
275 }
276
277 file_offset_ = 0;
278 state_ = FILE_OPENED;
279 client_->OnWriteComplete(cdm::CdmFileIOClient::kSuccess);
280 }
281
282 void CdmFileIOImpl::CloseFile() {
283 DVLOG(3) << __FUNCTION__;
284 PP_DCHECK(IsMainThread());
285
286 state_ = FILE_CLOSED;
287
288 file_io_.Close();
289 buffer_.clear();
290 file_offset_ = 0;
291 read_buffer_.clear();
292 }
293
294 void CdmFileIOImpl::OnError(ErrorType error_type,
295 const std::string& error_msg) {
296 PostOnMain(callback_factory_.NewCallback(
297 &CdmFileIOImpl::NotifyClientOfError, error_type, error_msg));
298 }
299
300 void CdmFileIOImpl::NotifyClientOfError(int32_t /* result */,
ddorwin 2013/12/04 05:27:08 DCHECK(result == PP_OK)?
xhwang 2013/12/10 01:24:25 Done.
301 ErrorType error_type,
302 const std::string& error_msg) {
303 DVLOG(1) << error_msg;
304 switch (error_type) {
ddorwin 2013/12/04 05:27:08 I'm not wild about this conversion, but I can't th
xhwang 2013/12/10 01:24:25 Done.
305 case OPEN_ERROR:
306 client_->OnOpenComplete(cdm::CdmFileIOClient::kError);
307 break;
308 case READ_ERROR:
309 client_->OnReadComplete(cdm::CdmFileIOClient::kError, NULL, 0);
310 break;
311 case WRITE_ERROR:
312 client_->OnWriteComplete(cdm::CdmFileIOClient::kError);
313 break;
314 }
315 }
316
317 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698