Home | History | Annotate | Download | only in media
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CONTENT_RENDERER_MEDIA_BUFFERED_RESOURCE_LOADER_H_
      6 #define CONTENT_RENDERER_MEDIA_BUFFERED_RESOURCE_LOADER_H_
      7 
      8 #include <string>
      9 
     10 #include "base/callback.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/timer/timer.h"
     13 #include "content/common/content_export.h"
     14 #include "content/renderer/media/active_loader.h"
     15 #include "media/base/seekable_buffer.h"
     16 #include "third_party/WebKit/public/platform/WebURLLoader.h"
     17 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
     18 #include "third_party/WebKit/public/platform/WebURLRequest.h"
     19 #include "third_party/WebKit/public/web/WebFrame.h"
     20 #include "url/gurl.h"
     21 
     22 namespace media {
     23 class MediaLog;
     24 class SeekableBuffer;
     25 }
     26 
     27 namespace content {
     28 
     29 const int64 kPositionNotSpecified = -1;
     30 
     31 const char kHttpScheme[] = "http";
     32 const char kHttpsScheme[] = "https";
     33 
     34 // BufferedResourceLoader is single threaded and must be accessed on the
     35 // render thread. It wraps a WebURLLoader and does in-memory buffering,
     36 // pausing resource loading when the in-memory buffer is full and resuming
     37 // resource loading when there is available capacity.
     38 class CONTENT_EXPORT BufferedResourceLoader
     39     : NON_EXPORTED_BASE(public blink::WebURLLoaderClient) {
     40  public:
     41   // kNeverDefer - Aggresively buffer; never defer loading while paused.
     42   // kReadThenDefer - Request only enough data to fulfill read requests.
     43   // kCapacityDefer - Try to keep amount of buffered data at capacity.
     44   enum DeferStrategy {
     45     kNeverDefer,
     46     kReadThenDefer,
     47     kCapacityDefer,
     48   };
     49 
     50   // Status codes for start/read operations on BufferedResourceLoader.
     51   enum Status {
     52     // Everything went as planned.
     53     kOk,
     54 
     55     // The operation failed, which may have been due to:
     56     //   - Page navigation
     57     //   - Server replied 4xx/5xx
     58     //   - The response was invalid
     59     //   - Connection was terminated
     60     //
     61     // At this point you should delete the loader.
     62     kFailed,
     63 
     64     // The loader will never be able to satisfy the read request. Please stop,
     65     // delete, create a new loader, and try again.
     66     kCacheMiss,
     67   };
     68 
     69   // Keep in sync with WebMediaPlayer::CORSMode.
     70   enum CORSMode { kUnspecified, kAnonymous, kUseCredentials };
     71 
     72   enum LoadingState {
     73     kLoading,  // Actively attempting to download data.
     74     kLoadingDeferred,  // Loading intentionally deferred.
     75     kLoadingFinished,  // Loading finished normally; no more data will arrive.
     76     kLoadingFailed,  // Loading finished abnormally; no more data will arrive.
     77   };
     78 
     79   // |url| - URL for the resource to be loaded.
     80   // |cors_mode| - HTML media element's crossorigin attribute.
     81   // |first_byte_position| - First byte to start loading from,
     82   // |kPositionNotSpecified| for not specified.
     83   // |last_byte_position| - Last byte to be loaded,
     84   // |kPositionNotSpecified| for not specified.
     85   // |strategy| is the initial loading strategy to use.
     86   // |bitrate| is the bitrate of the media, 0 if unknown.
     87   // |playback_rate| is the current playback rate of the media.
     88   BufferedResourceLoader(
     89       const GURL& url,
     90       CORSMode cors_mode,
     91       int64 first_byte_position,
     92       int64 last_byte_position,
     93       DeferStrategy strategy,
     94       int bitrate,
     95       float playback_rate,
     96       media::MediaLog* media_log);
     97   virtual ~BufferedResourceLoader();
     98 
     99   // Start the resource loading with the specified URL and range.
    100   //
    101   // |loading_cb| is executed when the loading state has changed.
    102   // |progress_cb| is executed when additional data has arrived.
    103   typedef base::Callback<void(Status)> StartCB;
    104   typedef base::Callback<void(LoadingState)> LoadingStateChangedCB;
    105   typedef base::Callback<void(int64)> ProgressCB;
    106   void Start(const StartCB& start_cb,
    107              const LoadingStateChangedCB& loading_cb,
    108              const ProgressCB& progress_cb,
    109              blink::WebFrame* frame);
    110 
    111   // Stops everything associated with this loader, including active URL loads
    112   // and pending callbacks.
    113   //
    114   // It is safe to delete a BufferedResourceLoader after calling Stop().
    115   void Stop();
    116 
    117   // Copies |read_size| bytes from |position| into |buffer|, executing |read_cb|
    118   // when the operation has completed.
    119   //
    120   // The callback will contain the number of bytes read iff the status is kOk,
    121   // zero otherwise.
    122   //
    123   // If necessary will temporarily increase forward capacity of buffer to
    124   // accomodate an unusually large read.
    125   typedef base::Callback<void(Status, int)> ReadCB;
    126   void Read(int64 position, int read_size,
    127             uint8* buffer, const ReadCB& read_cb);
    128 
    129   // Gets the content length in bytes of the instance after this loader has been
    130   // started. If this value is |kPositionNotSpecified|, then content length is
    131   // unknown.
    132   int64 content_length();
    133 
    134   // Gets the original size of the file requested. If this value is
    135   // |kPositionNotSpecified|, then the size is unknown.
    136   int64 instance_size();
    137 
    138   // Returns true if the server supports byte range requests.
    139   bool range_supported();
    140 
    141   // blink::WebURLLoaderClient implementation.
    142   virtual void willSendRequest(
    143       blink::WebURLLoader* loader,
    144       blink::WebURLRequest& newRequest,
    145       const blink::WebURLResponse& redirectResponse);
    146   virtual void didSendData(
    147       blink::WebURLLoader* loader,
    148       unsigned long long bytesSent,
    149       unsigned long long totalBytesToBeSent);
    150   virtual void didReceiveResponse(
    151       blink::WebURLLoader* loader,
    152       const blink::WebURLResponse& response);
    153   virtual void didDownloadData(
    154       blink::WebURLLoader* loader,
    155       int data_length,
    156       int encoded_data_length);
    157   virtual void didReceiveData(
    158       blink::WebURLLoader* loader,
    159       const char* data,
    160       int data_length,
    161       int encoded_data_length);
    162   virtual void didReceiveCachedMetadata(
    163       blink::WebURLLoader* loader,
    164       const char* data, int dataLength);
    165   virtual void didFinishLoading(
    166       blink::WebURLLoader* loader,
    167       double finishTime);
    168   virtual void didFail(
    169       blink::WebURLLoader* loader,
    170       const blink::WebURLError&);
    171 
    172   // Returns true if the media resource has a single origin, false otherwise.
    173   // Only valid to call after Start() has completed.
    174   bool HasSingleOrigin() const;
    175 
    176   // Returns true if the media resource passed a CORS access control check.
    177   // Only valid to call after Start() has completed.
    178   bool DidPassCORSAccessCheck() const;
    179 
    180   // Sets the defer strategy to the given value unless it seems unwise.
    181   // Specifically downgrade kNeverDefer to kCapacityDefer if we know the
    182   // current response will not be used to satisfy future requests (the cache
    183   // won't help us).
    184   void UpdateDeferStrategy(DeferStrategy strategy);
    185 
    186   // Sets the playback rate to the given value and updates buffer window
    187   // accordingly.
    188   void SetPlaybackRate(float playback_rate);
    189 
    190   // Sets the bitrate to the given value and updates buffer window
    191   // accordingly.
    192   void SetBitrate(int bitrate);
    193 
    194   // Return the |first_byte_position| passed into the ctor.
    195   int64 first_byte_position() const;
    196 
    197   // Parse a Content-Range header into its component pieces and return true if
    198   // each of the expected elements was found & parsed correctly.
    199   // |*instance_size| may be set to kPositionNotSpecified if the range ends in
    200   // "/*".
    201   // NOTE: only public for testing!  This is an implementation detail of
    202   // VerifyPartialResponse (a private method).
    203   static bool ParseContentRange(
    204       const std::string& content_range_str, int64* first_byte_position,
    205       int64* last_byte_position, int64* instance_size);
    206 
    207  private:
    208   friend class BufferedDataSourceTest;
    209   friend class BufferedResourceLoaderTest;
    210   friend class MockBufferedDataSource;
    211 
    212   // Updates the |buffer_|'s forward and backward capacities.
    213   void UpdateBufferWindow();
    214 
    215   // Updates deferring behavior based on current buffering scheme.
    216   void UpdateDeferBehavior();
    217 
    218   // Sets |active_loader_|'s defer state and fires |loading_cb_| if the state
    219   // changed.
    220   void SetDeferred(bool deferred);
    221 
    222   // Returns true if we should defer resource loading based on the current
    223   // buffering scheme.
    224   bool ShouldDefer() const;
    225 
    226   // Returns true if the current read request can be fulfilled by what is in
    227   // the buffer.
    228   bool CanFulfillRead() const;
    229 
    230   // Returns true if the current read request will be fulfilled in the future.
    231   bool WillFulfillRead() const;
    232 
    233   // Method that does the actual read and calls the |read_cb_|, assuming the
    234   // request range is in |buffer_|.
    235   void ReadInternal();
    236 
    237   // If we have made a range request, verify the response from the server.
    238   bool VerifyPartialResponse(const blink::WebURLResponse& response);
    239 
    240   // Done with read. Invokes the read callback and reset parameters for the
    241   // read request.
    242   void DoneRead(Status status, int bytes_read);
    243 
    244   // Done with start. Invokes the start callback and reset it.
    245   void DoneStart(Status status);
    246 
    247   bool HasPendingRead() { return !read_cb_.is_null(); }
    248 
    249   // Helper function that returns true if a range request was specified.
    250   bool IsRangeRequest() const;
    251 
    252   // Log everything interesting to |media_log_|.
    253   void Log();
    254 
    255   // A sliding window of buffer.
    256   media::SeekableBuffer buffer_;
    257 
    258   // Keeps track of an active WebURLLoader and associated state.
    259   scoped_ptr<ActiveLoader> active_loader_;
    260 
    261   // Tracks if |active_loader_| failed. If so, then all calls to Read() will
    262   // fail.
    263   bool loader_failed_;
    264 
    265   // Current buffering algorithm in place for resource loading.
    266   DeferStrategy defer_strategy_;
    267 
    268   // True if the currently-reading response might be used to satisfy a future
    269   // request from the cache.
    270   bool might_be_reused_from_cache_in_future_;
    271 
    272   // True if Range header is supported.
    273   bool range_supported_;
    274 
    275   // Forward capacity to reset to after an extension.
    276   size_t saved_forward_capacity_;
    277 
    278   GURL url_;
    279   CORSMode cors_mode_;
    280   const int64 first_byte_position_;
    281   const int64 last_byte_position_;
    282   bool single_origin_;
    283 
    284   // Executed whenever the state of resource loading has changed.
    285   LoadingStateChangedCB loading_cb_;
    286 
    287   // Executed whenever additional data has been downloaded and reports the
    288   // zero-indexed file offset of the furthest buffered byte.
    289   ProgressCB progress_cb_;
    290 
    291   // Members used during request start.
    292   StartCB start_cb_;
    293   int64 offset_;
    294   int64 content_length_;
    295   int64 instance_size_;
    296 
    297   // Members used during a read operation. They should be reset after each
    298   // read has completed or failed.
    299   ReadCB read_cb_;
    300   int64 read_position_;
    301   int read_size_;
    302   uint8* read_buffer_;
    303 
    304   // Offsets of the requested first byte and last byte in |buffer_|. They are
    305   // written by Read().
    306   int first_offset_;
    307   int last_offset_;
    308 
    309   // Injected WebURLLoader instance for testing purposes.
    310   scoped_ptr<blink::WebURLLoader> test_loader_;
    311 
    312   // Bitrate of the media. Set to 0 if unknown.
    313   int bitrate_;
    314 
    315   // Playback rate of the media.
    316   float playback_rate_;
    317 
    318   scoped_refptr<media::MediaLog> media_log_;
    319 
    320   DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoader);
    321 };
    322 
    323 }  // namespace content
    324 
    325 #endif  // CONTENT_RENDERER_MEDIA_BUFFERED_RESOURCE_LOADER_H_
    326