| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "webkit/glue/media/buffered_data_source.h" |
| |
| #include "media/base/filter_host.h" |
| #include "net/base/net_errors.h" |
| #include "webkit/glue/media/web_data_source_factory.h" |
| #include "webkit/glue/webkit_glue.h" |
| |
| using WebKit::WebFrame; |
| |
| namespace webkit_glue { |
| |
| // Defines how long we should wait for more data before we declare a connection |
| // timeout and start a new request. |
| // TODO(hclam): Set it to 5s, calibrate this value later. |
| static const int kTimeoutMilliseconds = 5000; |
| |
| // Defines how many times we should try to read from a buffered resource loader |
| // before we declare a read error. After each failure of read from a buffered |
| // resource loader, a new one is created to be read. |
| static const int kReadTrials = 3; |
| |
| // BufferedDataSource has an intermediate buffer, this value governs the initial |
| // size of that buffer. It is set to 32KB because this is a typical read size |
| // of FFmpeg. |
| static const int kInitialReadBufferSize = 32768; |
| |
| static WebDataSource* NewBufferedDataSource(MessageLoop* render_loop, |
| WebKit::WebFrame* frame) { |
| return new BufferedDataSource(render_loop, frame); |
| } |
| |
| // static |
| media::DataSourceFactory* BufferedDataSource::CreateFactory( |
| MessageLoop* render_loop, |
| WebKit::WebFrame* frame, |
| WebDataSourceBuildObserverHack* build_observer) { |
| return new WebDataSourceFactory(render_loop, frame, &NewBufferedDataSource, |
| build_observer); |
| } |
| |
| BufferedDataSource::BufferedDataSource( |
| MessageLoop* render_loop, |
| WebFrame* frame) |
| : total_bytes_(kPositionNotSpecified), |
| buffered_bytes_(0), |
| loaded_(false), |
| streaming_(false), |
| frame_(frame), |
| loader_(NULL), |
| network_activity_(false), |
| initialize_callback_(NULL), |
| read_callback_(NULL), |
| read_position_(0), |
| read_size_(0), |
| read_buffer_(NULL), |
| read_attempts_(0), |
| intermediate_read_buffer_(new uint8[kInitialReadBufferSize]), |
| intermediate_read_buffer_size_(kInitialReadBufferSize), |
| render_loop_(render_loop), |
| stop_signal_received_(false), |
| stopped_on_render_loop_(false), |
| media_is_paused_(true), |
| media_has_played_(false), |
| preload_(media::METADATA), |
| using_range_request_(true) { |
| } |
| |
| BufferedDataSource::~BufferedDataSource() { |
| } |
| |
| // A factory method to create BufferedResourceLoader using the read parameters. |
| // This method can be overrided to inject mock BufferedResourceLoader object |
| // for testing purpose. |
| BufferedResourceLoader* BufferedDataSource::CreateResourceLoader( |
| int64 first_byte_position, int64 last_byte_position) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| |
| return new BufferedResourceLoader(url_, |
| first_byte_position, |
| last_byte_position); |
| } |
| |
| // This method simply returns kTimeoutMilliseconds. The purpose of this |
| // method is to be overidded so as to provide a different timeout value |
| // for testing purpose. |
| base::TimeDelta BufferedDataSource::GetTimeoutMilliseconds() { |
| return base::TimeDelta::FromMilliseconds(kTimeoutMilliseconds); |
| } |
| |
| void BufferedDataSource::set_host(media::FilterHost* host) { |
| DataSource::set_host(host); |
| |
| if (loader_.get()) |
| UpdateHostState(); |
| } |
| |
| void BufferedDataSource::Initialize(const std::string& url, |
| media::PipelineStatusCallback* callback) { |
| // Saves the url. |
| url_ = GURL(url); |
| |
| // This data source doesn't support data:// protocol so reject it. |
| if (url_.SchemeIs(kDataScheme)) { |
| callback->Run(media::DATASOURCE_ERROR_URL_NOT_SUPPORTED); |
| delete callback; |
| return; |
| } else if (!IsProtocolSupportedForMedia(url_)) { |
| callback->Run(media::PIPELINE_ERROR_NETWORK); |
| delete callback; |
| return; |
| } |
| |
| DCHECK(callback); |
| initialize_callback_.reset(callback); |
| |
| media_format_.SetAsString(media::MediaFormat::kURL, url); |
| |
| // Post a task to complete the initialization task. |
| render_loop_->PostTask(FROM_HERE, |
| NewRunnableMethod(this, &BufferedDataSource::InitializeTask)); |
| } |
| |
| void BufferedDataSource::CancelInitialize() { |
| base::AutoLock auto_lock(lock_); |
| DCHECK(initialize_callback_.get()); |
| |
| initialize_callback_.reset(); |
| |
| render_loop_->PostTask( |
| FROM_HERE, NewRunnableMethod(this, &BufferedDataSource::CleanupTask)); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // media::Filter implementation. |
| void BufferedDataSource::Stop(media::FilterCallback* callback) { |
| { |
| base::AutoLock auto_lock(lock_); |
| stop_signal_received_ = true; |
| } |
| if (callback) { |
| callback->Run(); |
| delete callback; |
| } |
| |
| render_loop_->PostTask(FROM_HERE, |
| NewRunnableMethod(this, &BufferedDataSource::CleanupTask)); |
| } |
| |
| void BufferedDataSource::SetPlaybackRate(float playback_rate) { |
| render_loop_->PostTask(FROM_HERE, |
| NewRunnableMethod(this, &BufferedDataSource::SetPlaybackRateTask, |
| playback_rate)); |
| } |
| |
| void BufferedDataSource::SetPreload(media::Preload preload) { |
| render_loop_->PostTask(FROM_HERE, |
| NewRunnableMethod(this, &BufferedDataSource::SetPreloadTask, |
| preload)); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // media::DataSource implementation. |
| void BufferedDataSource::Read(int64 position, size_t size, uint8* data, |
| media::DataSource::ReadCallback* read_callback) { |
| DCHECK(read_callback); |
| |
| { |
| base::AutoLock auto_lock(lock_); |
| DCHECK(!read_callback_.get()); |
| |
| if (stop_signal_received_ || stopped_on_render_loop_) { |
| read_callback->RunWithParams( |
| Tuple1<size_t>(static_cast<size_t>(media::DataSource::kReadError))); |
| delete read_callback; |
| return; |
| } |
| |
| read_callback_.reset(read_callback); |
| } |
| |
| render_loop_->PostTask(FROM_HERE, |
| NewRunnableMethod(this, &BufferedDataSource::ReadTask, |
| position, static_cast<int>(size), data)); |
| } |
| |
| bool BufferedDataSource::GetSize(int64* size_out) { |
| if (total_bytes_ != kPositionNotSpecified) { |
| *size_out = total_bytes_; |
| return true; |
| } |
| *size_out = 0; |
| return false; |
| } |
| |
| bool BufferedDataSource::IsStreaming() { |
| return streaming_; |
| } |
| |
| bool BufferedDataSource::HasSingleOrigin() { |
| DCHECK(MessageLoop::current() == render_loop_); |
| return loader_.get() ? loader_->HasSingleOrigin() : true; |
| } |
| |
| void BufferedDataSource::Abort() { |
| DCHECK(MessageLoop::current() == render_loop_); |
| |
| CleanupTask(); |
| frame_ = NULL; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Render thread tasks. |
| void BufferedDataSource::InitializeTask() { |
| DCHECK(MessageLoop::current() == render_loop_); |
| DCHECK(!loader_.get()); |
| if (stopped_on_render_loop_ || !initialize_callback_.get()) |
| return; |
| |
| // Kick starts the watch dog task that will handle connection timeout. |
| // We run the watch dog 2 times faster the actual timeout so as to catch |
| // the timeout more accurately. |
| watch_dog_timer_.Start( |
| GetTimeoutMilliseconds() / 2, |
| this, |
| &BufferedDataSource::WatchDogTask); |
| |
| if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { |
| // Do an unbounded range request starting at the beginning. If the server |
| // responds with 200 instead of 206 we'll fall back into a streaming mode. |
| loader_ = CreateResourceLoader(0, kPositionNotSpecified); |
| loader_->Start( |
| NewCallback(this, &BufferedDataSource::HttpInitialStartCallback), |
| NewCallback(this, &BufferedDataSource::NetworkEventCallback), |
| frame_); |
| } else { |
| // For all other protocols, assume they support range request. We fetch |
| // the full range of the resource to obtain the instance size because |
| // we won't be served HTTP headers. |
| loader_ = CreateResourceLoader(kPositionNotSpecified, |
| kPositionNotSpecified); |
| loader_->Start( |
| NewCallback(this, &BufferedDataSource::NonHttpInitialStartCallback), |
| NewCallback(this, &BufferedDataSource::NetworkEventCallback), |
| frame_); |
| } |
| } |
| |
| void BufferedDataSource::ReadTask( |
| int64 position, |
| int read_size, |
| uint8* buffer) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| { |
| base::AutoLock auto_lock(lock_); |
| if (stopped_on_render_loop_) |
| return; |
| |
| DCHECK(read_callback_.get()); |
| } |
| |
| // Saves the read parameters. |
| read_position_ = position; |
| read_size_ = read_size; |
| read_buffer_ = buffer; |
| read_submitted_time_ = base::Time::Now(); |
| read_attempts_ = 0; |
| |
| // Call to read internal to perform the actual read. |
| ReadInternal(); |
| } |
| |
| void BufferedDataSource::CleanupTask() { |
| DCHECK(MessageLoop::current() == render_loop_); |
| |
| { |
| base::AutoLock auto_lock(lock_); |
| if (stopped_on_render_loop_) |
| return; |
| |
| // Signal that stop task has finished execution. |
| // NOTE: it's vital that this be set under lock, as that's how Read() tests |
| // before registering a new |read_callback_| (which is cleared below). |
| stopped_on_render_loop_ = true; |
| |
| if (read_callback_.get()) |
| DoneRead_Locked(net::ERR_FAILED); |
| } |
| |
| // Stop the watch dog. |
| watch_dog_timer_.Stop(); |
| |
| // We just need to stop the loader, so it stops activity. |
| if (loader_.get()) |
| loader_->Stop(); |
| |
| // Reset the parameters of the current read request. |
| read_position_ = 0; |
| read_size_ = 0; |
| read_buffer_ = 0; |
| read_submitted_time_ = base::Time(); |
| read_attempts_ = 0; |
| } |
| |
| void BufferedDataSource::RestartLoadingTask() { |
| DCHECK(MessageLoop::current() == render_loop_); |
| if (stopped_on_render_loop_) |
| return; |
| |
| { |
| // If there's no outstanding read then return early. |
| base::AutoLock auto_lock(lock_); |
| if (!read_callback_.get()) |
| return; |
| } |
| |
| loader_ = CreateResourceLoader(read_position_, kPositionNotSpecified); |
| BufferedResourceLoader::DeferStrategy strategy = ChooseDeferStrategy(); |
| loader_->UpdateDeferStrategy(strategy); |
| loader_->Start( |
| NewCallback(this, &BufferedDataSource::PartialReadStartCallback), |
| NewCallback(this, &BufferedDataSource::NetworkEventCallback), |
| frame_); |
| } |
| |
| void BufferedDataSource::WatchDogTask() { |
| DCHECK(MessageLoop::current() == render_loop_); |
| if (stopped_on_render_loop_) |
| return; |
| |
| // We only care if there is an active read request. |
| { |
| base::AutoLock auto_lock(lock_); |
| if (!read_callback_.get()) |
| return; |
| } |
| |
| DCHECK(loader_.get()); |
| base::TimeDelta delta = base::Time::Now() - read_submitted_time_; |
| if (delta < GetTimeoutMilliseconds()) |
| return; |
| |
| // TODO(hclam): Maybe raise an error here. But if an error is reported |
| // the whole pipeline may get destroyed... |
| if (read_attempts_ >= kReadTrials) |
| return; |
| |
| ++read_attempts_; |
| read_submitted_time_ = base::Time::Now(); |
| |
| // Stops the current loader and creates a new resource loader and |
| // retry the request. |
| loader_->Stop(); |
| loader_ = CreateResourceLoader(read_position_, kPositionNotSpecified); |
| BufferedResourceLoader::DeferStrategy strategy = ChooseDeferStrategy(); |
| loader_->UpdateDeferStrategy(strategy); |
| loader_->Start( |
| NewCallback(this, &BufferedDataSource::PartialReadStartCallback), |
| NewCallback(this, &BufferedDataSource::NetworkEventCallback), |
| frame_); |
| } |
| |
| void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| DCHECK(loader_.get()); |
| |
| bool previously_paused = media_is_paused_; |
| media_is_paused_ = (playback_rate == 0.0); |
| |
| if (!media_has_played_ && previously_paused && !media_is_paused_) |
| media_has_played_ = true; |
| |
| BufferedResourceLoader::DeferStrategy strategy = ChooseDeferStrategy(); |
| loader_->UpdateDeferStrategy(strategy); |
| } |
| |
| void BufferedDataSource::SetPreloadTask(media::Preload preload) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| preload_ = preload; |
| } |
| |
| BufferedResourceLoader::DeferStrategy |
| BufferedDataSource::ChooseDeferStrategy() { |
| // If the user indicates preload=metadata, then just load exactly |
| // what is needed for starting the pipeline and prerolling frames. |
| if (preload_ == media::METADATA && !media_has_played_) |
| return BufferedResourceLoader::kReadThenDefer; |
| |
| // In general, we want to try to buffer the entire video when the video |
| // is paused. But we don't want to do this if the video hasn't played yet |
| // and preload!=auto. |
| if (media_is_paused_ && |
| (preload_ == media::AUTO || media_has_played_)) { |
| return BufferedResourceLoader::kNeverDefer; |
| } |
| |
| // When the video is playing, regardless of preload state, we buffer up |
| // to a hard limit and enable/disable deferring when the buffer is |
| // depleted/full. |
| return BufferedResourceLoader::kThresholdDefer; |
| } |
| |
| // This method is the place where actual read happens, |loader_| must be valid |
| // prior to make this method call. |
| void BufferedDataSource::ReadInternal() { |
| DCHECK(MessageLoop::current() == render_loop_); |
| DCHECK(loader_); |
| |
| // First we prepare the intermediate read buffer for BufferedResourceLoader |
| // to write to. |
| if (read_size_ > intermediate_read_buffer_size_) { |
| intermediate_read_buffer_.reset(new uint8[read_size_]); |
| } |
| |
| // Perform the actual read with BufferedResourceLoader. |
| loader_->Read(read_position_, read_size_, intermediate_read_buffer_.get(), |
| NewCallback(this, &BufferedDataSource::ReadCallback)); |
| } |
| |
| // Method to report the results of the current read request. Also reset all |
| // the read parameters. |
| void BufferedDataSource::DoneRead_Locked(int error) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| DCHECK(read_callback_.get()); |
| lock_.AssertAcquired(); |
| |
| if (error >= 0) { |
| read_callback_->RunWithParams(Tuple1<size_t>(error)); |
| } else { |
| read_callback_->RunWithParams( |
| Tuple1<size_t>(static_cast<size_t>(media::DataSource::kReadError))); |
| } |
| |
| read_callback_.reset(); |
| read_position_ = 0; |
| read_size_ = 0; |
| read_buffer_ = 0; |
| } |
| |
| void BufferedDataSource::DoneInitialization_Locked( |
| media::PipelineStatus status) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| DCHECK(initialize_callback_.get()); |
| lock_.AssertAcquired(); |
| |
| scoped_ptr<media::PipelineStatusCallback> initialize_callback( |
| initialize_callback_.release()); |
| initialize_callback->Run(status); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // BufferedResourceLoader callback methods. |
| void BufferedDataSource::HttpInitialStartCallback(int error) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| DCHECK(loader_.get()); |
| |
| int64 instance_size = loader_->instance_size(); |
| bool success = error == net::OK; |
| |
| if (!initialize_callback_.get()) { |
| loader_->Stop(); |
| return; |
| } |
| |
| if (success) { |
| // TODO(hclam): Needs more thinking about supporting servers without range |
| // request or their partial response is not complete. |
| total_bytes_ = instance_size; |
| loaded_ = false; |
| streaming_ = (instance_size == kPositionNotSpecified) || |
| !loader_->range_supported(); |
| } else { |
| // TODO(hclam): In case of failure, we can retry several times. |
| loader_->Stop(); |
| } |
| |
| if (error == net::ERR_INVALID_RESPONSE && using_range_request_) { |
| // Assuming that the Range header was causing the problem. Retry without |
| // the Range header. |
| using_range_request_ = false; |
| loader_ = CreateResourceLoader(kPositionNotSpecified, |
| kPositionNotSpecified); |
| loader_->Start( |
| NewCallback(this, &BufferedDataSource::HttpInitialStartCallback), |
| NewCallback(this, &BufferedDataSource::NetworkEventCallback), |
| frame_); |
| return; |
| } |
| |
| // Reference to prevent destruction while inside the |initialize_callback_| |
| // call. This is a temporary fix to prevent crashes caused by holding the |
| // lock and running the destructor. |
| // TODO: Review locking in this class and figure out a way to run the callback |
| // w/o the lock. |
| scoped_refptr<BufferedDataSource> destruction_guard(this); |
| { |
| // We need to prevent calling to filter host and running the callback if |
| // we have received the stop signal. We need to lock down the whole callback |
| // method to prevent bad things from happening. The reason behind this is |
| // that we cannot guarantee tasks on render thread have completely stopped |
| // when we receive the Stop() method call. The only way to solve this is to |
| // let tasks on render thread to run but make sure they don't call outside |
| // this object when Stop() method is ever called. Locking this method is |
| // safe because |lock_| is only acquired in tasks on render thread. |
| base::AutoLock auto_lock(lock_); |
| if (stop_signal_received_) |
| return; |
| |
| if (!success) { |
| DoneInitialization_Locked(media::PIPELINE_ERROR_NETWORK); |
| return; |
| } |
| |
| UpdateHostState(); |
| DoneInitialization_Locked(media::PIPELINE_OK); |
| } |
| } |
| |
| void BufferedDataSource::NonHttpInitialStartCallback(int error) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| DCHECK(loader_.get()); |
| |
| if (!initialize_callback_.get()) { |
| loader_->Stop(); |
| return; |
| } |
| |
| int64 instance_size = loader_->instance_size(); |
| bool success = error == net::OK && instance_size != kPositionNotSpecified; |
| |
| if (success) { |
| total_bytes_ = instance_size; |
| buffered_bytes_ = total_bytes_; |
| loaded_ = true; |
| } else { |
| loader_->Stop(); |
| } |
| |
| // Reference to prevent destruction while inside the |initialize_callback_| |
| // call. This is a temporary fix to prevent crashes caused by holding the |
| // lock and running the destructor. |
| // TODO: Review locking in this class and figure out a way to run the callback |
| // w/o the lock. |
| scoped_refptr<BufferedDataSource> destruction_guard(this); |
| { |
| // We need to prevent calling to filter host and running the callback if |
| // we have received the stop signal. We need to lock down the whole callback |
| // method to prevent bad things from happening. The reason behind this is |
| // that we cannot guarantee tasks on render thread have completely stopped |
| // when we receive the Stop() method call. The only way to solve this is to |
| // let tasks on render thread to run but make sure they don't call outside |
| // this object when Stop() method is ever called. Locking this method is |
| // safe because |lock_| is only acquired in tasks on render thread. |
| base::AutoLock auto_lock(lock_); |
| if (stop_signal_received_ || !initialize_callback_.get()) |
| return; |
| |
| if (!success) { |
| DoneInitialization_Locked(media::PIPELINE_ERROR_NETWORK); |
| return; |
| } |
| |
| UpdateHostState(); |
| DoneInitialization_Locked(media::PIPELINE_OK); |
| } |
| } |
| |
| void BufferedDataSource::PartialReadStartCallback(int error) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| DCHECK(loader_.get()); |
| |
| if (error == net::OK) { |
| // Once the request has started successfully, we can proceed with |
| // reading from it. |
| ReadInternal(); |
| return; |
| } |
| |
| // Stop the resource loader since we have received an error. |
| loader_->Stop(); |
| |
| // We need to prevent calling to filter host and running the callback if |
| // we have received the stop signal. We need to lock down the whole callback |
| // method to prevent bad things from happening. The reason behind this is |
| // that we cannot guarantee tasks on render thread have completely stopped |
| // when we receive the Stop() method call. So only way to solve this is to |
| // let tasks on render thread to run but make sure they don't call outside |
| // this object when Stop() method is ever called. Locking this method is |
| // safe because |lock_| is only acquired in tasks on render thread. |
| base::AutoLock auto_lock(lock_); |
| if (stop_signal_received_) |
| return; |
| DoneRead_Locked(net::ERR_INVALID_RESPONSE); |
| } |
| |
| void BufferedDataSource::ReadCallback(int error) { |
| DCHECK(MessageLoop::current() == render_loop_); |
| |
| if (error < 0) { |
| DCHECK(loader_.get()); |
| |
| // Stop the resource load if it failed. |
| loader_->Stop(); |
| |
| if (error == net::ERR_CACHE_MISS) { |
| render_loop_->PostTask(FROM_HERE, |
| NewRunnableMethod(this, &BufferedDataSource::RestartLoadingTask)); |
| return; |
| } |
| } |
| |
| // We need to prevent calling to filter host and running the callback if |
| // we have received the stop signal. We need to lock down the whole callback |
| // method to prevent bad things from happening. The reason behind this is |
| // that we cannot guarantee tasks on render thread have completely stopped |
| // when we receive the Stop() method call. So only way to solve this is to |
| // let tasks on render thread to run but make sure they don't call outside |
| // this object when Stop() method is ever called. Locking this method is safe |
| // because |lock_| is only acquired in tasks on render thread. |
| base::AutoLock auto_lock(lock_); |
| if (stop_signal_received_) |
| return; |
| |
| if (error > 0) { |
| // If a position error code is received, read was successful. So copy |
| // from intermediate read buffer to the target read buffer. |
| memcpy(read_buffer_, intermediate_read_buffer_.get(), error); |
| } else if (error == 0 && total_bytes_ == kPositionNotSpecified) { |
| // We've reached the end of the file and we didn't know the total size |
| // before. Update the total size so Read()s past the end of the file will |
| // fail like they would if we had known the file size at the beginning. |
| total_bytes_ = loader_->instance_size(); |
| |
| if (host() && total_bytes_ != kPositionNotSpecified) |
| host()->SetTotalBytes(total_bytes_); |
| } |
| DoneRead_Locked(error); |
| } |
| |
| void BufferedDataSource::NetworkEventCallback() { |
| DCHECK(MessageLoop::current() == render_loop_); |
| DCHECK(loader_.get()); |
| |
| // In case of non-HTTP request we don't need to report network events, |
| // so return immediately. |
| if (loaded_) |
| return; |
| |
| bool network_activity = loader_->network_activity(); |
| int64 buffered_position = loader_->GetBufferedPosition(); |
| |
| // If we get an unspecified value, return immediately. |
| if (buffered_position == kPositionNotSpecified) |
| return; |
| |
| // We need to prevent calling to filter host and running the callback if |
| // we have received the stop signal. We need to lock down the whole callback |
| // method to prevent bad things from happening. The reason behind this is |
| // that we cannot guarantee tasks on render thread have completely stopped |
| // when we receive the Stop() method call. So only way to solve this is to |
| // let tasks on render thread to run but make sure they don't call outside |
| // this object when Stop() method is ever called. Locking this method is safe |
| // because |lock_| is only acquired in tasks on render thread. |
| base::AutoLock auto_lock(lock_); |
| if (stop_signal_received_) |
| return; |
| |
| if (network_activity != network_activity_) { |
| network_activity_ = network_activity; |
| if (host()) |
| host()->SetNetworkActivity(network_activity); |
| } |
| |
| buffered_bytes_ = buffered_position + 1; |
| if (host()) |
| host()->SetBufferedBytes(buffered_bytes_); |
| } |
| |
| void BufferedDataSource::UpdateHostState() { |
| media::FilterHost* filter_host = host(); |
| if (!filter_host) |
| return; |
| |
| filter_host->SetLoaded(loaded_); |
| |
| if (streaming_) { |
| filter_host->SetStreaming(true); |
| } else { |
| filter_host->SetTotalBytes(total_bytes_); |
| filter_host->SetBufferedBytes(buffered_bytes_); |
| } |
| } |
| |
| } // namespace webkit_glue |