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
22namespace media {
23class MediaLog;
24class SeekableBuffer;
25
26const 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.
32class 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