buffered_data_source.h revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2010 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 WEBKIT_GLUE_MEDIA_BUFFERED_DATA_SOURCE_H_ 6#define WEBKIT_GLUE_MEDIA_BUFFERED_DATA_SOURCE_H_ 7 8#include <string> 9 10#include "base/callback.h" 11#include "base/lock.h" 12#include "base/scoped_ptr.h" 13#include "base/timer.h" 14#include "base/condition_variable.h" 15#include "googleurl/src/gurl.h" 16#include "media/base/filters.h" 17#include "media/base/media_format.h" 18#include "media/base/pipeline.h" 19#include "media/base/seekable_buffer.h" 20#include "net/base/completion_callback.h" 21#include "net/base/file_stream.h" 22#include "webkit/glue/media/media_resource_loader_bridge_factory.h" 23#include "webkit/glue/media/web_data_source.h" 24#include "webkit/glue/webmediaplayer_impl.h" 25 26namespace webkit_glue { 27///////////////////////////////////////////////////////////////////////////// 28// BufferedResourceLoader 29// This class works inside demuxer thread and render thread. It contains a 30// resource loader bridge and does the actual resource loading. This object 31// does buffering internally, it defers the resource loading if buffer is 32// full and un-defers the resource loading if it is under buffered. 33class BufferedResourceLoader : 34 public base::RefCountedThreadSafe<BufferedResourceLoader>, 35 public webkit_glue::ResourceLoaderBridge::Peer { 36 public: 37 typedef Callback0::Type NetworkEventCallback; 38 39 // |bridge_factory| - Factory to create a ResourceLoaderBridge. 40 // |url| - URL for the resource to be loaded. 41 // |first_byte_position| - First byte to start loading from, -1 for not 42 // specified. 43 // |last_byte_position| - Last byte to be loaded, -1 for not specified. 44 BufferedResourceLoader( 45 webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory, 46 const GURL& url, 47 int64 first_byte_position, 48 int64 last_byte_position); 49 50 // Start the resource loading with the specified URL and range. 51 // This method operates in asynchronous mode. Once there's a response from the 52 // server, success or fail |callback| is called with the result. 53 // |callback| is called with the following values: 54 // - net::OK 55 // The request has started successfully. 56 // - net::ERR_FAILED 57 // The request has failed because of an error with the network. 58 // - net::ERR_INVALID_RESPONSE 59 // An invalid response is received from the server. 60 // - (Anything else) 61 // An error code that indicates the request has failed. 62 // |event_callback| is called when the response is completed, data is 63 // received, the request is suspended or resumed. 64 virtual void Start(net::CompletionCallback* callback, 65 NetworkEventCallback* event_callback); 66 67 // Stop this loader, cancels and request and release internal buffer. 68 virtual void Stop(); 69 70 // Reads the specified |read_size| from |position| into |buffer| and when 71 // the operation is done invoke |callback| with number of bytes read or an 72 // error code. 73 // |callback| is called with the following values: 74 // - (Anything greater than or equal 0) 75 // Read was successful with the indicated number of bytes read. 76 // - net::ERR_FAILED 77 // The read has failed because of an error with the network. 78 // - net::ERR_CACHE_MISS 79 // The read was made too far away from the current buffered position. 80 virtual void Read(int64 position, int read_size, 81 uint8* buffer, net::CompletionCallback* callback); 82 83 // Returns the position of the first byte buffered. Returns -1 if such value 84 // is not available. 85 virtual int64 GetBufferedFirstBytePosition(); 86 87 // Returns the position of the last byte buffered. Returns -1 if such value 88 // is not available. 89 virtual int64 GetBufferedLastBytePosition(); 90 91 // Sets whether deferring data is allowed or disallowed. 92 virtual void SetAllowDefer(bool is_allowed); 93 94 // Gets the content length in bytes of the instance after this loader has been 95 // started. If this value is -1, then content length is unknown. 96 virtual int64 content_length() { return content_length_; } 97 98 // Gets the original size of the file requested. If this value is -1, then 99 // the size is unknown. 100 virtual int64 instance_size() { return instance_size_; } 101 102 // Returns true if the response for this loader is a partial response. 103 // It means a 206 response in HTTP/HTTPS protocol. 104 virtual bool partial_response() { return partial_response_; } 105 106 // Returns true if network is currently active. 107 virtual bool network_activity() { return !completed_ && !deferred_; } 108 109 // Returns resulting URL. 110 virtual const GURL& url() { return url_; } 111 112 ///////////////////////////////////////////////////////////////////////////// 113 // webkit_glue::ResourceLoaderBridge::Peer implementations. 114 virtual void OnUploadProgress(uint64 position, uint64 size) {} 115 virtual bool OnReceivedRedirect( 116 const GURL& new_url, 117 const webkit_glue::ResourceResponseInfo& info, 118 bool* has_new_first_party_for_cookies, 119 GURL* new_first_party_for_cookies); 120 virtual void OnReceivedResponse( 121 const webkit_glue::ResourceResponseInfo& info, 122 bool content_filtered); 123 virtual void OnDownloadedData(int len) {} 124 virtual void OnReceivedData(const char* data, int len); 125 virtual void OnCompletedRequest( 126 const URLRequestStatus& status, 127 const std::string& security_info, 128 const base::Time& completion_time); 129 130 protected: 131 friend class base::RefCountedThreadSafe<BufferedResourceLoader>; 132 133 virtual ~BufferedResourceLoader(); 134 135 private: 136 friend class BufferedResourceLoaderTest; 137 138 // Defer the resource loading if the buffer is full. 139 void EnableDeferIfNeeded(); 140 141 // Disable defer loading if we are under-buffered. 142 void DisableDeferIfNeeded(); 143 144 // Returns true if the current read request can be fulfilled by what is in 145 // the buffer. 146 bool CanFulfillRead(); 147 148 // Returns true if the current read request will be fulfilled in the future. 149 bool WillFulfillRead(); 150 151 // Method that does the actual read and calls the |read_callbac_|, assuming 152 // the request range is in |buffer_|. 153 void ReadInternal(); 154 155 // If we have made a range request, verify the response from the server. 156 bool VerifyPartialResponse(const ResourceResponseInfo& info); 157 158 // Done with read. Invokes the read callback and reset parameters for the 159 // read request. 160 void DoneRead(int error); 161 162 // Done with start. Invokes the start callback and reset it. 163 void DoneStart(int error); 164 165 // Calls |event_callback_| in terms of a network event. 166 void NotifyNetworkEvent(); 167 168 bool HasPendingRead() { return read_callback_.get() != NULL; } 169 170 // A sliding window of buffer. 171 scoped_ptr<media::SeekableBuffer> buffer_; 172 173 // True if resource loading was deferred. 174 bool deferred_; 175 176 // True if resource loader is allowed to defer, false otherwise. 177 bool defer_allowed_; 178 179 // True if resource loading has completed. 180 bool completed_; 181 182 // True if a range request was made. 183 bool range_requested_; 184 185 // True if response data received is a partial range. 186 bool partial_response_; 187 188 webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory_; 189 GURL url_; 190 int64 first_byte_position_; 191 int64 last_byte_position_; 192 193 // Callback method that listens to network events. 194 scoped_ptr<NetworkEventCallback> event_callback_; 195 196 // Members used during request start. 197 scoped_ptr<net::CompletionCallback> start_callback_; 198 scoped_ptr<webkit_glue::ResourceLoaderBridge> bridge_; 199 int64 offset_; 200 int64 content_length_; 201 int64 instance_size_; 202 203 // Members used during a read operation. They should be reset after each 204 // read has completed or failed. 205 scoped_ptr<net::CompletionCallback> read_callback_; 206 int64 read_position_; 207 int read_size_; 208 uint8* read_buffer_; 209 210 // Offsets of the requested first byte and last byte in |buffer_|. They are 211 // written by VerifyRead(). 212 int first_offset_; 213 int last_offset_; 214 215 DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoader); 216}; 217 218class BufferedDataSource : public WebDataSource { 219 public: 220 BufferedDataSource( 221 MessageLoop* render_loop, 222 webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory); 223 224 virtual ~BufferedDataSource(); 225 226 // media::MediaFilter implementation. 227 virtual void Initialize(const std::string& url, 228 media::FilterCallback* callback); 229 virtual bool IsUrlSupported(const std::string& url); 230 virtual void Stop(media::FilterCallback* callback); 231 virtual void SetPlaybackRate(float playback_rate); 232 233 // media::DataSource implementation. 234 // Called from demuxer thread. 235 virtual void Read(int64 position, size_t size, 236 uint8* data, 237 media::DataSource::ReadCallback* read_callback); 238 virtual bool GetSize(int64* size_out); 239 virtual bool IsStreaming(); 240 241 const media::MediaFormat& media_format() { 242 return media_format_; 243 } 244 245 // webkit_glue::WebDataSource implementation. 246 virtual bool HasSingleOrigin(); 247 virtual void Abort(); 248 249 protected: 250 251 // A factory method to create a BufferedResourceLoader based on the read 252 // parameters. We can override this file to object a mock 253 // BufferedResourceLoader for testing. 254 virtual BufferedResourceLoader* CreateResourceLoader( 255 int64 first_byte_position, int64 last_byte_position); 256 257 // Gets the number of milliseconds to declare a request timeout since 258 // the request was made. This method is made virtual so as to inject a 259 // different number for testing purpose. 260 virtual base::TimeDelta GetTimeoutMilliseconds(); 261 262 private: 263 // Posted to perform initialization on render thread and start resource 264 // loading. 265 void InitializeTask(); 266 267 // Task posted to perform actual reading on the render thread. 268 void ReadTask(int64 position, int read_size, uint8* read_buffer, 269 media::DataSource::ReadCallback* read_callback); 270 271 // Task posted when Stop() is called. Stops |watch_dog_timer_| and 272 // |loader_|, reset Read() variables, and set |stopped_on_render_loop_| 273 // to signal any remaining tasks to stop. 274 void CleanupTask(); 275 276 // Restart resource loading on render thread. 277 void RestartLoadingTask(); 278 279 // This task monitors the current active read request. If the current read 280 // request has timed out, this task will destroy the current loader and 281 // creates a new one to accommodate the read request. 282 void WatchDogTask(); 283 284 // This task uses the current playback rate with the previous playback rate 285 // to determine whether we are going from pause to play and play to pause, 286 // and signals the buffered resource loader accordingly. 287 void SetPlaybackRateTask(float playback_rate); 288 289 // The method that performs actual read. This method can only be executed on 290 // the render thread. 291 void ReadInternal(); 292 293 // Calls |read_callback_| and reset all read parameters. 294 void DoneRead_Locked(int error); 295 296 // Calls |initialize_callback_| and reset it. 297 void DoneInitialization_Locked(); 298 299 // Callback method for |loader_| if URL for the resource requested is using 300 // HTTP protocol. This method is called when response for initial request is 301 // received. 302 void HttpInitialStartCallback(int error); 303 304 // Callback method for |loader_| if URL for the resource requested is using 305 // a non-HTTP protocol, e.g. local files. This method is called when response 306 // for initial request is received. 307 void NonHttpInitialStartCallback(int error); 308 309 // Callback method to be passed to BufferedResourceLoader during range 310 // request. Once a resource request has started, this method will be called 311 // with the error code. This method will be executed on the thread 312 // BufferedResourceLoader lives, i.e. render thread. 313 void PartialReadStartCallback(int error); 314 315 // Callback method for making a read request to BufferedResourceLoader. 316 // If data arrives or the request has failed, this method is called with 317 // the error code or the number of bytes read. 318 void ReadCallback(int error); 319 320 // Callback method when a network event is received. 321 void NetworkEventCallback(); 322 323 media::MediaFormat media_format_; 324 325 // URL of the resource requested. 326 GURL url_; 327 328 // Members for total bytes of the requested object. It is written once on 329 // render thread but may be read from any thread. However reading of this 330 // member is guaranteed to happen after it is first written, so we don't 331 // need to protect it. 332 int64 total_bytes_; 333 334 // True if this data source is considered loaded. 335 bool loaded_; 336 337 // This value will be true if this data source can only support streaming. 338 // i.e. range request is not supported. 339 bool streaming_; 340 341 // True if the media resource has a single origin. 342 bool single_origin_; 343 344 // A factory object to produce ResourceLoaderBridge. 345 scoped_ptr<webkit_glue::MediaResourceLoaderBridgeFactory> bridge_factory_; 346 347 // A resource loader for the media resource. 348 scoped_refptr<BufferedResourceLoader> loader_; 349 350 // True if network is active. 351 bool network_activity_; 352 353 // Callback method from the pipeline for initialization. 354 scoped_ptr<media::FilterCallback> initialize_callback_; 355 356 // Read parameters received from the Read() method call. 357 scoped_ptr<media::DataSource::ReadCallback> read_callback_; 358 int64 read_position_; 359 int read_size_; 360 uint8* read_buffer_; 361 base::Time read_submitted_time_; 362 int read_attempts_; 363 364 // This buffer is intermediate, we use it for BufferedResourceLoader to write 365 // to. And when read in BufferedResourceLoader is done, we copy data from 366 // this buffer to |read_buffer_|. The reason for an additional copy is that 367 // we don't own |read_buffer_|. But since the read operation is asynchronous, 368 // |read_buffer| can be destroyed at any time, so we only copy into 369 // |read_buffer| in the final step when it is safe. 370 // Memory is allocated for this member during initialization of this object 371 // because we want buffer to be passed into BufferedResourceLoader to be 372 // always non-null. And by initializing this member with a default size we can 373 // avoid creating zero-sized buffered if the first read has zero size. 374 scoped_array<uint8> intermediate_read_buffer_; 375 int intermediate_read_buffer_size_; 376 377 // The message loop of the render thread. 378 MessageLoop* render_loop_; 379 380 // Protects |stopped_|. 381 Lock lock_; 382 383 // Stop signal to suppressing activities. This variable is set on the pipeline 384 // thread and read from the render thread. 385 bool stop_signal_received_; 386 387 // This variable is set by CleanupTask() that indicates this object is stopped 388 // on the render thread. 389 bool stopped_on_render_loop_; 390 391 // This variable is true when we are in a paused state and false when we 392 // are in a playing state. 393 bool media_is_paused_; 394 395 // This timer is to run the WatchDogTask repeatedly. We use a timer instead 396 // of doing PostDelayedTask() reduce the extra reference held by the message 397 // loop. The RepeatingTimer does PostDelayedTask() internally, by using it 398 // the message loop doesn't hold a reference for the watch dog task. 399 base::RepeatingTimer<BufferedDataSource> watch_dog_timer_; 400 401 // Keeps track of whether we used a Range header in the initialization 402 // request. 403 bool using_range_request_; 404 405 DISALLOW_COPY_AND_ASSIGN(BufferedDataSource); 406}; 407 408} // namespace webkit_glue 409 410#endif // WEBKIT_GLUE_MEDIA_BUFFERED_DATA_SOURCE_H_ 411