| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/audio_renderer_impl.h" | 5 #include "media/filters/audio_renderer_impl.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/callback.h" | 12 #include "base/callback.h" |
| 13 #include "base/callback_helpers.h" | 13 #include "base/callback_helpers.h" |
| 14 #include "base/command_line.h" | 14 #include "base/command_line.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/message_loop_proxy.h" |
| 16 #include "media/audio/audio_util.h" | 17 #include "media/audio/audio_util.h" |
| 18 #include "media/base/bind_to_loop.h" |
| 17 #include "media/base/demuxer_stream.h" | 19 #include "media/base/demuxer_stream.h" |
| 18 #include "media/base/media_switches.h" | 20 #include "media/base/media_switches.h" |
| 19 | 21 |
| 20 namespace media { | 22 namespace media { |
| 21 | 23 |
| 22 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) | 24 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) |
| 23 : state_(kUninitialized), | 25 : sink_(sink), |
| 26 state_(kUninitialized), |
| 24 pending_read_(false), | 27 pending_read_(false), |
| 25 received_end_of_stream_(false), | 28 received_end_of_stream_(false), |
| 26 rendered_end_of_stream_(false), | 29 rendered_end_of_stream_(false), |
| 27 audio_time_buffered_(kNoTimestamp()), | 30 audio_time_buffered_(kNoTimestamp()), |
| 28 current_time_(kNoTimestamp()), | 31 current_time_(kNoTimestamp()), |
| 29 bytes_per_frame_(0), | |
| 30 stopped_(false), | |
| 31 sink_(sink), | |
| 32 underflow_disabled_(false), | 32 underflow_disabled_(false), |
| 33 preroll_aborted_(false) { | 33 preroll_aborted_(false), |
| 34 actual_frames_per_buffer_(0) { |
| 35 // We're created on the render thread, but this thread checker is for another. |
| 36 pipeline_thread_checker_.DetachFromThread(); |
| 34 } | 37 } |
| 35 | 38 |
| 36 void AudioRendererImpl::Play(const base::Closure& callback) { | 39 void AudioRendererImpl::Play(const base::Closure& callback) { |
| 40 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 41 |
| 42 float playback_rate = 0; |
| 37 { | 43 { |
| 38 base::AutoLock auto_lock(lock_); | 44 base::AutoLock auto_lock(lock_); |
| 39 DCHECK_EQ(kPaused, state_); | 45 DCHECK_EQ(kPaused, state_); |
| 40 state_ = kPlaying; | 46 state_ = kPlaying; |
| 41 callback.Run(); | 47 callback.Run(); |
| 48 playback_rate = algorithm_->playback_rate(); |
| 42 } | 49 } |
| 43 | 50 |
| 44 if (stopped_) | 51 if (playback_rate != 0.0f) { |
| 45 return; | |
| 46 | |
| 47 if (GetPlaybackRate() != 0.0f) { | |
| 48 DoPlay(); | 52 DoPlay(); |
| 49 } else { | 53 } else { |
| 50 DoPause(); | 54 DoPause(); |
| 51 } | 55 } |
| 52 } | 56 } |
| 53 | 57 |
| 54 void AudioRendererImpl::DoPlay() { | 58 void AudioRendererImpl::DoPlay() { |
| 55 earliest_end_time_ = base::Time::Now(); | 59 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 60 DCHECK(sink_); |
| 61 { |
| 62 base::AutoLock auto_lock(lock_); |
| 63 earliest_end_time_ = base::Time::Now(); |
| 64 } |
| 56 sink_->Play(); | 65 sink_->Play(); |
| 57 } | 66 } |
| 58 | 67 |
| 59 void AudioRendererImpl::Pause(const base::Closure& callback) { | 68 void AudioRendererImpl::Pause(const base::Closure& callback) { |
| 69 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 70 |
| 60 { | 71 { |
| 61 base::AutoLock auto_lock(lock_); | 72 base::AutoLock auto_lock(lock_); |
| 62 DCHECK(state_ == kPlaying || state_ == kUnderflow || | 73 DCHECK(state_ == kPlaying || state_ == kUnderflow || |
| 63 state_ == kRebuffering); | 74 state_ == kRebuffering); |
| 64 pause_cb_ = callback; | 75 pause_cb_ = callback; |
| 65 state_ = kPaused; | 76 state_ = kPaused; |
| 66 | 77 |
| 67 // Pause only when we've completed our pending read. | 78 // Pause only when we've completed our pending read. |
| 68 if (!pending_read_) | 79 if (!pending_read_) |
| 69 base::ResetAndReturn(&pause_cb_).Run(); | 80 base::ResetAndReturn(&pause_cb_).Run(); |
| 70 } | 81 } |
| 71 | 82 |
| 72 if (stopped_) | |
| 73 return; | |
| 74 | |
| 75 DoPause(); | 83 DoPause(); |
| 76 } | 84 } |
| 77 | 85 |
| 78 void AudioRendererImpl::DoPause() { | 86 void AudioRendererImpl::DoPause() { |
| 87 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 88 DCHECK(sink_); |
| 79 sink_->Pause(false); | 89 sink_->Pause(false); |
| 80 } | 90 } |
| 81 | 91 |
| 82 void AudioRendererImpl::Flush(const base::Closure& callback) { | 92 void AudioRendererImpl::Flush(const base::Closure& callback) { |
| 93 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 83 decoder_->Reset(callback); | 94 decoder_->Reset(callback); |
| 84 } | 95 } |
| 85 | 96 |
| 86 void AudioRendererImpl::Stop(const base::Closure& callback) { | 97 void AudioRendererImpl::Stop(const base::Closure& callback) { |
| 98 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 87 DCHECK(!callback.is_null()); | 99 DCHECK(!callback.is_null()); |
| 88 | 100 |
| 101 if (sink_) { |
| 102 sink_->Stop(); |
| 103 sink_ = NULL; |
| 104 } |
| 105 |
| 89 { | 106 { |
| 90 base::AutoLock auto_lock(lock_); | 107 base::AutoLock auto_lock(lock_); |
| 91 if (!stopped_) { | |
| 92 sink_->Stop(); | |
| 93 stopped_ = true; | |
| 94 } | |
| 95 | |
| 96 state_ = kStopped; | 108 state_ = kStopped; |
| 97 algorithm_.reset(NULL); | 109 algorithm_.reset(NULL); |
| 98 init_cb_.Reset(); | 110 init_cb_.Reset(); |
| 99 underflow_cb_.Reset(); | 111 underflow_cb_.Reset(); |
| 100 time_cb_.Reset(); | 112 time_cb_.Reset(); |
| 101 } | 113 } |
| 102 | 114 |
| 103 callback.Run(); | 115 callback.Run(); |
| 104 } | 116 } |
| 105 | 117 |
| 106 void AudioRendererImpl::Preroll(base::TimeDelta time, | 118 void AudioRendererImpl::Preroll(base::TimeDelta time, |
| 107 const PipelineStatusCB& cb) { | 119 const PipelineStatusCB& cb) { |
| 108 base::AutoLock auto_lock(lock_); | 120 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 109 DCHECK_EQ(kPaused, state_); | 121 DCHECK(sink_); |
| 110 DCHECK(!pending_read_) << "Pending read must complete before seeking"; | |
| 111 DCHECK(pause_cb_.is_null()); | |
| 112 DCHECK(preroll_cb_.is_null()); | |
| 113 state_ = kPrerolling; | |
| 114 preroll_cb_ = cb; | |
| 115 preroll_timestamp_ = time; | |
| 116 | 122 |
| 117 // Throw away everything and schedule our reads. | 123 { |
| 118 audio_time_buffered_ = kNoTimestamp(); | 124 base::AutoLock auto_lock(lock_); |
| 119 current_time_ = kNoTimestamp(); | 125 DCHECK_EQ(kPaused, state_); |
| 120 received_end_of_stream_ = false; | 126 DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
| 121 rendered_end_of_stream_ = false; | 127 DCHECK(pause_cb_.is_null()); |
| 122 preroll_aborted_ = false; | 128 DCHECK(preroll_cb_.is_null()); |
| 129 state_ = kPrerolling; |
| 130 preroll_cb_ = cb; |
| 131 preroll_timestamp_ = time; |
| 123 | 132 |
| 124 // |algorithm_| will request more reads. | 133 // Throw away everything and schedule our reads. |
| 125 algorithm_->FlushBuffers(); | 134 audio_time_buffered_ = kNoTimestamp(); |
| 135 current_time_ = kNoTimestamp(); |
| 136 received_end_of_stream_ = false; |
| 137 rendered_end_of_stream_ = false; |
| 138 preroll_aborted_ = false; |
| 126 | 139 |
| 127 if (stopped_) | 140 // |algorithm_| will request more reads. |
| 128 return; | 141 algorithm_->FlushBuffers(); |
| 142 earliest_end_time_ = base::Time::Now(); |
| 143 } |
| 129 | 144 |
| 130 // Pause and flush the stream when we preroll to a new location. | 145 // Pause and flush the stream when we preroll to a new location. |
| 131 earliest_end_time_ = base::Time::Now(); | |
| 132 sink_->Pause(true); | 146 sink_->Pause(true); |
| 133 } | 147 } |
| 134 | 148 |
| 135 void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream, | 149 void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream, |
| 136 const AudioDecoderList& decoders, | 150 const AudioDecoderList& decoders, |
| 137 const PipelineStatusCB& init_cb, | 151 const PipelineStatusCB& init_cb, |
| 138 const StatisticsCB& statistics_cb, | 152 const StatisticsCB& statistics_cb, |
| 139 const base::Closure& underflow_cb, | 153 const base::Closure& underflow_cb, |
| 140 const TimeCB& time_cb, | 154 const TimeCB& time_cb, |
| 141 const base::Closure& ended_cb, | 155 const base::Closure& ended_cb, |
| 142 const base::Closure& disabled_cb, | 156 const base::Closure& disabled_cb, |
| 143 const PipelineStatusCB& error_cb) { | 157 const PipelineStatusCB& error_cb) { |
| 144 base::AutoLock auto_lock(lock_); | 158 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 145 DCHECK(stream); | 159 DCHECK(stream); |
| 146 DCHECK(!decoders.empty()); | 160 DCHECK(!decoders.empty()); |
| 147 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | 161 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
| 148 DCHECK(!init_cb.is_null()); | 162 DCHECK(!init_cb.is_null()); |
| 149 DCHECK(!statistics_cb.is_null()); | 163 DCHECK(!statistics_cb.is_null()); |
| 150 DCHECK(!underflow_cb.is_null()); | 164 DCHECK(!underflow_cb.is_null()); |
| 151 DCHECK(!time_cb.is_null()); | 165 DCHECK(!time_cb.is_null()); |
| 152 DCHECK(!ended_cb.is_null()); | 166 DCHECK(!ended_cb.is_null()); |
| 153 DCHECK(!disabled_cb.is_null()); | 167 DCHECK(!disabled_cb.is_null()); |
| 154 DCHECK(!error_cb.is_null()); | 168 DCHECK(!error_cb.is_null()); |
| 155 DCHECK_EQ(kUninitialized, state_); | 169 DCHECK_EQ(kUninitialized, state_); |
| 170 DCHECK(sink_); |
| 156 | 171 |
| 157 init_cb_ = init_cb; | 172 init_cb_ = init_cb; |
| 158 statistics_cb_ = statistics_cb; | 173 statistics_cb_ = statistics_cb; |
| 159 underflow_cb_ = underflow_cb; | 174 underflow_cb_ = underflow_cb; |
| 160 time_cb_ = time_cb; | 175 time_cb_ = time_cb; |
| 161 ended_cb_ = ended_cb; | 176 ended_cb_ = ended_cb; |
| 162 disabled_cb_ = disabled_cb; | 177 disabled_cb_ = disabled_cb; |
| 163 error_cb_ = error_cb; | 178 error_cb_ = error_cb; |
| 164 | 179 |
| 165 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders)); | 180 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders)); |
| 166 InitializeNextDecoder(stream, decoder_list.Pass()); | 181 InitializeNextDecoder(stream, decoder_list.Pass()); |
| 167 } | 182 } |
| 168 | 183 |
| 169 void AudioRendererImpl::InitializeNextDecoder( | 184 void AudioRendererImpl::InitializeNextDecoder( |
| 170 const scoped_refptr<DemuxerStream>& demuxer_stream, | 185 const scoped_refptr<DemuxerStream>& demuxer_stream, |
| 171 scoped_ptr<AudioDecoderList> decoders) { | 186 scoped_ptr<AudioDecoderList> decoders) { |
| 172 lock_.AssertAcquired(); | 187 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 173 DCHECK(!decoders->empty()); | 188 DCHECK(!decoders->empty()); |
| 174 | 189 |
| 175 scoped_refptr<AudioDecoder> decoder = decoders->front(); | 190 scoped_refptr<AudioDecoder> decoder = decoders->front(); |
| 176 decoders->pop_front(); | 191 decoders->pop_front(); |
| 177 | 192 |
| 178 DCHECK(decoder); | 193 DCHECK(decoder); |
| 179 decoder_ = decoder; | 194 decoder_ = decoder; |
| 180 | |
| 181 base::AutoUnlock auto_unlock(lock_); | |
| 182 decoder->Initialize( | 195 decoder->Initialize( |
| 183 demuxer_stream, | 196 demuxer_stream, BindToLoop(base::MessageLoopProxy::current(), base::Bind( |
| 184 base::Bind(&AudioRendererImpl::OnDecoderInitDone, this, | 197 &AudioRendererImpl::OnDecoderInitDone, this, demuxer_stream, |
| 185 demuxer_stream, | 198 base::Passed(&decoders))), |
| 186 base::Passed(&decoders)), | |
| 187 statistics_cb_); | 199 statistics_cb_); |
| 188 } | 200 } |
| 189 | 201 |
| 190 void AudioRendererImpl::OnDecoderInitDone( | 202 void AudioRendererImpl::OnDecoderInitDone( |
| 191 const scoped_refptr<DemuxerStream>& demuxer_stream, | 203 const scoped_refptr<DemuxerStream>& demuxer_stream, |
| 192 scoped_ptr<AudioDecoderList> decoders, | 204 scoped_ptr<AudioDecoderList> decoders, |
| 193 PipelineStatus status) { | 205 PipelineStatus status) { |
| 194 base::AutoLock auto_lock(lock_); | 206 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 195 | 207 |
| 196 if (state_ == kStopped) { | 208 if (state_ == kStopped) { |
| 197 DCHECK(stopped_); | 209 DCHECK(!sink_); |
| 198 return; | 210 return; |
| 199 } | 211 } |
| 200 | 212 |
| 201 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { | 213 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { |
| 202 InitializeNextDecoder(demuxer_stream, decoders.Pass()); | 214 InitializeNextDecoder(demuxer_stream, decoders.Pass()); |
| 203 return; | 215 return; |
| 204 } | 216 } |
| 205 | 217 |
| 206 if (status != PIPELINE_OK) { | 218 if (status != PIPELINE_OK) { |
| 207 base::ResetAndReturn(&init_cb_).Run(status); | 219 base::ResetAndReturn(&init_cb_).Run(status); |
| 208 return; | 220 return; |
| 209 } | 221 } |
| 210 | 222 |
| 211 // We're all good! Continue initializing the rest of the audio renderer based | 223 // We're all good! Continue initializing the rest of the audio renderer based |
| 212 // on the decoder format. | 224 // on the decoder format. |
| 213 | 225 |
| 214 ChannelLayout channel_layout = decoder_->channel_layout(); | 226 ChannelLayout channel_layout = decoder_->channel_layout(); |
| 215 int channels = ChannelLayoutToChannelCount(channel_layout); | 227 int channels = ChannelLayoutToChannelCount(channel_layout); |
| 216 int bits_per_channel = decoder_->bits_per_channel(); | 228 int bits_per_channel = decoder_->bits_per_channel(); |
| 217 int sample_rate = decoder_->samples_per_second(); | 229 int sample_rate = decoder_->samples_per_second(); |
| 218 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. | |
| 219 bytes_per_frame_ = channels * bits_per_channel / 8; | |
| 220 | 230 |
| 221 algorithm_.reset(new AudioRendererAlgorithm()); | 231 algorithm_.reset(new AudioRendererAlgorithm()); |
| 222 if (!algorithm_->ValidateConfig(channels, sample_rate, bits_per_channel)) { | 232 if (!algorithm_->ValidateConfig(channels, sample_rate, bits_per_channel)) { |
| 223 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); | 233 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
| 224 return; | 234 return; |
| 225 } | 235 } |
| 226 | 236 |
| 227 algorithm_->Initialize( | 237 algorithm_->Initialize( |
| 228 channels, sample_rate, bits_per_channel, 0.0f, | 238 channels, sample_rate, bits_per_channel, 0.0f, |
| 229 base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this)); | 239 base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this)); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 260 // purposes it's okay that this buffer size might lead to jitter since it's | 270 // purposes it's okay that this buffer size might lead to jitter since it's |
| 261 // not a multiple of the hardware buffer size. | 271 // not a multiple of the hardware buffer size. |
| 262 format = AudioParameters::AUDIO_PCM_LOW_LATENCY; | 272 format = AudioParameters::AUDIO_PCM_LOW_LATENCY; |
| 263 buffer_size = 2048; | 273 buffer_size = 2048; |
| 264 } | 274 } |
| 265 #endif | 275 #endif |
| 266 | 276 |
| 267 audio_parameters_ = AudioParameters( | 277 audio_parameters_ = AudioParameters( |
| 268 format, channel_layout, sample_rate, bits_per_channel, buffer_size); | 278 format, channel_layout, sample_rate, bits_per_channel, buffer_size); |
| 269 | 279 |
| 280 state_ = kPaused; |
| 281 |
| 270 sink_->Initialize(audio_parameters_, this); | 282 sink_->Initialize(audio_parameters_, this); |
| 271 sink_->Start(); | 283 sink_->Start(); |
| 272 | 284 |
| 273 state_ = kPaused; | |
| 274 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 285 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 275 } | 286 } |
| 276 | 287 |
| 277 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { | 288 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { |
| 289 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 278 base::AutoLock auto_lock(lock_); | 290 base::AutoLock auto_lock(lock_); |
| 279 if (state_ == kUnderflow) { | 291 if (state_ == kUnderflow) { |
| 280 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we | 292 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we |
| 281 // shouldn't even reach the kUnderflow state to begin with. But for now | 293 // shouldn't even reach the kUnderflow state to begin with. But for now |
| 282 // we're just making sure that the audio buffer capacity (i.e. the | 294 // we're just making sure that the audio buffer capacity (i.e. the |
| 283 // number of bytes that need to be buffered for preroll to complete) | 295 // number of bytes that need to be buffered for preroll to complete) |
| 284 // does not increase due to an aborted preroll. | 296 // does not increase due to an aborted preroll. |
| 285 // TODO(vrk): Fix this bug correctly! (crbug.com/151352) | 297 // TODO(vrk): Fix this bug correctly! (crbug.com/151352) |
| 286 if (buffer_more_audio && !preroll_aborted_) | 298 if (buffer_more_audio && !preroll_aborted_) |
| 287 algorithm_->IncreaseQueueCapacity(); | 299 algorithm_->IncreaseQueueCapacity(); |
| 288 | 300 |
| 289 state_ = kRebuffering; | 301 state_ = kRebuffering; |
| 290 } | 302 } |
| 291 } | 303 } |
| 292 | 304 |
| 293 void AudioRendererImpl::SetVolume(float volume) { | 305 void AudioRendererImpl::SetVolume(float volume) { |
| 294 if (stopped_) | 306 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 295 return; | 307 DCHECK(sink_); |
| 296 sink_->SetVolume(volume); | 308 sink_->SetVolume(volume); |
| 297 } | 309 } |
| 298 | 310 |
| 299 AudioRendererImpl::~AudioRendererImpl() { | 311 AudioRendererImpl::~AudioRendererImpl() { |
| 300 // Stop() should have been called and |algorithm_| should have been destroyed. | 312 // Stop() should have been called and |algorithm_| should have been destroyed. |
| 301 DCHECK(state_ == kUninitialized || state_ == kStopped); | 313 DCHECK(state_ == kUninitialized || state_ == kStopped); |
| 302 DCHECK(!algorithm_.get()); | 314 DCHECK(!algorithm_.get()); |
| 303 } | 315 } |
| 304 | 316 |
| 305 void AudioRendererImpl::DecodedAudioReady(AudioDecoder::Status status, | 317 void AudioRendererImpl::DecodedAudioReady(AudioDecoder::Status status, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 | 381 |
| 370 void AudioRendererImpl::ScheduleRead_Locked() { | 382 void AudioRendererImpl::ScheduleRead_Locked() { |
| 371 lock_.AssertAcquired(); | 383 lock_.AssertAcquired(); |
| 372 if (pending_read_ || state_ == kPaused) | 384 if (pending_read_ || state_ == kPaused) |
| 373 return; | 385 return; |
| 374 pending_read_ = true; | 386 pending_read_ = true; |
| 375 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, this)); | 387 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, this)); |
| 376 } | 388 } |
| 377 | 389 |
| 378 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { | 390 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { |
| 391 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 379 DCHECK_LE(0.0f, playback_rate); | 392 DCHECK_LE(0.0f, playback_rate); |
| 393 DCHECK(sink_); |
| 380 | 394 |
| 381 if (!stopped_) { | 395 // We have two cases here: |
| 382 // We have two cases here: | 396 // Play: current_playback_rate == 0.0 && playback_rate != 0.0 |
| 383 // Play: GetPlaybackRate() == 0.0 && playback_rate != 0.0 | 397 // Pause: current_playback_rate != 0.0 && playback_rate == 0.0 |
| 384 // Pause: GetPlaybackRate() != 0.0 && playback_rate == 0.0 | 398 float current_playback_rate = algorithm_->playback_rate(); |
| 385 if (GetPlaybackRate() == 0.0f && playback_rate != 0.0f) { | 399 if (current_playback_rate == 0.0f && playback_rate != 0.0f) { |
| 386 DoPlay(); | 400 DoPlay(); |
| 387 } else if (GetPlaybackRate() != 0.0f && playback_rate == 0.0f) { | 401 } else if (current_playback_rate != 0.0f && playback_rate == 0.0f) { |
| 388 // Pause is easy, we can always pause. | 402 // Pause is easy, we can always pause. |
| 389 DoPause(); | 403 DoPause(); |
| 390 } | |
| 391 } | 404 } |
| 392 | 405 |
| 393 base::AutoLock auto_lock(lock_); | 406 base::AutoLock auto_lock(lock_); |
| 394 algorithm_->SetPlaybackRate(playback_rate); | 407 algorithm_->SetPlaybackRate(playback_rate); |
| 395 } | 408 } |
| 396 | 409 |
| 397 float AudioRendererImpl::GetPlaybackRate() { | |
| 398 base::AutoLock auto_lock(lock_); | |
| 399 return algorithm_->playback_rate(); | |
| 400 } | |
| 401 | |
| 402 bool AudioRendererImpl::IsBeforePrerollTime( | 410 bool AudioRendererImpl::IsBeforePrerollTime( |
| 403 const scoped_refptr<Buffer>& buffer) { | 411 const scoped_refptr<Buffer>& buffer) { |
| 404 return (state_ == kPrerolling) && buffer && !buffer->IsEndOfStream() && | 412 return (state_ == kPrerolling) && buffer && !buffer->IsEndOfStream() && |
| 405 (buffer->GetTimestamp() + buffer->GetDuration()) < preroll_timestamp_; | 413 (buffer->GetTimestamp() + buffer->GetDuration()) < preroll_timestamp_; |
| 406 } | 414 } |
| 407 | 415 |
| 408 int AudioRendererImpl::Render(AudioBus* audio_bus, | 416 int AudioRendererImpl::Render(AudioBus* audio_bus, |
| 409 int audio_delay_milliseconds) { | 417 int audio_delay_milliseconds) { |
| 410 if (stopped_ || GetPlaybackRate() == 0.0f) { | 418 if (actual_frames_per_buffer_ != audio_bus->frames()) { |
| 411 // Output silence if stopped. | 419 audio_buffer_.reset( |
| 412 audio_bus->Zero(); | 420 new uint8[audio_bus->frames() * audio_parameters_.GetBytesPerFrame()]); |
| 413 return 0; | 421 actual_frames_per_buffer_ = audio_bus->frames(); |
| 414 } | 422 } |
| 415 | 423 |
| 416 // Adjust the playback delay. | 424 int frames_filled = FillBuffer( |
| 417 base::TimeDelta request_delay = | 425 audio_buffer_.get(), audio_bus->frames(), audio_delay_milliseconds); |
| 418 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); | 426 DCHECK_LE(frames_filled, actual_frames_per_buffer_); |
| 419 | |
| 420 // Finally we need to adjust the delay according to playback rate. | |
| 421 if (GetPlaybackRate() != 1.0f) { | |
| 422 request_delay = base::TimeDelta::FromMicroseconds( | |
| 423 static_cast<int64>(ceil(request_delay.InMicroseconds() * | |
| 424 GetPlaybackRate()))); | |
| 425 } | |
| 426 | |
| 427 int bytes_per_frame = audio_parameters_.GetBytesPerFrame(); | |
| 428 | |
| 429 const int buf_size = audio_bus->frames() * bytes_per_frame; | |
| 430 scoped_array<uint8> buf(new uint8[buf_size]); | |
| 431 | |
| 432 int frames_filled = FillBuffer(buf.get(), audio_bus->frames(), request_delay); | |
| 433 int bytes_filled = frames_filled * bytes_per_frame; | |
| 434 DCHECK_LE(bytes_filled, buf_size); | |
| 435 UpdateEarliestEndTime(bytes_filled, request_delay, base::Time::Now()); | |
| 436 | 427 |
| 437 // Deinterleave audio data into the output bus. | 428 // Deinterleave audio data into the output bus. |
| 438 audio_bus->FromInterleaved( | 429 audio_bus->FromInterleaved( |
| 439 buf.get(), frames_filled, audio_parameters_.bits_per_sample() / 8); | 430 audio_buffer_.get(), frames_filled, |
| 431 audio_parameters_.bits_per_sample() / 8); |
| 440 | 432 |
| 441 return frames_filled; | 433 return frames_filled; |
| 442 } | 434 } |
| 443 | 435 |
| 444 uint32 AudioRendererImpl::FillBuffer(uint8* dest, | 436 uint32 AudioRendererImpl::FillBuffer(uint8* dest, |
| 445 uint32 requested_frames, | 437 uint32 requested_frames, |
| 446 const base::TimeDelta& playback_delay) { | 438 int audio_delay_milliseconds) { |
| 447 base::TimeDelta current_time = kNoTimestamp(); | 439 base::TimeDelta current_time = kNoTimestamp(); |
| 448 base::TimeDelta max_time = kNoTimestamp(); | 440 base::TimeDelta max_time = kNoTimestamp(); |
| 449 | 441 |
| 450 size_t frames_written = 0; | 442 size_t frames_written = 0; |
| 451 base::Closure underflow_cb; | 443 base::Closure underflow_cb; |
| 452 { | 444 { |
| 453 base::AutoLock auto_lock(lock_); | 445 base::AutoLock auto_lock(lock_); |
| 454 | 446 |
| 447 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. |
| 448 if (!algorithm_) |
| 449 return 0; |
| 450 |
| 451 float playback_rate = algorithm_->playback_rate(); |
| 452 if (playback_rate == 0.0f) |
| 453 return 0; |
| 454 |
| 455 // Adjust the delay according to playback rate. |
| 456 base::TimeDelta playback_delay = |
| 457 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); |
| 458 if (playback_rate != 1.0f) { |
| 459 playback_delay = base::TimeDelta::FromMicroseconds(static_cast<int64>( |
| 460 ceil(playback_delay.InMicroseconds() * playback_rate))); |
| 461 } |
| 462 |
| 455 if (state_ == kRebuffering && algorithm_->IsQueueFull()) | 463 if (state_ == kRebuffering && algorithm_->IsQueueFull()) |
| 456 state_ = kPlaying; | 464 state_ = kPlaying; |
| 457 | 465 |
| 458 // Mute audio by returning 0 when not playing. | 466 // Mute audio by returning 0 when not playing. |
| 459 if (state_ != kPlaying) { | 467 if (state_ != kPlaying) { |
| 460 // TODO(scherkus): To keep the audio hardware busy we write at most 8k of | 468 // TODO(scherkus): To keep the audio hardware busy we write at most 8k of |
| 461 // zeros. This gets around the tricky situation of pausing and resuming | 469 // zeros. This gets around the tricky situation of pausing and resuming |
| 462 // the audio IPC layer in Chrome. Ideally, we should return zero and then | 470 // the audio IPC layer in Chrome. Ideally, we should return zero and then |
| 463 // the subclass can restart the conversation. | 471 // the subclass can restart the conversation. |
| 464 // | 472 // |
| 465 // This should get handled by the subclass http://crbug.com/106600 | 473 // This should get handled by the subclass http://crbug.com/106600 |
| 466 const uint32 kZeroLength = 8192; | 474 const uint32 kZeroLength = 8192; |
| 467 size_t zeros_to_write = | 475 size_t zeros_to_write = std::min( |
| 468 std::min(kZeroLength, requested_frames * bytes_per_frame_); | 476 kZeroLength, requested_frames * audio_parameters_.GetBytesPerFrame()); |
| 469 memset(dest, 0, zeros_to_write); | 477 memset(dest, 0, zeros_to_write); |
| 470 return zeros_to_write / bytes_per_frame_; | 478 return zeros_to_write / audio_parameters_.GetBytesPerFrame(); |
| 471 } | 479 } |
| 472 | 480 |
| 473 // We use the following conditions to determine end of playback: | 481 // We use the following conditions to determine end of playback: |
| 474 // 1) Algorithm can not fill the audio callback buffer | 482 // 1) Algorithm can not fill the audio callback buffer |
| 475 // 2) We received an end of stream buffer | 483 // 2) We received an end of stream buffer |
| 476 // 3) We haven't already signalled that we've ended | 484 // 3) We haven't already signalled that we've ended |
| 477 // 4) Our estimated earliest end time has expired | 485 // 4) Our estimated earliest end time has expired |
| 478 // | 486 // |
| 479 // TODO(enal): we should replace (4) with a check that the browser has no | 487 // TODO(enal): we should replace (4) with a check that the browser has no |
| 480 // more audio data or at least use a delayed callback. | 488 // more audio data or at least use a delayed callback. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 // delay after we've revamped our audio IPC subsystem. | 534 // delay after we've revamped our audio IPC subsystem. |
| 527 if (current_time_ > previous_time && !rendered_end_of_stream_) { | 535 if (current_time_ > previous_time && !rendered_end_of_stream_) { |
| 528 current_time = current_time_; | 536 current_time = current_time_; |
| 529 } | 537 } |
| 530 } | 538 } |
| 531 | 539 |
| 532 // The call to FillBuffer() on |algorithm_| has increased the amount of | 540 // The call to FillBuffer() on |algorithm_| has increased the amount of |
| 533 // buffered audio data. Update the new amount of time buffered. | 541 // buffered audio data. Update the new amount of time buffered. |
| 534 max_time = algorithm_->GetTime(); | 542 max_time = algorithm_->GetTime(); |
| 535 audio_time_buffered_ = max_time; | 543 audio_time_buffered_ = max_time; |
| 544 |
| 545 UpdateEarliestEndTime_Locked( |
| 546 frames_written, playback_rate, playback_delay, base::Time::Now()); |
| 536 } | 547 } |
| 537 | 548 |
| 538 if (current_time != kNoTimestamp() && max_time != kNoTimestamp()) { | 549 if (current_time != kNoTimestamp() && max_time != kNoTimestamp()) { |
| 539 time_cb_.Run(current_time, max_time); | 550 time_cb_.Run(current_time, max_time); |
| 540 } | 551 } |
| 541 | 552 |
| 542 if (!underflow_cb.is_null()) | 553 if (!underflow_cb.is_null()) |
| 543 underflow_cb.Run(); | 554 underflow_cb.Run(); |
| 544 | 555 |
| 545 return frames_written; | 556 return frames_written; |
| 546 } | 557 } |
| 547 | 558 |
| 548 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled, | 559 void AudioRendererImpl::UpdateEarliestEndTime_Locked( |
| 549 base::TimeDelta request_delay, | 560 int frames_filled, float playback_rate, base::TimeDelta playback_delay, |
| 550 base::Time time_now) { | 561 base::Time time_now) { |
| 551 if (bytes_filled != 0) { | 562 if (frames_filled <= 0) |
| 552 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled); | 563 return; |
| 553 float playback_rate = GetPlaybackRate(); | 564 |
| 554 if (playback_rate != 1.0f) { | 565 base::TimeDelta predicted_play_time = base::TimeDelta::FromMicroseconds( |
| 555 predicted_play_time = base::TimeDelta::FromMicroseconds( | 566 static_cast<float>(frames_filled) * base::Time::kMicrosecondsPerSecond / |
| 556 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * | 567 audio_parameters_.sample_rate()); |
| 557 playback_rate))); | 568 |
| 558 } | 569 if (playback_rate != 1.0f) { |
| 559 earliest_end_time_ = | 570 predicted_play_time = base::TimeDelta::FromMicroseconds( |
| 560 std::max(earliest_end_time_, | 571 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * |
| 561 time_now + request_delay + predicted_play_time); | 572 playback_rate))); |
| 562 } | 573 } |
| 563 } | |
| 564 | 574 |
| 565 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { | 575 lock_.AssertAcquired(); |
| 566 int bytes_per_second = audio_parameters_.GetBytesPerSecond(); | 576 earliest_end_time_ = std::max( |
| 567 CHECK(bytes_per_second); | 577 earliest_end_time_, time_now + playback_delay + predicted_play_time); |
| 568 return base::TimeDelta::FromMicroseconds( | |
| 569 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second); | |
| 570 } | 578 } |
| 571 | 579 |
| 572 void AudioRendererImpl::OnRenderError() { | 580 void AudioRendererImpl::OnRenderError() { |
| 573 disabled_cb_.Run(); | 581 disabled_cb_.Run(); |
| 574 } | 582 } |
| 575 | 583 |
| 576 void AudioRendererImpl::DisableUnderflowForTesting() { | 584 void AudioRendererImpl::DisableUnderflowForTesting() { |
| 577 underflow_disabled_ = true; | 585 underflow_disabled_ = true; |
| 578 } | 586 } |
| 579 | 587 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 598 case kUnderflow: | 606 case kUnderflow: |
| 599 case kRebuffering: | 607 case kRebuffering: |
| 600 case kStopped: | 608 case kStopped: |
| 601 if (status != PIPELINE_OK) | 609 if (status != PIPELINE_OK) |
| 602 error_cb_.Run(status); | 610 error_cb_.Run(status); |
| 603 return; | 611 return; |
| 604 } | 612 } |
| 605 } | 613 } |
| 606 | 614 |
| 607 } // namespace media | 615 } // namespace media |
| OLD | NEW |