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