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