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> | |
10 | |
9 #include "base/bind.h" | 11 #include "base/bind.h" |
10 #include "base/callback.h" | 12 #include "base/callback.h" |
11 #include "base/callback_helpers.h" | 13 #include "base/callback_helpers.h" |
12 #include "base/logging.h" | 14 #include "base/logging.h" |
13 #include "media/audio/audio_util.h" | 15 #include "media/audio/audio_util.h" |
16 #include "media/base/demuxer_stream.h" | |
14 | 17 |
15 namespace media { | 18 namespace media { |
16 | 19 |
17 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) | 20 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) |
18 : state_(kUninitialized), | 21 : state_(kUninitialized), |
19 pending_read_(false), | 22 pending_read_(false), |
20 received_end_of_stream_(false), | 23 received_end_of_stream_(false), |
21 rendered_end_of_stream_(false), | 24 rendered_end_of_stream_(false), |
22 audio_time_buffered_(kNoTimestamp()), | 25 audio_time_buffered_(kNoTimestamp()), |
23 current_time_(kNoTimestamp()), | 26 current_time_(kNoTimestamp()), |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
76 void AudioRendererImpl::DoPause() { | 79 void AudioRendererImpl::DoPause() { |
77 DCHECK(sink_.get()); | 80 DCHECK(sink_.get()); |
78 sink_->Pause(false); | 81 sink_->Pause(false); |
79 } | 82 } |
80 | 83 |
81 void AudioRendererImpl::Flush(const base::Closure& callback) { | 84 void AudioRendererImpl::Flush(const base::Closure& callback) { |
82 decoder_->Reset(callback); | 85 decoder_->Reset(callback); |
83 } | 86 } |
84 | 87 |
85 void AudioRendererImpl::Stop(const base::Closure& callback) { | 88 void AudioRendererImpl::Stop(const base::Closure& callback) { |
89 DCHECK(!callback.is_null()); | |
90 | |
86 if (!stopped_) { | 91 if (!stopped_) { |
87 DCHECK(sink_.get()); | 92 DCHECK(sink_.get()); |
88 sink_->Stop(); | 93 sink_->Stop(); |
89 | 94 |
90 stopped_ = true; | 95 stopped_ = true; |
91 } | 96 } |
92 { | 97 { |
93 base::AutoLock auto_lock(lock_); | 98 base::AutoLock auto_lock(lock_); |
94 state_ = kStopped; | 99 state_ = kStopped; |
95 algorithm_.reset(NULL); | 100 algorithm_.reset(NULL); |
101 init_cb_.Reset(); | |
102 underflow_cb_.Reset(); | |
96 time_cb_.Reset(); | 103 time_cb_.Reset(); |
97 underflow_cb_.Reset(); | |
98 } | 104 } |
99 if (!callback.is_null()) { | 105 |
100 callback.Run(); | 106 callback.Run(); |
xhwang
2012/10/15 22:52:23
I found AudioDecoder doesn't have a Stop() method.
acolwell GONE FROM CHROMIUM
2012/10/16 16:23:38
I was a little surprised to see that the decode in
| |
101 } | |
102 } | 107 } |
103 | 108 |
104 void AudioRendererImpl::Preroll(base::TimeDelta time, | 109 void AudioRendererImpl::Preroll(base::TimeDelta time, |
105 const PipelineStatusCB& cb) { | 110 const PipelineStatusCB& cb) { |
106 base::AutoLock auto_lock(lock_); | 111 base::AutoLock auto_lock(lock_); |
107 DCHECK_EQ(kPaused, state_); | 112 DCHECK_EQ(kPaused, state_); |
108 DCHECK(!pending_read_) << "Pending read must complete before seeking"; | 113 DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
109 DCHECK(pause_cb_.is_null()); | 114 DCHECK(pause_cb_.is_null()); |
110 DCHECK(preroll_cb_.is_null()); | 115 DCHECK(preroll_cb_.is_null()); |
111 state_ = kPrerolling; | 116 state_ = kPrerolling; |
(...skipping 11 matching lines...) Expand all Loading... | |
123 algorithm_->FlushBuffers(); | 128 algorithm_->FlushBuffers(); |
124 | 129 |
125 if (stopped_) | 130 if (stopped_) |
126 return; | 131 return; |
127 | 132 |
128 // Pause and flush the stream when we preroll to a new location. | 133 // Pause and flush the stream when we preroll to a new location. |
129 earliest_end_time_ = base::Time::Now(); | 134 earliest_end_time_ = base::Time::Now(); |
130 sink_->Pause(true); | 135 sink_->Pause(true); |
131 } | 136 } |
132 | 137 |
133 void AudioRendererImpl::Initialize(const scoped_refptr<AudioDecoder>& decoder, | 138 void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream, |
139 const AudioDecoderList& decoders, | |
134 const PipelineStatusCB& init_cb, | 140 const PipelineStatusCB& init_cb, |
141 const StatisticsCB& statistics_cb, | |
135 const base::Closure& underflow_cb, | 142 const base::Closure& underflow_cb, |
136 const TimeCB& time_cb, | 143 const TimeCB& time_cb, |
137 const base::Closure& ended_cb, | 144 const base::Closure& ended_cb, |
138 const base::Closure& disabled_cb, | 145 const base::Closure& disabled_cb, |
139 const PipelineStatusCB& error_cb) { | 146 const PipelineStatusCB& error_cb) { |
140 DCHECK(decoder); | 147 base::AutoLock auto_lock(lock_); |
148 DCHECK(stream); | |
149 DCHECK(!decoders.empty()); | |
150 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | |
141 DCHECK(!init_cb.is_null()); | 151 DCHECK(!init_cb.is_null()); |
142 DCHECK(!underflow_cb.is_null()); | 152 DCHECK(!underflow_cb.is_null()); |
143 DCHECK(!time_cb.is_null()); | 153 DCHECK(!time_cb.is_null()); |
144 DCHECK(!ended_cb.is_null()); | 154 DCHECK(!ended_cb.is_null()); |
145 DCHECK(!disabled_cb.is_null()); | 155 DCHECK(!disabled_cb.is_null()); |
146 DCHECK(!error_cb.is_null()); | 156 DCHECK(!error_cb.is_null()); |
147 DCHECK_EQ(kUninitialized, state_); | 157 DCHECK_EQ(kUninitialized, state_); |
148 decoder_ = decoder; | 158 |
159 init_cb_ = init_cb; | |
160 statistics_cb_ = statistics_cb; | |
149 underflow_cb_ = underflow_cb; | 161 underflow_cb_ = underflow_cb; |
150 time_cb_ = time_cb; | 162 time_cb_ = time_cb; |
151 ended_cb_ = ended_cb; | 163 ended_cb_ = ended_cb; |
152 disabled_cb_ = disabled_cb; | 164 disabled_cb_ = disabled_cb; |
153 error_cb_ = error_cb; | 165 error_cb_ = error_cb; |
154 | 166 |
167 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders)); | |
168 InitializeNextDecoder(stream, decoder_list.Pass()); | |
169 } | |
170 | |
171 void AudioRendererImpl::InitializeNextDecoder( | |
172 const scoped_refptr<DemuxerStream>& demuxer_stream, | |
173 scoped_ptr<AudioDecoderList> decoders) { | |
174 lock_.AssertAcquired(); | |
175 DCHECK(!decoders->empty()); | |
176 | |
177 scoped_refptr<AudioDecoder> decoder = decoders->front(); | |
178 decoders->pop_front(); | |
179 | |
180 DCHECK(decoder); | |
181 decoder_ = decoder; | |
182 | |
183 base::AutoUnlock auto_unlock(lock_); | |
184 decoder->Initialize( | |
185 demuxer_stream, | |
186 base::Bind(&AudioRendererImpl::OnDecoderInitDone, this, | |
187 demuxer_stream, | |
188 base::Passed(&decoders)), | |
189 statistics_cb_); | |
190 } | |
191 | |
192 void AudioRendererImpl::OnDecoderInitDone( | |
193 const scoped_refptr<DemuxerStream>& demuxer_stream, | |
194 scoped_ptr<AudioDecoderList> decoders, | |
195 PipelineStatus status) { | |
196 base::AutoLock auto_lock(lock_); | |
197 | |
198 if (state_ == kStopped) | |
scherkus (not reviewing)
2012/10/18 00:30:28
also check stopped_?
xhwang
2012/10/18 01:35:02
Done.
| |
199 return; | |
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 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
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 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
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 |