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 |