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 const char kHttpScheme[] = "http"; 32 const char kHttpsScheme[] = "https"; 33 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) { 40 public: 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. 44 enum DeferStrategy { 45 kNeverDefer, 46 kReadThenDefer, 47 kCapacityDefer, 48 }; 49 50 // Status codes for start/read operations on BufferedResourceLoader. 51 enum Status { 52 // Everything went as planned. 53 kOk, 54 55 // The operation failed, which may have been due to: 56 // - Page navigation 57 // - Server replied 4xx/5xx 58 // - The response was invalid 59 // - Connection was terminated 60 // 61 // At this point you should delete the loader. 62 kFailed, 63 64 // The loader will never be able to satisfy the read request. Please stop, 65 // delete, create a new loader, and try again. 66 kCacheMiss, 67 }; 68 69 // Keep in sync with WebMediaPlayer::CORSMode. 70 enum CORSMode { kUnspecified, kAnonymous, kUseCredentials }; 71 72 enum LoadingState { 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. 77 }; 78 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( 89 const GURL& url, 90 CORSMode cors_mode, 91 int64 first_byte_position, 92 int64 last_byte_position, 93 DeferStrategy strategy, 94 int bitrate, 95 float playback_rate, 96 media::MediaLog* media_log); 97 virtual ~BufferedResourceLoader(); 98 99 // Start the resource loading with the specified URL and range. 100 // 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); 110 111 // Stops everything associated with this loader, including active URL loads 112 // and pending callbacks. 113 // 114 // It is safe to delete a BufferedResourceLoader after calling Stop(). 115 void Stop(); 116 117 // Copies |read_size| bytes from |position| into |buffer|, executing |read_cb| 118 // when the operation has completed. 119 // 120 // The callback will contain the number of bytes read iff the status is kOk, 121 // zero otherwise. 122 // 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); 128 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 131 // unknown. 132 int64 content_length(); 133 134 // Gets the original size of the file requested. If this value is 135 // |kPositionNotSpecified|, then the size is unknown. 136 int64 instance_size(); 137 138 // Returns true if the server supports byte range requests. 139 bool range_supported(); 140 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, 155 int data_length); 156 virtual void didReceiveData( 157 WebKit::WebURLLoader* loader, 158 const char* data, 159 int data_length, 160 int encoded_data_length); 161 virtual void didReceiveCachedMetadata( 162 WebKit::WebURLLoader* loader, 163 const char* data, int dataLength); 164 virtual void didFinishLoading( 165 WebKit::WebURLLoader* loader, 166 double finishTime); 167 virtual void didFail( 168 WebKit::WebURLLoader* loader, 169 const WebKit::WebURLError&); 170 171 // Returns true if the media resource has a single origin, false otherwise. 172 // Only valid to call after Start() has completed. 173 bool HasSingleOrigin() const; 174 175 // Returns true if the media resource passed a CORS access control check. 176 // Only valid to call after Start() has completed. 177 bool DidPassCORSAccessCheck() const; 178 179 // Sets the defer strategy to the given value unless it seems unwise. 180 // Specifically downgrade kNeverDefer to kCapacityDefer if we know the 181 // current response will not be used to satisfy future requests (the cache 182 // won't help us). 183 void UpdateDeferStrategy(DeferStrategy strategy); 184 185 // Sets the playback rate to the given value and updates buffer window 186 // accordingly. 187 void SetPlaybackRate(float playback_rate); 188 189 // Sets the bitrate to the given value and updates buffer window 190 // accordingly. 191 void SetBitrate(int bitrate); 192 193 // Return the |first_byte_position| passed into the ctor. 194 int64 first_byte_position() const; 195 196 // Parse a Content-Range header into its component pieces and return true if 197 // each of the expected elements was found & parsed correctly. 198 // |*instance_size| may be set to kPositionNotSpecified if the range ends in 199 // "/*". 200 // NOTE: only public for testing! This is an implementation detail of 201 // VerifyPartialResponse (a private method). 202 static bool ParseContentRange( 203 const std::string& content_range_str, int64* first_byte_position, 204 int64* last_byte_position, int64* instance_size); 205 206 private: 207 friend class BufferedDataSourceTest; 208 friend class BufferedResourceLoaderTest; 209 friend class MockBufferedDataSource; 210 211 // Updates the |buffer_|'s forward and backward capacities. 212 void UpdateBufferWindow(); 213 214 // Updates deferring behavior based on current buffering scheme. 215 void UpdateDeferBehavior(); 216 217 // Sets |active_loader_|'s defer state and fires |loading_cb_| if the state 218 // changed. 219 void SetDeferred(bool deferred); 220 221 // Returns true if we should defer resource loading based on the current 222 // buffering scheme. 223 bool ShouldDefer() const; 224 225 // Returns true if the current read request can be fulfilled by what is in 226 // the buffer. 227 bool CanFulfillRead() const; 228 229 // Returns true if the current read request will be fulfilled in the future. 230 bool WillFulfillRead() const; 231 232 // Method that does the actual read and calls the |read_cb_|, assuming the 233 // request range is in |buffer_|. 234 void ReadInternal(); 235 236 // If we have made a range request, verify the response from the server. 237 bool VerifyPartialResponse(const WebKit::WebURLResponse& response); 238 239 // Returns the value for a range request header using parameters 240 // |first_byte_position| and |last_byte_position|. Negative numbers other 241 // than |kPositionNotSpecified| are not allowed for |first_byte_position| and 242 // |last_byte_position|. |first_byte_position| should always be less than or 243 // equal to |last_byte_position| if they are both not |kPositionNotSpecified|. 244 // Empty string is returned on invalid parameters. 245 std::string GenerateHeaders(int64 first_byte_position, 246 int64 last_byte_position); 247 248 // Done with read. Invokes the read callback and reset parameters for the 249 // read request. 250 void DoneRead(Status status, int bytes_read); 251 252 // Done with start. Invokes the start callback and reset it. 253 void DoneStart(Status status); 254 255 bool HasPendingRead() { return !read_cb_.is_null(); } 256 257 // Helper function that returns true if a range request was specified. 258 bool IsRangeRequest() const; 259 260 // Log everything interesting to |media_log_|. 261 void Log(); 262 263 // A sliding window of buffer. 264 media::SeekableBuffer buffer_; 265 266 // Keeps track of an active WebURLLoader and associated state. 267 scoped_ptr<ActiveLoader> active_loader_; 268 269 // Tracks if |active_loader_| failed. If so, then all calls to Read() will 270 // fail. 271 bool loader_failed_; 272 273 // Current buffering algorithm in place for resource loading. 274 DeferStrategy defer_strategy_; 275 276 // True if the currently-reading response might be used to satisfy a future 277 // request from the cache. 278 bool might_be_reused_from_cache_in_future_; 279 280 // True if Range header is supported. 281 bool range_supported_; 282 283 // Forward capacity to reset to after an extension. 284 size_t saved_forward_capacity_; 285 286 GURL url_; 287 CORSMode cors_mode_; 288 const int64 first_byte_position_; 289 const int64 last_byte_position_; 290 bool single_origin_; 291 292 // Executed whenever the state of resource loading has changed. 293 LoadingStateChangedCB loading_cb_; 294 295 // Executed whenever additional data has been downloaded and reports the 296 // zero-indexed file offset of the furthest buffered byte. 297 ProgressCB progress_cb_; 298 299 // Members used during request start. 300 StartCB start_cb_; 301 int64 offset_; 302 int64 content_length_; 303 int64 instance_size_; 304 305 // Members used during a read operation. They should be reset after each 306 // read has completed or failed. 307 ReadCB read_cb_; 308 int64 read_position_; 309 int read_size_; 310 uint8* read_buffer_; 311 312 // Offsets of the requested first byte and last byte in |buffer_|. They are 313 // written by Read(). 314 int first_offset_; 315 int last_offset_; 316 317 // Injected WebURLLoader instance for testing purposes. 318 scoped_ptr<WebKit::WebURLLoader> test_loader_; 319 320 // Bitrate of the media. Set to 0 if unknown. 321 int bitrate_; 322 323 // Playback rate of the media. 324 float playback_rate_; 325 326 scoped_refptr<media::MediaLog> media_log_; 327 328 DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoader); 329 }; 330 331 } // namespace content 332 333 #endif // CONTENT_RENDERER_MEDIA_BUFFERED_RESOURCE_LOADER_H_ 334