| // 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. |
| |
| #ifndef WEBKIT_GLUE_MEDIA_BUFFERED_RESOURCE_LOADER_H_ |
| #define WEBKIT_GLUE_MEDIA_BUFFERED_RESOURCE_LOADER_H_ |
| |
| #include <string> |
| |
| #include "base/callback.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/timer.h" |
| #include "googleurl/src/gurl.h" |
| #include "media/base/seekable_buffer.h" |
| #include "net/base/file_stream.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoader.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderClient.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h" |
| #include "webkit/glue/media/web_data_source.h" |
| #include "webkit/glue/webmediaplayer_impl.h" |
| |
| namespace webkit_glue { |
| |
| const int64 kPositionNotSpecified = -1; |
| |
| const char kHttpScheme[] = "http"; |
| const char kHttpsScheme[] = "https"; |
| const char kDataScheme[] = "data"; |
| |
| // This class works inside demuxer thread and render thread. It contains a |
| // WebURLLoader and does the actual resource loading. This object does |
| // buffering internally, it defers the resource loading if buffer is full |
| // and un-defers the resource loading if it is under buffered. |
| class BufferedResourceLoader : |
| public base::RefCountedThreadSafe<BufferedResourceLoader>, |
| public WebKit::WebURLLoaderClient { |
| public: |
| // kNeverDefer - Aggresively buffer; never defer loading while paused. |
| // kReadThenDefer - Request only enough data to fulfill read requests. |
| // kThresholdDefer - Try to keep amount of buffered data at a threshold. |
| enum DeferStrategy { |
| kNeverDefer, |
| kReadThenDefer, |
| kThresholdDefer, |
| }; |
| |
| typedef Callback0::Type NetworkEventCallback; |
| |
| // |url| - URL for the resource to be loaded. |
| // |first_byte_position| - First byte to start loading from, |
| // |kPositionNotSpecified| for not specified. |
| // |last_byte_position| - Last byte to be loaded, |
| // |kPositionNotSpecified| for not specified. |
| BufferedResourceLoader(const GURL& url, |
| int64 first_byte_position, |
| int64 last_byte_position); |
| |
| // Start the resource loading with the specified URL and range. |
| // This method operates in asynchronous mode. Once there's a response from the |
| // server, success or fail |callback| is called with the result. |
| // |callback| is called with the following values: |
| // - net::OK |
| // The request has started successfully. |
| // - net::ERR_FAILED |
| // The request has failed because of an error with the network. |
| // - net::ERR_INVALID_RESPONSE |
| // An invalid response is received from the server. |
| // - (Anything else) |
| // An error code that indicates the request has failed. |
| // |event_callback| is called when the response is completed, data is |
| // received, the request is suspended or resumed. |
| virtual void Start(net::CompletionCallback* callback, |
| NetworkEventCallback* event_callback, |
| WebKit::WebFrame* frame); |
| |
| // Stop this loader, cancels and request and release internal buffer. |
| virtual void Stop(); |
| |
| // Reads the specified |read_size| from |position| into |buffer| and when |
| // the operation is done invoke |callback| with number of bytes read or an |
| // error code. |
| // |callback| is called with the following values: |
| // - (Anything greater than or equal 0) |
| // Read was successful with the indicated number of bytes read. |
| // - net::ERR_FAILED |
| // The read has failed because of an error with the network. |
| // - net::ERR_CACHE_MISS |
| // The read was made too far away from the current buffered position. |
| virtual void Read(int64 position, int read_size, |
| uint8* buffer, net::CompletionCallback* callback); |
| |
| // Returns the position of the last byte buffered. Returns |
| // |kPositionNotSpecified| if such value is not available. |
| virtual int64 GetBufferedPosition(); |
| |
| // Gets the content length in bytes of the instance after this loader has been |
| // started. If this value is |kPositionNotSpecified|, then content length is |
| // unknown. |
| virtual int64 content_length(); |
| |
| // Gets the original size of the file requested. If this value is |
| // |kPositionNotSpecified|, then the size is unknown. |
| virtual int64 instance_size(); |
| |
| // Returns true if the server supports byte range requests. |
| virtual bool range_supported(); |
| |
| // Returns true if network is currently active. |
| virtual bool network_activity(); |
| |
| // Returns resulting URL. |
| virtual const GURL& url(); |
| |
| // Used to inject a mock used for unittests. |
| virtual void SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader); |
| |
| // WebKit::WebURLLoaderClient implementation. |
| virtual void willSendRequest( |
| WebKit::WebURLLoader* loader, |
| WebKit::WebURLRequest& newRequest, |
| const WebKit::WebURLResponse& redirectResponse); |
| virtual void didSendData( |
| WebKit::WebURLLoader* loader, |
| unsigned long long bytesSent, |
| unsigned long long totalBytesToBeSent); |
| virtual void didReceiveResponse( |
| WebKit::WebURLLoader* loader, |
| const WebKit::WebURLResponse& response); |
| virtual void didDownloadData( |
| WebKit::WebURLLoader* loader, |
| int data_length); |
| virtual void didReceiveData( |
| WebKit::WebURLLoader* loader, |
| const char* data, |
| int data_length, |
| int encoded_data_length); |
| virtual void didReceiveCachedMetadata( |
| WebKit::WebURLLoader* loader, |
| const char* data, int dataLength); |
| virtual void didFinishLoading( |
| WebKit::WebURLLoader* loader, |
| double finishTime); |
| virtual void didFail( |
| WebKit::WebURLLoader* loader, |
| const WebKit::WebURLError&); |
| |
| bool HasSingleOrigin() const; |
| |
| // Sets the defer strategy to the given value. |
| void UpdateDeferStrategy(DeferStrategy strategy); |
| |
| protected: |
| friend class base::RefCountedThreadSafe<BufferedResourceLoader>; |
| virtual ~BufferedResourceLoader(); |
| |
| private: |
| friend class BufferedResourceLoaderTest; |
| |
| // Toggles whether the resource loading is deferred or not. |
| // Returns true if a network event was fired. |
| bool ToggleDeferring(); |
| |
| // Returns true if we should defer resource loading, based |
| // on current buffering scheme. |
| bool ShouldEnableDefer(); |
| |
| // Returns true if we should enable resource loading, based |
| // on current buffering scheme. |
| bool ShouldDisableDefer(); |
| |
| // Updates deferring behavior based on current buffering scheme. |
| void UpdateDeferBehavior(); |
| |
| // Returns true if the current read request can be fulfilled by what is in |
| // the buffer. |
| bool CanFulfillRead(); |
| |
| // Returns true if the current read request will be fulfilled in the future. |
| bool WillFulfillRead(); |
| |
| // Method that does the actual read and calls the |read_callback_|, assuming |
| // the request range is in |buffer_|. |
| void ReadInternal(); |
| |
| // If we have made a range request, verify the response from the server. |
| bool VerifyPartialResponse(const WebKit::WebURLResponse& response); |
| |
| // Returns the value for a range request header using parameters |
| // |first_byte_position| and |last_byte_position|. Negative numbers other |
| // than |kPositionNotSpecified| are not allowed for |first_byte_position| and |
| // |last_byte_position|. |first_byte_position| should always be less than or |
| // equal to |last_byte_position| if they are both not |kPositionNotSpecified|. |
| // Empty string is returned on invalid parameters. |
| std::string GenerateHeaders(int64 first_byte_position, |
| int64 last_byte_position); |
| |
| // Done with read. Invokes the read callback and reset parameters for the |
| // read request. |
| void DoneRead(int error); |
| |
| // Done with start. Invokes the start callback and reset it. |
| void DoneStart(int error); |
| |
| // Calls |event_callback_| in terms of a network event. |
| void NotifyNetworkEvent(); |
| |
| bool HasPendingRead() { return read_callback_.get() != NULL; } |
| |
| // Helper function that returns true if a range request was specified. |
| bool IsRangeRequest() const; |
| |
| // A sliding window of buffer. |
| scoped_ptr<media::SeekableBuffer> buffer_; |
| |
| // True if resource loading was deferred. |
| bool deferred_; |
| |
| // Current buffering algorithm in place for resource loading. |
| DeferStrategy defer_strategy_; |
| |
| // True if resource loading has completed. |
| bool completed_; |
| |
| // True if a range request was made. |
| bool range_requested_; |
| |
| // True if Range header is supported. |
| bool range_supported_; |
| |
| // Does the work of loading and sends data back to this client. |
| scoped_ptr<WebKit::WebURLLoader> url_loader_; |
| |
| GURL url_; |
| int64 first_byte_position_; |
| int64 last_byte_position_; |
| bool single_origin_; |
| |
| // Callback method that listens to network events. |
| scoped_ptr<NetworkEventCallback> event_callback_; |
| |
| // Members used during request start. |
| scoped_ptr<net::CompletionCallback> start_callback_; |
| int64 offset_; |
| int64 content_length_; |
| int64 instance_size_; |
| |
| // Members used during a read operation. They should be reset after each |
| // read has completed or failed. |
| scoped_ptr<net::CompletionCallback> read_callback_; |
| int64 read_position_; |
| int read_size_; |
| uint8* read_buffer_; |
| |
| // Offsets of the requested first byte and last byte in |buffer_|. They are |
| // written by Read(). |
| int first_offset_; |
| int last_offset_; |
| |
| // Used to ensure mocks for unittests are used instead of reset in Start(). |
| bool keep_test_loader_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoader); |
| }; |
| |
| } // namespace webkit_glue |
| |
| #endif // WEBKIT_GLUE_MEDIA_BUFFERED_RESOURCE_LOADER_H_ |