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