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