Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "webkit/media/buffered_data_source.h" | 5 #include "webkit/media/buffered_data_source.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "media/base/media_log.h" | 9 #include "media/base/media_log.h" |
| 10 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
| 11 | 11 |
| 12 using WebKit::WebFrame; | 12 using WebKit::WebFrame; |
| 13 | 13 |
| 14 namespace { | 14 namespace { |
| 15 | 15 |
| 16 // BufferedDataSource has an intermediate buffer, this value governs the initial | 16 // BufferedDataSource has an intermediate buffer, this value governs the initial |
| 17 // size of that buffer. It is set to 32KB because this is a typical read size | 17 // size of that buffer. It is set to 32KB because this is a typical read size |
| 18 // of FFmpeg. | 18 // of FFmpeg. |
| 19 const int kInitialReadBufferSize = 32768; | 19 const int kInitialReadBufferSize = 32768; |
| 20 | 20 |
| 21 // Number of cache misses we allow for a single Read() before signaling an | 21 // Number of cache misses we allow for a single Read() before signaling an |
| 22 // error. | 22 // error. |
| 23 const int kNumCacheMissRetries = 3; | 23 const int kNumCacheMissRetries = 3; |
| 24 | 24 |
| 25 } // namespace | 25 } // namespace |
| 26 | 26 |
| 27 namespace webkit_media { | 27 namespace webkit_media { |
| 28 | 28 |
| 29 // Non-HTTP resources are assumed to be fully loaded so we ignore any | |
| 30 // loading/progress related callbacks. | |
| 31 static void NonHttpLoadingStateChangedCallback( | |
| 32 BufferedResourceLoader::LoadingState) { | |
| 33 } | |
| 34 static void NonHttpProgressCallback(int64) {} | |
| 35 | |
| 29 BufferedDataSource::BufferedDataSource( | 36 BufferedDataSource::BufferedDataSource( |
| 30 MessageLoop* render_loop, | 37 MessageLoop* render_loop, |
| 31 WebFrame* frame, | 38 WebFrame* frame, |
| 32 media::MediaLog* media_log, | 39 media::MediaLog* media_log, |
| 33 const DownloadingCB& downloading_cb) | 40 const DownloadingCB& downloading_cb) |
| 34 : cors_mode_(BufferedResourceLoader::kUnspecified), | 41 : cors_mode_(BufferedResourceLoader::kUnspecified), |
| 35 total_bytes_(kPositionNotSpecified), | 42 total_bytes_(kPositionNotSpecified), |
| 36 buffered_bytes_(0), | 43 buffered_bytes_(0), |
| 37 streaming_(false), | 44 streaming_(false), |
| 38 frame_(frame), | 45 frame_(frame), |
| 39 is_downloading_data_(false), | |
| 40 read_size_(0), | 46 read_size_(0), |
| 41 read_buffer_(NULL), | 47 read_buffer_(NULL), |
| 42 last_read_start_(0), | 48 last_read_start_(0), |
| 43 intermediate_read_buffer_(new uint8[kInitialReadBufferSize]), | 49 intermediate_read_buffer_(new uint8[kInitialReadBufferSize]), |
| 44 intermediate_read_buffer_size_(kInitialReadBufferSize), | 50 intermediate_read_buffer_size_(kInitialReadBufferSize), |
| 45 render_loop_(render_loop), | 51 render_loop_(render_loop), |
| 46 stop_signal_received_(false), | 52 stop_signal_received_(false), |
| 47 stopped_on_render_loop_(false), | 53 stopped_on_render_loop_(false), |
| 48 media_has_played_(false), | 54 media_has_played_(false), |
| 49 preload_(AUTO), | 55 preload_(AUTO), |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 cors_mode_ = cors_mode; | 104 cors_mode_ = cors_mode; |
| 99 | 105 |
| 100 initialize_cb_ = initialize_cb; | 106 initialize_cb_ = initialize_cb; |
| 101 | 107 |
| 102 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { | 108 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { |
| 103 // Do an unbounded range request starting at the beginning. If the server | 109 // Do an unbounded range request starting at the beginning. If the server |
| 104 // responds with 200 instead of 206 we'll fall back into a streaming mode. | 110 // responds with 200 instead of 206 we'll fall back into a streaming mode. |
| 105 loader_.reset(CreateResourceLoader(0, kPositionNotSpecified)); | 111 loader_.reset(CreateResourceLoader(0, kPositionNotSpecified)); |
| 106 loader_->Start( | 112 loader_->Start( |
| 107 base::Bind(&BufferedDataSource::HttpInitialStartCallback, this), | 113 base::Bind(&BufferedDataSource::HttpInitialStartCallback, this), |
| 108 base::Bind(&BufferedDataSource::NetworkEventCallback, this), | 114 base::Bind(&BufferedDataSource::HttpLoadingStateChangedCallback, this), |
| 115 base::Bind(&BufferedDataSource::HttpProgressCallback, this), | |
| 109 frame_); | 116 frame_); |
| 110 return; | 117 return; |
| 111 } | 118 } |
| 112 | 119 |
| 113 // For all other protocols, assume they support range request. We fetch | 120 // For all other protocols, assume they support range request. We fetch |
| 114 // the full range of the resource to obtain the instance size because | 121 // the full range of the resource to obtain the instance size because |
| 115 // we won't be served HTTP headers. | 122 // we won't be served HTTP headers. |
| 116 loader_.reset(CreateResourceLoader(kPositionNotSpecified, | 123 loader_.reset(CreateResourceLoader(kPositionNotSpecified, |
| 117 kPositionNotSpecified)); | 124 kPositionNotSpecified)); |
| 118 loader_->Start( | 125 loader_->Start( |
| 119 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), | 126 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), |
| 120 base::Bind(&BufferedDataSource::NetworkEventCallback, this), | 127 base::Bind(&NonHttpLoadingStateChangedCallback), |
| 128 base::Bind(&NonHttpProgressCallback), | |
| 121 frame_); | 129 frame_); |
| 122 } | 130 } |
| 123 | 131 |
| 124 void BufferedDataSource::SetPreload(Preload preload) { | 132 void BufferedDataSource::SetPreload(Preload preload) { |
| 125 DCHECK(MessageLoop::current() == render_loop_); | 133 DCHECK(MessageLoop::current() == render_loop_); |
| 126 preload_ = preload; | 134 preload_ = preload; |
| 127 } | 135 } |
| 128 | 136 |
| 129 bool BufferedDataSource::HasSingleOrigin() { | 137 bool BufferedDataSource::HasSingleOrigin() { |
| 130 DCHECK(MessageLoop::current() == render_loop_); | 138 DCHECK(MessageLoop::current() == render_loop_); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 if (stopped_on_render_loop_) | 270 if (stopped_on_render_loop_) |
| 263 return; | 271 return; |
| 264 | 272 |
| 265 { | 273 { |
| 266 // If there's no outstanding read then return early. | 274 // If there's no outstanding read then return early. |
| 267 base::AutoLock auto_lock(lock_); | 275 base::AutoLock auto_lock(lock_); |
| 268 if (read_cb_.is_null()) | 276 if (read_cb_.is_null()) |
| 269 return; | 277 return; |
| 270 } | 278 } |
| 271 | 279 |
| 280 // Start reading from where we last left off until the end of the resource. | |
| 272 loader_.reset( | 281 loader_.reset( |
| 273 CreateResourceLoader(last_read_start_, kPositionNotSpecified)); | 282 CreateResourceLoader(last_read_start_, kPositionNotSpecified)); |
| 274 loader_->Start( | 283 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { |
| 275 base::Bind(&BufferedDataSource::PartialReadStartCallback, this), | 284 loader_->Start( |
| 276 base::Bind(&BufferedDataSource::NetworkEventCallback, this), | 285 base::Bind(&BufferedDataSource::PartialReadStartCallback, this), |
| 277 frame_); | 286 base::Bind(&BufferedDataSource::HttpLoadingStateChangedCallback, this), |
| 287 base::Bind(&BufferedDataSource::HttpProgressCallback, this), | |
| 288 frame_); | |
| 289 } else { | |
| 290 loader_->Start( | |
| 291 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), | |
| 292 base::Bind(&NonHttpLoadingStateChangedCallback), | |
| 293 base::Bind(&NonHttpProgressCallback), | |
| 294 frame_); | |
| 295 } | |
| 278 } | 296 } |
| 279 | 297 |
| 280 void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { | 298 void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { |
| 281 DCHECK(MessageLoop::current() == render_loop_); | 299 DCHECK(MessageLoop::current() == render_loop_); |
| 282 DCHECK(loader_.get()); | 300 DCHECK(loader_.get()); |
| 283 | 301 |
| 284 if (playback_rate != 0) | 302 if (playback_rate != 0) |
| 285 media_has_played_ = true; | 303 media_has_played_ = true; |
| 286 | 304 |
| 287 playback_rate_ = playback_rate; | 305 playback_rate_ = playback_rate; |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 511 cache_miss_retries_left_--; | 529 cache_miss_retries_left_--; |
| 512 render_loop_->PostTask(FROM_HERE, | 530 render_loop_->PostTask(FROM_HERE, |
| 513 base::Bind(&BufferedDataSource::RestartLoadingTask, this)); | 531 base::Bind(&BufferedDataSource::RestartLoadingTask, this)); |
| 514 return; | 532 return; |
| 515 } | 533 } |
| 516 | 534 |
| 517 // Fall through to signal a read error. | 535 // Fall through to signal a read error. |
| 518 bytes_read = kReadError; | 536 bytes_read = kReadError; |
| 519 } | 537 } |
| 520 | 538 |
| 521 // We need to prevent calling to filter host and running the callback if | 539 // TODO(scherkus): we shouldn't have to lock to signal host(), see |
| 522 // we have received the stop signal. We need to lock down the whole callback | 540 // http://crbug.com/113712 for details. |
| 523 // method to prevent bad things from happening. The reason behind this is | |
| 524 // that we cannot guarantee tasks on render thread have completely stopped | |
| 525 // when we receive the Stop() method call. So only way to solve this is to | |
| 526 // let tasks on render thread to run but make sure they don't call outside | |
| 527 // this object when Stop() method is ever called. Locking this method is safe | |
| 528 // because |lock_| is only acquired in tasks on render thread. | |
| 529 base::AutoLock auto_lock(lock_); | 541 base::AutoLock auto_lock(lock_); |
| 530 if (stop_signal_received_) | 542 if (stop_signal_received_) |
| 531 return; | 543 return; |
| 532 | 544 |
| 533 if (bytes_read > 0) { | 545 if (bytes_read > 0) { |
| 534 memcpy(read_buffer_, intermediate_read_buffer_.get(), bytes_read); | 546 memcpy(read_buffer_, intermediate_read_buffer_.get(), bytes_read); |
| 535 } else if (bytes_read == 0 && total_bytes_ == kPositionNotSpecified) { | 547 } else if (bytes_read == 0 && total_bytes_ == kPositionNotSpecified) { |
| 536 // We've reached the end of the file and we didn't know the total size | 548 // We've reached the end of the file and we didn't know the total size |
| 537 // before. Update the total size so Read()s past the end of the file will | 549 // before. Update the total size so Read()s past the end of the file will |
| 538 // fail like they would if we had known the file size at the beginning. | 550 // fail like they would if we had known the file size at the beginning. |
| 539 total_bytes_ = loader_->instance_size(); | 551 total_bytes_ = loader_->instance_size(); |
| 540 | 552 |
| 541 if (host() && total_bytes_ != kPositionNotSpecified) { | 553 if (host() && total_bytes_ != kPositionNotSpecified) { |
| 542 host()->SetTotalBytes(total_bytes_); | 554 host()->SetTotalBytes(total_bytes_); |
| 543 host()->AddBufferedByteRange(loader_->first_byte_position(), | 555 host()->AddBufferedByteRange(loader_->first_byte_position(), |
| 544 total_bytes_); | 556 total_bytes_); |
| 545 } | 557 } |
| 546 } | 558 } |
| 547 DoneRead_Locked(bytes_read); | 559 DoneRead_Locked(bytes_read); |
| 548 } | 560 } |
| 549 | 561 |
| 550 void BufferedDataSource::NetworkEventCallback() { | 562 void BufferedDataSource::HttpLoadingStateChangedCallback( |
| 563 BufferedResourceLoader::LoadingState state) { | |
| 551 DCHECK(MessageLoop::current() == render_loop_); | 564 DCHECK(MessageLoop::current() == render_loop_); |
| 552 DCHECK(loader_.get()); | 565 DCHECK(url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)); |
| 553 | 566 |
| 554 // In case of non-HTTP request we don't need to report network events, | 567 // TODO(scherkus): we shouldn't have to lock to signal host(), see |
| 555 // so return immediately. | 568 // http://crbug.com/113712 for details. |
| 556 if (!url_.SchemeIs(kHttpScheme) && !url_.SchemeIs(kHttpsScheme)) | |
| 557 return; | |
| 558 | |
| 559 downloading_cb_.Run(loader_->is_downloading_data()); | |
| 560 | |
| 561 int64 current_buffered_position = loader_->GetBufferedPosition(); | |
| 562 | |
| 563 // If we get an unspecified value, return immediately. | |
| 564 if (current_buffered_position == kPositionNotSpecified) | |
| 565 return; | |
| 566 | |
| 567 // We need to prevent calling to filter host and running the callback if | |
| 568 // we have received the stop signal. We need to lock down the whole callback | |
| 569 // method to prevent bad things from happening. The reason behind this is | |
| 570 // that we cannot guarantee tasks on render thread have completely stopped | |
| 571 // when we receive the Stop() method call. So only way to solve this is to | |
| 572 // let tasks on render thread to run but make sure they don't call outside | |
| 573 // this object when Stop() method is ever called. Locking this method is safe | |
| 574 // because |lock_| is only acquired in tasks on render thread. | |
| 575 base::AutoLock auto_lock(lock_); | 569 base::AutoLock auto_lock(lock_); |
| 576 if (stop_signal_received_) | 570 if (stop_signal_received_) |
| 577 return; | 571 return; |
| 578 | 572 |
| 579 int64 start = loader_->first_byte_position(); | 573 bool is_downloading_data; |
| 580 if (host() && current_buffered_position > start) | 574 switch (state) { |
| 581 host()->AddBufferedByteRange(start, current_buffered_position); | 575 case BufferedResourceLoader::kLoading: |
| 576 is_downloading_data = true; | |
| 577 break; | |
| 578 case BufferedResourceLoader::kLoadingDeferred: | |
| 579 is_downloading_data = false; | |
| 580 break; | |
| 581 | |
| 582 // TODO(scherkus): we don't signal network activity changes when loads | |
| 583 // complete or fail to preserve existing behaviour when deferring is | |
| 584 // toggled, however we considering changing DownloadingCB to also | |
| 585 // propagate loading state. For example there isn't any signal today | |
| 586 // to notify the client that loading has failed/finished (we only get | |
| 587 // errors on subsequent reads). | |
| 588 case BufferedResourceLoader::kLoadingFailed: | |
| 589 case BufferedResourceLoader::kLoadingFinished: | |
| 590 return; | |
| 591 } | |
| 592 | |
| 593 downloading_cb_.Run(is_downloading_data); | |
|
Ami GONE FROM CHROMIUM
2012/07/10 02:43:53
This is now run under lock, where it didn't use to
scherkus (not reviewing)
2012/07/10 04:10:53
I don't *think* it should be an issue, but now tha
| |
| 594 } | |
| 595 | |
| 596 void BufferedDataSource::HttpProgressCallback(int64 position) { | |
| 597 DCHECK(MessageLoop::current() == render_loop_); | |
| 598 DCHECK(url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)); | |
| 599 | |
| 600 // TODO(scherkus): we shouldn't have to lock to signal host(), see | |
| 601 // http://crbug.com/113712 for details. | |
| 602 base::AutoLock auto_lock(lock_); | |
| 603 if (stop_signal_received_) | |
| 604 return; | |
| 605 | |
| 606 if (host() && position > last_read_start_) | |
| 607 host()->AddBufferedByteRange(last_read_start_, position); | |
| 582 } | 608 } |
| 583 | 609 |
| 584 void BufferedDataSource::UpdateHostState_Locked() { | 610 void BufferedDataSource::UpdateHostState_Locked() { |
| 585 // Called from various threads, under lock. | |
| 586 lock_.AssertAcquired(); | 611 lock_.AssertAcquired(); |
| 587 | 612 |
| 588 if (!host()) | 613 if (!host()) |
| 589 return; | 614 return; |
| 590 | 615 |
| 591 if (total_bytes_ != kPositionNotSpecified) | 616 if (total_bytes_ != kPositionNotSpecified) |
| 592 host()->SetTotalBytes(total_bytes_); | 617 host()->SetTotalBytes(total_bytes_); |
| 593 int64 start = loader_->first_byte_position(); | 618 int64 start = loader_->first_byte_position(); |
| 594 if (buffered_bytes_ > start) | 619 if (buffered_bytes_ > start) |
| 595 host()->AddBufferedByteRange(start, buffered_bytes_); | 620 host()->AddBufferedByteRange(start, buffered_bytes_); |
| 596 } | 621 } |
| 597 | 622 |
| 598 } // namespace webkit_media | 623 } // namespace webkit_media |
| OLD | NEW |