Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: media/filters/audio_renderer_impl.cc

Issue 11275087: Move OnDecoderInitDone() from decoder to pipeline thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 // We're created on the render thread, but this thread checker is for another.
35 pipeline_thread_checker_.DetachFromThread();
34 } 36 }
35 37
36 void AudioRendererImpl::Play(const base::Closure& callback) { 38 void AudioRendererImpl::Play(const base::Closure& callback) {
39 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
40
37 { 41 {
38 base::AutoLock auto_lock(lock_); 42 base::AutoLock auto_lock(lock_);
39 DCHECK_EQ(kPaused, state_); 43 DCHECK_EQ(kPaused, state_);
40 state_ = kPlaying; 44 state_ = kPlaying;
41 callback.Run(); 45 callback.Run();
Ami GONE FROM CHROMIUM 2012/11/03 00:11:45 running the callback under lock looks strange. Is
DaleCurtis 2012/11/03 01:32:47 Yeah, it should removed, but that's a base class c
42 } 46 }
43 47
44 if (stopped_) 48 // Since playback rate is only set on the pipeline thread, we can query the
45 return; 49 // algorithm directly instead of using GetPlaybackRate().
46 50 if (algorithm_->playback_rate() != 0.0f) {
Ami GONE FROM CHROMIUM 2012/11/03 00:11:45 depending on impl detail of algorithm_ that this i
DaleCurtis 2012/11/03 01:32:47 Done.
47 if (GetPlaybackRate() != 0.0f) {
48 DoPlay(); 51 DoPlay();
49 } else { 52 } else {
50 DoPause(); 53 DoPause();
51 } 54 }
52 } 55 }
53 56
54 void AudioRendererImpl::DoPlay() { 57 void AudioRendererImpl::DoPlay() {
55 earliest_end_time_ = base::Time::Now(); 58 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
59 DCHECK(sink_);
60 {
61 base::AutoLock auto_lock(lock_);
62 earliest_end_time_ = base::Time::Now();
63 }
56 sink_->Play(); 64 sink_->Play();
57 } 65 }
58 66
59 void AudioRendererImpl::Pause(const base::Closure& callback) { 67 void AudioRendererImpl::Pause(const base::Closure& callback) {
68 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
69
60 { 70 {
61 base::AutoLock auto_lock(lock_); 71 base::AutoLock auto_lock(lock_);
62 DCHECK(state_ == kPlaying || state_ == kUnderflow || 72 DCHECK(state_ == kPlaying || state_ == kUnderflow ||
63 state_ == kRebuffering); 73 state_ == kRebuffering);
64 pause_cb_ = callback; 74 pause_cb_ = callback;
65 state_ = kPaused; 75 state_ = kPaused;
66 76
67 // Pause only when we've completed our pending read. 77 // Pause only when we've completed our pending read.
68 if (!pending_read_) 78 if (!pending_read_)
69 base::ResetAndReturn(&pause_cb_).Run(); 79 base::ResetAndReturn(&pause_cb_).Run();
70 } 80 }
71 81
72 if (stopped_)
73 return;
74
75 DoPause(); 82 DoPause();
76 } 83 }
77 84
78 void AudioRendererImpl::DoPause() { 85 void AudioRendererImpl::DoPause() {
86 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
87 DCHECK(sink_);
79 sink_->Pause(false); 88 sink_->Pause(false);
80 } 89 }
81 90
82 void AudioRendererImpl::Flush(const base::Closure& callback) { 91 void AudioRendererImpl::Flush(const base::Closure& callback) {
92 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
83 decoder_->Reset(callback); 93 decoder_->Reset(callback);
84 } 94 }
85 95
86 void AudioRendererImpl::Stop(const base::Closure& callback) { 96 void AudioRendererImpl::Stop(const base::Closure& callback) {
97 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
87 DCHECK(!callback.is_null()); 98 DCHECK(!callback.is_null());
88 99
100 if (sink_) {
101 sink_->Stop();
102 sink_ = NULL;
103 }
104
89 { 105 {
90 base::AutoLock auto_lock(lock_); 106 base::AutoLock auto_lock(lock_);
91 if (!stopped_) {
92 sink_->Stop();
93 stopped_ = true;
94 }
95
96 state_ = kStopped; 107 state_ = kStopped;
97 algorithm_.reset(NULL); 108 algorithm_.reset(NULL);
98 init_cb_.Reset(); 109 init_cb_.Reset();
99 underflow_cb_.Reset(); 110 underflow_cb_.Reset();
100 time_cb_.Reset(); 111 time_cb_.Reset();
101 } 112 }
102 113
103 callback.Run(); 114 callback.Run();
104 } 115 }
105 116
106 void AudioRendererImpl::Preroll(base::TimeDelta time, 117 void AudioRendererImpl::Preroll(base::TimeDelta time,
107 const PipelineStatusCB& cb) { 118 const PipelineStatusCB& cb) {
108 base::AutoLock auto_lock(lock_); 119 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
109 DCHECK_EQ(kPaused, state_); 120 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 121
117 // Throw away everything and schedule our reads. 122 {
118 audio_time_buffered_ = kNoTimestamp(); 123 base::AutoLock auto_lock(lock_);
119 current_time_ = kNoTimestamp(); 124 DCHECK_EQ(kPaused, state_);
120 received_end_of_stream_ = false; 125 DCHECK(!pending_read_) << "Pending read must complete before seeking";
121 rendered_end_of_stream_ = false; 126 DCHECK(pause_cb_.is_null());
122 preroll_aborted_ = false; 127 DCHECK(preroll_cb_.is_null());
128 state_ = kPrerolling;
129 preroll_cb_ = cb;
130 preroll_timestamp_ = time;
123 131
124 // |algorithm_| will request more reads. 132 // Throw away everything and schedule our reads.
125 algorithm_->FlushBuffers(); 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;
126 138
127 if (stopped_) 139 // |algorithm_| will request more reads.
128 return; 140 algorithm_->FlushBuffers();
141 earliest_end_time_ = base::Time::Now();
142 }
129 143
130 // Pause and flush the stream when we preroll to a new location. 144 // Pause and flush the stream when we preroll to a new location.
131 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_);
169 DCHECK(sink_);
156 170
157 init_cb_ = init_cb; 171 init_cb_ = init_cb;
158 statistics_cb_ = statistics_cb; 172 statistics_cb_ = statistics_cb;
159 underflow_cb_ = underflow_cb; 173 underflow_cb_ = underflow_cb;
160 time_cb_ = time_cb; 174 time_cb_ = time_cb;
161 ended_cb_ = ended_cb; 175 ended_cb_ = ended_cb;
162 disabled_cb_ = disabled_cb; 176 disabled_cb_ = disabled_cb;
163 error_cb_ = error_cb; 177 error_cb_ = error_cb;
164 178
165 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders)); 179 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders));
166 InitializeNextDecoder(stream, decoder_list.Pass()); 180 InitializeNextDecoder(stream, decoder_list.Pass());
167 } 181 }
168 182
169 void AudioRendererImpl::InitializeNextDecoder( 183 void AudioRendererImpl::InitializeNextDecoder(
170 const scoped_refptr<DemuxerStream>& demuxer_stream, 184 const scoped_refptr<DemuxerStream>& demuxer_stream,
171 scoped_ptr<AudioDecoderList> decoders) { 185 scoped_ptr<AudioDecoderList> decoders) {
172 lock_.AssertAcquired(); 186 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
173 DCHECK(!decoders->empty()); 187 DCHECK(!decoders->empty());
174 188
175 scoped_refptr<AudioDecoder> decoder = decoders->front(); 189 scoped_refptr<AudioDecoder> decoder = decoders->front();
176 decoders->pop_front(); 190 decoders->pop_front();
177 191
178 DCHECK(decoder); 192 DCHECK(decoder);
179 decoder_ = decoder; 193 decoder_ = decoder;
180
181 base::AutoUnlock auto_unlock(lock_);
182 decoder->Initialize( 194 decoder->Initialize(
183 demuxer_stream, 195 demuxer_stream, BindToLoop(base::MessageLoopProxy::current(), base::Bind(
184 base::Bind(&AudioRendererImpl::OnDecoderInitDone, this, 196 &AudioRendererImpl::OnDecoderInitDone, this, demuxer_stream,
185 demuxer_stream, 197 base::Passed(&decoders))),
186 base::Passed(&decoders)),
187 statistics_cb_); 198 statistics_cb_);
188 } 199 }
189 200
190 void AudioRendererImpl::OnDecoderInitDone( 201 void AudioRendererImpl::OnDecoderInitDone(
191 const scoped_refptr<DemuxerStream>& demuxer_stream, 202 const scoped_refptr<DemuxerStream>& demuxer_stream,
192 scoped_ptr<AudioDecoderList> decoders, 203 scoped_ptr<AudioDecoderList> decoders,
193 PipelineStatus status) { 204 PipelineStatus status) {
194 base::AutoLock auto_lock(lock_); 205 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
195 206
196 if (state_ == kStopped) { 207 if (state_ == kStopped) {
197 DCHECK(stopped_); 208 DCHECK(!sink_);
198 return; 209 return;
199 } 210 }
200 211
201 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { 212 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) {
202 InitializeNextDecoder(demuxer_stream, decoders.Pass()); 213 InitializeNextDecoder(demuxer_stream, decoders.Pass());
203 return; 214 return;
204 } 215 }
205 216
206 if (status != PIPELINE_OK) { 217 if (status != PIPELINE_OK) {
207 base::ResetAndReturn(&init_cb_).Run(status); 218 base::ResetAndReturn(&init_cb_).Run(status);
208 return; 219 return;
209 } 220 }
210 221
211 // We're all good! Continue initializing the rest of the audio renderer based 222 // We're all good! Continue initializing the rest of the audio renderer based
212 // on the decoder format. 223 // on the decoder format.
213 224
214 ChannelLayout channel_layout = decoder_->channel_layout(); 225 ChannelLayout channel_layout = decoder_->channel_layout();
215 int channels = ChannelLayoutToChannelCount(channel_layout); 226 int channels = ChannelLayoutToChannelCount(channel_layout);
216 int bits_per_channel = decoder_->bits_per_channel(); 227 int bits_per_channel = decoder_->bits_per_channel();
217 int sample_rate = decoder_->samples_per_second(); 228 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 229
221 algorithm_.reset(new AudioRendererAlgorithm()); 230 algorithm_.reset(new AudioRendererAlgorithm());
Ami GONE FROM CHROMIUM 2012/11/03 00:11:45 doesn't this need to be done under lock?
DaleCurtis 2012/11/03 01:32:47 No since it's not used until Initialize() complete
222 if (!algorithm_->ValidateConfig(channels, sample_rate, bits_per_channel)) { 231 if (!algorithm_->ValidateConfig(channels, sample_rate, bits_per_channel)) {
223 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); 232 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
224 return; 233 return;
225 } 234 }
226 235
227 algorithm_->Initialize( 236 algorithm_->Initialize(
228 channels, sample_rate, bits_per_channel, 0.0f, 237 channels, sample_rate, bits_per_channel, 0.0f,
229 base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this)); 238 base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this));
230 239
231 int buffer_size = GetHighLatencyOutputBufferSize(sample_rate); 240 int buffer_size = GetHighLatencyOutputBufferSize(sample_rate);
(...skipping 28 matching lines...) Expand all
260 // purposes it's okay that this buffer size might lead to jitter since it's 269 // purposes it's okay that this buffer size might lead to jitter since it's
261 // not a multiple of the hardware buffer size. 270 // not a multiple of the hardware buffer size.
262 format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 271 format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
263 buffer_size = 2048; 272 buffer_size = 2048;
264 } 273 }
265 #endif 274 #endif
266 275
267 audio_parameters_ = AudioParameters( 276 audio_parameters_ = AudioParameters(
268 format, channel_layout, sample_rate, bits_per_channel, buffer_size); 277 format, channel_layout, sample_rate, bits_per_channel, buffer_size);
269 278
279 state_ = kPaused;
280
270 sink_->Initialize(audio_parameters_, this); 281 sink_->Initialize(audio_parameters_, this);
271 sink_->Start(); 282 sink_->Start();
272 283
273 state_ = kPaused;
274 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 284 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
275 } 285 }
276 286
277 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { 287 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) {
288 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
278 base::AutoLock auto_lock(lock_); 289 base::AutoLock auto_lock(lock_);
279 if (state_ == kUnderflow) { 290 if (state_ == kUnderflow) {
280 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we 291 // 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 292 // 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 293 // 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) 294 // number of bytes that need to be buffered for preroll to complete)
284 // does not increase due to an aborted preroll. 295 // does not increase due to an aborted preroll.
285 // TODO(vrk): Fix this bug correctly! (crbug.com/151352) 296 // TODO(vrk): Fix this bug correctly! (crbug.com/151352)
286 if (buffer_more_audio && !preroll_aborted_) 297 if (buffer_more_audio && !preroll_aborted_)
287 algorithm_->IncreaseQueueCapacity(); 298 algorithm_->IncreaseQueueCapacity();
288 299
289 state_ = kRebuffering; 300 state_ = kRebuffering;
290 } 301 }
291 } 302 }
292 303
293 void AudioRendererImpl::SetVolume(float volume) { 304 void AudioRendererImpl::SetVolume(float volume) {
294 if (stopped_) 305 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
295 return; 306 DCHECK(sink_);
296 sink_->SetVolume(volume); 307 sink_->SetVolume(volume);
297 } 308 }
298 309
299 AudioRendererImpl::~AudioRendererImpl() { 310 AudioRendererImpl::~AudioRendererImpl() {
300 // Stop() should have been called and |algorithm_| should have been destroyed. 311 // Stop() should have been called and |algorithm_| should have been destroyed.
301 DCHECK(state_ == kUninitialized || state_ == kStopped); 312 DCHECK(state_ == kUninitialized || state_ == kStopped);
302 DCHECK(!algorithm_.get()); 313 DCHECK(!algorithm_.get());
303 } 314 }
304 315
305 void AudioRendererImpl::DecodedAudioReady(AudioDecoder::Status status, 316 void AudioRendererImpl::DecodedAudioReady(AudioDecoder::Status status,
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 380
370 void AudioRendererImpl::ScheduleRead_Locked() { 381 void AudioRendererImpl::ScheduleRead_Locked() {
371 lock_.AssertAcquired(); 382 lock_.AssertAcquired();
372 if (pending_read_ || state_ == kPaused) 383 if (pending_read_ || state_ == kPaused)
373 return; 384 return;
374 pending_read_ = true; 385 pending_read_ = true;
375 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, this)); 386 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, this));
376 } 387 }
377 388
378 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { 389 void AudioRendererImpl::SetPlaybackRate(float playback_rate) {
390 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
379 DCHECK_LE(0.0f, playback_rate); 391 DCHECK_LE(0.0f, playback_rate);
392 DCHECK(sink_);
380 393
381 if (!stopped_) { 394 // We have two cases here:
382 // We have two cases here: 395 // Play: current_playback_rate == 0.0 && playback_rate != 0.0
383 // Play: GetPlaybackRate() == 0.0 && playback_rate != 0.0 396 // Pause: current_playback_rate != 0.0 && playback_rate == 0.0
384 // Pause: GetPlaybackRate() != 0.0 && playback_rate == 0.0 397 float current_playback_rate = algorithm_->playback_rate();
385 if (GetPlaybackRate() == 0.0f && playback_rate != 0.0f) { 398 if (current_playback_rate == 0.0f && playback_rate != 0.0f) {
386 DoPlay(); 399 DoPlay();
387 } else if (GetPlaybackRate() != 0.0f && playback_rate == 0.0f) { 400 } else if (current_playback_rate != 0.0f && playback_rate == 0.0f) {
388 // Pause is easy, we can always pause. 401 // Pause is easy, we can always pause.
389 DoPause(); 402 DoPause();
390 }
391 } 403 }
392 404
393 base::AutoLock auto_lock(lock_); 405 base::AutoLock auto_lock(lock_);
394 algorithm_->SetPlaybackRate(playback_rate); 406 algorithm_->SetPlaybackRate(playback_rate);
395 } 407 }
396 408
397 float AudioRendererImpl::GetPlaybackRate() { 409 float AudioRendererImpl::GetPlaybackRate() {
398 base::AutoLock auto_lock(lock_); 410 base::AutoLock auto_lock(lock_);
399 return algorithm_->playback_rate(); 411 return algorithm_ ? algorithm_->playback_rate() : 0;
Ami GONE FROM CHROMIUM 2012/11/03 00:11:45 How can this fail to be non-NULL? Is it the case
DaleCurtis 2012/11/03 01:32:47 If Stop() happens on the pipeline thread and destr
400 } 412 }
401 413
402 bool AudioRendererImpl::IsBeforePrerollTime( 414 bool AudioRendererImpl::IsBeforePrerollTime(
403 const scoped_refptr<Buffer>& buffer) { 415 const scoped_refptr<Buffer>& buffer) {
404 return (state_ == kPrerolling) && buffer && !buffer->IsEndOfStream() && 416 return (state_ == kPrerolling) && buffer && !buffer->IsEndOfStream() &&
405 (buffer->GetTimestamp() + buffer->GetDuration()) < preroll_timestamp_; 417 (buffer->GetTimestamp() + buffer->GetDuration()) < preroll_timestamp_;
406 } 418 }
407 419
408 int AudioRendererImpl::Render(AudioBus* audio_bus, 420 int AudioRendererImpl::Render(AudioBus* audio_bus,
409 int audio_delay_milliseconds) { 421 int audio_delay_milliseconds) {
410 if (stopped_ || GetPlaybackRate() == 0.0f) { 422 float playback_rate = GetPlaybackRate();
423 if (playback_rate == 0.0f) {
Ami GONE FROM CHROMIUM 2012/11/03 00:11:45 Part of the point of my previous comment on this c
DaleCurtis 2012/11/03 01:32:47 WHY U SO DIFFICULT! Fixed, don't blame me as the p
411 // Output silence if stopped. 424 // Output silence if stopped.
412 audio_bus->Zero(); 425 audio_bus->Zero();
413 return 0; 426 return 0;
414 } 427 }
415 428
416 // Adjust the playback delay. 429 // Adjust the playback delay.
417 base::TimeDelta request_delay = 430 base::TimeDelta request_delay =
418 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); 431 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
419 432
420 // Finally we need to adjust the delay according to playback rate. 433 // Finally we need to adjust the delay according to playback rate.
421 if (GetPlaybackRate() != 1.0f) { 434 if (playback_rate != 1.0f) {
422 request_delay = base::TimeDelta::FromMicroseconds( 435 request_delay = base::TimeDelta::FromMicroseconds(static_cast<int64>(ceil(
423 static_cast<int64>(ceil(request_delay.InMicroseconds() * 436 request_delay.InMicroseconds() * playback_rate)));
424 GetPlaybackRate())));
425 } 437 }
426 438
427 int bytes_per_frame = audio_parameters_.GetBytesPerFrame(); 439 int bytes_per_frame = audio_parameters_.GetBytesPerFrame();
428 440
429 const int buf_size = audio_bus->frames() * bytes_per_frame; 441 const int buf_size = audio_bus->frames() * bytes_per_frame;
430 scoped_array<uint8> buf(new uint8[buf_size]); 442 scoped_array<uint8> buf(new uint8[buf_size]);
431 443
432 int frames_filled = FillBuffer(buf.get(), audio_bus->frames(), request_delay); 444 int frames_filled = FillBuffer(buf.get(), audio_bus->frames(), request_delay);
433 int bytes_filled = frames_filled * bytes_per_frame; 445 int bytes_filled = frames_filled * bytes_per_frame;
434 DCHECK_LE(bytes_filled, buf_size); 446 DCHECK_LE(bytes_filled, buf_size);
435 UpdateEarliestEndTime(bytes_filled, request_delay, base::Time::Now()); 447 UpdateEarliestEndTime(
448 bytes_filled, playback_rate, request_delay, base::Time::Now());
436 449
437 // Deinterleave audio data into the output bus. 450 // Deinterleave audio data into the output bus.
438 audio_bus->FromInterleaved( 451 audio_bus->FromInterleaved(
439 buf.get(), frames_filled, audio_parameters_.bits_per_sample() / 8); 452 buf.get(), frames_filled, audio_parameters_.bits_per_sample() / 8);
440 453
441 return frames_filled; 454 return frames_filled;
442 } 455 }
443 456
444 uint32 AudioRendererImpl::FillBuffer(uint8* dest, 457 uint32 AudioRendererImpl::FillBuffer(uint8* dest,
445 uint32 requested_frames, 458 uint32 requested_frames,
446 const base::TimeDelta& playback_delay) { 459 const base::TimeDelta& playback_delay) {
447 base::TimeDelta current_time = kNoTimestamp(); 460 base::TimeDelta current_time = kNoTimestamp();
448 base::TimeDelta max_time = kNoTimestamp(); 461 base::TimeDelta max_time = kNoTimestamp();
449 462
450 size_t frames_written = 0; 463 size_t frames_written = 0;
451 base::Closure underflow_cb; 464 base::Closure underflow_cb;
452 { 465 {
453 base::AutoLock auto_lock(lock_); 466 base::AutoLock auto_lock(lock_);
467 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
468 if (!algorithm_)
469 return 0;
454 470
455 if (state_ == kRebuffering && algorithm_->IsQueueFull()) 471 if (state_ == kRebuffering && algorithm_->IsQueueFull())
456 state_ = kPlaying; 472 state_ = kPlaying;
457 473
458 // Mute audio by returning 0 when not playing. 474 // Mute audio by returning 0 when not playing.
459 if (state_ != kPlaying) { 475 if (state_ != kPlaying) {
460 // TODO(scherkus): To keep the audio hardware busy we write at most 8k of 476 // 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 477 // 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 478 // the audio IPC layer in Chrome. Ideally, we should return zero and then
463 // the subclass can restart the conversation. 479 // the subclass can restart the conversation.
464 // 480 //
465 // This should get handled by the subclass http://crbug.com/106600 481 // This should get handled by the subclass http://crbug.com/106600
466 const uint32 kZeroLength = 8192; 482 const uint32 kZeroLength = 8192;
467 size_t zeros_to_write = 483 size_t zeros_to_write = std::min(
468 std::min(kZeroLength, requested_frames * bytes_per_frame_); 484 kZeroLength, requested_frames * audio_parameters_.GetBytesPerFrame());
469 memset(dest, 0, zeros_to_write); 485 memset(dest, 0, zeros_to_write);
470 return zeros_to_write / bytes_per_frame_; 486 return zeros_to_write / audio_parameters_.GetBytesPerFrame();
471 } 487 }
472 488
473 // We use the following conditions to determine end of playback: 489 // We use the following conditions to determine end of playback:
474 // 1) Algorithm can not fill the audio callback buffer 490 // 1) Algorithm can not fill the audio callback buffer
475 // 2) We received an end of stream buffer 491 // 2) We received an end of stream buffer
476 // 3) We haven't already signalled that we've ended 492 // 3) We haven't already signalled that we've ended
477 // 4) Our estimated earliest end time has expired 493 // 4) Our estimated earliest end time has expired
478 // 494 //
479 // TODO(enal): we should replace (4) with a check that the browser has no 495 // 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. 496 // more audio data or at least use a delayed callback.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 time_cb_.Run(current_time, max_time); 555 time_cb_.Run(current_time, max_time);
540 } 556 }
541 557
542 if (!underflow_cb.is_null()) 558 if (!underflow_cb.is_null())
543 underflow_cb.Run(); 559 underflow_cb.Run();
544 560
545 return frames_written; 561 return frames_written;
546 } 562 }
547 563
548 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled, 564 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled,
565 float playback_rate,
549 base::TimeDelta request_delay, 566 base::TimeDelta request_delay,
550 base::Time time_now) { 567 base::Time time_now) {
551 if (bytes_filled != 0) { 568 if (bytes_filled != 0) {
552 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled); 569 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled);
553 float playback_rate = GetPlaybackRate();
554 if (playback_rate != 1.0f) { 570 if (playback_rate != 1.0f) {
555 predicted_play_time = base::TimeDelta::FromMicroseconds( 571 predicted_play_time = base::TimeDelta::FromMicroseconds(
556 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * 572 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() *
557 playback_rate))); 573 playback_rate)));
558 } 574 }
559 earliest_end_time_ = 575
560 std::max(earliest_end_time_, 576 base::AutoLock auto_lock(lock_);
561 time_now + request_delay + predicted_play_time); 577 earliest_end_time_ = std::max(
578 earliest_end_time_, time_now + request_delay + predicted_play_time);
562 } 579 }
563 } 580 }
564 581
565 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { 582 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) {
566 int bytes_per_second = audio_parameters_.GetBytesPerSecond(); 583 int bytes_per_second = audio_parameters_.GetBytesPerSecond();
567 CHECK(bytes_per_second); 584 CHECK(bytes_per_second);
568 return base::TimeDelta::FromMicroseconds( 585 return base::TimeDelta::FromMicroseconds(
569 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second); 586 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second);
570 } 587 }
571 588
(...skipping 26 matching lines...) Expand all
598 case kUnderflow: 615 case kUnderflow:
599 case kRebuffering: 616 case kRebuffering:
600 case kStopped: 617 case kStopped:
601 if (status != PIPELINE_OK) 618 if (status != PIPELINE_OK)
602 error_cb_.Run(status); 619 error_cb_.Run(status);
603 return; 620 return;
604 } 621 }
605 } 622 }
606 623
607 } // namespace media 624 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698