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

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: Fix unittest. 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
« no previous file with comments | « media/filters/audio_renderer_impl.h ('k') | media/filters/audio_renderer_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 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
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
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
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
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
OLDNEW
« no previous file with comments | « media/filters/audio_renderer_impl.h ('k') | media/filters/audio_renderer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698