1// Copyright (c) 2011 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/memory/scoped_ptr.h"
12#include "base/synchronization/lock.h"
13#include "media/base/filter_factories.h"
14#include "media/base/filters.h"
15#include "webkit/glue/media/buffered_resource_loader.h"
16
17namespace webkit_glue {
18
19class BufferedDataSource : public WebDataSource {
20 public:
21  // Creates a DataSourceFactory for building BufferedDataSource objects.
22  static media::DataSourceFactory* CreateFactory(
23      MessageLoop* render_loop,
24      WebKit::WebFrame* frame,
25      WebDataSourceBuildObserverHack* build_observer);
26
27  BufferedDataSource(MessageLoop* render_loop,
28                     WebKit::WebFrame* frame);
29
30  virtual ~BufferedDataSource();
31
32  // media::Filter implementation.
33  virtual void set_host(media::FilterHost* host);
34  virtual void Stop(media::FilterCallback* callback);
35  virtual void SetPlaybackRate(float playback_rate);
36
37  // media::DataSource implementation.
38  // Called from demuxer thread.
39  virtual void Read(int64 position, size_t size,
40                    uint8* data,
41                    media::DataSource::ReadCallback* read_callback);
42  virtual bool GetSize(int64* size_out);
43  virtual bool IsStreaming();
44  virtual void SetPreload(media::Preload preload);
45
46  const media::MediaFormat& media_format() {
47    return media_format_;
48  }
49
50  // webkit_glue::WebDataSource implementation.
51  virtual void Initialize(const std::string& url,
52                          media::PipelineStatusCallback* callback);
53  virtual void CancelInitialize();
54  virtual bool HasSingleOrigin();
55  virtual void Abort();
56
57 protected:
58  // A factory method to create a BufferedResourceLoader based on the read
59  // parameters. We can override this file to object a mock
60  // BufferedResourceLoader for testing.
61  virtual BufferedResourceLoader* CreateResourceLoader(
62      int64 first_byte_position, int64 last_byte_position);
63
64  // Gets the number of milliseconds to declare a request timeout since
65  // the request was made. This method is made virtual so as to inject a
66  // different number for testing purpose.
67  virtual base::TimeDelta GetTimeoutMilliseconds();
68
69 private:
70  // Posted to perform initialization on render thread and start resource
71  // loading.
72  void InitializeTask();
73
74  // Task posted to perform actual reading on the render thread.
75  void ReadTask(int64 position, int read_size, uint8* read_buffer);
76
77  // Task posted when Stop() is called. Stops |watch_dog_timer_| and
78  // |loader_|, reset Read() variables, and set |stopped_on_render_loop_|
79  // to signal any remaining tasks to stop.
80  void CleanupTask();
81
82  // Restart resource loading on render thread.
83  void RestartLoadingTask();
84
85  // This task monitors the current active read request. If the current read
86  // request has timed out, this task will destroy the current loader and
87  // creates a new one to accommodate the read request.
88  void WatchDogTask();
89
90  // This task uses the current playback rate with the previous playback rate
91  // to determine whether we are going from pause to play and play to pause,
92  // and signals the buffered resource loader accordingly.
93  void SetPlaybackRateTask(float playback_rate);
94
95  // This task saves the preload value for the media.
96  void SetPreloadTask(media::Preload preload);
97
98  // Decides which DeferStrategy to used based on the current state of the
99  // BufferedDataSource.
100  BufferedResourceLoader::DeferStrategy ChooseDeferStrategy();
101
102  // The method that performs actual read. This method can only be executed on
103  // the render thread.
104  void ReadInternal();
105
106  // Calls |read_callback_| and reset all read parameters.
107  void DoneRead_Locked(int error);
108
109  // Calls |initialize_callback_| and reset it.
110  void DoneInitialization_Locked(media::PipelineStatus status);
111
112  // Callback method for |loader_| if URL for the resource requested is using
113  // HTTP protocol. This method is called when response for initial request is
114  // received.
115  void HttpInitialStartCallback(int error);
116
117  // Callback method for |loader_| if URL for the resource requested is using
118  // a non-HTTP protocol, e.g. local files. This method is called when response
119  // for initial request is received.
120  void NonHttpInitialStartCallback(int error);
121
122  // Callback method to be passed to BufferedResourceLoader during range
123  // request. Once a resource request has started, this method will be called
124  // with the error code. This method will be executed on the thread
125  // BufferedResourceLoader lives, i.e. render thread.
126  void PartialReadStartCallback(int error);
127
128  // Callback method for making a read request to BufferedResourceLoader.
129  // If data arrives or the request has failed, this method is called with
130  // the error code or the number of bytes read.
131  void ReadCallback(int error);
132
133  // Callback method when a network event is received.
134  void NetworkEventCallback();
135
136  void UpdateHostState();
137
138  media::MediaFormat media_format_;
139
140  // URL of the resource requested.
141  GURL url_;
142
143  // Members for total bytes of the requested object. It is written once on
144  // render thread but may be read from any thread. However reading of this
145  // member is guaranteed to happen after it is first written, so we don't
146  // need to protect it.
147  int64 total_bytes_;
148  int64 buffered_bytes_;
149
150  // True if this data source is considered loaded.
151  bool loaded_;
152
153  // This value will be true if this data source can only support streaming.
154  // i.e. range request is not supported.
155  bool streaming_;
156
157  // A webframe for loading.
158  WebKit::WebFrame* frame_;
159
160  // A resource loader for the media resource.
161  scoped_refptr<BufferedResourceLoader> loader_;
162
163  // True if network is active.
164  bool network_activity_;
165
166  // Callback method from the pipeline for initialization.
167  scoped_ptr<media::PipelineStatusCallback> initialize_callback_;
168
169  // Read parameters received from the Read() method call.
170  scoped_ptr<media::DataSource::ReadCallback> read_callback_;
171  int64 read_position_;
172  int read_size_;
173  uint8* read_buffer_;
174  base::Time read_submitted_time_;
175  int read_attempts_;
176
177  // This buffer is intermediate, we use it for BufferedResourceLoader to write
178  // to. And when read in BufferedResourceLoader is done, we copy data from
179  // this buffer to |read_buffer_|. The reason for an additional copy is that
180  // we don't own |read_buffer_|. But since the read operation is asynchronous,
181  // |read_buffer| can be destroyed at any time, so we only copy into
182  // |read_buffer| in the final step when it is safe.
183  // Memory is allocated for this member during initialization of this object
184  // because we want buffer to be passed into BufferedResourceLoader to be
185  // always non-null. And by initializing this member with a default size we can
186  // avoid creating zero-sized buffered if the first read has zero size.
187  scoped_array<uint8> intermediate_read_buffer_;
188  int intermediate_read_buffer_size_;
189
190  // The message loop of the render thread.
191  MessageLoop* render_loop_;
192
193  // Protects |stopped_|.
194  base::Lock lock_;
195
196  // Stop signal to suppressing activities. This variable is set on the pipeline
197  // thread and read from the render thread.
198  bool stop_signal_received_;
199
200  // This variable is set by CleanupTask() that indicates this object is stopped
201  // on the render thread and work should no longer progress.
202  bool stopped_on_render_loop_;
203
204  // This variable is true when we are in a paused state and false when we
205  // are in a playing state.
206  bool media_is_paused_;
207
208  // This variable is true when the user has requested the video to play at
209  // least once.
210  bool media_has_played_;
211
212  // This variable holds the value of the preload attribute for the video
213  // element.
214  media::Preload preload_;
215
216  // This timer is to run the WatchDogTask repeatedly. We use a timer instead
217  // of doing PostDelayedTask() reduce the extra reference held by the message
218  // loop. The RepeatingTimer does PostDelayedTask() internally, by using it
219  // the message loop doesn't hold a reference for the watch dog task.
220  base::RepeatingTimer<BufferedDataSource> watch_dog_timer_;
221
222  // Keeps track of whether we used a Range header in the initialization
223  // request.
224  bool using_range_request_;
225
226  DISALLOW_COPY_AND_ASSIGN(BufferedDataSource);
227};
228
229}  // namespace webkit_glue
230
231#endif  // WEBKIT_GLUE_MEDIA_BUFFERED_DATA_SOURCE_H_
232