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 "base/string_util.h" |
| 9 #include "chrome/common/extensions/url_pattern.h" |
| 10 #include "chrome/renderer/media/buffered_data_source.h" |
| 11 #include "chrome/renderer/render_view.h" |
| 12 #include "chrome/renderer/webmediaplayer_delegate_impl.h" |
| 13 #include "chrome/renderer/render_thread.h" |
| 14 #include "media/base/filter_host.h" |
| 15 #include "net/base/load_flags.h" |
| 16 #include "net/base/net_errors.h" |
| 17 #include "net/http/http_response_headers.h" |
| 18 #include "webkit/glue/webappcachecontext.h" |
| 19 |
| 20 namespace { |
| 21 |
| 22 const char kHttpScheme[] = "http"; |
| 23 const char kHttpsScheme[] = "https"; |
| 24 const int64 kPositionNotSpecified = -1; |
| 25 const int kHttpOK = 200; |
| 26 const int kHttpPartialContent = 206; |
| 27 |
| 28 // A helper method that accepts only HTTP, HTTPS and FILE protocol. |
| 29 bool IsSchemeSupported(const GURL& url) { |
| 30 return url.SchemeIs(kHttpScheme) || |
| 31 url.SchemeIs(kHttpsScheme) || |
| 32 url.SchemeIsFile(); |
| 33 } |
| 34 |
| 35 } // namespace |
| 36 |
| 37 ///////////////////////////////////////////////////////////////////////////// |
| 38 // BufferedResourceLoader |
| 39 BufferedResourceLoader::BufferedResourceLoader(int route_id, |
| 40 const GURL& url, |
| 41 int64 first_byte_position, |
| 42 int64 last_byte_position) |
| 43 : start_callback_(NULL), |
| 44 bridge_(NULL), |
| 45 offset_(0), |
| 46 content_length_(kPositionNotSpecified), |
| 47 buffered_bytes_(0), |
| 48 buffer_limit_(10240000), // By default 10MB. |
| 49 buffer_event_(false, false), |
| 50 deferred_(false), |
| 51 stopped_(false), |
| 52 completed_(false), |
| 53 range_requested_(false), |
| 54 async_start_(false), |
| 55 route_id_(route_id), |
| 56 url_(url), |
| 57 first_byte_position_(first_byte_position), |
| 58 last_byte_position_(last_byte_position), |
| 59 render_loop_(RenderThread::current()->message_loop()) { |
| 60 } |
| 61 |
| 62 BufferedResourceLoader::~BufferedResourceLoader() { |
| 63 for (size_t i = 0; i < buffers_.size(); ++i) |
| 64 delete buffers_[i]; |
| 65 buffers_.clear(); |
| 66 } |
| 67 |
| 68 int BufferedResourceLoader::Start(net::CompletionCallback* start_callback) { |
| 69 // Make sure we only start no more than once. |
| 70 DCHECK(!bridge_.get()); |
| 71 DCHECK(!start_callback_.get()); |
| 72 start_callback_.reset(start_callback); |
| 73 |
| 74 // Save the information that we are doing an asynchronous start since |
| 75 // start_callback_ may get reset, we can't rely on it. |
| 76 if (start_callback_.get()) |
| 77 async_start_ = true; |
| 78 |
| 79 std::string header; |
| 80 if (first_byte_position_ != kPositionNotSpecified && |
| 81 last_byte_position_ != kPositionNotSpecified) { |
| 82 header = StringPrintf("Range: bytes=%lld-%lld", |
| 83 first_byte_position_, |
| 84 last_byte_position_); |
| 85 range_requested_ = true; |
| 86 offset_ = first_byte_position_; |
| 87 } else if (first_byte_position_ != kPositionNotSpecified) { |
| 88 header = StringPrintf("Range: bytes=%lld-", first_byte_position_); |
| 89 range_requested_ = true; |
| 90 offset_ = first_byte_position_; |
| 91 } else if (last_byte_position_ != kPositionNotSpecified) { |
| 92 NOTIMPLEMENTED() << "Suffix length range request not implemented."; |
| 93 } |
| 94 |
| 95 bridge_.reset(RenderThread::current()->resource_dispatcher()->CreateBridge( |
| 96 "GET", |
| 97 GURL(url_), |
| 98 GURL(url_), |
| 99 GURL(), // TODO(hclam): provide referer here. |
| 100 "null", // TODO(abarth): provide frame_origin |
| 101 "null", // TODO(abarth): provide main_frame_origin |
| 102 header, |
| 103 net::LOAD_BYPASS_CACHE, |
| 104 base::GetCurrentProcId(), |
| 105 ResourceType::MEDIA, |
| 106 0, |
| 107 // TODO(michaeln): delegate->mediaplayer->frame-> |
| 108 // app_cache_context()->context_id() |
| 109 // For now don't service media resource requests from the appcache. |
| 110 WebAppCacheContext::kNoAppCacheContextId, |
| 111 route_id_)); |
| 112 |
| 113 // We may receive stop signal while we are inside this method, it's because |
| 114 // Start() may get called on demuxer thread while Stop() is called on |
| 115 // pipeline thread, so we want to protect the posting of OnStart() task |
| 116 // with a lock. |
| 117 bool task_posted = false; |
| 118 { |
| 119 AutoLock auto_lock(lock_); |
| 120 if (!stopped_) { |
| 121 task_posted = true; |
| 122 render_loop_->PostTask(FROM_HERE, |
| 123 NewRunnableMethod(this, &BufferedResourceLoader::OnStart)); |
| 124 } |
| 125 } |
| 126 |
| 127 // Wait for response to arrive we don't have an async start. |
| 128 if (task_posted && !async_start_) |
| 129 buffer_event_.Wait(); |
| 130 |
| 131 { |
| 132 AutoLock auto_lock(lock_); |
| 133 // We may have stopped because of a bad response from the server. |
| 134 if (stopped_) |
| 135 return net::ERR_ABORTED; |
| 136 else if (completed_) |
| 137 return net::ERR_FAILED; |
| 138 else if (async_start_) |
| 139 return net::ERR_IO_PENDING; |
| 140 return net::OK; |
| 141 } |
| 142 } |
| 143 |
| 144 void BufferedResourceLoader::Stop() { |
| 145 { |
| 146 AutoLock auto_lock(lock_); |
| 147 stopped_ = true; |
| 148 } |
| 149 |
| 150 // Wakes up the waiting thread so they can catch the stop signal. |
| 151 render_loop_->PostTask(FROM_HERE, |
| 152 NewRunnableMethod(this, &BufferedResourceLoader::OnDestroy)); |
| 153 buffer_event_.Signal(); |
| 154 } |
| 155 |
| 156 size_t BufferedResourceLoader::Read(uint8* data, size_t size) { |
| 157 size_t taken = 0; |
| 158 while (taken < size) { |
| 159 Buffer* buffer = NULL; |
| 160 { |
| 161 AutoLock auto_lock(lock_); |
| 162 if (stopped_) |
| 163 break; |
| 164 if (!buffers_.empty()) |
| 165 buffer = buffers_.front(); |
| 166 else if (completed_) |
| 167 break; |
| 168 } |
| 169 if (buffer) { |
| 170 size_t copy = std::min(size - taken, buffer->size - buffer->taken); |
| 171 memcpy(data + taken, buffer->data.get() + buffer->taken, copy); |
| 172 taken += copy; |
| 173 buffer->taken += copy; |
| 174 if (buffer->taken == buffer->size) { |
| 175 // The buffer has been consumed, remove it. |
| 176 { |
| 177 AutoLock auto_lock(lock_); |
| 178 buffers_.pop_front(); |
| 179 } |
| 180 delete buffer; |
| 181 } |
| 182 } else { |
| 183 buffer_event_.Wait(); |
| 184 } |
| 185 } |
| 186 if (taken > 0) { |
| 187 offset_ += taken; |
| 188 { |
| 189 AutoLock auto_lock(lock_); |
| 190 buffered_bytes_ -= taken; |
| 191 DCHECK(buffered_bytes_ >= 0); |
| 192 } |
| 193 if (ShouldDisableDefer()) { |
| 194 AutoLock auto_lock(lock_); |
| 195 if (!stopped_) { |
| 196 render_loop_->PostTask(FROM_HERE, |
| 197 NewRunnableMethod(this, |
| 198 &BufferedResourceLoader::OnDisableDeferLoading)); |
| 199 } |
| 200 } |
| 201 } |
| 202 return taken; |
| 203 } |
| 204 |
| 205 bool BufferedResourceLoader::SeekForward(int64 position) { |
| 206 // Use of |offset_| is safe without a lock, because it's modified only in |
| 207 // Read() and this method after Start(). Read() and SeekForward() happens |
| 208 // on the same thread. |
| 209 // Seeking backward. |
| 210 if (position < offset_) |
| 211 return false; |
| 212 // Done seeking forward. |
| 213 else if (position == offset_) |
| 214 return true; |
| 215 |
| 216 while(true) { |
| 217 { |
| 218 AutoLock auto_lock(lock_); |
| 219 // Loader has stopped. |
| 220 if (stopped_) |
| 221 return false; |
| 222 // Seek position exceeds bufferable range, buffer_limit_ can be changed. |
| 223 if (position >= offset_ + buffer_limit_) |
| 224 return false; |
| 225 // Response completed and seek position exceeds buffered range. |
| 226 if (completed_ && position >= offset_ + buffered_bytes_) |
| 227 return false; |
| 228 |
| 229 if (!buffers_.empty()) { |
| 230 Buffer* buffer = buffers_.front(); |
| 231 int64 bytes_to_take = position - offset_; |
| 232 if (!buffers_.empty()) { |
| 233 size_t available_bytes_in_buffer = buffer->size - buffer->taken; |
| 234 size_t taken = 0; |
| 235 if (available_bytes_in_buffer <= bytes_to_take) { |
| 236 taken = available_bytes_in_buffer; |
| 237 buffers_.pop_front(); |
| 238 delete buffer; |
| 239 } else { |
| 240 taken = static_cast<size_t>(bytes_to_take); |
| 241 buffer->taken += taken; |
| 242 } |
| 243 offset_ += taken; |
| 244 if (bytes_to_take == taken) |
| 245 return true; |
| 246 } |
| 247 continue; |
| 248 } |
| 249 } |
| 250 buffer_event_.Wait(); |
| 251 } |
| 252 } |
| 253 |
| 254 int64 BufferedResourceLoader::GetOffset() { |
| 255 AutoLock auto_lock(lock_); |
| 256 return offset_; |
| 257 } |
| 258 |
| 259 int64 BufferedResourceLoader::GetBufferLimit() { |
| 260 AutoLock auto_lock(lock_); |
| 261 return buffer_limit_; |
| 262 } |
| 263 |
| 264 void BufferedResourceLoader::SetBufferLimit(size_t buffer_limit) { |
| 265 { |
| 266 AutoLock auto_lock(lock_); |
| 267 buffer_limit_ = buffer_limit; |
| 268 } |
| 269 |
| 270 if (ShouldDisableDefer()) { |
| 271 AutoLock auto_lock(lock_); |
| 272 if (!stopped_) { |
| 273 render_loop_->PostTask(FROM_HERE, |
| 274 NewRunnableMethod(this, |
| 275 &BufferedResourceLoader::OnDisableDeferLoading)); |
| 276 } |
| 277 } |
| 278 if (ShouldEnableDefer()) { |
| 279 AutoLock auto_lock(lock_); |
| 280 if (!stopped_) { |
| 281 render_loop_->PostTask(FROM_HERE, |
| 282 NewRunnableMethod(this, |
| 283 &BufferedResourceLoader::OnEnableDeferLoading)); |
| 284 } |
| 285 } |
| 286 } |
| 287 |
| 288 size_t BufferedResourceLoader::GetTimeout() { |
| 289 // TODO(hclam): implement. |
| 290 return 0; |
| 291 } |
| 292 |
| 293 void BufferedResourceLoader::SetTimeout(size_t milliseconds) { |
| 294 // TODO(hclam): implement. |
| 295 } |
| 296 |
| 297 ///////////////////////////////////////////////////////////////////////////// |
| 298 // BufferedResourceLoader, |
| 299 // webkit_glue::ResourceLoaderBridge::Peer implementations |
| 300 void BufferedResourceLoader::OnReceivedRedirect(const GURL& new_url) { |
| 301 url_ = new_url; |
| 302 |
| 303 // If we got redirected to an unsupported protocol then stop. |
| 304 if (!IsSchemeSupported(new_url)) |
| 305 Stop(); |
| 306 } |
| 307 |
| 308 void BufferedResourceLoader::OnReceivedResponse( |
| 309 const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, |
| 310 bool content_filtered) { |
| 311 int64 first_byte_position = -1; |
| 312 int64 last_byte_position = -1; |
| 313 int64 instance_size = -1; |
| 314 |
| 315 // The file:// protocol should be able to serve any request we want, so we |
| 316 // take an exception for file protocol. |
| 317 if (!url_.SchemeIsFile()) { |
| 318 if (!info.headers) { |
| 319 // We expect to receive headers because this is a HTTP or HTTPS protocol, |
| 320 // if not report failure. |
| 321 InvokeAndResetStartCallback(net::ERR_INVALID_RESPONSE); |
| 322 Stop(); |
| 323 return; |
| 324 } else if (range_requested_) { |
| 325 if (info.headers->response_code() != kHttpPartialContent || |
| 326 !info.headers->GetContentRange(&first_byte_position, |
| 327 &last_byte_position, |
| 328 &instance_size)) { |
| 329 // We requested a range, but server didn't reply with partial content or |
| 330 // the "Content-Range" header is corrupted. |
| 331 InvokeAndResetStartCallback(net::ERR_INVALID_RESPONSE); |
| 332 Stop(); |
| 333 return; |
| 334 } |
| 335 } else if (info.headers->response_code() != kHttpOK) { |
| 336 // We didn't request a range but server didn't reply with "200 OK". |
| 337 InvokeAndResetStartCallback(net::ERR_FAILED); |
| 338 Stop(); |
| 339 return; |
| 340 } |
| 341 } |
| 342 |
| 343 { |
| 344 AutoLock auto_lock(lock_); |
| 345 // |info.content_length| can be -1, in that case |content_length_| is |
| 346 // not specified and this is a streaming response. |
| 347 content_length_ = info.content_length; |
| 348 // We only care about the first byte position if it's given by the server. |
| 349 if (first_byte_position != kPositionNotSpecified) |
| 350 offset_ = first_byte_position; |
| 351 } |
| 352 |
| 353 // If we have started asynchronously we just need to invoke the callback or |
| 354 // we need to signal the Start() method to wake up. |
| 355 if (async_start_) |
| 356 InvokeAndResetStartCallback(net::OK); |
| 357 else |
| 358 buffer_event_.Signal(); |
| 359 } |
| 360 |
| 361 void BufferedResourceLoader::OnReceivedData(const char* data, int len) { |
| 362 DCHECK(bridge_.get()); |
| 363 |
| 364 AppendToBuffer(reinterpret_cast<const uint8*>(data), len); |
| 365 if (ShouldEnableDefer()) |
| 366 bridge_->SetDefersLoading(true); |
| 367 } |
| 368 |
| 369 void BufferedResourceLoader::OnCompletedRequest( |
| 370 const URLRequestStatus& status, const std::string& security_info) { |
| 371 SignalComplete(); |
| 372 // After the response has completed, we don't need the bridge any more. |
| 373 bridge_.reset(); |
| 374 |
| 375 if (async_start_) |
| 376 InvokeAndResetStartCallback(status.os_error()); |
| 377 } |
| 378 |
| 379 ///////////////////////////////////////////////////////////////////////////// |
| 380 // BufferedResourceLoader, private |
| 381 void BufferedResourceLoader::AppendToBuffer(const uint8* data, size_t size) { |
| 382 Buffer* buffer = new Buffer(size); |
| 383 memcpy(buffer->data.get(), data, size); |
| 384 { |
| 385 AutoLock auto_lock(lock_); |
| 386 buffers_.push_back(buffer); |
| 387 buffered_bytes_ += size; |
| 388 } |
| 389 buffer_event_.Signal(); |
| 390 } |
| 391 |
| 392 void BufferedResourceLoader::SignalComplete() { |
| 393 { |
| 394 AutoLock auto_lock(lock_); |
| 395 completed_ = true; |
| 396 } |
| 397 buffer_event_.Signal(); |
| 398 } |
| 399 |
| 400 bool BufferedResourceLoader::ShouldEnableDefer() { |
| 401 AutoLock auto_lock(lock_); |
| 402 if (deferred_) { |
| 403 return false; |
| 404 } else if (buffered_bytes_ >= buffer_limit_) { |
| 405 deferred_ = true; |
| 406 return true; |
| 407 } |
| 408 return false; |
| 409 } |
| 410 |
| 411 bool BufferedResourceLoader::ShouldDisableDefer() { |
| 412 AutoLock auto_lock(lock_); |
| 413 if (deferred_ && buffered_bytes_ < buffer_limit_ / 2) |
| 414 return true; |
| 415 else |
| 416 return false; |
| 417 } |
| 418 |
| 419 void BufferedResourceLoader::OnStart() { |
| 420 DCHECK(MessageLoop::current() == render_loop_); |
| 421 DCHECK(bridge_.get()); |
| 422 bridge_->Start(this); |
| 423 } |
| 424 |
| 425 void BufferedResourceLoader::OnDestroy() { |
| 426 DCHECK(MessageLoop::current() == render_loop_); |
| 427 bridge_.reset(); |
| 428 } |
| 429 |
| 430 void BufferedResourceLoader::OnEnableDeferLoading() { |
| 431 DCHECK(MessageLoop::current() == render_loop_); |
| 432 // This message may arrive after the bridge is destroyed. |
| 433 if (bridge_.get()) |
| 434 bridge_->SetDefersLoading(true); |
| 435 } |
| 436 |
| 437 void BufferedResourceLoader::OnDisableDeferLoading() { |
| 438 DCHECK(MessageLoop::current() == render_loop_); |
| 439 // This message may arrive after the bridge is destroyed. |
| 440 if (bridge_.get()) |
| 441 bridge_->SetDefersLoading(false); |
| 442 } |
| 443 |
| 444 void BufferedResourceLoader::InvokeAndResetStartCallback(int error) { |
| 445 AutoLock auto_lock(lock_); |
| 446 if (start_callback_.get()) { |
| 447 start_callback_->Run(error); |
| 448 start_callback_.reset(); |
| 449 } |
| 450 } |
| 451 |
| 452 ////////////////////////////////////////////////////////////////////////////// |
| 453 // BufferedDataSource |
| 454 BufferedDataSource::BufferedDataSource(WebMediaPlayerDelegateImpl* delegate) |
| 455 : delegate_(delegate), |
| 456 stopped_(false), |
| 457 position_(0), |
| 458 total_bytes_(kPositionNotSpecified), |
| 459 buffered_resource_loader_(NULL), |
| 460 pipeline_loop_(MessageLoop::current()) { |
| 461 } |
| 462 |
| 463 BufferedDataSource::~BufferedDataSource() { |
| 464 } |
| 465 |
| 466 void BufferedDataSource::Stop() { |
| 467 scoped_refptr<BufferedResourceLoader> resource_loader = NULL; |
| 468 // Set the stop signal first. |
| 469 { |
| 470 AutoLock auto_lock(lock_); |
| 471 stopped_ = true; |
| 472 resource_loader = buffered_resource_loader_; |
| 473 // Release the reference to the resource loader. |
| 474 buffered_resource_loader_ = NULL; |
| 475 } |
| 476 // Tell the loader to stop. |
| 477 if (resource_loader) |
| 478 resource_loader->Stop(); |
| 479 } |
| 480 |
| 481 bool BufferedDataSource::Initialize(const std::string& url) { |
| 482 // Save the url. |
| 483 url_ = GURL(url); |
| 484 |
| 485 // Make sure we support the scheme of the URL. |
| 486 if (!IsSchemeSupported(url_)) { |
| 487 host_->Error(media::PIPELINE_ERROR_NETWORK); |
| 488 return false; |
| 489 } |
| 490 |
| 491 media_format_.SetAsString(media::MediaFormat::kMimeType, |
| 492 media::mime_type::kApplicationOctetStream); |
| 493 media_format_.SetAsString(media::MediaFormat::kURL, url); |
| 494 |
| 495 // Setup the BufferedResourceLoader here. |
| 496 scoped_refptr<BufferedResourceLoader> resource_loader = NULL; |
| 497 { |
| 498 AutoLock auto_lock(lock_); |
| 499 if (!stopped_) { |
| 500 buffered_resource_loader_ = new BufferedResourceLoader( |
| 501 delegate_->view()->routing_id(), |
| 502 url_, kPositionNotSpecified, kPositionNotSpecified); |
| 503 resource_loader = buffered_resource_loader_; |
| 504 } |
| 505 } |
| 506 |
| 507 // Use the local reference to start the request. |
| 508 if (resource_loader) { |
| 509 if (net::ERR_IO_PENDING != resource_loader->Start( |
| 510 NewCallback(this, &BufferedDataSource::InitialRequestStarted))) { |
| 511 host_->Error(media::PIPELINE_ERROR_NETWORK); |
| 512 return false; |
| 513 } |
| 514 return true; |
| 515 } |
| 516 host_->Error(media::PIPELINE_ERROR_NETWORK); |
| 517 return false; |
| 518 } |
| 519 |
| 520 size_t BufferedDataSource::Read(uint8* data, size_t size) { |
| 521 // We try two times here: |
| 522 // 1. Use the existing resource loader to seek forward and read from it. |
| 523 // 2. If any of the above operations failed, we create a new resource loader |
| 524 // starting with a new range. Goto 1. |
| 525 // TODO(hclam): change the logic here to do connection recovery and allow a |
| 526 // maximum of trials. |
| 527 for (int trials = 2; trials > 0; --trials) { |
| 528 scoped_refptr<BufferedResourceLoader> resource_loader = NULL; |
| 529 { |
| 530 AutoLock auto_lock(lock_); |
| 531 resource_loader = buffered_resource_loader_; |
| 532 } |
| 533 |
| 534 if (resource_loader && resource_loader->SeekForward(position_)) { |
| 535 size_t read = resource_loader->Read(data, size); |
| 536 if (read >= 0) { |
| 537 position_ += read; |
| 538 return read; |
| 539 } else { |
| 540 return DataSource::kReadError; |
| 541 } |
| 542 } else { |
| 543 // We enter here because the current resource loader cannot serve the |
| 544 // range requested, we will need to create a new request for doing it. |
| 545 scoped_refptr<BufferedResourceLoader> old_resource_loader = NULL; |
| 546 { |
| 547 AutoLock auto_lock(lock_); |
| 548 if (stopped_) |
| 549 return DataSource::kReadError; |
| 550 old_resource_loader = buffered_resource_loader_; |
| 551 buffered_resource_loader_ = |
| 552 new BufferedResourceLoader(delegate_->view()->routing_id(), |
| 553 url_, position_, |
| 554 kPositionNotSpecified); |
| 555 resource_loader = buffered_resource_loader_; |
| 556 } |
| 557 if (old_resource_loader) |
| 558 old_resource_loader->Stop(); |
| 559 if (resource_loader) { |
| 560 if (net::OK != resource_loader->Start(NULL)) { |
| 561 // We have started a new request but failed, report that. |
| 562 // TODO(hclam): should allow some retry mechanism here. |
| 563 HandleError(media::PIPELINE_ERROR_NETWORK); |
| 564 return DataSource::kReadError; |
| 565 } |
| 566 } |
| 567 } |
| 568 } |
| 569 return DataSource::kReadError; |
| 570 } |
| 571 |
| 572 bool BufferedDataSource::GetPosition(int64* position_out) { |
| 573 *position_out = position_; |
| 574 return true; |
| 575 } |
| 576 |
| 577 bool BufferedDataSource::SetPosition(int64 position) { |
| 578 position_ = position; |
| 579 return true; |
| 580 } |
| 581 |
| 582 bool BufferedDataSource::GetSize(int64* size_out) { |
| 583 if (total_bytes_ != kPositionNotSpecified) { |
| 584 *size_out = total_bytes_; |
| 585 return true; |
| 586 } |
| 587 *size_out = 0; |
| 588 return false; |
| 589 } |
| 590 |
| 591 bool BufferedDataSource::IsSeekable() { |
| 592 return total_bytes_ != kPositionNotSpecified; |
| 593 } |
| 594 |
| 595 void BufferedDataSource::HandleError(media::PipelineError error) { |
| 596 AutoLock auto_lock(lock_); |
| 597 if (!stopped_) { |
| 598 host_->Error(error); |
| 599 } |
| 600 } |
| 601 |
| 602 void BufferedDataSource::InitialRequestStarted(int error) { |
| 603 // Don't take any lock and call to |host_| here, this method is called from |
| 604 // BufferedResourceLoader after the response has started or failed, it is |
| 605 // very likely we are called within a lock in BufferedResourceLoader. |
| 606 // Acquiring an additional lock here we might have a deadlock situation, |
| 607 // but one thing very sure is that pipeline thread is still alive, so we |
| 608 // just need to post a task on that thread. |
| 609 total_bytes_ = buffered_resource_loader_->content_length(); |
| 610 pipeline_loop_->PostTask(FROM_HERE, |
| 611 NewRunnableMethod(this, |
| 612 &BufferedDataSource::OnInitialRequestStarted, error)); |
| 613 } |
| 614 |
| 615 void BufferedDataSource::OnInitialRequestStarted(int error) { |
| 616 // Acquiring a lock should not be needed because stopped_ is only written |
| 617 // on pipeline thread and we are on pipeline thread but just to be safe. |
| 618 AutoLock auto_lock(lock_); |
| 619 if (!stopped_) { |
| 620 if (error == net::OK) { |
| 621 if (IsSeekable()) { |
| 622 host_->SetTotalBytes(total_bytes_); |
| 623 // TODO(hclam): report the amount of bytes buffered accurately. |
| 624 host_->SetBufferedBytes(total_bytes_); |
| 625 } |
| 626 host_->InitializationComplete(); |
| 627 } else { |
| 628 host_->Error(media::PIPELINE_ERROR_NETWORK); |
| 629 } |
| 630 } |
| 631 } |
| 632 |
| 633 const media::MediaFormat& BufferedDataSource::media_format() { |
| 634 return media_format_; |
| 635 } |
OLD | NEW |