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