| Index: media/renderers/audio_renderer_impl.cc
|
| diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
|
| index 379c9570b114175ad358f3c31ec1e0f9af0f2759..19e5e0d65d0b0d44abcd19932a0301831b9c4119 100644
|
| --- a/media/renderers/audio_renderer_impl.cc
|
| +++ b/media/renderers/audio_renderer_impl.cc
|
| @@ -24,6 +24,7 @@
|
| #include "media/base/audio_splicer.h"
|
| #include "media/base/bind_to_current_loop.h"
|
| #include "media/base/demuxer_stream.h"
|
| +#include "media/base/media_client.h"
|
| #include "media/base/media_log.h"
|
| #include "media/base/media_switches.h"
|
| #include "media/base/renderer_client.h"
|
| @@ -33,6 +34,8 @@
|
|
|
| namespace media {
|
|
|
| +static const int kMaxFramesPerCompressedAudioBuffer = 4096;
|
| +
|
| AudioRendererImpl::AudioRendererImpl(
|
| const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
|
| media::AudioRendererSink* sink,
|
| @@ -57,6 +60,7 @@ AudioRendererImpl::AudioRendererImpl(
|
| received_end_of_stream_(false),
|
| rendered_end_of_stream_(false),
|
| is_suspending_(false),
|
| + is_passthrough_(false),
|
| last_reported_media_time_(kNoTimestamp),
|
| weak_factory_(this) {
|
| audio_buffer_stream_->set_splice_observer(base::Bind(
|
| @@ -364,11 +368,35 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream,
|
| // failed.
|
| init_cb_ = BindToCurrentLoop(init_cb);
|
|
|
| + AudioCodec codec = stream->audio_decoder_config().codec();
|
| + MediaClient* media_client = GetMediaClient();
|
| + is_passthrough_ =
|
| + media_client && media_client->IsPassthroughAudioSupported(codec);
|
| +
|
| const AudioParameters& hw_params =
|
| sink_->GetOutputDeviceInfo().output_params();
|
| expecting_config_changes_ = stream->SupportsConfigChanges();
|
| - if (!expecting_config_changes_ || !hw_params.IsValid() ||
|
| - hw_params.format() == AudioParameters::AUDIO_FAKE) {
|
| +
|
| + if (is_passthrough_) {
|
| + AudioParameters::Format format = AudioParameters::AUDIO_FAKE;
|
| + if (codec == kCodecAC3) {
|
| + format = AudioParameters::AUDIO_RAW_AC3;
|
| + } else if (codec == kCodecEAC3) {
|
| + format = AudioParameters::AUDIO_RAW_EAC3;
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| +
|
| + const int buffer_size = kMaxFramesPerCompressedAudioBuffer *
|
| + stream->audio_decoder_config().bytes_per_frame();
|
| +
|
| + audio_parameters_.Reset(
|
| + format, stream->audio_decoder_config().channel_layout(),
|
| + stream->audio_decoder_config().samples_per_second(),
|
| + stream->audio_decoder_config().bits_per_channel(), buffer_size);
|
| + buffer_converter_.reset();
|
| + } else if (!expecting_config_changes_ || !hw_params.IsValid() ||
|
| + hw_params.format() == AudioParameters::AUDIO_FAKE) {
|
| // The actual buffer size is controlled via the size of the AudioBus
|
| // provided to Render(), but we should choose a value here based on hardware
|
| // parameters if possible since it affects the initial buffer size used by
|
| @@ -580,6 +608,20 @@ void AudioRendererImpl::DecodedAudioReady(
|
| return;
|
| }
|
|
|
| + if (buffer->sample_format() == kSampleFormatRaw) {
|
| + if (last_decoded_sample_rate_ &&
|
| + buffer->sample_rate() != last_decoded_sample_rate_) {
|
| + OnConfigChange();
|
| + }
|
| + last_decoded_sample_rate_ = buffer->sample_rate();
|
| +
|
| + if (!HandleSplicerBuffer_Locked(buffer) && !CanRead_Locked())
|
| + return;
|
| +
|
| + AttemptRead_Locked();
|
| + return;
|
| + }
|
| +
|
| if (expecting_config_changes_) {
|
| if (last_decoded_sample_rate_ &&
|
| buffer->sample_rate() != last_decoded_sample_rate_) {
|
| @@ -647,7 +689,14 @@ bool AudioRendererImpl::HandleSplicerBuffer_Locked(
|
| if (buffer->end_of_stream()) {
|
| received_end_of_stream_ = true;
|
| } else {
|
| - if (state_ == kPlaying) {
|
| + if (buffer->sample_format() == kSampleFormatRaw) {
|
| + if (state_ == kPlaying && IsBeforeStartTime(buffer))
|
| + return true;
|
| +
|
| + // TODO(tsunghung): Need a mechanism to report the actual start time since
|
| + // we are unable to trim the audio buffer to the correct start time.
|
| +
|
| + } else if (state_ == kPlaying) {
|
| if (IsBeforeStartTime(buffer))
|
| return true;
|
|
|
| @@ -746,6 +795,13 @@ void AudioRendererImpl::SetPlaybackRate(double playback_rate) {
|
|
|
| base::AutoLock auto_lock(lock_);
|
|
|
| + if (is_passthrough_ && playback_rate != 0 && playback_rate != 1) {
|
| + MEDIA_LOG(ERROR, media_log_)
|
| + << "Unsupported playback rate when outputing in raw."
|
| + << " Playback Rate: " << playback_rate;
|
| + return;
|
| + }
|
| +
|
| // We have two cases here:
|
| // Play: current_playback_rate == 0 && playback_rate != 0
|
| // Pause: current_playback_rate != 0 && playback_rate == 0
|
| @@ -776,7 +832,7 @@ bool AudioRendererImpl::IsBeforeStartTime(
|
| int AudioRendererImpl::Render(AudioBus* audio_bus,
|
| uint32_t frames_delayed,
|
| uint32_t frames_skipped) {
|
| - const int frames_requested = audio_bus->frames();
|
| + int frames_requested = audio_bus->frames();
|
| DVLOG(4) << __func__ << " frames_delayed:" << frames_delayed
|
| << " frames_skipped:" << frames_skipped
|
| << " frames_requested:" << frames_requested;
|
| @@ -812,9 +868,13 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
|
| return 0;
|
| }
|
|
|
| - // Delay playback by writing silence if we haven't reached the first
|
| - // timestamp yet; this can occur if the video starts before the audio.
|
| - if (algorithm_->frames_buffered() > 0) {
|
| + if (is_passthrough_ && algorithm_->frames_buffered() > 0) {
|
| + frames_written += algorithm_->FillBuffer(audio_bus, 0, frames_requested,
|
| + playback_rate_);
|
| + frames_requested = frames_written;
|
| + } else if (algorithm_->frames_buffered() > 0) {
|
| + // Delay playback by writing silence if we haven't reached the first
|
| + // timestamp yet; this can occur if the video starts before the audio.
|
| CHECK_NE(first_packet_timestamp_, kNoTimestamp);
|
| CHECK_GE(first_packet_timestamp_, base::TimeDelta());
|
| const base::TimeDelta play_delay =
|
|
|