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

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

Issue 545983005: CdmFileIOImpl: Refactor Write() implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Cannot use "ERROR" on Windows!!! Also polished tests. Created 6 years, 3 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/cdm/ppapi/cdm_file_io_impl.h" 5 #include "media/cdm/ppapi/cdm_file_io_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <sstream> 8 #include <sstream>
9 9
10 #include "media/cdm/ppapi/cdm_logging.h" 10 #include "media/cdm/ppapi/cdm_logging.h"
11 #include "ppapi/c/pp_errors.h" 11 #include "ppapi/c/pp_errors.h"
12 #include "ppapi/cpp/dev/url_util_dev.h" 12 #include "ppapi/cpp/dev/url_util_dev.h"
13 13
14 namespace media { 14 namespace media {
15 15
16 const int kReadSize = 4 * 1024; // Arbitrary choice. 16 // Arbitrary choice based on the following heuristic ideas:
17 // - not too big to avoid unnecessarily large memory allocation;
18 // - not too small to avoid breaking most reads into multiple read operations.
19 const int kReadSize = 8 * 1024;
17 20
18 // Call func_call and check the result. If the result is not 21 // Call func_call and check the result. If the result is not
19 // PP_OK_COMPLETIONPENDING, print out logs, call OnError() and return. 22 // PP_OK_COMPLETIONPENDING, print out logs, call OnError() and return.
20 #define CHECK_PP_OK_COMPLETIONPENDING(func_call, error_type) \ 23 #define CHECK_PP_OK_COMPLETIONPENDING(func_call, error_type) \
21 do { \ 24 do { \
22 int32_t result = func_call; \ 25 int32_t result = func_call; \
23 PP_DCHECK(result != PP_OK); \ 26 PP_DCHECK(result != PP_OK); \
24 if (result != PP_OK_COMPLETIONPENDING) { \ 27 if (result != PP_OK_COMPLETIONPENDING) { \
25 CDM_DLOG() << #func_call << " failed with result: " << result; \ 28 CDM_DLOG() << #func_call << " failed with result: " << result; \
29 state_ = STATE_ERROR; \
26 OnError(error_type); \ 30 OnError(error_type); \
27 return; \ 31 return; \
28 } \ 32 } \
29 } while (0) 33 } while (0)
30 34
31 #if !defined(NDEBUG) 35 #if !defined(NDEBUG)
32 // PPAPI calls should only be made on the main thread. In this file, main thread 36 // PPAPI calls should only be made on the main thread. In this file, main thread
33 // checking is only performed in public APIs and the completion callbacks. This 37 // checking is only performed in public APIs and the completion callbacks. This
34 // ensures all functions are running on the main thread since internal methods 38 // ensures all functions are running on the main thread since internal methods
35 // are called either by the public APIs or by the completion callbacks. 39 // are called either by the public APIs or by the completion callbacks.
(...skipping 16 matching lines...) Expand all
52 } 56 }
53 57
54 CdmFileIOImpl::ResourceTracker::~ResourceTracker() { 58 CdmFileIOImpl::ResourceTracker::~ResourceTracker() {
55 delete CdmFileIOImpl::file_lock_map_; 59 delete CdmFileIOImpl::file_lock_map_;
56 } 60 }
57 61
58 CdmFileIOImpl::CdmFileIOImpl( 62 CdmFileIOImpl::CdmFileIOImpl(
59 cdm::FileIOClient* client, 63 cdm::FileIOClient* client,
60 PP_Instance pp_instance, 64 PP_Instance pp_instance,
61 const pp::CompletionCallback& first_file_read_cb) 65 const pp::CompletionCallback& first_file_read_cb)
62 : state_(FILE_UNOPENED), 66 : state_(STATE_UNOPENED),
63 client_(client), 67 client_(client),
64 pp_instance_handle_(pp_instance), 68 pp_instance_handle_(pp_instance),
65 callback_factory_(this),
66 io_offset_(0), 69 io_offset_(0),
67 first_file_read_reported_(false), 70 first_file_read_reported_(false),
68 first_file_read_cb_(first_file_read_cb) { 71 first_file_read_cb_(first_file_read_cb),
72 callback_factory_(this) {
69 PP_DCHECK(IsMainThread()); 73 PP_DCHECK(IsMainThread());
70 PP_DCHECK(pp_instance); // 0 indicates a "NULL handle". 74 PP_DCHECK(pp_instance); // 0 indicates a "NULL handle".
71 } 75 }
72 76
73 CdmFileIOImpl::~CdmFileIOImpl() { 77 CdmFileIOImpl::~CdmFileIOImpl() {
74 PP_DCHECK(state_ == FILE_CLOSED); 78 // The dtor is private. |this| can only be destructed through Close().
ddorwin 2014/09/16 18:07:36 "destructor" should fit
xhwang 2014/09/17 21:02:31 Done.
79 PP_DCHECK(state_ == STATE_CLOSED);
75 } 80 }
76 81
77 // Call sequence: Open() -> OpenFileSystem() -> OpenFile() -> FILE_OPENED. 82 // Call sequence: Open() -> OpenFileSystem() -> FILE_OPENED.
ddorwin 2014/09/16 18:07:36 FILE_OPENED does not exist anymore and is no longe
xhwang 2014/09/17 21:02:31 Done.
83 // Note: This only stores file name and opens the file system. The real file
84 // open is deferred to when Read() or Write() is called.
78 void CdmFileIOImpl::Open(const char* file_name, uint32_t file_name_size) { 85 void CdmFileIOImpl::Open(const char* file_name, uint32_t file_name_size) {
79 CDM_DLOG() << __FUNCTION__; 86 CDM_DLOG() << __FUNCTION__;
80 PP_DCHECK(IsMainThread()); 87 PP_DCHECK(IsMainThread());
81 88
82 if (state_ != FILE_UNOPENED) { 89 if (state_ != STATE_UNOPENED) {
83 CDM_DLOG() << "Open() called in an invalid state."; 90 CDM_DLOG() << "Open() called in an invalid state.";
84 OnError(OPEN_ERROR); 91 OnError(OPEN_ERROR);
85 return; 92 return;
86 } 93 }
87 94
95 // File name should not be empty and should not start with '_'.
96 std::string file_name_str(file_name, file_name_size);
97 if (file_name_str.empty() || file_name_str[0] == '_') {
98 CDM_DLOG() << "Invalid file name.";
99 state_ = STATE_ERROR;
100 OnError(OPEN_ERROR);
101 return;
102 }
103
88 // File name should not contain any path separators. 104 // File name should not contain any path separators.
89 std::string file_name_str(file_name, file_name_size);
90 if (file_name_str.find('/') != std::string::npos || 105 if (file_name_str.find('/') != std::string::npos ||
ddorwin 2014/09/16 18:07:37 combine into one block with above?
xhwang 2014/09/17 21:02:31 Done.
91 file_name_str.find('\\') != std::string::npos) { 106 file_name_str.find('\\') != std::string::npos) {
92 CDM_DLOG() << "Invalid file name."; 107 CDM_DLOG() << "Invalid file name.";
108 state_ = STATE_ERROR;
93 OnError(OPEN_ERROR); 109 OnError(OPEN_ERROR);
94 return; 110 return;
95 } 111 }
96 112
97 // pp::FileRef only accepts path that begins with a '/' character. 113 // pp::FileRef only accepts path that begins with a '/' character.
98 file_name_ = '/' + file_name_str; 114 file_name_ = '/' + file_name_str;
99 115
100 if (!AcquireFileLock()) { 116 if (!AcquireFileLock()) {
101 CDM_DLOG() << "File is in use by other cdm::FileIO objects."; 117 CDM_DLOG() << "File is in use by other cdm::FileIO objects.";
102 OnError(OPEN_WHILE_IN_USE); 118 OnError(OPEN_WHILE_IN_USE);
103 return; 119 return;
104 } 120 }
105 121
106 state_ = OPENING_FILE_SYSTEM; 122 state_ = STATE_OPENING_FILE_SYSTEM;
107 OpenFileSystem(); 123 OpenFileSystem();
108 } 124 }
109 125
110 // Call sequence: 126 // Call sequence:
111 // finished 127 // Read() -> OpenFileForRead() -> ReadFile() -> Done.
112 // Read() -> ReadFile() -> OnFileRead() ----------> Done.
113 // ^ |
114 // | not finished |
115 // |--------------|
116 void CdmFileIOImpl::Read() { 128 void CdmFileIOImpl::Read() {
117 CDM_DLOG() << __FUNCTION__; 129 CDM_DLOG() << __FUNCTION__;
118 PP_DCHECK(IsMainThread()); 130 PP_DCHECK(IsMainThread());
119 131
120 if (state_ == READING_FILE || state_ == WRITING_FILE) { 132 if (state_ == STATE_READING || state_ == STATE_WRITING) {
121 CDM_DLOG() << "Read() called during pending read/write."; 133 CDM_DLOG() << "Read() called during pending read/write.";
122 OnError(READ_WHILE_IN_USE); 134 OnError(READ_WHILE_IN_USE);
123 return; 135 return;
124 } 136 }
125 137
126 if (state_ != FILE_OPENED) { 138 if (state_ != STATE_OPENED) {
127 CDM_DLOG() << "Read() called in an invalid state."; 139 CDM_DLOG() << "Read() called in an invalid state.";
128 OnError(READ_ERROR); 140 OnError(READ_ERROR);
129 return; 141 return;
130 } 142 }
131 143
144 PP_DCHECK(io_offset_ == 0);
132 PP_DCHECK(io_buffer_.empty()); 145 PP_DCHECK(io_buffer_.empty());
133 PP_DCHECK(cumulative_read_buffer_.empty()); 146 PP_DCHECK(cumulative_read_buffer_.empty());
134
135 io_buffer_.resize(kReadSize); 147 io_buffer_.resize(kReadSize);
136 io_offset_ = 0; 148 io_offset_ = 0;
137 149
138 state_ = READING_FILE; 150 state_ = STATE_READING;
139 ReadFile(); 151 OpenFileForRead();
140 } 152 }
141 153
142 // Call sequence: 154 // Call sequence:
143 // finished 155 // Write() -> OpenTempFileForWrite() -> WriteTempFile() -> RenameTempFile().
144 // Write() -> WriteFile() -> OnFileWritten() ----------> Done. 156 // The file name of the temparory file is /_<original_file_name>.
145 // ^ |
146 // | | not finished
147 // |------------------|
148 void CdmFileIOImpl::Write(const uint8_t* data, uint32_t data_size) { 157 void CdmFileIOImpl::Write(const uint8_t* data, uint32_t data_size) {
149 CDM_DLOG() << __FUNCTION__; 158 CDM_DLOG() << __FUNCTION__;
150 PP_DCHECK(IsMainThread()); 159 PP_DCHECK(IsMainThread());
151 160
152 if (state_ == READING_FILE || state_ == WRITING_FILE) { 161 if (state_ == STATE_READING || state_ == STATE_WRITING) {
153 CDM_DLOG() << "Write() called during pending read/write."; 162 CDM_DLOG() << "Write() called during pending read/write.";
154 OnError(WRITE_WHILE_IN_USE); 163 OnError(WRITE_WHILE_IN_USE);
155 return; 164 return;
156 } 165 }
157 166
158 if (state_ != FILE_OPENED) { 167 if (state_ != STATE_OPENED) {
159 CDM_DLOG() << "Write() called in an invalid state."; 168 CDM_DLOG() << "Write() called in an invalid state.";
160 OnError(WRITE_ERROR); 169 OnError(WRITE_ERROR);
161 return; 170 return;
162 } 171 }
163 172
164 PP_DCHECK(io_offset_ == 0); 173 PP_DCHECK(io_offset_ == 0);
165 PP_DCHECK(io_buffer_.empty()); 174 PP_DCHECK(io_buffer_.empty());
166 if (data_size > 0) 175 if (data_size > 0)
167 io_buffer_.assign(data, data + data_size); 176 io_buffer_.assign(data, data + data_size);
168 else 177 else
169 PP_DCHECK(!data); 178 PP_DCHECK(!data);
170 179
171 state_ = WRITING_FILE; 180 state_ = STATE_WRITING;
172 181 OpenTempFileForWrite();
173 // Always SetLength() in case |data_size| is less than the file size.
174 SetLength(data_size);
175 } 182 }
176 183
177 void CdmFileIOImpl::Close() { 184 void CdmFileIOImpl::Close() {
178 CDM_DLOG() << __FUNCTION__; 185 CDM_DLOG() << __FUNCTION__;
179 PP_DCHECK(IsMainThread()); 186 PP_DCHECK(IsMainThread());
180 PP_DCHECK(state_ != FILE_CLOSED); 187 PP_DCHECK(state_ != STATE_CLOSED);
181 CloseFile(); 188 Reset();
189 state_ = STATE_CLOSED;
182 ReleaseFileLock(); 190 ReleaseFileLock();
183 // All pending callbacks are canceled since |callback_factory_| is destroyed. 191 // All pending callbacks are canceled since |callback_factory_| is destroyed.
184 delete this; 192 delete this;
185 } 193 }
186 194
187 bool CdmFileIOImpl::SetFileID() { 195 bool CdmFileIOImpl::SetFileID() {
188 PP_DCHECK(file_id_.empty()); 196 PP_DCHECK(file_id_.empty());
189 PP_DCHECK(!file_name_.empty() && file_name_[0] == '/'); 197 PP_DCHECK(!file_name_.empty() && file_name_[0] == '/');
190 198
191 // Not taking ownership of |url_util_dev| (which is a singleton). 199 // Not taking ownership of |url_util_dev| (which is a singleton).
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 238
231 if (!file_lock_map_) 239 if (!file_lock_map_)
232 return; 240 return;
233 241
234 FileLockMap::iterator found = file_lock_map_->find(file_id_); 242 FileLockMap::iterator found = file_lock_map_->find(file_id_);
235 if (found != file_lock_map_->end() && found->second) 243 if (found != file_lock_map_->end() && found->second)
236 found->second = false; 244 found->second = false;
237 } 245 }
238 246
239 void CdmFileIOImpl::OpenFileSystem() { 247 void CdmFileIOImpl::OpenFileSystem() {
240 PP_DCHECK(state_ == OPENING_FILE_SYSTEM); 248 PP_DCHECK(state_ == STATE_OPENING_FILE_SYSTEM);
241 249
242 pp::CompletionCallbackWithOutput<pp::FileSystem> cb = 250 pp::CompletionCallbackWithOutput<pp::FileSystem> cb =
243 callback_factory_.NewCallbackWithOutput( 251 callback_factory_.NewCallbackWithOutput(
244 &CdmFileIOImpl::OnFileSystemOpened); 252 &CdmFileIOImpl::OnFileSystemOpened);
245 isolated_file_system_ = pp::IsolatedFileSystemPrivate( 253 isolated_file_system_ = pp::IsolatedFileSystemPrivate(
246 pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE); 254 pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE);
247 255
248 CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system_.Open(cb), OPEN_ERROR); 256 CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system_.Open(cb), OPEN_ERROR);
249 } 257 }
250 258
251 void CdmFileIOImpl::OnFileSystemOpened(int32_t result, 259 void CdmFileIOImpl::OnFileSystemOpened(int32_t result,
252 pp::FileSystem file_system) { 260 pp::FileSystem file_system) {
253 PP_DCHECK(IsMainThread()); 261 PP_DCHECK(IsMainThread());
254 PP_DCHECK(state_ == OPENING_FILE_SYSTEM); 262 PP_DCHECK(state_ == STATE_OPENING_FILE_SYSTEM);
255 263
256 if (result != PP_OK) { 264 if (result != PP_OK) {
257 CDM_DLOG() << "File system open failed asynchronously."; 265 CDM_DLOG() << "File system open failed asynchronously.";
258 ReleaseFileLock(); 266 ReleaseFileLock();
267 state_ = STATE_ERROR;
259 OnError(OPEN_ERROR); 268 OnError(OPEN_ERROR);
260 return; 269 return;
261 } 270 }
262 271
263 file_system_ = file_system; 272 file_system_ = file_system;
264 state_ = OPENING_FILE; 273
265 OpenFile(); 274 state_ = STATE_OPENED;
ddorwin 2014/09/16 18:07:37 So it is STATE_FILE_SYSTEM_OPENED
xhwang 2014/09/17 21:02:32 Done.
275 client_->OnOpenComplete(cdm::FileIOClient::kSuccess);
266 } 276 }
267 277
268 void CdmFileIOImpl::OpenFile() { 278 void CdmFileIOImpl::OpenFileForRead() {
269 PP_DCHECK(state_ == OPENING_FILE); 279 PP_DCHECK(state_ == STATE_READING);
270 280
281 PP_DCHECK(file_io_.is_null());
282 PP_DCHECK(file_ref_.is_null());
271 file_io_ = pp::FileIO(pp_instance_handle_); 283 file_io_ = pp::FileIO(pp_instance_handle_);
272 file_ref_ = pp::FileRef(file_system_, file_name_.c_str()); 284 file_ref_ = pp::FileRef(file_system_, file_name_.c_str());
273 int32_t file_open_flag = PP_FILEOPENFLAG_READ | 285
274 PP_FILEOPENFLAG_WRITE | 286 // Open file for read. If file doesn't exist, create a new empty file.
ddorwin 2014/09/16 18:07:36 We should update the CDM.h API to allow the CDM to
xhwang 2014/09/17 21:02:31 Changed to impl not to create a new file for read
275 PP_FILEOPENFLAG_CREATE; 287 int32_t file_open_flag = PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_CREATE;
288
276 pp::CompletionCallback cb = 289 pp::CompletionCallback cb =
277 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpened); 290 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpenedForRead);
278 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb), 291 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb),
279 OPEN_ERROR); 292 READ_ERROR);
280 } 293 }
281 294
282 void CdmFileIOImpl::OnFileOpened(int32_t result) { 295 void CdmFileIOImpl::OnFileOpenedForRead(int32_t result) {
283 PP_DCHECK(IsMainThread()); 296 PP_DCHECK(IsMainThread());
284 PP_DCHECK(state_ == OPENING_FILE); 297 PP_DCHECK(state_ == STATE_READING);
285 298
286 if (result != PP_OK) { 299 if (result != PP_OK) {
287 CDM_DLOG() << "File open failed."; 300 CDM_DLOG() << "File open failed.";
288 ReleaseFileLock(); 301 ReleaseFileLock();
302 state_ = STATE_ERROR;
289 OnError(OPEN_ERROR); 303 OnError(OPEN_ERROR);
290 return; 304 return;
291 } 305 }
292 306
293 state_ = FILE_OPENED; 307 ReadFile();
294 client_->OnOpenComplete(cdm::FileIOClient::kSuccess);
295 } 308 }
296 309
310 // Call sequence:
311 // finished
ddorwin 2014/09/16 18:07:37 What is the purpose of the finished/not finished p
xhwang 2014/09/17 21:02:31 Changed "not finished" to "partially read"... Is t
ddorwin 2014/09/17 23:16:38 Acknowledged.
312 // ReadFile() -> OnFileRead() ----------> Done.
313 // ^ |
314 // | not finished |
315 // |--------------|
297 void CdmFileIOImpl::ReadFile() { 316 void CdmFileIOImpl::ReadFile() {
298 PP_DCHECK(state_ == READING_FILE); 317 PP_DCHECK(state_ == STATE_READING);
299 PP_DCHECK(!io_buffer_.empty()); 318 PP_DCHECK(!io_buffer_.empty());
300 319
301 pp::CompletionCallback cb = 320 pp::CompletionCallback cb =
302 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead); 321 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead);
303 CHECK_PP_OK_COMPLETIONPENDING( 322 CHECK_PP_OK_COMPLETIONPENDING(
304 file_io_.Read(io_offset_, &io_buffer_[0], io_buffer_.size(), cb), 323 file_io_.Read(io_offset_, &io_buffer_[0], io_buffer_.size(), cb),
305 READ_ERROR); 324 READ_ERROR);
306 } 325 }
307 326
308 void CdmFileIOImpl::OnFileRead(int32_t bytes_read) { 327 void CdmFileIOImpl::OnFileRead(int32_t bytes_read) {
309 CDM_DLOG() << __FUNCTION__ << ": " << bytes_read; 328 CDM_DLOG() << __FUNCTION__ << ": " << bytes_read;
310 PP_DCHECK(IsMainThread()); 329 PP_DCHECK(IsMainThread());
311 PP_DCHECK(state_ == READING_FILE); 330 PP_DCHECK(state_ == STATE_READING);
312 331
313 // 0 |bytes_read| indicates end-of-file reached. 332 // 0 |bytes_read| indicates end-of-file reached.
314 if (bytes_read < PP_OK) { 333 if (bytes_read < PP_OK) {
315 CDM_DLOG() << "Read file failed."; 334 CDM_DLOG() << "Read file failed.";
335 state_ = STATE_ERROR;
316 OnError(READ_ERROR); 336 OnError(READ_ERROR);
317 return; 337 return;
318 } 338 }
319 339
320 PP_DCHECK(static_cast<size_t>(bytes_read) <= io_buffer_.size()); 340 PP_DCHECK(static_cast<size_t>(bytes_read) <= io_buffer_.size());
321 // Append |bytes_read| in |io_buffer_| to |cumulative_read_buffer_|. 341 // Append |bytes_read| in |io_buffer_| to |cumulative_read_buffer_|.
322 cumulative_read_buffer_.insert(cumulative_read_buffer_.end(), 342 cumulative_read_buffer_.insert(cumulative_read_buffer_.end(),
323 io_buffer_.begin(), 343 io_buffer_.begin(),
324 io_buffer_.begin() + bytes_read); 344 io_buffer_.begin() + bytes_read);
325 io_offset_ += bytes_read; 345 io_offset_ += bytes_read;
326 346
327 // Not received end-of-file yet. 347 // Not received end-of-file yet. Keep reading.
328 if (bytes_read > 0) { 348 if (bytes_read > 0) {
329 ReadFile(); 349 ReadFile();
330 return; 350 return;
331 } 351 }
332 352
333 // We hit end-of-file. Return read data to the client. 353 // We hit end-of-file. Return read data to the client.
334 io_buffer_.clear(); 354
335 io_offset_ = 0;
336 // Clear |cumulative_read_buffer_| in case OnReadComplete() calls Read() or 355 // Clear |cumulative_read_buffer_| in case OnReadComplete() calls Read() or
337 // Write(). 356 // Write().
338 std::vector<char> local_buffer; 357 std::vector<char> local_buffer;
339 std::swap(cumulative_read_buffer_, local_buffer); 358 std::swap(cumulative_read_buffer_, local_buffer);
340 359
341 state_ = FILE_OPENED;
342 const uint8_t* data = local_buffer.empty() ? 360 const uint8_t* data = local_buffer.empty() ?
343 NULL : reinterpret_cast<const uint8_t*>(&local_buffer[0]); 361 NULL : reinterpret_cast<const uint8_t*>(&local_buffer[0]);
344 362
345 // Call this before OnReadComplete() so that we always have the latest file 363 // Call this before OnReadComplete() so that we always have the latest file
346 // size before CDM fires errors. 364 // size before CDM fires errors.
347 if (!first_file_read_reported_) { 365 if (!first_file_read_reported_) {
348 first_file_read_cb_.Run(local_buffer.size()); 366 first_file_read_cb_.Run(local_buffer.size());
349 first_file_read_reported_ = true; 367 first_file_read_reported_ = true;
350 } 368 }
351 369
370 Reset();
371
372 state_ = STATE_OPENED;
352 client_->OnReadComplete( 373 client_->OnReadComplete(
353 cdm::FileIOClient::kSuccess, data, local_buffer.size()); 374 cdm::FileIOClient::kSuccess, data, local_buffer.size());
354 } 375 }
355 376
356 void CdmFileIOImpl::SetLength(uint32_t length) { 377 void CdmFileIOImpl::OpenTempFileForWrite() {
357 PP_DCHECK(state_ == WRITING_FILE); 378 PP_DCHECK(state_ == STATE_WRITING);
379
380 PP_DCHECK(file_name_.size() > 1 && file_name_[0] == '/');
381 // Temporary file name format: /_<original_file_name>
382 std::string temp_file_name = "/_" + file_name_.substr(1);
383
384 PP_DCHECK(file_io_.is_null());
385 PP_DCHECK(file_ref_.is_null());
386 file_io_ = pp::FileIO(pp_instance_handle_);
387 file_ref_ = pp::FileRef(file_system_, temp_file_name.c_str());
388
389 // Create the file if it doesn't exist. Truncate the file to length 0 if it
ddorwin 2014/09/16 18:07:37 Should we UMA the case where we find a temp file?
xhwang 2014/09/17 21:02:31 Good point. But since we are using TRUNCATE, we ha
390 // exists.
391 int32_t file_open_flag = PP_FILEOPENFLAG_WRITE |
392 PP_FILEOPENFLAG_TRUNCATE |
393 PP_FILEOPENFLAG_CREATE;
358 394
359 pp::CompletionCallback cb = 395 pp::CompletionCallback cb =
360 callback_factory_.NewCallback(&CdmFileIOImpl::OnLengthSet); 396 callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileOpenedForWrite);
361 CHECK_PP_OK_COMPLETIONPENDING(file_io_.SetLength(length, cb), WRITE_ERROR); 397 CHECK_PP_OK_COMPLETIONPENDING(
398 file_io_.Open(file_ref_, file_open_flag, cb), WRITE_ERROR);
362 } 399 }
363 400
364 void CdmFileIOImpl::OnLengthSet(int32_t result) { 401 void CdmFileIOImpl::OnTempFileOpenedForWrite(int32_t result) {
365 CDM_DLOG() << __FUNCTION__ << ": " << result; 402 CDM_DLOG() << __FUNCTION__ << ": " << result;
366 PP_DCHECK(IsMainThread()); 403 PP_DCHECK(IsMainThread());
367 PP_DCHECK(state_ == WRITING_FILE); 404 PP_DCHECK(state_ == STATE_WRITING);
368 405
369 if (result != PP_OK) { 406 if (result != PP_OK) {
370 CDM_DLOG() << "File SetLength failed."; 407 CDM_DLOG() << "Open temporary file failed.";
408 state_ = STATE_ERROR;
371 OnError(WRITE_ERROR); 409 OnError(WRITE_ERROR);
372 return; 410 return;
373 } 411 }
374 412
375 if (io_buffer_.empty()) { 413 if (io_buffer_.empty()) {
ddorwin 2014/09/16 18:07:36 Does this indicate we were told to write 0 bytes?
xhwang 2014/09/17 21:02:31 Done.
376 state_ = FILE_OPENED; 414 RenameTempFile();
377 client_->OnWriteComplete(cdm::FileIOClient::kSuccess);
378 return; 415 return;
379 } 416 }
380 417
381 WriteFile(); 418 PP_DCHECK(io_offset_ == 0);
419 io_offset_ = 0;
420 WriteTempFile();
382 } 421 }
383 422
384 void CdmFileIOImpl::WriteFile() { 423 // Call sequence:
385 PP_DCHECK(state_ == WRITING_FILE); 424 // finished
425 // WriteTempFile() -> OnTempFileWritten() ----------> RenameTempFile().
426 // ^ |
427 // | not finished |
428 // |----------------------|
429 void CdmFileIOImpl::WriteTempFile() {
430 PP_DCHECK(state_ == STATE_WRITING);
386 PP_DCHECK(io_offset_ < io_buffer_.size()); 431 PP_DCHECK(io_offset_ < io_buffer_.size());
387 432
388 pp::CompletionCallback cb = 433 pp::CompletionCallback cb =
389 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileWritten); 434 callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileWritten);
390 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Write(io_offset_, 435 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Write(io_offset_,
391 &io_buffer_[io_offset_], 436 &io_buffer_[io_offset_],
392 io_buffer_.size() - io_offset_, 437 io_buffer_.size() - io_offset_,
393 cb), 438 cb),
394 WRITE_ERROR); 439 WRITE_ERROR);
395 } 440 }
396 441
397 void CdmFileIOImpl::OnFileWritten(int32_t bytes_written) { 442 void CdmFileIOImpl::OnTempFileWritten(int32_t bytes_written) {
398 CDM_DLOG() << __FUNCTION__ << ": " << bytes_written; 443 CDM_DLOG() << __FUNCTION__ << ": " << bytes_written;
399 PP_DCHECK(IsMainThread()); 444 PP_DCHECK(IsMainThread());
400 PP_DCHECK(state_ == WRITING_FILE); 445 PP_DCHECK(state_ == STATE_WRITING);
401 446
402 if (bytes_written <= PP_OK) { 447 if (bytes_written <= PP_OK) {
403 CDM_DLOG() << "Write file failed."; 448 CDM_DLOG() << "Write temporary file failed.";
404 OnError(READ_ERROR); 449 state_ = STATE_ERROR;
450 OnError(WRITE_ERROR);
405 return; 451 return;
406 } 452 }
407 453
408 io_offset_ += bytes_written; 454 io_offset_ += bytes_written;
409 PP_DCHECK(io_offset_ <= io_buffer_.size()); 455 PP_DCHECK(io_offset_ <= io_buffer_.size());
410 456
411 if (io_offset_ < io_buffer_.size()) { 457 if (io_offset_ < io_buffer_.size()) {
412 WriteFile(); 458 WriteTempFile();
413 return; 459 return;
414 } 460 }
415 461
416 io_buffer_.clear(); 462 // All data written. Now rename the temporary file to the real file.
417 io_offset_ = 0; 463 RenameTempFile();
418 state_ = FILE_OPENED; 464 }
465
466 void CdmFileIOImpl::RenameTempFile() {
ddorwin 2014/09/16 18:07:37 Comment that this is actually a move and thus over
xhwang 2014/09/17 21:02:31 Done.
467 PP_DCHECK(state_ == STATE_WRITING);
468
469 pp::CompletionCallback cb =
470 callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileRenamed);
471 CHECK_PP_OK_COMPLETIONPENDING(
472 file_ref_.Rename(pp::FileRef(file_system_, file_name_.c_str()), cb),
473 WRITE_ERROR);
474 }
475
476 void CdmFileIOImpl::OnTempFileRenamed(int32_t result) {
477 CDM_DLOG() << __FUNCTION__ << ": " << result;
478 PP_DCHECK(IsMainThread());
479 PP_DCHECK(state_ == STATE_WRITING);
480
481 if (result != PP_OK) {
482 CDM_DLOG() << "Rename temporary file failed.";
483 state_ = STATE_ERROR;
484 OnError(WRITE_ERROR);
485 return;
486 }
487
488 Reset();
ddorwin 2014/09/16 18:07:36 Note: The period between line 471 and here is the
xhwang 2014/09/17 21:02:31 Added comment in .h file
489
490 state_ = STATE_OPENED;
419 client_->OnWriteComplete(cdm::FileIOClient::kSuccess); 491 client_->OnWriteComplete(cdm::FileIOClient::kSuccess);
420 } 492 }
421 493
422 void CdmFileIOImpl::CloseFile() { 494 void CdmFileIOImpl::Reset() {
423 PP_DCHECK(IsMainThread()); 495 PP_DCHECK(IsMainThread());
424
425 state_ = FILE_CLOSED;
426
427 file_io_.Close();
428 io_buffer_.clear(); 496 io_buffer_.clear();
429 io_offset_ = 0; 497 io_offset_ = 0;
430 cumulative_read_buffer_.clear(); 498 cumulative_read_buffer_.clear();
499 file_io_.Close();
500 file_io_.detach();
ddorwin 2014/09/16 18:07:37 Why detach? This is leaking a reference I believe.
xhwang 2014/09/17 21:02:31 Done.
501 file_ref_.detach();
431 } 502 }
432 503
433 void CdmFileIOImpl::OnError(ErrorType error_type) { 504 void CdmFileIOImpl::OnError(ErrorType error_type) {
434 // For *_WHILE_IN_USE errors, do not reset these values. Otherwise, the 505 // For *_WHILE_IN_USE errors, do not reset these values. Otherwise, the
435 // existing read/write operation will fail. 506 // existing read/write operation will fail.
436 if (error_type == READ_ERROR || error_type == WRITE_ERROR) { 507 if (error_type == READ_ERROR || error_type == WRITE_ERROR)
437 io_buffer_.clear(); 508 Reset();
438 io_offset_ = 0; 509
439 cumulative_read_buffer_.clear();
440 }
441 PostOnMain(callback_factory_.NewCallback(&CdmFileIOImpl::NotifyClientOfError, 510 PostOnMain(callback_factory_.NewCallback(&CdmFileIOImpl::NotifyClientOfError,
442 error_type)); 511 error_type));
443 } 512 }
444 513
445 void CdmFileIOImpl::NotifyClientOfError(int32_t result, 514 void CdmFileIOImpl::NotifyClientOfError(int32_t result,
446 ErrorType error_type) { 515 ErrorType error_type) {
447 PP_DCHECK(result == PP_OK); 516 PP_DCHECK(result == PP_OK);
448 switch (error_type) { 517 switch (error_type) {
449 case OPEN_ERROR: 518 case OPEN_ERROR:
450 client_->OnOpenComplete(cdm::FileIOClient::kError); 519 client_->OnOpenComplete(cdm::FileIOClient::kError);
(...skipping 10 matching lines...) Expand all
461 case READ_WHILE_IN_USE: 530 case READ_WHILE_IN_USE:
462 client_->OnReadComplete(cdm::FileIOClient::kInUse, NULL, 0); 531 client_->OnReadComplete(cdm::FileIOClient::kInUse, NULL, 0);
463 break; 532 break;
464 case WRITE_WHILE_IN_USE: 533 case WRITE_WHILE_IN_USE:
465 client_->OnWriteComplete(cdm::FileIOClient::kInUse); 534 client_->OnWriteComplete(cdm::FileIOClient::kInUse);
466 break; 535 break;
467 } 536 }
468 } 537 }
469 538
470 } // namespace media 539 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698