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