Revert of Update AudioRenderer API to fire changes in BufferingState (round 2). ...
[chromium-blink-merge.git] / media / base / pipeline.h
blobb5bba8d4a04b163551e853119b868d2cbf08410e
1 // Copyright (c) 2012 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.
5 #ifndef MEDIA_BASE_PIPELINE_H_
6 #define MEDIA_BASE_PIPELINE_H_
8 #include <string>
10 #include "base/gtest_prod_util.h"
11 #include "base/synchronization/condition_variable.h"
12 #include "base/synchronization/lock.h"
13 #include "base/threading/thread_checker.h"
14 #include "base/time/default_tick_clock.h"
15 #include "media/base/audio_renderer.h"
16 #include "media/base/buffering_state.h"
17 #include "media/base/demuxer.h"
18 #include "media/base/media_export.h"
19 #include "media/base/pipeline_status.h"
20 #include "media/base/ranges.h"
21 #include "media/base/serial_runner.h"
22 #include "ui/gfx/size.h"
24 namespace base {
25 class SingleThreadTaskRunner;
26 class TimeDelta;
29 namespace media {
31 class Clock;
32 class FilterCollection;
33 class MediaLog;
34 class TextRenderer;
35 class TextTrackConfig;
36 class VideoRenderer;
38 // Metadata describing a pipeline once it has been initialized.
39 struct PipelineMetadata {
40 PipelineMetadata() : has_audio(false), has_video(false) {}
42 bool has_audio;
43 bool has_video;
44 gfx::Size natural_size;
45 base::Time timeline_offset;
48 typedef base::Callback<void(PipelineMetadata)> PipelineMetadataCB;
50 // Pipeline runs the media pipeline. Filters are created and called on the
51 // task runner injected into this object. Pipeline works like a state
52 // machine to perform asynchronous initialization, pausing, seeking and playing.
54 // Here's a state diagram that describes the lifetime of this object.
56 // [ *Created ] [ Any State ]
57 // | Start() | Stop() / SetError()
58 // V V
59 // [ InitXXX (for each filter) ] [ Stopping ]
60 // | |
61 // V V
62 // [ InitPrerolling ] [ Stopped ]
63 // |
64 // V
65 // [ Playing ] <-- [ Seeking ]
66 // | ^
67 // `---------------'
68 // Seek()
70 // Initialization is a series of state transitions from "Created" through each
71 // filter initialization state. When all filter initialization states have
72 // completed, we are implicitly in a "Paused" state. At that point we simulate
73 // a Seek() to the beginning of the media to give filters a chance to preroll.
74 // From then on the normal Seek() transitions are carried out and we start
75 // playing the media.
77 // If any error ever happens, this object will transition to the "Error" state
78 // from any state. If Stop() is ever called, this object will transition to
79 // "Stopped" state.
80 class MEDIA_EXPORT Pipeline : public DemuxerHost {
81 public:
82 // Constructs a media pipeline that will execute on |task_runner|.
83 Pipeline(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
84 MediaLog* media_log);
85 virtual ~Pipeline();
87 // Build a pipeline to using the given filter collection to construct a filter
88 // chain, executing |seek_cb| when the initial seek has completed.
90 // |filter_collection| must be a complete collection containing a demuxer,
91 // audio/video decoders, and audio/video renderers. Failing to do so will
92 // result in a crash.
94 // The following permanent callbacks will be executed as follows up until
95 // Stop() has completed:
96 // |ended_cb| will be executed whenever the media reaches the end.
97 // |error_cb| will be executed whenever an error occurs but hasn't been
98 // reported already through another callback.
99 // |metadata_cb| will be executed when the content duration, container video
100 // size, start time, and whether the content has audio and/or
101 // video in supported formats are known.
102 // |buffering_state_cb| will be executed whenever there are changes in the
103 // overall buffering state of the pipeline.
104 // |duration_change_cb| optional callback that will be executed whenever the
105 // presentation duration changes.
106 // It is an error to call this method after the pipeline has already started.
107 void Start(scoped_ptr<FilterCollection> filter_collection,
108 const base::Closure& ended_cb,
109 const PipelineStatusCB& error_cb,
110 const PipelineStatusCB& seek_cb,
111 const PipelineMetadataCB& metadata_cb,
112 const BufferingStateCB& buffering_state_cb,
113 const base::Closure& duration_change_cb);
115 // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline
116 // teardown has completed.
118 // Stop() must complete before destroying the pipeline. It it permissible to
119 // call Stop() at any point during the lifetime of the pipeline.
121 // It is safe to delete the pipeline during the execution of |stop_cb|.
122 void Stop(const base::Closure& stop_cb);
124 // Attempt to seek to the position specified by time. |seek_cb| will be
125 // executed when the all filters in the pipeline have processed the seek.
127 // Clients are expected to call GetMediaTime() to check whether the seek
128 // succeeded.
130 // It is an error to call this method if the pipeline has not started.
131 void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb);
133 // Returns true if the pipeline has been started via Start(). If IsRunning()
134 // returns true, it is expected that Stop() will be called before destroying
135 // the pipeline.
136 bool IsRunning() const;
138 // Gets the current playback rate of the pipeline. When the pipeline is
139 // started, the playback rate will be 0.0f. A rate of 1.0f indicates
140 // that the pipeline is rendering the media at the standard rate. Valid
141 // values for playback rate are >= 0.0f.
142 float GetPlaybackRate() const;
144 // Attempt to adjust the playback rate. Setting a playback rate of 0.0f pauses
145 // all rendering of the media. A rate of 1.0f indicates a normal playback
146 // rate. Values for the playback rate must be greater than or equal to 0.0f.
148 // TODO(scherkus): What about maximum rate? Does HTML5 specify a max?
149 void SetPlaybackRate(float playback_rate);
151 // Gets the current volume setting being used by the audio renderer. When
152 // the pipeline is started, this value will be 1.0f. Valid values range
153 // from 0.0f to 1.0f.
154 float GetVolume() const;
156 // Attempt to set the volume of the audio renderer. Valid values for volume
157 // range from 0.0f (muted) to 1.0f (full volume). This value affects all
158 // channels proportionately for multi-channel audio streams.
159 void SetVolume(float volume);
161 // Returns the current media playback time, which progresses from 0 until
162 // GetMediaDuration().
163 base::TimeDelta GetMediaTime() const;
165 // Get approximate time ranges of buffered media.
166 Ranges<base::TimeDelta> GetBufferedTimeRanges() const;
168 // Get the duration of the media in microseconds. If the duration has not
169 // been determined yet, then returns 0.
170 base::TimeDelta GetMediaDuration() const;
172 // Return true if loading progress has been made since the last time this
173 // method was called.
174 bool DidLoadingProgress();
176 // Gets the current pipeline statistics.
177 PipelineStatistics GetStatistics() const;
179 void SetClockForTesting(Clock* clock);
180 void SetErrorForTesting(PipelineStatus status);
182 private:
183 FRIEND_TEST_ALL_PREFIXES(PipelineTest, GetBufferedTimeRanges);
184 FRIEND_TEST_ALL_PREFIXES(PipelineTest, EndedCallback);
185 FRIEND_TEST_ALL_PREFIXES(PipelineTest, AudioStreamShorterThanVideo);
186 friend class MediaLog;
188 // Pipeline states, as described above.
189 enum State {
190 kCreated,
191 kInitDemuxer,
192 kInitAudioRenderer,
193 kInitVideoRenderer,
194 kInitPrerolling,
195 kSeeking,
196 kPlaying,
197 kStopping,
198 kStopped,
201 // Updates |state_|. All state transitions should use this call.
202 void SetState(State next_state);
204 static const char* GetStateString(State state);
205 State GetNextState() const;
207 // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_|
208 // and |seek_pending_|.
209 void FinishSeek();
211 // DemuxerHost implementaion.
212 virtual void AddBufferedTimeRange(base::TimeDelta start,
213 base::TimeDelta end) OVERRIDE;
214 virtual void SetDuration(base::TimeDelta duration) OVERRIDE;
215 virtual void OnDemuxerError(PipelineStatus error) OVERRIDE;
216 virtual void AddTextStream(DemuxerStream* text_stream,
217 const TextTrackConfig& config) OVERRIDE;
218 virtual void RemoveTextStream(DemuxerStream* text_stream) OVERRIDE;
220 // Initiates teardown sequence in response to a runtime error.
222 // Safe to call from any thread.
223 void SetError(PipelineStatus error);
225 // Callbacks executed when a renderer has ended.
226 void OnAudioRendererEnded();
227 void OnVideoRendererEnded();
228 void OnTextRendererEnded();
230 // Callback executed by filters to update statistics.
231 void OnUpdateStatistics(const PipelineStatistics& stats);
233 // Callback executed by audio renderer to update clock time.
234 void OnAudioTimeUpdate(base::TimeDelta time, base::TimeDelta max_time);
236 // Callback executed by video renderer to update clock time.
237 void OnVideoTimeUpdate(base::TimeDelta max_time);
239 // The following "task" methods correspond to the public methods, but these
240 // methods are run as the result of posting a task to the Pipeline's
241 // task runner.
242 void StartTask();
244 // Stops and destroys all filters, placing the pipeline in the kStopped state.
245 void StopTask(const base::Closure& stop_cb);
247 // Carries out stopping and destroying all filters, placing the pipeline in
248 // the kStopped state.
249 void ErrorChangedTask(PipelineStatus error);
251 // Carries out notifying filters that the playback rate has changed.
252 void PlaybackRateChangedTask(float playback_rate);
254 // Carries out notifying filters that the volume has changed.
255 void VolumeChangedTask(float volume);
257 // Carries out notifying filters that we are seeking to a new timestamp.
258 void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb);
260 // Handles audio/video/text ended logic and running |ended_cb_|.
261 void DoAudioRendererEnded();
262 void DoVideoRendererEnded();
263 void DoTextRendererEnded();
264 void RunEndedCallbackIfNeeded();
266 // Carries out adding a new text stream to the text renderer.
267 void AddTextStreamTask(DemuxerStream* text_stream,
268 const TextTrackConfig& config);
270 // Carries out removing a text stream from the text renderer.
271 void RemoveTextStreamTask(DemuxerStream* text_stream);
273 // Kicks off initialization for each media object, executing |done_cb| with
274 // the result when completed.
275 void InitializeDemuxer(const PipelineStatusCB& done_cb);
276 void InitializeAudioRenderer(const PipelineStatusCB& done_cb);
277 void InitializeVideoRenderer(const PipelineStatusCB& done_cb);
279 // Kicks off destroying filters. Called by StopTask() and ErrorChangedTask().
280 // When we start to tear down the pipeline, we will consider two cases:
281 // 1. when pipeline has not been initialized, we will transit to stopping
282 // state first.
283 // 2. when pipeline has been initialized, we will first transit to pausing
284 // => flushing => stopping => stopped state.
285 // This will remove the race condition during stop between filters.
286 void TearDownPipeline();
288 // Compute the time corresponding to a byte offset.
289 base::TimeDelta TimeForByteOffset_Locked(int64 byte_offset) const;
291 void OnStateTransition(PipelineStatus status);
292 void StateTransitionTask(PipelineStatus status);
294 // Initiates an asynchronous preroll call sequence executing |done_cb|
295 // with the final status when completed.
296 void DoInitialPreroll(const PipelineStatusCB& done_cb);
298 // Initiates an asynchronous pause-flush-seek-preroll call sequence
299 // executing |done_cb| with the final status when completed.
301 // TODO(scherkus): Prerolling should be separate from seeking so we can report
302 // finer grained ready states (HAVE_CURRENT_DATA vs. HAVE_FUTURE_DATA)
303 // indepentent from seeking.
304 void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb);
306 // Initiates an asynchronous pause-flush-stop call sequence executing
307 // |done_cb| when completed.
308 void DoStop(const PipelineStatusCB& done_cb);
309 void OnStopCompleted(PipelineStatus status);
311 void OnAudioUnderflow();
313 // Collection of callback methods and helpers for tracking changes in
314 // buffering state and transition from paused/underflow states and playing
315 // states.
317 // While in the kPlaying state:
318 // - A waiting to non-waiting transition indicates preroll has completed
319 // and StartPlayback() should be called
320 // - A non-waiting to waiting transition indicates underflow has occurred
321 // and StartWaitingForEnoughData() should be called
322 void BufferingStateChanged(BufferingState* buffering_state,
323 BufferingState new_buffering_state);
324 bool WaitingForEnoughData() const;
325 void StartWaitingForEnoughData();
326 void StartPlayback();
328 void PauseClockAndStopRendering_Locked();
329 void StartClockIfWaitingForTimeUpdate_Locked();
331 // Task runner used to execute pipeline tasks.
332 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
334 // MediaLog to which to log events.
335 scoped_refptr<MediaLog> media_log_;
337 // Lock used to serialize access for the following data members.
338 mutable base::Lock lock_;
340 // Whether or not the pipeline is running.
341 bool running_;
343 // Amount of available buffered data as reported by |demuxer_|.
344 Ranges<base::TimeDelta> buffered_time_ranges_;
346 // True when AddBufferedTimeRange() has been called more recently than
347 // DidLoadingProgress().
348 bool did_loading_progress_;
350 // Current volume level (from 0.0f to 1.0f). This value is set immediately
351 // via SetVolume() and a task is dispatched on the task runner to notify the
352 // filters.
353 float volume_;
355 // Current playback rate (>= 0.0f). This value is set immediately via
356 // SetPlaybackRate() and a task is dispatched on the task runner to notify
357 // the filters.
358 float playback_rate_;
360 // base::TickClock used by |clock_|.
361 base::DefaultTickClock default_tick_clock_;
363 // Reference clock. Keeps track of current playback time. Uses system
364 // clock and linear interpolation, but can have its time manually set
365 // by filters.
366 scoped_ptr<Clock> clock_;
368 enum ClockState {
369 // Audio (if present) is not rendering. Clock isn't playing.
370 CLOCK_PAUSED,
372 // Audio (if present) is rendering. Clock isn't playing.
373 CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE,
375 // Audio (if present) is rendering. Clock is playing.
376 CLOCK_PLAYING,
379 ClockState clock_state_;
381 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that
382 // the pipeline is operating correctly. Any other value indicates that the
383 // pipeline is stopped or is stopping. Clients can call the Stop() method to
384 // reset the pipeline state, and restore this to PIPELINE_OK.
385 PipelineStatus status_;
387 // The following data members are only accessed by tasks posted to
388 // |task_runner_|.
390 // Member that tracks the current state.
391 State state_;
393 // Whether we've received the audio/video/text ended events.
394 bool audio_ended_;
395 bool video_ended_;
396 bool text_ended_;
398 BufferingState audio_buffering_state_;
399 BufferingState video_buffering_state_;
401 // Temporary callback used for Start() and Seek().
402 PipelineStatusCB seek_cb_;
404 // Temporary callback used for Stop().
405 base::Closure stop_cb_;
407 // Permanent callbacks passed in via Start().
408 base::Closure ended_cb_;
409 PipelineStatusCB error_cb_;
410 PipelineMetadataCB metadata_cb_;
411 BufferingStateCB buffering_state_cb_;
412 base::Closure duration_change_cb_;
414 // Contains the demuxer and renderers to use when initializing.
415 scoped_ptr<FilterCollection> filter_collection_;
417 // Holds the initialized demuxer. Used for seeking. Owned by client.
418 Demuxer* demuxer_;
420 // Holds the initialized renderers. Used for setting the volume,
421 // playback rate, and determining when playback has finished.
422 scoped_ptr<AudioRenderer> audio_renderer_;
423 scoped_ptr<VideoRenderer> video_renderer_;
424 scoped_ptr<TextRenderer> text_renderer_;
426 PipelineStatistics statistics_;
428 scoped_ptr<SerialRunner> pending_callbacks_;
430 base::ThreadChecker thread_checker_;
432 DISALLOW_COPY_AND_ASSIGN(Pipeline);
435 } // namespace media
437 #endif // MEDIA_BASE_PIPELINE_H_