blob: 66fef53c56c62503af950e518f0608cd44b93dc0 [file] [log] [blame]
// Copyright 2015 The Cobalt Authors. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/optional.h"
#include "base/synchronization/lock.h"
#include "cobalt/base/circular_buffer_shell.h"
#include "cobalt/csp/content_security_policy.h"
#include "cobalt/loader/fetcher.h"
#include "cobalt/loader/origin.h"
#include "cobalt/loader/url_fetcher_string_writer.h"
#include "cobalt/media/player/buffered_data_source.h"
#include "cobalt/network/network_module.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"
namespace cobalt {
namespace media {
// TODO: This class requires a large block of memory. Consider to
// use ShellBufferFactory for its memory if possible to avoid possible OOM.
// A BufferedDataSource based on net::URLFetcher that can be used to retrieve
// progressive videos from both local and network sources.
// It uses a fixed size circular buffer so we may not be able to store all data
// into this buffer. It is based on the following assumptions/strategies:
// 1. It assumes that the buffer is large enough to fulfill one Read() request.
// So any outstanding request only requires at most one request.
// 2. It will do one initial request to retrieve the target resource. If the
// whole resource can be fit into the buffer, no further request will be
// fired.
// 3. If the resource doesn't fit into the buffer. The class will store
// kBackwardBytes bytes before the last read offset(LRO) and kForwardBytes
// after LRO. Note that if LRO is less than kBackwardBytes, then data starts
// from offset 0 will be cached.
// 4. It assumes that the server supports range request.
// 5. All data stored are continuous.
class FetcherBufferedDataSource : public BufferedDataSource,
private net::URLFetcherDelegate {
static const int64 kInvalidSize = -1;
// Because the Fetchers have to be created and destroyed on the same thread,
// we use the task_runner passed in to create and destroy Fetchers.
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
const GURL& url, const csp::SecurityCallback& security_callback,
network::NetworkModule* network_module, loader::RequestMode requset_mode,
loader::Origin origin);
~FetcherBufferedDataSource() override;
// DataSource methods.
void Read(int64 position, int size, uint8* data,
const ReadCB& read_cb) override;
void Stop() override;
bool GetSize(int64* size_out) override;
bool IsStreaming() override { return false; }
void SetBitrate(int bitrate) override { SB_UNREFERENCED_PARAMETER(bitrate); }
// BufferedDataSource methods.
void SetDownloadingStatusCB(
const DownloadingStatusCB& downloading_status_cb) override;
class CancelableClosure
: public base::RefCountedThreadSafe<CancelableClosure> {
explicit CancelableClosure(const base::Closure& closure);
void Cancel();
base::Closure AsClosure();
void Call();
base::Lock lock_;
base::Closure closure_;
// net::URLFetcherDelegate methods
void OnURLFetchResponseStarted(const net::URLFetcher* source) override;
void OnURLFetchDownloadProgress(const net::URLFetcher* source,
int64_t current, int64_t total,
int64_t current_network_bytes) override;
void OnURLFetchComplete(const net::URLFetcher* source) override;
void CreateNewFetcher();
void UpdateDownloadingStatus(bool is_downloading);
void Read_Locked(uint64 position, size_t size, uint8* data,
const ReadCB& read_cb);
void ProcessPendingRead_Locked();
void TryToSendRequest_Locked();
base::Lock lock_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
GURL url_;
network::NetworkModule* network_module_;
std::unique_ptr<net::URLFetcher> fetcher_;
bool is_downloading_;
DownloadingStatusCB downloading_status_cb_;
// |fetcher_| has to be destroyed on the thread it's created. So it cannot be
// safely destroyed inside Read_Locked(). Save |fetcher_| into
// |fetcher_to_be_destroyed_| to ensure that it is properly destroyed either
// inside CreateNewFetcher() or in the dtor while still allow |fetcher_| to be
// set to NULL to invalidate outstanding read.
std::unique_ptr<net::URLFetcher> fetcher_to_be_destroyed_;
// |buffer_| stores a continuous block of data of target resource starts from
// |buffer_offset_|. When the target resource can be fit into |buffer_|,
// |buffer_offset_| will always be 0.
base::CircularBufferShell buffer_;
uint64 buffer_offset_;
base::Optional<uint64> total_size_of_resource_;
bool error_occured_;
uint64 last_request_offset_;
uint64 last_request_size_;
// This is usually the same as pending_read_position_. Represent it
// explicitly using a separate variable.
uint64 last_read_position_;
ReadCB pending_read_cb_;
uint64 pending_read_position_;
size_t pending_read_size_;
uint8* pending_read_data_;
csp::SecurityCallback security_callback_;
scoped_refptr<CancelableClosure> cancelable_create_fetcher_closure_;
loader::RequestMode request_mode_;
loader::Origin document_origin_;
// True if the origin is allowed to fetch resource data.
bool is_origin_safe_;
} // namespace media
} // namespace cobalt