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

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: comments addressed 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 "ppapi/c/pp_errors.h"
11
12 // TODO(xhwang): Rebase and remove this.
13 #include "base/logging.h"
14 #define CDM_DLOG() DVLOG(3)
15
16 namespace media {
17
18 const int kReadSize = 4 * 1024; // Arbitrary choice.
19
20 // Call func_call and check the result. If the result is not
21 // PP_OK_COMPLETIONPENDING, print out logs, call OnError() and return.
22 #define CHECK_PP_OK_COMPLETIONPENDING(func_call, error_type) \
23 do { \
24 int32_t result = func_call; \
25 PP_DCHECK(result != PP_OK); \
26 if (result != PP_OK_COMPLETIONPENDING) { \
27 CDM_DLOG() << #func_call << " failed with result: " << result; \
28 OnError(error_type); \
29 return; \
30 } \
31 } while (0)
32
33 // PPAPI calls should only be made on the main thread. In this file, main thread
34 // checking is only performed in public APIs and the completion callbacks. This
35 // ensures all functions are running on the main thread since internal methods
36 // are called either by the public APIs or by the completion callbacks.
37 static bool IsMainThread() {
38 return pp::Module::Get()->core()->IsMainThread();
39 }
40
41 // Posts a task to run |cb| on the main thread. The task is posted even if the
42 // current thread is the main thread.
43 static void PostOnMain(pp::CompletionCallback cb) {
44 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
45 }
46
47 CdmFileIOImpl::CdmFileIOImpl(cdm::FileIOClient* client, PP_Instance pp_instance)
48 : state_(FILE_UNOPENED),
49 client_(client),
50 pp_instance_handle_(pp_instance),
51 callback_factory_(this),
52 io_offset_(0) {
53 PP_DCHECK(IsMainThread());
54 PP_DCHECK(pp_instance); // 0 indicates a "NULL handle".
55 }
56
57 CdmFileIOImpl::~CdmFileIOImpl() {
58 if (state_ != FILE_CLOSED)
59 CloseFile();
60 }
61
62 // Call sequence: Open() -> OpenFileSystem() -> OpenFile() -> FILE_OPENED.
63 void CdmFileIOImpl::Open(const char* file_name, uint32_t file_name_size) {
64 CDM_DLOG() << __FUNCTION__;
65 PP_DCHECK(IsMainThread());
66
67 if (state_ != FILE_UNOPENED) {
68 CDM_DLOG() << "Open() called in an invalid state.";
69 OnError(OPEN_ERROR);
70 return;
71 }
72
73 state_ = OPENING_FILE_SYSTEM;
74
75 // File name should not contain any path separators.
76 std::string file_name_str(file_name, file_name_size);
77 if (file_name_str.find('/') != std::string::npos ||
78 file_name_str.find('\\') != std::string::npos) {
79 CDM_DLOG() << "Invalid file name.";
80 OnError(OPEN_ERROR);
81 return;
82 }
83
84 // pp::FileRef only accepts path that begins with a '/' character.
85 file_name_ = '/' + file_name_str;
86 OpenFileSystem();
87 }
88
89 // Call sequence:
90 // finished
91 // Read() -> ReadFile() -> OnFileRead() ----------> Done.
92 // ^ |
93 // | not finished |
94 // |--------------|
95 void CdmFileIOImpl::Read() {
96 CDM_DLOG() << __FUNCTION__;
97 PP_DCHECK(IsMainThread());
98
99 if (state_ == READING_FILE || state_ == WRITING_FILE) {
100 CDM_DLOG() << "Read() called during pending read/write.";
101 OnError(READ_WHILE_IN_USE);
102 return;
103 }
104
105 if (state_ != FILE_OPENED) {
106 CDM_DLOG() << "Read() called in an invalid state.";
107 OnError(READ_ERROR);
108 return;
109 }
110
111 PP_DCHECK(io_buffer_.empty());
112 PP_DCHECK(cumulative_read_buffer_.empty());
113
114 io_buffer_.resize(kReadSize);
115 io_offset_ = 0;
116
117 state_ = READING_FILE;
118 ReadFile();
119 }
120
121 // Call sequence:
122 // finished
123 // Write() -> WriteFile() -> OnFileWritten() ----------> Done.
124 // ^ |
125 // | | not finished
126 // |------------------|
127 void CdmFileIOImpl::Write(const uint8_t* data, uint32_t data_size) {
128 CDM_DLOG() << __FUNCTION__;
129 PP_DCHECK(IsMainThread());
130
131 if (state_ == READING_FILE || state_ == WRITING_FILE) {
132 CDM_DLOG() << "Write() called during pending read/write.";
133 OnError(WRITE_WHILE_IN_USE);
134 return;
135 }
136
137 if (state_ != FILE_OPENED) {
138 CDM_DLOG() << "Write() called in an invalid state.";
139 OnError(WRITE_ERROR);
140 return;
141 }
142
143 PP_DCHECK(io_offset_ == 0);
144 PP_DCHECK(io_buffer_.empty());
145 if (data_size > 0)
146 io_buffer_.assign(data, data + data_size);
147 else
148 PP_DCHECK(!data);
149
150 state_ = WRITING_FILE;
151
152 // Always SetLength() in case |data_size| is less than the file size.
153 SetLength(data_size);
154 }
155
156 void CdmFileIOImpl::Close() {
157 CDM_DLOG() << __FUNCTION__;
158 PP_DCHECK(IsMainThread());
159 if (state_ != FILE_CLOSED)
160 CloseFile();
161 delete this;
162 }
163
164 void CdmFileIOImpl::OpenFileSystem() {
165 PP_DCHECK(state_ == OPENING_FILE_SYSTEM);
166
167 pp::CompletionCallbackWithOutput<pp::FileSystem> cb =
168 callback_factory_.NewCallbackWithOutput(
169 &CdmFileIOImpl::OnFileSystemOpened);
170 isolated_file_system_ = pp::IsolatedFileSystemPrivate(
171 pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE);
172
173 CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system_.Open(cb), OPEN_ERROR);
174 }
175
176 void CdmFileIOImpl::OnFileSystemOpened(int32_t result,
177 pp::FileSystem file_system) {
178 PP_DCHECK(IsMainThread());
179 PP_DCHECK(state_ == OPENING_FILE_SYSTEM);
180
181 if (result != PP_OK) {
182 CDM_DLOG() << "File system open failed asynchronously.";
183 OnError(OPEN_ERROR);
184 return;
185 }
186
187 file_system_ = file_system;
188 state_ = OPENING_FILE;
189 OpenFile();
190 }
191
192 void CdmFileIOImpl::OpenFile() {
193 PP_DCHECK(state_ == OPENING_FILE);
194
195 file_io_ = pp::FileIO(pp_instance_handle_);
196 file_ref_ = pp::FileRef(file_system_, file_name_.c_str());
197 int32_t file_open_flag = PP_FILEOPENFLAG_READ |
198 PP_FILEOPENFLAG_WRITE |
199 PP_FILEOPENFLAG_CREATE;
200 pp::CompletionCallback cb =
201 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpened);
202 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb),
203 OPEN_ERROR);
204 }
205
206 void CdmFileIOImpl::OnFileOpened(int32_t result) {
207 PP_DCHECK(IsMainThread());
208 PP_DCHECK(state_ == OPENING_FILE);
209
210 if (result != PP_OK) {
211 CDM_DLOG() << "File open failed.";
212 OnError(OPEN_ERROR);
213 return;
214 }
215
216 state_ = FILE_OPENED;
217 client_->OnOpenComplete(cdm::FileIOClient::kSuccess);
218 }
219
220 void CdmFileIOImpl::ReadFile() {
221 PP_DCHECK(state_ == READING_FILE);
222 PP_DCHECK(!io_buffer_.empty());
223
224 pp::CompletionCallback cb =
225 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead);
226 CHECK_PP_OK_COMPLETIONPENDING(
227 file_io_.Read(io_offset_, &io_buffer_[0], io_buffer_.size(), cb),
228 READ_ERROR);
229 }
230
231 void CdmFileIOImpl::OnFileRead(int32_t bytes_read) {
232 CDM_DLOG() << __FUNCTION__ << ": " << bytes_read;
233 PP_DCHECK(IsMainThread());
234 PP_DCHECK(state_ == READING_FILE);
235
236 // 0 |bytes_read| indicates end-of-file reached.
237 if (bytes_read < PP_OK) {
238 CDM_DLOG() << "Read file failed.";
239 OnError(READ_ERROR);
240 return;
241 }
242
243 PP_DCHECK(static_cast<size_t>(bytes_read) <= io_buffer_.size());
244 // Append |bytes_read| in |io_buffer_| to |cumulative_read_buffer_|.
245 cumulative_read_buffer_.insert(cumulative_read_buffer_.end(),
246 io_buffer_.begin(),
247 io_buffer_.begin() + bytes_read);
248 io_offset_ += bytes_read;
249
250 // Not received end-of-file yet.
251 if (bytes_read > 0) {
252 ReadFile();
253 return;
254 }
255
256 // We hit end-of-file. Return read data to the client.
257 io_buffer_.clear();
258 io_offset_ = 0;
259 // Clear |cumulative_read_buffer_| in case OnReadComplete() calls Read() or
260 // Write().
261 std::vector<char> local_buffer;
262 std::swap(cumulative_read_buffer_, local_buffer);
263
264 state_ = FILE_OPENED;
265 const uint8_t* data = local_buffer.empty() ?
266 NULL : reinterpret_cast<const uint8_t*>(&local_buffer[0]);
267 client_->OnReadComplete(
268 cdm::FileIOClient::kSuccess, data, local_buffer.size());
269 }
270
271 void CdmFileIOImpl::SetLength(uint32_t length) {
272 PP_DCHECK(state_ == WRITING_FILE);
273
274 pp::CompletionCallback cb =
275 callback_factory_.NewCallback(&CdmFileIOImpl::OnLengthSet);
276 CHECK_PP_OK_COMPLETIONPENDING(file_io_.SetLength(length, cb), WRITE_ERROR);
277 }
278
279 void CdmFileIOImpl::OnLengthSet(int32_t result) {
280 CDM_DLOG() << __FUNCTION__ << ": " << result;
281 PP_DCHECK(IsMainThread());
282 PP_DCHECK(state_ == WRITING_FILE);
283
284 if (result != PP_OK) {
285 CDM_DLOG() << "File SetLength failed.";
286 OnError(WRITE_ERROR);
287 return;
288 }
289
290 if (io_buffer_.empty()) {
291 state_ = FILE_OPENED;
292 client_->OnWriteComplete(cdm::FileIOClient::kSuccess);
293 return;
294 }
295
296 WriteFile();
297 }
298
299 void CdmFileIOImpl::WriteFile() {
300 PP_DCHECK(state_ == WRITING_FILE);
301 PP_DCHECK(io_offset_ < io_buffer_.size());
302
303 pp::CompletionCallback cb =
304 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileWritten);
305 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Write(io_offset_,
306 &io_buffer_[io_offset_],
307 io_buffer_.size() - io_offset_,
308 cb),
309 WRITE_ERROR);
310 }
311
312 void CdmFileIOImpl::OnFileWritten(int32_t bytes_written) {
313 CDM_DLOG() << __FUNCTION__ << ": " << bytes_written;
314 PP_DCHECK(IsMainThread());
315 PP_DCHECK(state_ == WRITING_FILE);
316
317 if (bytes_written <= PP_OK) {
318 CDM_DLOG() << "Write file failed.";
319 OnError(READ_ERROR);
320 return;
321 }
322
323 io_offset_ += bytes_written;
324 PP_DCHECK(io_offset_ <= io_buffer_.size());
325
326 if (io_offset_ < io_buffer_.size()) {
327 WriteFile();
328 return;
329 }
330
331 io_buffer_.clear();
332 io_offset_ = 0;
333 state_ = FILE_OPENED;
334 client_->OnWriteComplete(cdm::FileIOClient::kSuccess);
335 }
336
337 void CdmFileIOImpl::CloseFile() {
338 PP_DCHECK(IsMainThread());
339
340 state_ = FILE_CLOSED;
341
342 file_io_.Close();
343 io_buffer_.clear();
344 io_offset_ = 0;
345 cumulative_read_buffer_.clear();
346 }
347
348 void CdmFileIOImpl::OnError(ErrorType error_type) {
349 // For *_WHILE_IN_USE errors, do not reset these values. Otherwise, the
ddorwin 2013/12/17 00:17:04 nit: The comment and check don't match. This would
xhwang 2013/12/17 00:31:29 Hmm, this appears to be the cleanest I can get now
350 // existing read/write operation will fail.
351 if (error_type == READ_ERROR || error_type == WRITE_ERROR) {
ddorwin 2013/12/17 00:17:04 On an OPEN_ERROR,these are already at the reset va
xhwang 2013/12/17 00:31:29 OPEN_ERROR is only reported during opening a file.
352 io_buffer_.clear();
353 io_offset_ = 0;
354 cumulative_read_buffer_.clear();
355 }
356 PostOnMain(callback_factory_.NewCallback(&CdmFileIOImpl::NotifyClientOfError,
357 error_type));
358 }
359
360 void CdmFileIOImpl::NotifyClientOfError(int32_t result,
361 ErrorType error_type) {
362 PP_DCHECK(result == PP_OK);
363 switch (error_type) {
364 case OPEN_ERROR:
365 client_->OnOpenComplete(cdm::FileIOClient::kError);
366 break;
367 case READ_ERROR:
368 client_->OnReadComplete(cdm::FileIOClient::kError, NULL, 0);
369 break;
370 case WRITE_ERROR:
371 client_->OnWriteComplete(cdm::FileIOClient::kError);
372 break;
373 case OPEN_WHILE_IN_USE:
374 client_->OnOpenComplete(cdm::FileIOClient::kInUse);
375 break;
376 case READ_WHILE_IN_USE:
377 client_->OnReadComplete(cdm::FileIOClient::kInUse, NULL, 0);
378 break;
379 case WRITE_WHILE_IN_USE:
380 client_->OnWriteComplete(cdm::FileIOClient::kInUse);
381 break;
382 }
383 }
384
385 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698