Chromium Code Reviews| 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 : state_(kUninitialized), |
| 24 pending_read_(false), | 26 pending_read_(false), |
| 25 received_end_of_stream_(false), | 27 received_end_of_stream_(false), |
| 26 rendered_end_of_stream_(false), | 28 rendered_end_of_stream_(false), |
| 27 audio_time_buffered_(kNoTimestamp()), | 29 audio_time_buffered_(kNoTimestamp()), |
| 28 current_time_(kNoTimestamp()), | 30 current_time_(kNoTimestamp()), |
| 29 bytes_per_frame_(0), | 31 bytes_per_frame_(0), |
| 30 stopped_(false), | 32 stopped_(false), |
| 31 sink_(sink), | 33 sink_(sink), |
| 32 underflow_disabled_(false), | 34 underflow_disabled_(false), |
| 33 preroll_aborted_(false) { | 35 preroll_aborted_(false) { |
| 36 // We're created on the render thread, but this thread checker is for another. | |
| 37 pipeline_thread_checker_.DetachFromThread(); | |
| 34 } | 38 } |
| 35 | 39 |
| 36 void AudioRendererImpl::Play(const base::Closure& callback) { | 40 void AudioRendererImpl::Play(const base::Closure& callback) { |
| 41 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); | |
| 37 { | 42 { |
| 38 base::AutoLock auto_lock(lock_); | 43 base::AutoLock auto_lock(lock_); |
| 39 DCHECK_EQ(kPaused, state_); | 44 DCHECK_EQ(kPaused, state_); |
| 40 state_ = kPlaying; | 45 state_ = kPlaying; |
| 41 callback.Run(); | 46 callback.Run(); |
| 42 } | 47 } |
| 43 | 48 |
| 44 if (stopped_) | 49 if (stopped_) |
| 45 return; | 50 return; |
| 46 | 51 |
| 47 if (GetPlaybackRate() != 0.0f) { | 52 if (GetPlaybackRate() != 0.0f) { |
| 48 DoPlay(); | 53 DoPlay(); |
| 49 } else { | 54 } else { |
| 50 DoPause(); | 55 DoPause(); |
| 51 } | 56 } |
| 52 } | 57 } |
| 53 | 58 |
| 54 void AudioRendererImpl::DoPlay() { | 59 void AudioRendererImpl::DoPlay() { |
| 60 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); | |
| 55 earliest_end_time_ = base::Time::Now(); | 61 earliest_end_time_ = base::Time::Now(); |
| 56 sink_->Play(); | 62 sink_->Play(); |
| 57 } | 63 } |
| 58 | 64 |
| 59 void AudioRendererImpl::Pause(const base::Closure& callback) { | 65 void AudioRendererImpl::Pause(const base::Closure& callback) { |
| 66 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); | |
| 60 { | 67 { |
| 61 base::AutoLock auto_lock(lock_); | 68 base::AutoLock auto_lock(lock_); |
| 62 DCHECK(state_ == kPlaying || state_ == kUnderflow || | 69 DCHECK(state_ == kPlaying || state_ == kUnderflow || |
| 63 state_ == kRebuffering); | 70 state_ == kRebuffering); |
| 64 pause_cb_ = callback; | 71 pause_cb_ = callback; |
| 65 state_ = kPaused; | 72 state_ = kPaused; |
| 66 | 73 |
| 67 // Pause only when we've completed our pending read. | 74 // Pause only when we've completed our pending read. |
| 68 if (!pending_read_) | 75 if (!pending_read_) |
| 69 base::ResetAndReturn(&pause_cb_).Run(); | 76 base::ResetAndReturn(&pause_cb_).Run(); |
| 70 } | 77 } |
| 71 | 78 |
| 72 if (stopped_) | 79 if (stopped_) |
| 73 return; | 80 return; |
| 74 | 81 |
| 75 DoPause(); | 82 DoPause(); |
| 76 } | 83 } |
| 77 | 84 |
| 78 void AudioRendererImpl::DoPause() { | 85 void AudioRendererImpl::DoPause() { |
| 86 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); | |
| 79 sink_->Pause(false); | 87 sink_->Pause(false); |
| 80 } | 88 } |
| 81 | 89 |
| 82 void AudioRendererImpl::Flush(const base::Closure& callback) { | 90 void AudioRendererImpl::Flush(const base::Closure& callback) { |
| 91 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); | |
| 83 decoder_->Reset(callback); | 92 decoder_->Reset(callback); |
| 84 } | 93 } |
| 85 | 94 |
| 86 void AudioRendererImpl::Stop(const base::Closure& callback) { | 95 void AudioRendererImpl::Stop(const base::Closure& callback) { |
| 96 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); | |
| 87 DCHECK(!callback.is_null()); | 97 DCHECK(!callback.is_null()); |
| 88 | 98 |
| 99 if (!stopped_) { | |
| 100 sink_->Stop(); | |
| 101 stopped_ = true; | |
| 102 } | |
| 103 | |
| 89 { | 104 { |
| 90 base::AutoLock auto_lock(lock_); | 105 base::AutoLock auto_lock(lock_); |
| 91 if (!stopped_) { | |
| 92 sink_->Stop(); | |
| 93 stopped_ = true; | |
| 94 } | |
| 95 | |
| 96 state_ = kStopped; | 106 state_ = kStopped; |
| 97 algorithm_.reset(NULL); | 107 algorithm_.reset(NULL); |
| 98 init_cb_.Reset(); | 108 init_cb_.Reset(); |
| 99 underflow_cb_.Reset(); | 109 underflow_cb_.Reset(); |
| 100 time_cb_.Reset(); | 110 time_cb_.Reset(); |
| 101 } | 111 } |
| 102 | 112 |
| 103 callback.Run(); | 113 callback.Run(); |
| 104 } | 114 } |
| 105 | 115 |
| 106 void AudioRendererImpl::Preroll(base::TimeDelta time, | 116 void AudioRendererImpl::Preroll(base::TimeDelta time, |
| 107 const PipelineStatusCB& cb) { | 117 const PipelineStatusCB& cb) { |
| 108 base::AutoLock auto_lock(lock_); | 118 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 109 DCHECK_EQ(kPaused, state_); | |
| 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 | |
| 117 // Throw away everything and schedule our reads. | |
| 118 audio_time_buffered_ = kNoTimestamp(); | |
| 119 current_time_ = kNoTimestamp(); | |
| 120 received_end_of_stream_ = false; | |
| 121 rendered_end_of_stream_ = false; | |
| 122 preroll_aborted_ = false; | |
| 123 | |
| 124 // |algorithm_| will request more reads. | |
| 125 algorithm_->FlushBuffers(); | |
| 126 | |
| 127 if (stopped_) | 119 if (stopped_) |
| 128 return; | 120 return; |
| 129 | 121 |
| 122 { | |
| 123 base::AutoLock auto_lock(lock_); | |
| 124 DCHECK_EQ(kPaused, state_); | |
| 125 DCHECK(!pending_read_) << "Pending read must complete before seeking"; | |
| 126 DCHECK(pause_cb_.is_null()); | |
| 127 DCHECK(preroll_cb_.is_null()); | |
| 128 state_ = kPrerolling; | |
| 129 preroll_cb_ = cb; | |
| 130 preroll_timestamp_ = time; | |
| 131 | |
| 132 // Throw away everything and schedule our reads. | |
| 133 audio_time_buffered_ = kNoTimestamp(); | |
| 134 current_time_ = kNoTimestamp(); | |
| 135 received_end_of_stream_ = false; | |
| 136 rendered_end_of_stream_ = false; | |
| 137 preroll_aborted_ = false; | |
| 138 | |
| 139 // |algorithm_| will request more reads. | |
| 140 algorithm_->FlushBuffers(); | |
| 141 } | |
| 142 | |
| 130 // Pause and flush the stream when we preroll to a new location. | 143 // Pause and flush the stream when we preroll to a new location. |
| 131 earliest_end_time_ = base::Time::Now(); | 144 earliest_end_time_ = base::Time::Now(); |
| 132 sink_->Pause(true); | 145 sink_->Pause(true); |
| 133 } | 146 } |
| 134 | 147 |
| 135 void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream, | 148 void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream, |
| 136 const AudioDecoderList& decoders, | 149 const AudioDecoderList& decoders, |
| 137 const PipelineStatusCB& init_cb, | 150 const PipelineStatusCB& init_cb, |
| 138 const StatisticsCB& statistics_cb, | 151 const StatisticsCB& statistics_cb, |
| 139 const base::Closure& underflow_cb, | 152 const base::Closure& underflow_cb, |
| 140 const TimeCB& time_cb, | 153 const TimeCB& time_cb, |
| 141 const base::Closure& ended_cb, | 154 const base::Closure& ended_cb, |
| 142 const base::Closure& disabled_cb, | 155 const base::Closure& disabled_cb, |
| 143 const PipelineStatusCB& error_cb) { | 156 const PipelineStatusCB& error_cb) { |
| 144 base::AutoLock auto_lock(lock_); | 157 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 145 DCHECK(stream); | 158 DCHECK(stream); |
| 146 DCHECK(!decoders.empty()); | 159 DCHECK(!decoders.empty()); |
| 147 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | 160 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
| 148 DCHECK(!init_cb.is_null()); | 161 DCHECK(!init_cb.is_null()); |
| 149 DCHECK(!statistics_cb.is_null()); | 162 DCHECK(!statistics_cb.is_null()); |
| 150 DCHECK(!underflow_cb.is_null()); | 163 DCHECK(!underflow_cb.is_null()); |
| 151 DCHECK(!time_cb.is_null()); | 164 DCHECK(!time_cb.is_null()); |
| 152 DCHECK(!ended_cb.is_null()); | 165 DCHECK(!ended_cb.is_null()); |
| 153 DCHECK(!disabled_cb.is_null()); | 166 DCHECK(!disabled_cb.is_null()); |
| 154 DCHECK(!error_cb.is_null()); | 167 DCHECK(!error_cb.is_null()); |
| 155 DCHECK_EQ(kUninitialized, state_); | 168 DCHECK_EQ(kUninitialized, state_); |
| 156 | 169 |
| 157 init_cb_ = init_cb; | 170 init_cb_ = init_cb; |
| 158 statistics_cb_ = statistics_cb; | 171 statistics_cb_ = statistics_cb; |
| 159 underflow_cb_ = underflow_cb; | 172 underflow_cb_ = underflow_cb; |
| 160 time_cb_ = time_cb; | 173 time_cb_ = time_cb; |
| 161 ended_cb_ = ended_cb; | 174 ended_cb_ = ended_cb; |
| 162 disabled_cb_ = disabled_cb; | 175 disabled_cb_ = disabled_cb; |
| 163 error_cb_ = error_cb; | 176 error_cb_ = error_cb; |
| 164 | 177 |
| 165 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders)); | 178 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders)); |
| 166 InitializeNextDecoder(stream, decoder_list.Pass()); | 179 InitializeNextDecoder(stream, decoder_list.Pass()); |
| 167 } | 180 } |
| 168 | 181 |
| 169 void AudioRendererImpl::InitializeNextDecoder( | 182 void AudioRendererImpl::InitializeNextDecoder( |
| 170 const scoped_refptr<DemuxerStream>& demuxer_stream, | 183 const scoped_refptr<DemuxerStream>& demuxer_stream, |
| 171 scoped_ptr<AudioDecoderList> decoders) { | 184 scoped_ptr<AudioDecoderList> decoders) { |
| 172 lock_.AssertAcquired(); | 185 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 173 DCHECK(!decoders->empty()); | 186 DCHECK(!decoders->empty()); |
| 174 | 187 |
| 175 scoped_refptr<AudioDecoder> decoder = decoders->front(); | 188 scoped_refptr<AudioDecoder> decoder = decoders->front(); |
| 176 decoders->pop_front(); | 189 decoders->pop_front(); |
| 177 | 190 |
| 178 DCHECK(decoder); | 191 DCHECK(decoder); |
| 179 decoder_ = decoder; | 192 decoder_ = decoder; |
| 180 | |
| 181 base::AutoUnlock auto_unlock(lock_); | |
| 182 decoder->Initialize( | 193 decoder->Initialize( |
| 183 demuxer_stream, | 194 demuxer_stream, BindToLoop(base::MessageLoopProxy::current(), base::Bind( |
| 184 base::Bind(&AudioRendererImpl::OnDecoderInitDone, this, | 195 &AudioRendererImpl::OnDecoderInitDone, this, demuxer_stream, |
| 185 demuxer_stream, | 196 base::Passed(&decoders))), |
| 186 base::Passed(&decoders)), | |
| 187 statistics_cb_); | 197 statistics_cb_); |
| 188 } | 198 } |
| 189 | 199 |
| 190 void AudioRendererImpl::OnDecoderInitDone( | 200 void AudioRendererImpl::OnDecoderInitDone( |
| 191 const scoped_refptr<DemuxerStream>& demuxer_stream, | 201 const scoped_refptr<DemuxerStream>& demuxer_stream, |
| 192 scoped_ptr<AudioDecoderList> decoders, | 202 scoped_ptr<AudioDecoderList> decoders, |
| 193 PipelineStatus status) { | 203 PipelineStatus status) { |
| 194 base::AutoLock auto_lock(lock_); | 204 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); |
| 195 | 205 |
| 196 if (state_ == kStopped) { | 206 if (state_ == kStopped) { |
| 197 DCHECK(stopped_); | 207 DCHECK(stopped_); |
| 198 return; | 208 return; |
| 199 } | 209 } |
| 200 | 210 |
| 201 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { | 211 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { |
| 202 InitializeNextDecoder(demuxer_stream, decoders.Pass()); | 212 InitializeNextDecoder(demuxer_stream, decoders.Pass()); |
| 203 return; | 213 return; |
| 204 } | 214 } |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after 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) { |
| 306 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); | |
| 294 if (stopped_) | 307 if (stopped_) |
| 295 return; | 308 return; |
| 296 sink_->SetVolume(volume); | 309 sink_->SetVolume(volume); |
| 297 } | 310 } |
| 298 | 311 |
| 299 AudioRendererImpl::~AudioRendererImpl() { | 312 AudioRendererImpl::~AudioRendererImpl() { |
| 300 // Stop() should have been called and |algorithm_| should have been destroyed. | 313 // Stop() should have been called and |algorithm_| should have been destroyed. |
| 301 DCHECK(state_ == kUninitialized || state_ == kStopped); | 314 DCHECK(state_ == kUninitialized || state_ == kStopped); |
| 302 DCHECK(!algorithm_.get()); | 315 DCHECK(!algorithm_.get()); |
| 303 } | 316 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 369 | 382 |
| 370 void AudioRendererImpl::ScheduleRead_Locked() { | 383 void AudioRendererImpl::ScheduleRead_Locked() { |
| 371 lock_.AssertAcquired(); | 384 lock_.AssertAcquired(); |
| 372 if (pending_read_ || state_ == kPaused) | 385 if (pending_read_ || state_ == kPaused) |
| 373 return; | 386 return; |
| 374 pending_read_ = true; | 387 pending_read_ = true; |
| 375 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, this)); | 388 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, this)); |
| 376 } | 389 } |
| 377 | 390 |
| 378 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { | 391 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { |
| 392 DCHECK(pipeline_thread_checker_.CalledOnValidThread()); | |
| 379 DCHECK_LE(0.0f, playback_rate); | 393 DCHECK_LE(0.0f, playback_rate); |
| 380 | 394 |
| 381 if (!stopped_) { | 395 if (!stopped_) { |
| 382 // We have two cases here: | 396 // We have two cases here: |
| 383 // Play: GetPlaybackRate() == 0.0 && playback_rate != 0.0 | 397 // Play: GetPlaybackRate() == 0.0 && playback_rate != 0.0 |
| 384 // Pause: GetPlaybackRate() != 0.0 && playback_rate == 0.0 | 398 // Pause: GetPlaybackRate() != 0.0 && playback_rate == 0.0 |
| 385 if (GetPlaybackRate() == 0.0f && playback_rate != 0.0f) { | 399 if (GetPlaybackRate() == 0.0f && playback_rate != 0.0f) { |
| 386 DoPlay(); | 400 DoPlay(); |
| 387 } else if (GetPlaybackRate() != 0.0f && playback_rate == 0.0f) { | 401 } else if (GetPlaybackRate() != 0.0f && playback_rate == 0.0f) { |
| 388 // Pause is easy, we can always pause. | 402 // Pause is easy, we can always pause. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 400 } | 414 } |
| 401 | 415 |
| 402 bool AudioRendererImpl::IsBeforePrerollTime( | 416 bool AudioRendererImpl::IsBeforePrerollTime( |
| 403 const scoped_refptr<Buffer>& buffer) { | 417 const scoped_refptr<Buffer>& buffer) { |
| 404 return (state_ == kPrerolling) && buffer && !buffer->IsEndOfStream() && | 418 return (state_ == kPrerolling) && buffer && !buffer->IsEndOfStream() && |
| 405 (buffer->GetTimestamp() + buffer->GetDuration()) < preroll_timestamp_; | 419 (buffer->GetTimestamp() + buffer->GetDuration()) < preroll_timestamp_; |
| 406 } | 420 } |
| 407 | 421 |
| 408 int AudioRendererImpl::Render(AudioBus* audio_bus, | 422 int AudioRendererImpl::Render(AudioBus* audio_bus, |
| 409 int audio_delay_milliseconds) { | 423 int audio_delay_milliseconds) { |
| 410 if (stopped_ || GetPlaybackRate() == 0.0f) { | 424 if (stopped_ || GetPlaybackRate() == 0.0f) { |
|
Ami GONE FROM CHROMIUM
2012/11/01 19:57:01
Must not read stopped_ off pipeline thread.
Ami GONE FROM CHROMIUM
2012/11/01 19:57:01
GetPlaybackRate() locks lock_ for its duration, bu
DaleCurtis
2012/11/01 22:02:59
Done.
DaleCurtis
2012/11/01 22:02:59
Fixed. Read once and saved for the duration of Ren
| |
| 411 // Output silence if stopped. | 425 // Output silence if stopped. |
| 412 audio_bus->Zero(); | 426 audio_bus->Zero(); |
| 413 return 0; | 427 return 0; |
| 414 } | 428 } |
| 415 | 429 |
| 416 // Adjust the playback delay. | 430 // Adjust the playback delay. |
| 417 base::TimeDelta request_delay = | 431 base::TimeDelta request_delay = |
| 418 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); | 432 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); |
| 419 | 433 |
| 420 // Finally we need to adjust the delay according to playback rate. | 434 // Finally we need to adjust the delay according to playback rate. |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 598 case kUnderflow: | 612 case kUnderflow: |
| 599 case kRebuffering: | 613 case kRebuffering: |
| 600 case kStopped: | 614 case kStopped: |
| 601 if (status != PIPELINE_OK) | 615 if (status != PIPELINE_OK) |
| 602 error_cb_.Run(status); | 616 error_cb_.Run(status); |
| 603 return; | 617 return; |
| 604 } | 618 } |
| 605 } | 619 } |
| 606 | 620 |
| 607 } // namespace media | 621 } // namespace media |
| OLD | NEW |