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.
5 #ifndef CONTENT_RENDERER_MEDIA_BUFFERED_RESOURCE_LOADER_H_
6 #define CONTENT_RENDERER_MEDIA_BUFFERED_RESOURCE_LOADER_H_
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"
29 const int64 kPositionNotSpecified = -1;
31 const char kHttpScheme[] = "http";
32 const char kHttpsScheme[] = "https";
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 WebKit::WebURLLoaderClient) {
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.
50 // Status codes for start/read operations on BufferedResourceLoader.
52 // Everything went as planned.
55 // The operation failed, which may have been due to:
57 // - Server replied 4xx/5xx
58 // - The response was invalid
59 // - Connection was terminated
61 // At this point you should delete the loader.
64 // The loader will never be able to satisfy the read request. Please stop,
65 // delete, create a new loader, and try again.
69 // Keep in sync with WebMediaPlayer::CORSMode.
70 enum CORSMode { kUnspecified, kAnonymous, kUseCredentials };
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.
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(
91 int64 first_byte_position,
92 int64 last_byte_position,
93 DeferStrategy strategy,
96 media::MediaLog* media_log);
97 virtual ~BufferedResourceLoader();
99 // Start the resource loading with the specified URL and range.
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 WebKit::WebFrame* frame);
111 // Stops everything associated with this loader, including active URL loads
112 // and pending callbacks.
114 // It is safe to delete a BufferedResourceLoader after calling Stop().
117 // Copies |read_size| bytes from |position| into |buffer|, executing |read_cb|
118 // when the operation has completed.
120 // The callback will contain the number of bytes read iff the status is kOk,
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);
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
132 int64 content_length();
134 // Gets the original size of the file requested. If this value is
135 // |kPositionNotSpecified|, then the size is unknown.
136 int64 instance_size();
138 // Returns true if the server supports byte range requests.
139 bool range_supported();
141 // WebKit::WebURLLoaderClient implementation.
142 virtual void willSendRequest(
143 WebKit::WebURLLoader* loader,
144 WebKit::WebURLRequest& newRequest,
145 const WebKit::WebURLResponse& redirectResponse);
146 virtual void didSendData(
147 WebKit::WebURLLoader* loader,
148 unsigned long long bytesSent,
149 unsigned long long totalBytesToBeSent);
150 virtual void didReceiveResponse(
151 WebKit::WebURLLoader* loader,
152 const WebKit::WebURLResponse& response);
153 virtual void didDownloadData(
154 WebKit::WebURLLoader* loader,
156 int encoded_data_length);
157 virtual void didReceiveData(
158 WebKit::WebURLLoader* loader,
161 int encoded_data_length);
162 virtual void didReceiveCachedMetadata(
163 WebKit::WebURLLoader* loader,
164 const char* data, int dataLength);
165 virtual void didFinishLoading(
166 WebKit::WebURLLoader* loader,
168 virtual void didFail(
169 WebKit::WebURLLoader* loader,
170 const WebKit::WebURLError&);
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;
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;
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
184 void UpdateDeferStrategy(DeferStrategy strategy);
186 // Sets the playback rate to the given value and updates buffer window
188 void SetPlaybackRate(float playback_rate);
190 // Sets the bitrate to the given value and updates buffer window
192 void SetBitrate(int bitrate);
194 // Return the |first_byte_position| passed into the ctor.
195 int64 first_byte_position() const;
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
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);
208 friend class BufferedDataSourceTest;
209 friend class BufferedResourceLoaderTest;
210 friend class MockBufferedDataSource;
212 // Updates the |buffer_|'s forward and backward capacities.
213 void UpdateBufferWindow();
215 // Updates deferring behavior based on current buffering scheme.
216 void UpdateDeferBehavior();
218 // Sets |active_loader_|'s defer state and fires |loading_cb_| if the state
220 void SetDeferred(bool deferred);
222 // Returns true if we should defer resource loading based on the current
224 bool ShouldDefer() const;
226 // Returns true if the current read request can be fulfilled by what is in
228 bool CanFulfillRead() const;
230 // Returns true if the current read request will be fulfilled in the future.
231 bool WillFulfillRead() const;
233 // Method that does the actual read and calls the |read_cb_|, assuming the
234 // request range is in |buffer_|.
237 // If we have made a range request, verify the response from the server.
238 bool VerifyPartialResponse(const WebKit::WebURLResponse& response);
240 // Returns the value for a range request header using parameters
241 // |first_byte_position| and |last_byte_position|. Negative numbers other
242 // than |kPositionNotSpecified| are not allowed for |first_byte_position| and
243 // |last_byte_position|. |first_byte_position| should always be less than or
244 // equal to |last_byte_position| if they are both not |kPositionNotSpecified|.
245 // Empty string is returned on invalid parameters.
246 std::string GenerateHeaders(int64 first_byte_position,
247 int64 last_byte_position);
249 // Done with read. Invokes the read callback and reset parameters for the
251 void DoneRead(Status status, int bytes_read);
253 // Done with start. Invokes the start callback and reset it.
254 void DoneStart(Status status);
256 bool HasPendingRead() { return !read_cb_.is_null(); }
258 // Helper function that returns true if a range request was specified.
259 bool IsRangeRequest() const;
261 // Log everything interesting to |media_log_|.
264 // A sliding window of buffer.
265 media::SeekableBuffer buffer_;
267 // Keeps track of an active WebURLLoader and associated state.
268 scoped_ptr<ActiveLoader> active_loader_;
270 // Tracks if |active_loader_| failed. If so, then all calls to Read() will
274 // Current buffering algorithm in place for resource loading.
275 DeferStrategy defer_strategy_;
277 // True if the currently-reading response might be used to satisfy a future
278 // request from the cache.
279 bool might_be_reused_from_cache_in_future_;
281 // True if Range header is supported.
282 bool range_supported_;
284 // Forward capacity to reset to after an extension.
285 size_t saved_forward_capacity_;
289 const int64 first_byte_position_;
290 const int64 last_byte_position_;
293 // Executed whenever the state of resource loading has changed.
294 LoadingStateChangedCB loading_cb_;
296 // Executed whenever additional data has been downloaded and reports the
297 // zero-indexed file offset of the furthest buffered byte.
298 ProgressCB progress_cb_;
300 // Members used during request start.
303 int64 content_length_;
304 int64 instance_size_;
306 // Members used during a read operation. They should be reset after each
307 // read has completed or failed.
309 int64 read_position_;
313 // Offsets of the requested first byte and last byte in |buffer_|. They are
314 // written by Read().
318 // Injected WebURLLoader instance for testing purposes.
319 scoped_ptr<WebKit::WebURLLoader> test_loader_;
321 // Bitrate of the media. Set to 0 if unknown.
324 // Playback rate of the media.
325 float playback_rate_;
327 scoped_refptr<media::MediaLog> media_log_;
329 DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoader);
332 } // namespace content
334 #endif // CONTENT_RENDERER_MEDIA_BUFFERED_RESOURCE_LOADER_H_