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