| 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/logging.h" | 14 #include "base/logging.h" |
| 15 #include "media/audio/audio_util.h" | 15 #include "media/audio/audio_util.h" |
| 16 #include "media/base/demuxer_stream.h" | 16 #include "media/base/demuxer_stream.h" |
| 17 | 17 |
| 18 namespace media { | 18 namespace media { |
| 19 | 19 |
| 20 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) | 20 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) |
| 21 : state_(kUninitialized), | 21 : state_(kUninitialized), |
| 22 pending_read_(false), | 22 pending_read_(false), |
| 23 received_end_of_stream_(false), | 23 received_end_of_stream_(false), |
| 24 rendered_end_of_stream_(false), | 24 rendered_end_of_stream_(false), |
| 25 audio_time_buffered_(kNoTimestamp()), | 25 audio_time_buffered_(kNoTimestamp()), |
| 26 current_time_(kNoTimestamp()), | 26 current_time_(kNoTimestamp()), |
| 27 bytes_per_frame_(0), | 27 bytes_per_frame_(0), |
| 28 bytes_per_second_(0), | |
| 29 stopped_(false), | 28 stopped_(false), |
| 30 sink_(sink), | 29 sink_(sink), |
| 31 is_initialized_(false), | |
| 32 underflow_disabled_(false), | 30 underflow_disabled_(false), |
| 33 preroll_aborted_(false) { | 31 preroll_aborted_(false) { |
| 34 } | 32 } |
| 35 | 33 |
| 36 void AudioRendererImpl::Play(const base::Closure& callback) { | 34 void AudioRendererImpl::Play(const base::Closure& callback) { |
| 37 { | 35 { |
| 38 base::AutoLock auto_lock(lock_); | 36 base::AutoLock auto_lock(lock_); |
| 39 DCHECK_EQ(kPaused, state_); | 37 DCHECK_EQ(kPaused, state_); |
| 40 state_ = kPlaying; | 38 state_ = kPlaying; |
| 41 callback.Run(); | 39 callback.Run(); |
| 42 } | 40 } |
| 43 | 41 |
| 44 if (stopped_) | 42 if (stopped_) |
| 45 return; | 43 return; |
| 46 | 44 |
| 47 if (GetPlaybackRate() != 0.0f) { | 45 if (GetPlaybackRate() != 0.0f) { |
| 48 DoPlay(); | 46 DoPlay(); |
| 49 } else { | 47 } else { |
| 50 DoPause(); | 48 DoPause(); |
| 51 } | 49 } |
| 52 } | 50 } |
| 53 | 51 |
| 54 void AudioRendererImpl::DoPlay() { | 52 void AudioRendererImpl::DoPlay() { |
| 55 earliest_end_time_ = base::Time::Now(); | 53 earliest_end_time_ = base::Time::Now(); |
| 56 DCHECK(sink_.get()); | |
| 57 sink_->Play(); | 54 sink_->Play(); |
| 58 } | 55 } |
| 59 | 56 |
| 60 void AudioRendererImpl::Pause(const base::Closure& callback) { | 57 void AudioRendererImpl::Pause(const base::Closure& callback) { |
| 61 { | 58 { |
| 62 base::AutoLock auto_lock(lock_); | 59 base::AutoLock auto_lock(lock_); |
| 63 DCHECK(state_ == kPlaying || state_ == kUnderflow || | 60 DCHECK(state_ == kPlaying || state_ == kUnderflow || |
| 64 state_ == kRebuffering); | 61 state_ == kRebuffering); |
| 65 pause_cb_ = callback; | 62 pause_cb_ = callback; |
| 66 state_ = kPaused; | 63 state_ = kPaused; |
| 67 | 64 |
| 68 // Pause only when we've completed our pending read. | 65 // Pause only when we've completed our pending read. |
| 69 if (!pending_read_) | 66 if (!pending_read_) |
| 70 base::ResetAndReturn(&pause_cb_).Run(); | 67 base::ResetAndReturn(&pause_cb_).Run(); |
| 71 } | 68 } |
| 72 | 69 |
| 73 if (stopped_) | 70 if (stopped_) |
| 74 return; | 71 return; |
| 75 | 72 |
| 76 DoPause(); | 73 DoPause(); |
| 77 } | 74 } |
| 78 | 75 |
| 79 void AudioRendererImpl::DoPause() { | 76 void AudioRendererImpl::DoPause() { |
| 80 DCHECK(sink_.get()); | |
| 81 sink_->Pause(false); | 77 sink_->Pause(false); |
| 82 } | 78 } |
| 83 | 79 |
| 84 void AudioRendererImpl::Flush(const base::Closure& callback) { | 80 void AudioRendererImpl::Flush(const base::Closure& callback) { |
| 85 decoder_->Reset(callback); | 81 decoder_->Reset(callback); |
| 86 } | 82 } |
| 87 | 83 |
| 88 void AudioRendererImpl::Stop(const base::Closure& callback) { | 84 void AudioRendererImpl::Stop(const base::Closure& callback) { |
| 89 DCHECK(!callback.is_null()); | 85 DCHECK(!callback.is_null()); |
| 90 | 86 |
| 91 if (!stopped_) { | 87 if (!stopped_) { |
| 92 DCHECK(sink_.get()); | |
| 93 sink_->Stop(); | 88 sink_->Stop(); |
| 94 | |
| 95 stopped_ = true; | 89 stopped_ = true; |
| 96 } | 90 } |
| 97 { | 91 { |
| 98 base::AutoLock auto_lock(lock_); | 92 base::AutoLock auto_lock(lock_); |
| 99 state_ = kStopped; | 93 state_ = kStopped; |
| 100 algorithm_.reset(NULL); | 94 algorithm_.reset(NULL); |
| 101 init_cb_.Reset(); | 95 init_cb_.Reset(); |
| 102 underflow_cb_.Reset(); | 96 underflow_cb_.Reset(); |
| 103 time_cb_.Reset(); | 97 time_cb_.Reset(); |
| 104 } | 98 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 const base::Closure& underflow_cb, | 136 const base::Closure& underflow_cb, |
| 143 const TimeCB& time_cb, | 137 const TimeCB& time_cb, |
| 144 const base::Closure& ended_cb, | 138 const base::Closure& ended_cb, |
| 145 const base::Closure& disabled_cb, | 139 const base::Closure& disabled_cb, |
| 146 const PipelineStatusCB& error_cb) { | 140 const PipelineStatusCB& error_cb) { |
| 147 base::AutoLock auto_lock(lock_); | 141 base::AutoLock auto_lock(lock_); |
| 148 DCHECK(stream); | 142 DCHECK(stream); |
| 149 DCHECK(!decoders.empty()); | 143 DCHECK(!decoders.empty()); |
| 150 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | 144 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
| 151 DCHECK(!init_cb.is_null()); | 145 DCHECK(!init_cb.is_null()); |
| 146 DCHECK(!statistics_cb.is_null()); |
| 152 DCHECK(!underflow_cb.is_null()); | 147 DCHECK(!underflow_cb.is_null()); |
| 153 DCHECK(!time_cb.is_null()); | 148 DCHECK(!time_cb.is_null()); |
| 154 DCHECK(!ended_cb.is_null()); | 149 DCHECK(!ended_cb.is_null()); |
| 155 DCHECK(!disabled_cb.is_null()); | 150 DCHECK(!disabled_cb.is_null()); |
| 156 DCHECK(!error_cb.is_null()); | 151 DCHECK(!error_cb.is_null()); |
| 157 DCHECK_EQ(kUninitialized, state_); | 152 DCHECK_EQ(kUninitialized, state_); |
| 158 | 153 |
| 159 init_cb_ = init_cb; | 154 init_cb_ = init_cb; |
| 160 statistics_cb_ = statistics_cb; | 155 statistics_cb_ = statistics_cb; |
| 161 underflow_cb_ = underflow_cb; | 156 underflow_cb_ = underflow_cb; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { | 196 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { |
| 202 InitializeNextDecoder(demuxer_stream, decoders.Pass()); | 197 InitializeNextDecoder(demuxer_stream, decoders.Pass()); |
| 203 return; | 198 return; |
| 204 } | 199 } |
| 205 | 200 |
| 206 if (status != PIPELINE_OK) { | 201 if (status != PIPELINE_OK) { |
| 207 base::ResetAndReturn(&init_cb_).Run(status); | 202 base::ResetAndReturn(&init_cb_).Run(status); |
| 208 return; | 203 return; |
| 209 } | 204 } |
| 210 | 205 |
| 211 // Create a callback so our algorithm can request more reads. | 206 // We're all good! Continue initializing the rest of the audio renderer based |
| 212 base::Closure cb = base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this); | 207 // on the decoder format. |
| 213 | 208 |
| 214 // Construct the algorithm. | |
| 215 algorithm_.reset(new AudioRendererAlgorithm()); | |
| 216 | |
| 217 // Initialize our algorithm with media properties, initial playback rate, | |
| 218 // and a callback to request more reads from the data source. | |
| 219 ChannelLayout channel_layout = decoder_->channel_layout(); | 209 ChannelLayout channel_layout = decoder_->channel_layout(); |
| 220 int channels = ChannelLayoutToChannelCount(channel_layout); | 210 int channels = ChannelLayoutToChannelCount(channel_layout); |
| 221 int bits_per_channel = decoder_->bits_per_channel(); | 211 int bits_per_channel = decoder_->bits_per_channel(); |
| 222 int sample_rate = decoder_->samples_per_second(); | 212 int sample_rate = decoder_->samples_per_second(); |
| 223 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. | 213 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. |
| 224 bytes_per_frame_ = channels * bits_per_channel / 8; | 214 bytes_per_frame_ = channels * bits_per_channel / 8; |
| 225 | 215 |
| 226 bool config_ok = algorithm_->ValidateConfig(channels, sample_rate, | 216 algorithm_.reset(new AudioRendererAlgorithm()); |
| 227 bits_per_channel); | 217 if (!algorithm_->ValidateConfig(channels, sample_rate, bits_per_channel)) { |
| 228 if (!config_ok || is_initialized_) { | |
| 229 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); | 218 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
| 230 return; | 219 return; |
| 231 } | 220 } |
| 232 | 221 |
| 233 if (config_ok) | 222 algorithm_->Initialize( |
| 234 algorithm_->Initialize(channels, sample_rate, bits_per_channel, 0.0f, cb); | 223 channels, sample_rate, bits_per_channel, 0.0f, |
| 224 base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this)); |
| 235 | 225 |
| 236 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY | 226 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY |
| 237 // does not currently support all the sample-rates that we require. | 227 // does not currently support all the sample-rates that we require. |
| 238 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 | 228 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 |
| 239 // for more details. | 229 // for more details. |
| 240 audio_parameters_ = AudioParameters( | 230 audio_parameters_ = AudioParameters( |
| 241 AudioParameters::AUDIO_PCM_LINEAR, channel_layout, sample_rate, | 231 AudioParameters::AUDIO_PCM_LINEAR, channel_layout, sample_rate, |
| 242 bits_per_channel, GetHighLatencyOutputBufferSize(sample_rate)); | 232 bits_per_channel, GetHighLatencyOutputBufferSize(sample_rate)); |
| 243 | 233 |
| 244 bytes_per_second_ = audio_parameters_.GetBytesPerSecond(); | 234 sink_->Initialize(audio_parameters_, this); |
| 235 sink_->Start(); |
| 245 | 236 |
| 246 DCHECK(sink_.get()); | |
| 247 DCHECK(!is_initialized_); | |
| 248 | |
| 249 sink_->Initialize(audio_parameters_, this); | |
| 250 | |
| 251 sink_->Start(); | |
| 252 is_initialized_ = true; | |
| 253 | |
| 254 // Finally, execute the start callback. | |
| 255 state_ = kPaused; | 237 state_ = kPaused; |
| 256 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 238 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 257 } | 239 } |
| 258 | 240 |
| 259 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { | 241 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { |
| 260 base::AutoLock auto_lock(lock_); | 242 base::AutoLock auto_lock(lock_); |
| 261 if (state_ == kUnderflow) { | 243 if (state_ == kUnderflow) { |
| 262 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we | 244 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we |
| 263 // shouldn't even reach the kUnderflow state to begin with. But for now | 245 // shouldn't even reach the kUnderflow state to begin with. But for now |
| 264 // we're just making sure that the audio buffer capacity (i.e. the | 246 // we're just making sure that the audio buffer capacity (i.e. the |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * | 520 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * |
| 539 playback_rate))); | 521 playback_rate))); |
| 540 } | 522 } |
| 541 earliest_end_time_ = | 523 earliest_end_time_ = |
| 542 std::max(earliest_end_time_, | 524 std::max(earliest_end_time_, |
| 543 time_now + request_delay + predicted_play_time); | 525 time_now + request_delay + predicted_play_time); |
| 544 } | 526 } |
| 545 } | 527 } |
| 546 | 528 |
| 547 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { | 529 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { |
| 548 if (bytes_per_second_) { | 530 int bytes_per_second = audio_parameters_.GetBytesPerSecond(); |
| 549 return base::TimeDelta::FromMicroseconds( | 531 CHECK(bytes_per_second); |
| 550 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); | 532 return base::TimeDelta::FromMicroseconds( |
| 551 } | 533 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second); |
| 552 return base::TimeDelta(); | |
| 553 } | 534 } |
| 554 | 535 |
| 555 void AudioRendererImpl::OnRenderError() { | 536 void AudioRendererImpl::OnRenderError() { |
| 556 disabled_cb_.Run(); | 537 disabled_cb_.Run(); |
| 557 } | 538 } |
| 558 | 539 |
| 559 void AudioRendererImpl::DisableUnderflowForTesting() { | 540 void AudioRendererImpl::DisableUnderflowForTesting() { |
| 560 DCHECK(!is_initialized_); | |
| 561 underflow_disabled_ = true; | 541 underflow_disabled_ = true; |
| 562 } | 542 } |
| 563 | 543 |
| 564 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { | 544 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { |
| 565 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK; | 545 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK; |
| 566 switch (state_) { | 546 switch (state_) { |
| 567 case kUninitialized: | 547 case kUninitialized: |
| 568 NOTREACHED(); | 548 NOTREACHED(); |
| 569 return; | 549 return; |
| 570 case kPaused: | 550 case kPaused: |
| (...skipping 11 matching lines...) Expand all Loading... |
| 582 case kUnderflow: | 562 case kUnderflow: |
| 583 case kRebuffering: | 563 case kRebuffering: |
| 584 case kStopped: | 564 case kStopped: |
| 585 if (status != PIPELINE_OK) | 565 if (status != PIPELINE_OK) |
| 586 error_cb_.Run(status); | 566 error_cb_.Run(status); |
| 587 return; | 567 return; |
| 588 } | 568 } |
| 589 } | 569 } |
| 590 | 570 |
| 591 } // namespace media | 571 } // namespace media |
| OLD | NEW |