| 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 |