OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | |
2 // source code is governed by a BSD-style license that can be found in the | |
3 // LICENSE file. | |
4 | |
5 #include "base/compiler_specific.h" | |
6 #include "base/message_loop.h" | |
7 #include "base/process_util.h" | |
8 #include "chrome/renderer/media/data_source_impl.h" | |
9 #include "chrome/renderer/render_view.h" | |
10 #include "chrome/renderer/webmediaplayer_delegate_impl.h" | |
11 #include "chrome/renderer/render_thread.h" | |
12 #include "media/base/filter_host.h" | |
13 #include "net/base/load_flags.h" | |
14 #include "net/base/net_errors.h" | |
15 #include "webkit/glue/webappcachecontext.h" | |
16 | |
17 DataSourceImpl::DataSourceImpl(WebMediaPlayerDelegateImpl* delegate) | |
18 : delegate_(delegate), | |
19 render_loop_(RenderThread::current()->message_loop()), | |
20 stopped_(false), | |
21 download_event_(false, false), | |
22 downloaded_bytes_(0), | |
23 total_bytes_(0), | |
24 total_bytes_known_(false), | |
25 download_completed_(false), | |
26 resource_loader_bridge_(NULL), | |
27 read_event_(false, false), | |
28 ALLOW_THIS_IN_INITIALIZER_LIST( | |
29 read_callback_(this, &DataSourceImpl::OnDidFileStreamRead)), | |
30 stream_(NULL), | |
31 last_read_size_(0), | |
32 position_(0), | |
33 io_loop_(delegate->view()->GetMessageLoopForIO()), | |
34 seek_event_(false, false) { | |
35 } | |
36 | |
37 DataSourceImpl::~DataSourceImpl() { | |
38 } | |
39 | |
40 void DataSourceImpl::Stop() { | |
41 AutoLock auto_lock(lock_); | |
42 if (stopped_) | |
43 return; | |
44 stopped_ = true; | |
45 | |
46 // Wakes up demuxer waiting on |read_event_| in Read(). | |
47 read_event_.Signal(); | |
48 // Wakes up demuxer waiting on |seek_event_| in SetPosition(). | |
49 seek_event_.Signal(); | |
50 // Wakes up demuxer waiting on |download_event_| in Read() or SetPosition(). | |
51 download_event_.Signal(); | |
52 | |
53 render_loop_->PostTask(FROM_HERE, | |
54 NewRunnableMethod(this, &DataSourceImpl::OnDestroy)); | |
55 } | |
56 | |
57 bool DataSourceImpl::Initialize(const std::string& url) { | |
58 media_format_.SetAsString(media::MediaFormat::kMimeType, | |
59 media::mime_type::kApplicationOctetStream); | |
60 media_format_.SetAsString(media::MediaFormat::kURL, url); | |
61 render_loop_->PostTask(FROM_HERE, | |
62 NewRunnableMethod(this, &DataSourceImpl::OnInitialize, url)); | |
63 return true; | |
64 } | |
65 | |
66 size_t DataSourceImpl::Read(uint8* data, size_t size) { | |
67 DCHECK(stream_.get()); | |
68 // Wait until we have downloaded the requested bytes. | |
69 while (true) { | |
70 { | |
71 AutoLock auto_lock(lock_); | |
72 if (stopped_ || download_completed_ || | |
73 position_ + size <= downloaded_bytes_) | |
74 break; | |
75 } | |
76 download_event_.Wait(); | |
77 } | |
78 | |
79 last_read_size_ = media::DataSource::kReadError; | |
80 if (logging::DEBUG_MODE) { | |
81 AutoLock auto_lock(lock_); | |
82 DCHECK(stopped_ || download_completed_ || | |
83 position_ + size <= downloaded_bytes_); | |
84 } | |
85 | |
86 // Post a task to IO message loop to perform the actual reading. | |
87 bool task_posted = false; | |
88 { | |
89 AutoLock auto_lock(lock_); | |
90 if (!stopped_) { | |
91 io_loop_->PostTask(FROM_HERE, | |
92 NewRunnableMethod(this, &DataSourceImpl::OnReadFileStream, | |
93 data, size)); | |
94 task_posted = true; | |
95 } | |
96 } | |
97 | |
98 if (task_posted) | |
99 read_event_.Wait(); | |
100 | |
101 { | |
102 AutoLock auto_lock(lock_); | |
103 if (!stopped_) | |
104 return last_read_size_; | |
105 return media::DataSource::kReadError; | |
106 } | |
107 } | |
108 | |
109 bool DataSourceImpl::GetPosition(int64* position_out) { | |
110 AutoLock auto_lock(lock_); | |
111 *position_out = position_; | |
112 return true; | |
113 } | |
114 | |
115 bool DataSourceImpl::SetPosition(int64 position) { | |
116 DCHECK(stream_.get()); | |
117 while (true) { | |
118 { | |
119 AutoLock auto_lock(lock_); | |
120 if (stopped_ || download_completed_ || position < downloaded_bytes_) | |
121 break; | |
122 } | |
123 download_event_.Wait(); | |
124 } | |
125 | |
126 if (logging::DEBUG_MODE) { | |
127 AutoLock auto_lock(lock_); | |
128 DCHECK(stopped_ || download_completed_ || position < downloaded_bytes_); | |
129 } | |
130 | |
131 // Perform the seek operation on IO message loop. | |
132 bool task_posted = false; | |
133 { | |
134 AutoLock auto_lock(lock_); | |
135 if (!stopped_) { | |
136 io_loop_->PostTask(FROM_HERE, | |
137 NewRunnableMethod(this, | |
138 &DataSourceImpl::OnSeekFileStream, net::FROM_BEGIN, position)); | |
139 task_posted = true; | |
140 } | |
141 } | |
142 if (task_posted) | |
143 seek_event_.Wait(); | |
144 | |
145 if (logging::DEBUG_MODE) { | |
146 AutoLock auto_lock_(lock_); | |
147 DCHECK(stopped_ || position == position_); | |
148 } | |
149 return true; | |
150 } | |
151 | |
152 bool DataSourceImpl::GetSize(int64* size_out) { | |
153 AutoLock auto_lock(lock_); | |
154 if (total_bytes_known_) { | |
155 *size_out = total_bytes_; | |
156 return true; | |
157 } | |
158 *size_out = 0; | |
159 return false; | |
160 } | |
161 | |
162 bool DataSourceImpl::IsSeekable() { | |
163 // If URI is file then it is seekable. | |
164 // TODO(hclam): make other protocols seekable. | |
165 return uri_.find("file:///") == 0; | |
166 } | |
167 | |
168 void DataSourceImpl::OnCreateFileStream(base::PlatformFile file) { | |
169 AutoLock auto_lock(lock_); | |
170 if (stopped_) | |
171 return; | |
172 stream_.reset( | |
173 new net::FileStream( | |
174 file, base::PLATFORM_FILE_READ | base::PLATFORM_FILE_ASYNC)); | |
175 // TODO(hclam): maybe we should check the validity of the file handle. | |
176 host_->InitializationComplete(); | |
177 } | |
178 | |
179 void DataSourceImpl::OnReadFileStream(uint8* data, size_t size) { | |
180 int error = net::ERR_IO_PENDING; | |
181 { | |
182 AutoLock auto_lock(lock_); | |
183 if (!stopped_) { | |
184 // net::FileStream::Read wants a char*, not uint8*. | |
185 char* c_data = reinterpret_cast<char*>(data); | |
186 COMPILE_ASSERT(sizeof(*c_data) == sizeof(*data), data_not_sizeof_char); | |
187 error = stream_->Read(c_data, size, &read_callback_); | |
188 } | |
189 } | |
190 | |
191 // Since the file handle is asynchronous, return value other than | |
192 // ERROR_IO_PENDING is an error. | |
193 if (error != net::ERR_IO_PENDING) { | |
194 HandleError(media::PIPELINE_ERROR_READ); | |
195 } | |
196 } | |
197 | |
198 void DataSourceImpl::OnSeekFileStream(net::Whence whence, int64 position) { | |
199 { | |
200 AutoLock auto_lock(lock_); | |
201 if (!stopped_) | |
202 position_ = stream_->Seek(whence, position); | |
203 } | |
204 seek_event_.Signal(); | |
205 } | |
206 | |
207 void DataSourceImpl::OnDidFileStreamRead(int size) { | |
208 if (size < 0) { | |
209 HandleError(media::PIPELINE_ERROR_READ); | |
210 } else { | |
211 AutoLock auto_lock(lock_); | |
212 position_ += size; | |
213 } | |
214 last_read_size_ = size; | |
215 read_event_.Signal(); | |
216 } | |
217 | |
218 void DataSourceImpl::OnInitialize(std::string uri) { | |
219 uri_ = uri; | |
220 // Create the resource loader bridge. | |
221 resource_loader_bridge_.reset( | |
222 RenderThread::current()->resource_dispatcher()->CreateBridge( | |
223 "GET", | |
224 GURL(uri), | |
225 GURL(uri), | |
226 GURL(), // TODO(hclam): provide referer here. | |
227 "null", // TODO(abarth): provide frame_origin | |
228 "null", // TODO(abarth): provide main_frame_origin | |
229 std::string(), // Provide no header. | |
230 // Prefer to load from cache, also enable downloading the file, the | |
231 // resource will be saved to a single response data file if it's possible. | |
232 net::LOAD_PREFERRING_CACHE | net::LOAD_ENABLE_DOWNLOAD_FILE, | |
233 base::GetCurrentProcId(), | |
234 ResourceType::MEDIA, | |
235 0, | |
236 // TODO(michaeln): delegate->mediaplayer->frame-> | |
237 // app_cache_context()->context_id() | |
238 // For now don't service media resource requests from the appcache. | |
239 WebAppCacheContext::kNoAppCacheContextId, | |
240 delegate_->view()->routing_id())); | |
241 // Start the resource loading. | |
242 resource_loader_bridge_->Start(this); | |
243 } | |
244 | |
245 void DataSourceImpl::OnDestroy() { | |
246 DCHECK(MessageLoop::current() == render_loop_); | |
247 resource_loader_bridge_->Cancel(); | |
248 resource_loader_bridge_.reset(); | |
249 } | |
250 | |
251 void DataSourceImpl::OnDownloadProgress(uint64 position, uint64 size) { | |
252 { | |
253 AutoLock auto_lock(lock_); | |
254 downloaded_bytes_ = position; | |
255 if (!total_bytes_known_) { | |
256 if (size == kuint64max) { | |
257 // If we receive an invalid value for size, we keep on updating the | |
258 // total number of bytes. | |
259 total_bytes_ = position; | |
260 } else { | |
261 total_bytes_ = size; | |
262 total_bytes_known_ = true; | |
263 } | |
264 } | |
265 } | |
266 host_->SetBufferedBytes(downloaded_bytes_); | |
267 download_event_.Signal(); | |
268 } | |
269 | |
270 void DataSourceImpl::OnUploadProgress(uint64 position, uint64 size) { | |
271 // We don't care about upload progress. | |
272 } | |
273 | |
274 void DataSourceImpl::OnReceivedRedirect(const GURL& new_url) { | |
275 // TODO(hclam): what to do here? fire another resource request or show an | |
276 // error? | |
277 } | |
278 | |
279 void DataSourceImpl::OnReceivedResponse( | |
280 const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, | |
281 bool content_filtered) { | |
282 #if defined(OS_POSIX) | |
283 base::PlatformFile response_data_file = info.response_data_file.fd; | |
284 #elif defined(OS_WIN) | |
285 base::PlatformFile response_data_file = info.response_data_file; | |
286 #endif | |
287 | |
288 if (response_data_file != base::kInvalidPlatformFileValue) { | |
289 DCHECK(!position_ && !downloaded_bytes_); | |
290 if (info.content_length != -1) { | |
291 total_bytes_known_ = true; | |
292 total_bytes_ = info.content_length; | |
293 host_->SetTotalBytes(total_bytes_); | |
294 } | |
295 | |
296 { | |
297 // Post a task to the IO message loop to create the file stream. | |
298 // We don't want to post any more tasks once we are stopped. | |
299 AutoLock auto_lock(lock_); | |
300 if (!stopped_) { | |
301 io_loop_->PostTask(FROM_HERE, | |
302 NewRunnableMethod(this, &DataSourceImpl::OnCreateFileStream, | |
303 response_data_file)); | |
304 } | |
305 } | |
306 } else { | |
307 // TODO(hclam): handle the fallback case of using memory buffer here. | |
308 HandleError(media::PIPELINE_ERROR_NETWORK); | |
309 } | |
310 } | |
311 | |
312 void DataSourceImpl::OnReceivedData(const char* data, int len) { | |
313 // TODO(hclam): we will get this method call when browser process fails | |
314 // to provide us with a file handle, come up with some fallback mechanism. | |
315 } | |
316 | |
317 void DataSourceImpl::OnCompletedRequest(const URLRequestStatus& status, | |
318 const std::string& security_info) { | |
319 { | |
320 AutoLock auto_lock(lock_); | |
321 total_bytes_known_ = true; | |
322 download_completed_ = true; | |
323 } | |
324 if (status.status() != URLRequestStatus::SUCCESS) { | |
325 HandleError(media::PIPELINE_ERROR_NETWORK); | |
326 } | |
327 } | |
328 | |
329 void DataSourceImpl::HandleError(media::PipelineError error) { | |
330 AutoLock auto_lock(lock_); | |
331 if (!stopped_) { | |
332 host_->Error(error); | |
333 } | |
334 } | |
335 | |
336 std::string DataSourceImpl::GetURLForDebugging() { | |
337 return uri_; | |
338 } | |
339 | |
340 const media::MediaFormat& DataSourceImpl::media_format() { | |
341 return media_format_; | |
342 } | |
OLD | NEW |