OLD | NEW |
---|---|
(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; \ | |
22 PP_DCHECK(result != PP_OK); \ | |
23 if (result != PP_OK_COMPLETIONPENDING) { \ | |
24 std::ostringstream error_message; \ | |
ddorwin
2013/12/11 21:16:17
can we pipe directly to the DVLOG and eliminate th
xhwang
2013/12/13 02:51:47
Done.
| |
25 error_message << #func_call << " failed with result: " << result; \ | |
26 DVLOG(3) << error_message; \ | |
27 OnError(error_type); \ | |
28 return; \ | |
29 } \ | |
30 } while (0) | |
31 | |
32 // 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 | |
34 // 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. | |
36 static bool IsMainThread() { | |
37 return pp::Module::Get()->core()->IsMainThread(); | |
38 } | |
39 | |
40 // Posts a task to run |cb| on the main thread. The task is posted even if the | |
41 // current thread is the main thread. | |
42 static void PostOnMain(pp::CompletionCallback cb) { | |
43 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK); | |
44 } | |
45 | |
46 CdmFileIOImpl::CdmFileIOImpl(cdm::FileIOClient* client, PP_Instance pp_instance) | |
47 : state_(FILE_UNOPENED), | |
48 client_(client), | |
49 pp_instance_handle_(pp_instance), | |
50 callback_factory_(this), | |
51 io_offset_(0) { | |
52 PP_DCHECK(IsMainThread()); | |
53 PP_DCHECK(pp_instance); // 0 indicates a "NULL handle". | |
54 } | |
55 | |
56 CdmFileIOImpl::~CdmFileIOImpl() { | |
57 if (state_ != FILE_CLOSED) | |
58 CloseFile(); | |
59 } | |
60 | |
61 // Call sequence: Open() -> OpenFileSystem() -> OpenFile() -> FILE_OPENED. | |
62 void CdmFileIOImpl::Open(const char* file_name, uint32_t file_name_size) { | |
63 DVLOG(3) << __FUNCTION__; | |
64 PP_DCHECK(IsMainThread()); | |
65 | |
66 if (state_ != FILE_UNOPENED) { | |
67 DVLOG(3) << "Open() called in an invalid state."; | |
ddorwin
2013/12/11 21:16:17
CDM_DLOG?
xhwang
2013/12/13 02:51:47
Done.
| |
68 OnError(OPEN_ERROR); | |
69 return; | |
70 } | |
71 | |
72 state_ = OPENING_FILE_SYSTEM; | |
73 | |
74 // File name should not contain any path separators. | |
75 std::string file_name_str(file_name, file_name_size); | |
76 if (file_name_str.find('/') != std::string::npos || | |
77 file_name_str.find('\\') != std::string::npos) { | |
78 DVLOG(3) << "Invalid file name."; | |
79 OnError(OPEN_ERROR); | |
80 return; | |
81 } | |
82 | |
83 // pp::FileRef only accepts path that begins with a '/' character. | |
84 file_name_ = '/' + file_name_str; | |
85 OpenFileSystem(); | |
86 } | |
87 | |
88 // Call sequence: | |
89 // finished | |
90 // Read() -> ReadFile() -> OnFileRead() ----------> Done. | |
91 // ^ | | |
92 // | not finished | | |
93 // |--------------| | |
94 void CdmFileIOImpl::Read() { | |
95 DVLOG(3) << __FUNCTION__; | |
96 PP_DCHECK(IsMainThread()); | |
97 | |
98 if (state_ != FILE_OPENED) { | |
99 DVLOG(3) << "Read() called in an invalid state."; | |
100 OnError(READ_ERROR); | |
101 return; | |
102 } | |
103 | |
104 PP_DCHECK(io_buffer_.empty()); | |
105 PP_DCHECK(cumulative_read_buffer_.empty()); | |
106 | |
107 io_buffer_.resize(kReadSize); | |
108 io_offset_ = 0; | |
109 | |
110 state_ = READING_FILE; | |
111 ReadFile(); | |
112 } | |
113 | |
114 // Call sequence: | |
115 // finished | |
116 // Write() -> WriteFile() -> OnFileWritten() ----------> Done. | |
117 // ^ | | |
118 // | | not finished | |
119 // |------------------| | |
120 void CdmFileIOImpl::Write(const uint8_t* data, uint32_t data_size) { | |
121 DVLOG(3) << __FUNCTION__; | |
122 PP_DCHECK(IsMainThread()); | |
123 | |
124 if (state_ != FILE_OPENED) { | |
125 DVLOG(3) << "Write() called in an invalid state."; | |
126 OnError(WRITE_ERROR); | |
127 return; | |
128 } | |
129 | |
130 // TODO(xhwang): Support NULL |data|. | |
131 PP_DCHECK(data); | |
132 | |
133 io_buffer_.assign(data, data + data_size); | |
134 io_offset_ = 0; | |
135 | |
136 state_ = WRITING_FILE; | |
137 WriteFile(); | |
138 } | |
139 | |
140 void CdmFileIOImpl::Close() { | |
141 PP_DCHECK(IsMainThread()); | |
142 if (state_ != FILE_CLOSED) | |
143 CloseFile(); | |
144 delete this; | |
145 } | |
146 | |
147 void CdmFileIOImpl::OpenFileSystem() { | |
148 DVLOG(3) << __FUNCTION__; | |
149 PP_DCHECK(state_ == OPENING_FILE_SYSTEM); | |
150 | |
151 pp::CompletionCallbackWithOutput<pp::FileSystem> cb = | |
152 callback_factory_.NewCallbackWithOutput( | |
153 &CdmFileIOImpl::OnFileSystemOpened); | |
154 isolated_file_system_ = pp::IsolatedFileSystemPrivate( | |
155 pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE); | |
156 | |
157 CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system_.Open(cb), OPEN_ERROR); | |
158 } | |
159 | |
160 void CdmFileIOImpl::OnFileSystemOpened(int32_t result, | |
161 pp::FileSystem file_system) { | |
162 DVLOG(3) << __FUNCTION__; | |
163 PP_DCHECK(IsMainThread()); | |
164 PP_DCHECK(state_ == OPENING_FILE_SYSTEM); | |
165 | |
166 if (result != PP_OK) { | |
167 DVLOG(3) << "File system open failed asynchronously."; | |
168 OnError(OPEN_ERROR); | |
169 return; | |
170 } | |
171 | |
172 file_system_ = file_system; | |
173 state_ = OPENING_FILE; | |
174 OpenFile(); | |
175 } | |
176 | |
177 void CdmFileIOImpl::OpenFile() { | |
178 DVLOG(3) << __FUNCTION__; | |
179 PP_DCHECK(state_ == OPENING_FILE); | |
180 | |
181 file_io_ = pp::FileIO(pp_instance_handle_); | |
182 file_ref_ = pp::FileRef(file_system_, file_name_.c_str()); | |
183 int32_t file_open_flag = PP_FILEOPENFLAG_READ | | |
184 PP_FILEOPENFLAG_WRITE | | |
185 PP_FILEOPENFLAG_CREATE; | |
186 pp::CompletionCallback cb = | |
187 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpened); | |
188 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb), | |
189 OPEN_ERROR); | |
190 } | |
191 | |
192 void CdmFileIOImpl::OnFileOpened(int32_t result) { | |
193 PP_DCHECK(IsMainThread()); | |
194 PP_DCHECK(state_ == OPENING_FILE); | |
195 | |
196 if (result != PP_OK) { | |
197 DVLOG(3) << "File open failed."; | |
198 OnError(OPEN_ERROR); | |
199 return; | |
200 } | |
201 | |
202 state_ = FILE_OPENED; | |
203 client_->OnOpenComplete(cdm::FileIOClient::kSuccess); | |
204 } | |
205 | |
206 void CdmFileIOImpl::ReadFile() { | |
207 PP_DCHECK(state_ == READING_FILE); | |
208 PP_DCHECK(!io_buffer_.empty()); | |
209 | |
210 pp::CompletionCallback cb = | |
211 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead); | |
212 CHECK_PP_OK_COMPLETIONPENDING( | |
213 file_io_.Read(io_offset_, &io_buffer_[0], io_buffer_.size(), cb), | |
214 READ_ERROR); | |
215 } | |
216 | |
217 void CdmFileIOImpl::OnFileRead(int32_t bytes_read) { | |
218 PP_DCHECK(IsMainThread()); | |
219 PP_DCHECK(state_ == READING_FILE); | |
220 | |
221 // 0 |bytes_read| indicates end-of-file reached. | |
222 if (bytes_read < PP_OK) { | |
223 DVLOG(3) << "Read file failed."; | |
224 OnError(READ_ERROR); | |
225 return; | |
226 } | |
227 | |
228 PP_DCHECK(static_cast<size_t>(bytes_read) <= io_buffer_.size()); | |
229 // Append |bytes_read| in |io_buffer_| to |cumulative_read_buffer_|. | |
230 cumulative_read_buffer_.insert(cumulative_read_buffer_.end(), | |
231 io_buffer_.begin(), | |
232 io_buffer_.begin() + bytes_read); | |
233 io_offset_ += bytes_read; | |
234 | |
235 // Not received end-of-file yet. | |
236 if (bytes_read > 0) { | |
237 ReadFile(); | |
238 return; | |
239 } | |
240 | |
241 // We hit end-of-file. Return read data to the client. | |
242 io_buffer_.clear(); | |
243 io_offset_ = 0; | |
244 // Clear |cumulative_read_buffer_| in case OnReadComplete() calls Read() or | |
245 // Write(). | |
246 std::vector<char> local_buffer; | |
247 std::swap(cumulative_read_buffer_, local_buffer); | |
248 | |
249 state_ = FILE_OPENED; | |
250 client_->OnReadComplete(cdm::FileIOClient::kSuccess, | |
251 reinterpret_cast<const uint8_t*>(&local_buffer[0]), | |
252 local_buffer.size()); | |
253 } | |
254 | |
255 void CdmFileIOImpl::WriteFile() { | |
256 PP_DCHECK(state_ == WRITING_FILE); | |
257 PP_DCHECK(io_offset_ < io_buffer_.size()); | |
258 | |
259 pp::CompletionCallback cb = | |
260 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileWritten); | |
261 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Write(io_offset_, | |
262 &io_buffer_[io_offset_], | |
263 io_buffer_.size() - io_offset_, | |
264 cb), | |
265 WRITE_ERROR); | |
266 } | |
267 | |
268 void CdmFileIOImpl::OnFileWritten(int32_t bytes_written) { | |
269 PP_DCHECK(IsMainThread()); | |
270 PP_DCHECK(state_ == WRITING_FILE); | |
271 | |
272 if (bytes_written <= PP_OK) { | |
273 DVLOG(3) << "Write file failed."; | |
274 OnError(READ_ERROR); | |
275 return; | |
276 } | |
277 | |
278 io_offset_ += bytes_written; | |
279 PP_DCHECK(io_offset_ <= io_buffer_.size()); | |
280 | |
281 if (io_offset_ < io_buffer_.size()) { | |
282 WriteFile(); | |
283 return; | |
284 } | |
285 | |
286 io_buffer_.clear(); | |
287 io_offset_ = 0; | |
288 state_ = FILE_OPENED; | |
289 client_->OnWriteComplete(cdm::FileIOClient::kSuccess); | |
290 } | |
291 | |
292 void CdmFileIOImpl::CloseFile() { | |
293 DVLOG(3) << __FUNCTION__; | |
294 PP_DCHECK(IsMainThread()); | |
295 | |
296 state_ = FILE_CLOSED; | |
297 | |
298 file_io_.Close(); | |
299 io_buffer_.clear(); | |
300 io_offset_ = 0; | |
301 cumulative_read_buffer_.clear(); | |
302 } | |
303 | |
304 void CdmFileIOImpl::OnError(ErrorType error_type) { | |
305 io_buffer_.clear(); | |
306 cumulative_read_buffer_.clear(); | |
ddorwin
2013/12/11 21:16:17
reset offset too?
xhwang
2013/12/13 02:51:47
Done.
| |
307 PostOnMain(callback_factory_.NewCallback(&CdmFileIOImpl::NotifyClientOfError, | |
308 error_type)); | |
309 } | |
310 | |
311 void CdmFileIOImpl::NotifyClientOfError(int32_t result, | |
312 ErrorType error_type) { | |
313 DCHECK(result == PP_OK); | |
ddorwin
2013/12/11 21:16:17
PP_ ?
xhwang
2013/12/13 02:51:47
Done.
| |
314 switch (error_type) { | |
315 case OPEN_ERROR: | |
316 client_->OnOpenComplete(cdm::FileIOClient::kError); | |
317 break; | |
318 case READ_ERROR: | |
319 client_->OnReadComplete(cdm::FileIOClient::kError, NULL, 0); | |
320 break; | |
321 case WRITE_ERROR: | |
322 client_->OnWriteComplete(cdm::FileIOClient::kError); | |
323 break; | |
324 } | |
325 } | |
326 | |
327 } // namespace media | |
OLD | NEW |