Chromium Code Reviews| 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..5445ca8f67ce6dfea46aeb1e9375a55ab8040801 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->IsSupportedPassthroughAudio(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,7 @@ bool AudioRendererImpl::HandleSplicerBuffer_Locked( | 
| if (buffer->end_of_stream()) { | 
| received_end_of_stream_ = true; | 
| } else { | 
| - if (state_ == kPlaying) { | 
| + if (state_ == kPlaying && buffer->sample_format() != kSampleFormatRaw) { | 
| 
 
DaleCurtis
2016/11/01 23:05:13
This is incorrect, seeking is going to return the
 
AndyWu
2016/11/04 18:04:24
Thanks for pointing it out.
Mark reporting time as
 
DaleCurtis
2016/11/04 19:48:29
No, AV sync will never recover for this case since
 
AndyWu
2016/11/08 00:04:21
I see. I reset start_timestamp_and audio_clock_in
 
DaleCurtis
2016/11/08 00:11:47
I don't think this will work. There is code in oth
 
watk
2016/11/08 19:59:30
PipelineImpl::GetMediaTime() tracks the last repor
 
AndyWu
2016/11/11 17:52:48
Thanks a lot for your information. I guess I can d
 
 | 
| if (IsBeforeStartTime(buffer)) | 
| return true; | 
| @@ -776,7 +818,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 +854,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 = |