• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
NON_EXPORTED_BASE(public blink::WebURLLoaderClient)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