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 "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "media/audio/audio_util.h" | 13 #include "media/audio/audio_util.h" |
| 14 #include "media/base/demuxer_stream.h" | |
| 14 | 15 |
| 15 namespace media { | 16 namespace media { |
| 16 | 17 |
| 17 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) | 18 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) |
| 18 : state_(kUninitialized), | 19 : state_(kUninitialized), |
| 19 pending_read_(false), | 20 pending_read_(false), |
| 20 received_end_of_stream_(false), | 21 received_end_of_stream_(false), |
| 21 rendered_end_of_stream_(false), | 22 rendered_end_of_stream_(false), |
| 22 audio_time_buffered_(kNoTimestamp()), | 23 audio_time_buffered_(kNoTimestamp()), |
| 23 current_time_(kNoTimestamp()), | 24 current_time_(kNoTimestamp()), |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 | 90 |
| 90 stopped_ = true; | 91 stopped_ = true; |
| 91 } | 92 } |
| 92 { | 93 { |
| 93 base::AutoLock auto_lock(lock_); | 94 base::AutoLock auto_lock(lock_); |
| 94 state_ = kStopped; | 95 state_ = kStopped; |
| 95 algorithm_.reset(NULL); | 96 algorithm_.reset(NULL); |
| 96 time_cb_.Reset(); | 97 time_cb_.Reset(); |
| 97 underflow_cb_.Reset(); | 98 underflow_cb_.Reset(); |
| 98 } | 99 } |
| 99 if (!callback.is_null()) { | 100 if (!callback.is_null()) { |
|
acolwell GONE FROM CHROMIUM
2012/10/15 21:00:07
nit: Is this actually ever called w/o a callback?
xhwang
2012/10/15 22:52:23
Done.
| |
| 100 callback.Run(); | 101 callback.Run(); |
| 101 } | 102 } |
| 102 } | 103 } |
| 103 | 104 |
| 104 void AudioRendererImpl::Preroll(base::TimeDelta time, | 105 void AudioRendererImpl::Preroll(base::TimeDelta time, |
| 105 const PipelineStatusCB& cb) { | 106 const PipelineStatusCB& cb) { |
| 106 base::AutoLock auto_lock(lock_); | 107 base::AutoLock auto_lock(lock_); |
| 107 DCHECK_EQ(kPaused, state_); | 108 DCHECK_EQ(kPaused, state_); |
| 108 DCHECK(!pending_read_) << "Pending read must complete before seeking"; | 109 DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
| 109 DCHECK(pause_cb_.is_null()); | 110 DCHECK(pause_cb_.is_null()); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 123 algorithm_->FlushBuffers(); | 124 algorithm_->FlushBuffers(); |
| 124 | 125 |
| 125 if (stopped_) | 126 if (stopped_) |
| 126 return; | 127 return; |
| 127 | 128 |
| 128 // Pause and flush the stream when we preroll to a new location. | 129 // Pause and flush the stream when we preroll to a new location. |
| 129 earliest_end_time_ = base::Time::Now(); | 130 earliest_end_time_ = base::Time::Now(); |
| 130 sink_->Pause(true); | 131 sink_->Pause(true); |
| 131 } | 132 } |
| 132 | 133 |
| 133 void AudioRendererImpl::Initialize(const scoped_refptr<AudioDecoder>& decoder, | 134 void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream, |
| 135 const AudioDecoderList& decoders, | |
| 134 const PipelineStatusCB& init_cb, | 136 const PipelineStatusCB& init_cb, |
| 137 const StatisticsCB& statistics_cb, | |
| 135 const base::Closure& underflow_cb, | 138 const base::Closure& underflow_cb, |
| 136 const TimeCB& time_cb, | 139 const TimeCB& time_cb, |
| 137 const base::Closure& ended_cb, | 140 const base::Closure& ended_cb, |
| 138 const base::Closure& disabled_cb, | 141 const base::Closure& disabled_cb, |
| 139 const PipelineStatusCB& error_cb) { | 142 const PipelineStatusCB& error_cb) { |
| 140 DCHECK(decoder); | 143 base::AutoLock auto_lock(lock_); |
| 144 DCHECK(stream); | |
| 145 DCHECK(!decoders.empty()); | |
| 146 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | |
| 141 DCHECK(!init_cb.is_null()); | 147 DCHECK(!init_cb.is_null()); |
| 142 DCHECK(!underflow_cb.is_null()); | 148 DCHECK(!underflow_cb.is_null()); |
| 143 DCHECK(!time_cb.is_null()); | 149 DCHECK(!time_cb.is_null()); |
| 144 DCHECK(!ended_cb.is_null()); | 150 DCHECK(!ended_cb.is_null()); |
| 145 DCHECK(!disabled_cb.is_null()); | 151 DCHECK(!disabled_cb.is_null()); |
| 146 DCHECK(!error_cb.is_null()); | 152 DCHECK(!error_cb.is_null()); |
| 147 DCHECK_EQ(kUninitialized, state_); | 153 DCHECK_EQ(kUninitialized, state_); |
| 148 decoder_ = decoder; | 154 |
| 155 init_cb_ = init_cb; | |
| 156 statistics_cb_ = statistics_cb; | |
| 149 underflow_cb_ = underflow_cb; | 157 underflow_cb_ = underflow_cb; |
| 150 time_cb_ = time_cb; | 158 time_cb_ = time_cb; |
| 151 ended_cb_ = ended_cb; | 159 ended_cb_ = ended_cb; |
| 152 disabled_cb_ = disabled_cb; | 160 disabled_cb_ = disabled_cb; |
| 153 error_cb_ = error_cb; | 161 error_cb_ = error_cb; |
| 154 | 162 |
| 163 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders)); | |
| 164 InitializeNextDecoder(stream, decoder_list.Pass()); | |
| 165 } | |
| 166 | |
| 167 void AudioRendererImpl::InitializeNextDecoder( | |
| 168 const scoped_refptr<DemuxerStream>& demuxer_stream, | |
| 169 scoped_ptr<AudioDecoderList> decoders) { | |
| 170 lock_.AssertAcquired(); | |
| 171 DCHECK(!decoders->empty()); | |
| 172 | |
| 173 scoped_refptr<AudioDecoder> decoder = decoders->front(); | |
| 174 decoders->pop_front(); | |
| 175 | |
| 176 DCHECK(decoder); | |
| 177 decoder_ = decoder; | |
| 178 | |
| 179 base::AutoUnlock auto_unlock(lock_); | |
| 180 decoder->Initialize( | |
| 181 demuxer_stream, | |
| 182 base::Bind(&AudioRendererImpl::OnDecoderInitDone, this, | |
| 183 demuxer_stream, | |
| 184 base::Passed(&decoders)), | |
| 185 statistics_cb_); | |
| 186 } | |
| 187 | |
| 188 void AudioRendererImpl::OnDecoderInitDone( | |
| 189 const scoped_refptr<DemuxerStream>& demuxer_stream, | |
| 190 scoped_ptr<AudioDecoderList> decoders, | |
| 191 PipelineStatus status) { | |
| 192 base::AutoLock auto_lock(lock_); | |
| 193 | |
| 194 if (state_ == kStopped) { | |
| 195 // TODO(xhwang): Question! Do we need to return init_cb here? Is the | |
| 196 // pipeline teardown waiting for this? | |
|
xhwang
2012/10/15 17:50:28
In VideoRendererBase we return directly here w/o r
| |
| 197 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); | |
|
acolwell GONE FROM CHROMIUM
2012/10/15 21:00:07
No. You should not call init_cb_ here. init_cb_ sh
xhwang
2012/10/15 22:52:23
Done. Also added init_cb_.Reset() in Stop().
| |
| 198 return; | |
| 199 } | |
| 200 | |
| 201 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { | |
| 202 InitializeNextDecoder(demuxer_stream, decoders.Pass()); | |
| 203 return; | |
| 204 } | |
| 205 | |
| 206 if (status != PIPELINE_OK) { | |
| 207 base::ResetAndReturn(&init_cb_).Run(status); | |
| 208 return; | |
| 209 } | |
| 210 | |
| 155 // Create a callback so our algorithm can request more reads. | 211 // Create a callback so our algorithm can request more reads. |
| 156 base::Closure cb = base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this); | 212 base::Closure cb = base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this); |
| 157 | 213 |
| 158 // Construct the algorithm. | 214 // Construct the algorithm. |
| 159 algorithm_.reset(new AudioRendererAlgorithm()); | 215 algorithm_.reset(new AudioRendererAlgorithm()); |
| 160 | 216 |
| 161 // Initialize our algorithm with media properties, initial playback rate, | 217 // Initialize our algorithm with media properties, initial playback rate, |
| 162 // and a callback to request more reads from the data source. | 218 // and a callback to request more reads from the data source. |
| 163 ChannelLayout channel_layout = decoder_->channel_layout(); | 219 ChannelLayout channel_layout = decoder_->channel_layout(); |
| 164 int channels = ChannelLayoutToChannelCount(channel_layout); | 220 int channels = ChannelLayoutToChannelCount(channel_layout); |
| 165 int bits_per_channel = decoder_->bits_per_channel(); | 221 int bits_per_channel = decoder_->bits_per_channel(); |
| 166 int sample_rate = decoder_->samples_per_second(); | 222 int sample_rate = decoder_->samples_per_second(); |
| 167 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. | 223 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. |
| 168 bytes_per_frame_ = channels * bits_per_channel / 8; | 224 bytes_per_frame_ = channels * bits_per_channel / 8; |
| 169 | 225 |
| 170 bool config_ok = algorithm_->ValidateConfig(channels, sample_rate, | 226 bool config_ok = algorithm_->ValidateConfig(channels, sample_rate, |
| 171 bits_per_channel); | 227 bits_per_channel); |
| 172 if (!config_ok || is_initialized_) { | 228 if (!config_ok || is_initialized_) { |
| 173 init_cb.Run(PIPELINE_ERROR_INITIALIZATION_FAILED); | 229 init_cb_.Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
|
acolwell GONE FROM CHROMIUM
2012/10/15 21:00:07
nit: Change to base::ResetAndReturn(&init_cb_)
xhwang
2012/10/15 22:52:23
Done.
| |
| 174 return; | 230 return; |
| 175 } | 231 } |
| 176 | 232 |
| 177 if (config_ok) | 233 if (config_ok) |
| 178 algorithm_->Initialize(channels, sample_rate, bits_per_channel, 0.0f, cb); | 234 algorithm_->Initialize(channels, sample_rate, bits_per_channel, 0.0f, cb); |
| 179 | 235 |
| 180 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY | 236 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY |
| 181 // does not currently support all the sample-rates that we require. | 237 // does not currently support all the sample-rates that we require. |
| 182 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 | 238 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 |
| 183 // for more details. | 239 // for more details. |
| 184 audio_parameters_ = AudioParameters( | 240 audio_parameters_ = AudioParameters( |
| 185 AudioParameters::AUDIO_PCM_LINEAR, channel_layout, sample_rate, | 241 AudioParameters::AUDIO_PCM_LINEAR, channel_layout, sample_rate, |
| 186 bits_per_channel, GetHighLatencyOutputBufferSize(sample_rate)); | 242 bits_per_channel, GetHighLatencyOutputBufferSize(sample_rate)); |
| 187 | 243 |
| 188 bytes_per_second_ = audio_parameters_.GetBytesPerSecond(); | 244 bytes_per_second_ = audio_parameters_.GetBytesPerSecond(); |
| 189 | 245 |
| 190 DCHECK(sink_.get()); | 246 DCHECK(sink_.get()); |
| 191 DCHECK(!is_initialized_); | 247 DCHECK(!is_initialized_); |
| 192 | 248 |
| 193 sink_->Initialize(audio_parameters_, this); | 249 sink_->Initialize(audio_parameters_, this); |
| 194 | 250 |
| 195 sink_->Start(); | 251 sink_->Start(); |
| 196 is_initialized_ = true; | 252 is_initialized_ = true; |
| 197 | 253 |
| 198 // Finally, execute the start callback. | 254 // Finally, execute the start callback. |
| 199 state_ = kPaused; | 255 state_ = kPaused; |
| 200 init_cb.Run(PIPELINE_OK); | 256 init_cb_.Run(PIPELINE_OK); |
|
acolwell GONE FROM CHROMIUM
2012/10/15 21:00:07
ditto
xhwang
2012/10/15 22:52:23
Done.
| |
| 201 } | 257 } |
| 202 | 258 |
| 203 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { | 259 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { |
| 204 base::AutoLock auto_lock(lock_); | 260 base::AutoLock auto_lock(lock_); |
| 205 if (state_ == kUnderflow) { | 261 if (state_ == kUnderflow) { |
| 206 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we | 262 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we |
| 207 // shouldn't even reach the kUnderflow state to begin with. But for now | 263 // shouldn't even reach the kUnderflow state to begin with. But for now |
| 208 // we're just making sure that the audio buffer capacity (i.e. the | 264 // we're just making sure that the audio buffer capacity (i.e. the |
| 209 // number of bytes that need to be buffered for preroll to complete) | 265 // number of bytes that need to be buffered for preroll to complete) |
| 210 // does not increase due to an aborted preroll. | 266 // does not increase due to an aborted preroll. |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 526 case kUnderflow: | 582 case kUnderflow: |
| 527 case kRebuffering: | 583 case kRebuffering: |
| 528 case kStopped: | 584 case kStopped: |
| 529 if (status != PIPELINE_OK) | 585 if (status != PIPELINE_OK) |
| 530 error_cb_.Run(status); | 586 error_cb_.Run(status); |
| 531 return; | 587 return; |
| 532 } | 588 } |
| 533 } | 589 } |
| 534 | 590 |
| 535 } // namespace media | 591 } // namespace media |
| OLD | NEW |