blob: 0a6d660d6d5b384b569289388a4cbbfe85e330c2 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Audio rendering unit utilizing an AudioRendererSink to output data.
//
// This class lives inside three threads during it's lifetime, namely:
// 1. Render thread.
// This object is created on the render thread.
// 2. Pipeline thread
// Initialize() is called here with the audio format.
// Play/Pause/Seek also happens here.
// 3. Audio thread created by the AudioRendererSink.
// Render() is called here where audio data is decoded into raw PCM data.
//
// AudioRendererImpl talks to an AudioRendererAlgorithm that takes care of
// queueing audio data and stretching/shrinking audio data when playback rate !=
// 1.0 or 0.0.
#ifndef MEDIA_FILTERS_AUDIO_RENDERER_IMPL_H_
#define MEDIA_FILTERS_AUDIO_RENDERER_IMPL_H_
#include <deque>
#include "base/synchronization/lock.h"
#include "media/base/audio_decoder.h"
#include "media/base/audio_renderer_sink.h"
#include "media/base/buffers.h"
#include "media/base/filters.h"
#include "media/filters/audio_renderer_algorithm.h"
namespace media {
class MEDIA_EXPORT AudioRendererImpl
: public AudioRenderer,
NON_EXPORTED_BASE(public media::AudioRendererSink::RenderCallback) {
public:
// Methods called on Render thread ------------------------------------------
// An AudioRendererSink is used as the destination for the rendered audio.
explicit AudioRendererImpl(media::AudioRendererSink* sink);
// Methods called on pipeline thread ----------------------------------------
// Filter implementation.
virtual void Play(const base::Closure& callback) OVERRIDE;
virtual void Pause(const base::Closure& callback) OVERRIDE;
virtual void Flush(const base::Closure& callback) OVERRIDE;
virtual void Stop(const base::Closure& callback) OVERRIDE;
virtual void SetPlaybackRate(float rate) OVERRIDE;
virtual void Seek(base::TimeDelta time, const PipelineStatusCB& cb) OVERRIDE;
// AudioRenderer implementation.
virtual void Initialize(const scoped_refptr<AudioDecoder>& decoder,
const PipelineStatusCB& init_cb,
const base::Closure& underflow_cb,
const TimeCB& time_cb) OVERRIDE;
virtual bool HasEnded() OVERRIDE;
virtual void ResumeAfterUnderflow(bool buffer_more_audio) OVERRIDE;
virtual void SetVolume(float volume) OVERRIDE;
protected:
virtual ~AudioRendererImpl();
private:
friend class AudioRendererImplTest;
FRIEND_TEST_ALL_PREFIXES(AudioRendererImplTest, EndOfStream);
FRIEND_TEST_ALL_PREFIXES(AudioRendererImplTest, Underflow_EndOfStream);
// Callback from the audio decoder delivering decoded audio samples.
void DecodedAudioReady(scoped_refptr<Buffer> buffer);
// Fills the given buffer with audio data by delegating to its |algorithm_|.
// FillBuffer() also takes care of updating the clock. Returns the number of
// frames copied into |dest|, which may be less than or equal to
// |requested_frames|.
//
// If this method returns fewer frames than |requested_frames|, it could
// be a sign that the pipeline is stalled or unable to stream the data fast
// enough. In such scenarios, the callee should zero out unused portions
// of their buffer to playback silence.
//
// FillBuffer() updates the pipeline's playback timestamp. If FillBuffer() is
// not called at the same rate as audio samples are played, then the reported
// timestamp in the pipeline will be ahead of the actual audio playback. In
// this case |playback_delay| should be used to indicate when in the future
// should the filled buffer be played. If FillBuffer() is called as the audio
// hardware plays the buffer, then |playback_delay| should be zero.
//
// FillBuffer() calls SignalEndOfStream() when it reaches end of stream.
//
// Safe to call on any thread.
uint32 FillBuffer(uint8* dest,
uint32 requested_frames,
const base::TimeDelta& playback_delay);
// Called at the end of stream when all the hardware buffers become empty
// (i.e. when all the data written to the device has been played).
void SignalEndOfStream();
// Get the playback rate of |algorithm_|.
float GetPlaybackRate();
// Convert number of bytes to duration of time using information about the
// number of channels, sample rate and sample bits.
base::TimeDelta ConvertToDuration(int bytes);
// Estimate earliest time when current buffer can stop playing.
void UpdateEarliestEndTime(int bytes_filled,
base::TimeDelta request_delay,
base::Time time_now);
// Methods called on pipeline thread ----------------------------------------
void DoPlay();
void DoPause();
void DoSeek();
// media::AudioRendererSink::RenderCallback implementation.
virtual int Render(const std::vector<float*>& audio_data,
int number_of_frames,
int audio_delay_milliseconds) OVERRIDE;
virtual void OnRenderError() OVERRIDE;
// Helper method that schedules an asynchronous read from the decoder and
// increments |pending_reads_|.
//
// Safe to call from any thread.
void ScheduleRead_Locked();
// Returns true if the data in the buffer is all before
// |seek_timestamp_|. This can only return true while
// in the kSeeking state.
bool IsBeforeSeekTime(const scoped_refptr<Buffer>& buffer);
// Audio decoder.
scoped_refptr<AudioDecoder> decoder_;
// Algorithm for scaling audio.
scoped_ptr<AudioRendererAlgorithm> algorithm_;
base::Lock lock_;
// Simple state tracking variable.
enum State {
kUninitialized,
kPaused,
kSeeking,
kPlaying,
kStopped,
kUnderflow,
kRebuffering,
};
State state_;
// Keep track of our outstanding read to |decoder_|.
bool pending_read_;
// Keeps track of whether we received and rendered the end of stream buffer.
bool received_end_of_stream_;
bool rendered_end_of_stream_;
// The timestamp of the last frame (i.e. furthest in the future) buffered as
// well as the current time that takes current playback delay into account.
base::TimeDelta audio_time_buffered_;
base::TimeDelta current_time_;
// Filter callbacks.
base::Closure pause_cb_;
PipelineStatusCB seek_cb_;
base::Closure underflow_cb_;
TimeCB time_cb_;
base::TimeDelta seek_timestamp_;
uint32 bytes_per_frame_;
// Used to calculate audio delay given bytes.
uint32 bytes_per_second_;
// A flag that indicates this filter is called to stop.
bool stopped_;
// The sink (destination) for rendered audio.
scoped_refptr<media::AudioRendererSink> sink_;
// Set to true when OnInitialize() is called.
bool is_initialized_;
// We're supposed to know amount of audio data OS or hardware buffered, but
// that is not always so -- on my Linux box
// AudioBuffersState::hardware_delay_bytes never reaches 0.
//
// As a result we cannot use it to find when stream ends. If we just ignore
// buffered data we will notify host that stream ended before it is actually
// did so, I've seen it done ~140ms too early when playing ~150ms file.
//
// Instead of trying to invent OS-specific solution for each and every OS we
// are supporting, use simple workaround: every time we fill the buffer we
// remember when it should stop playing, and do not assume that buffer is
// empty till that time. Workaround is not bulletproof, as we don't exactly
// know when that particular data would start playing, but it is much better
// than nothing.
base::Time earliest_end_time_;
AudioParameters audio_parameters_;
AudioDecoder::ReadCB read_cb_;
DISALLOW_COPY_AND_ASSIGN(AudioRendererImpl);
};
} // namespace media
#endif // MEDIA_FILTERS_AUDIO_RENDERER_IMPL_H_