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

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

Issue 9826023: Merge AudioRendererImpl and AudioRendererBase; add NullAudioSink (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 9 months 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_base.h" 5 #include "media/filters/audio_renderer_base.h"
6 6
7 #include <algorithm> 7 #include <math.h>
8 #include <string>
9 8
10 #include "base/bind.h" 9 #include "base/bind.h"
11 #include "base/callback.h" 10 #include "base/callback.h"
12 #include "base/logging.h" 11 #include "base/logging.h"
13 #include "media/base/filter_host.h" 12 #include "media/base/filter_host.h"
13 #include "media/audio/audio_util.h"
14 14
15 namespace media { 15 namespace media {
16 16
17 AudioRendererBase::AudioRendererBase() 17 AudioRendererBase::AudioRendererBase(media::AudioRendererSink* sink)
18 : state_(kUninitialized), 18 : state_(kUninitialized),
19 pending_read_(false), 19 pending_read_(false),
20 received_end_of_stream_(false), 20 received_end_of_stream_(false),
21 rendered_end_of_stream_(false), 21 rendered_end_of_stream_(false),
22 bytes_per_frame_(0), 22 bytes_per_frame_(0),
23 bytes_per_second_(0),
24 stopped_(false),
25 sink_(sink),
26 is_initialized_(false),
23 read_cb_(base::Bind(&AudioRendererBase::DecodedAudioReady, 27 read_cb_(base::Bind(&AudioRendererBase::DecodedAudioReady,
24 base::Unretained(this))) { 28 base::Unretained(this))) {
25 } 29 }
26 30
27 AudioRendererBase::~AudioRendererBase() { 31 AudioRendererBase::~AudioRendererBase() {
28 // Stop() should have been called and |algorithm_| should have been destroyed. 32 // Stop() should have been called and |algorithm_| should have been destroyed.
29 DCHECK(state_ == kUninitialized || state_ == kStopped); 33 DCHECK(state_ == kUninitialized || state_ == kStopped);
30 DCHECK(!algorithm_.get()); 34 DCHECK(!algorithm_.get());
31 } 35 }
32 36
33 void AudioRendererBase::Play(const base::Closure& callback) { 37 void AudioRendererBase::Play(const base::Closure& callback) {
34 base::AutoLock auto_lock(lock_); 38 {
35 DCHECK_EQ(kPaused, state_); 39 base::AutoLock auto_lock(lock_);
36 state_ = kPlaying; 40 DCHECK_EQ(kPaused, state_);
37 callback.Run(); 41 state_ = kPlaying;
42 callback.Run();
43 }
44
45 if (stopped_)
46 return;
47
48 if (GetPlaybackRate() != 0.0f) {
49 DoPlay();
50 } else {
51 DoPause();
52 }
53 }
54
55 void AudioRendererBase::DoPlay() {
56 earliest_end_time_ = base::Time::Now();
57 DCHECK(sink_.get());
58 sink_->Play();
38 } 59 }
39 60
40 void AudioRendererBase::Pause(const base::Closure& callback) { 61 void AudioRendererBase::Pause(const base::Closure& callback) {
41 base::AutoLock auto_lock(lock_); 62 {
42 DCHECK(state_ == kPlaying || state_ == kUnderflow || state_ == kRebuffering); 63 base::AutoLock auto_lock(lock_);
43 pause_cb_ = callback; 64 DCHECK(state_ == kPlaying || state_ == kUnderflow ||
44 state_ = kPaused; 65 state_ == kRebuffering);
66 pause_cb_ = callback;
67 state_ = kPaused;
45 68
46 // Pause only when we've completed our pending read. 69 // Pause only when we've completed our pending read.
47 if (!pending_read_) { 70 if (!pending_read_) {
48 pause_cb_.Run(); 71 pause_cb_.Run();
49 pause_cb_.Reset(); 72 pause_cb_.Reset();
50 } else { 73 } else {
51 state_ = kPaused; 74 state_ = kPaused;
75 }
52 } 76 }
77
78 if (stopped_)
79 return;
80
81 DoPause();
82 }
83
84 void AudioRendererBase::DoPause() {
85 DCHECK(sink_.get());
86 sink_->Pause(false);
53 } 87 }
54 88
55 void AudioRendererBase::Flush(const base::Closure& callback) { 89 void AudioRendererBase::Flush(const base::Closure& callback) {
56 decoder_->Reset(callback); 90 decoder_->Reset(callback);
57 } 91 }
58 92
59 void AudioRendererBase::Stop(const base::Closure& callback) { 93 void AudioRendererBase::Stop(const base::Closure& callback) {
60 OnStop(); 94 if (!stopped_) {
95 DCHECK(sink_.get());
96 sink_->Stop();
97
98 stopped_ = true;
99 }
61 { 100 {
62 base::AutoLock auto_lock(lock_); 101 base::AutoLock auto_lock(lock_);
63 state_ = kStopped; 102 state_ = kStopped;
64 algorithm_.reset(NULL); 103 algorithm_.reset(NULL);
65 time_cb_.Reset(); 104 time_cb_.Reset();
66 underflow_cb_.Reset(); 105 underflow_cb_.Reset();
67 } 106 }
68 if (!callback.is_null()) { 107 if (!callback.is_null()) {
69 callback.Run(); 108 callback.Run();
70 } 109 }
71 } 110 }
72 111
73 void AudioRendererBase::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { 112 void AudioRendererBase::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
74 base::AutoLock auto_lock(lock_); 113 base::AutoLock auto_lock(lock_);
75 DCHECK_EQ(kPaused, state_); 114 DCHECK_EQ(kPaused, state_);
76 DCHECK(!pending_read_) << "Pending read must complete before seeking"; 115 DCHECK(!pending_read_) << "Pending read must complete before seeking";
77 DCHECK(pause_cb_.is_null()); 116 DCHECK(pause_cb_.is_null());
78 DCHECK(seek_cb_.is_null()); 117 DCHECK(seek_cb_.is_null());
79 state_ = kSeeking; 118 state_ = kSeeking;
80 seek_cb_ = cb; 119 seek_cb_ = cb;
81 seek_timestamp_ = time; 120 seek_timestamp_ = time;
82 121
83 // Throw away everything and schedule our reads. 122 // Throw away everything and schedule our reads.
84 last_fill_buffer_time_ = base::TimeDelta(); 123 audio_time_buffered_ = base::TimeDelta();
85 received_end_of_stream_ = false; 124 received_end_of_stream_ = false;
86 rendered_end_of_stream_ = false; 125 rendered_end_of_stream_ = false;
87 126
88 // |algorithm_| will request more reads. 127 // |algorithm_| will request more reads.
89 algorithm_->FlushBuffers(); 128 algorithm_->FlushBuffers();
129
130 if (stopped_)
131 return;
132
133 DoSeek();
134 }
135
136 void AudioRendererBase::DoSeek() {
137 earliest_end_time_ = base::Time::Now();
138
139 // Pause and flush the stream when we seek to a new location.
140 DCHECK(sink_.get());
scherkus (not reviewing) 2012/03/23 15:24:52 nit: DCHECK-before-dereferencing aren't very usefu
vrk (LEFT CHROMIUM) 2012/04/02 21:17:54 Deleted! Yeah I just copy/pasted logic verbatim fr
141 sink_->Pause(true);
90 } 142 }
91 143
92 void AudioRendererBase::Initialize(const scoped_refptr<AudioDecoder>& decoder, 144 void AudioRendererBase::Initialize(const scoped_refptr<AudioDecoder>& decoder,
93 const PipelineStatusCB& init_cb, 145 const PipelineStatusCB& init_cb,
94 const base::Closure& underflow_cb, 146 const base::Closure& underflow_cb,
95 const TimeCB& time_cb) { 147 const TimeCB& time_cb) {
96 DCHECK(decoder); 148 DCHECK(decoder);
97 DCHECK(!init_cb.is_null()); 149 DCHECK(!init_cb.is_null());
98 DCHECK(!underflow_cb.is_null()); 150 DCHECK(!underflow_cb.is_null());
99 DCHECK(!time_cb.is_null()); 151 DCHECK(!time_cb.is_null());
(...skipping 12 matching lines...) Expand all
112 // and a callback to request more reads from the data source. 164 // and a callback to request more reads from the data source.
113 ChannelLayout channel_layout = decoder_->channel_layout(); 165 ChannelLayout channel_layout = decoder_->channel_layout();
114 int channels = ChannelLayoutToChannelCount(channel_layout); 166 int channels = ChannelLayoutToChannelCount(channel_layout);
115 int bits_per_channel = decoder_->bits_per_channel(); 167 int bits_per_channel = decoder_->bits_per_channel();
116 int sample_rate = decoder_->samples_per_second(); 168 int sample_rate = decoder_->samples_per_second();
117 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. 169 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame.
118 bytes_per_frame_ = channels * bits_per_channel / 8; 170 bytes_per_frame_ = channels * bits_per_channel / 8;
119 171
120 bool config_ok = algorithm_->ValidateConfig(channels, sample_rate, 172 bool config_ok = algorithm_->ValidateConfig(channels, sample_rate,
121 bits_per_channel); 173 bits_per_channel);
122 if (config_ok) 174 if (!config_ok || is_initialized_) {
scherkus (not reviewing) 2012/03/23 15:24:52 wouldn't calling Initialize() when is_initialized_
vrk (LEFT CHROMIUM) 2012/04/02 21:17:54 I agree, and actually I think the DCHECK_EQ(kUnini
123 algorithm_->Initialize(channels, sample_rate, bits_per_channel, 0.0f, cb);
124
125 // Give the subclass an opportunity to initialize itself.
126 if (!config_ok || !OnInitialize(bits_per_channel, channel_layout,
127 sample_rate)) {
128 init_cb.Run(PIPELINE_ERROR_INITIALIZATION_FAILED); 175 init_cb.Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
129 return; 176 return;
130 } 177 }
131 178
179 if (config_ok)
180 algorithm_->Initialize(channels, sample_rate, bits_per_channel, 0.0f, cb);
181
182 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY
183 // does not currently support all the sample-rates that we require.
184 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627
185 // for more details.
186 audio_parameters_ = AudioParameters(
187 AudioParameters::AUDIO_PCM_LINEAR, channel_layout, sample_rate,
188 bits_per_channel, GetHighLatencyOutputBufferSize(sample_rate));
189
190 bytes_per_second_ = audio_parameters_.GetBytesPerSecond();
191
192 DCHECK(sink_.get());
193 DCHECK(!is_initialized_);
194
195 sink_->Initialize(audio_parameters_, this);
196
197 sink_->Start();
198 is_initialized_ = true;
199
132 // Finally, execute the start callback. 200 // Finally, execute the start callback.
133 state_ = kPaused; 201 state_ = kPaused;
134 init_cb.Run(PIPELINE_OK); 202 init_cb.Run(PIPELINE_OK);
135 } 203 }
136 204
137 bool AudioRendererBase::HasEnded() { 205 bool AudioRendererBase::HasEnded() {
138 base::AutoLock auto_lock(lock_); 206 base::AutoLock auto_lock(lock_);
139 DCHECK(!rendered_end_of_stream_ || algorithm_->NeedsMoreData()); 207 DCHECK(!rendered_end_of_stream_ || algorithm_->NeedsMoreData());
140 208
141 return received_end_of_stream_ && rendered_end_of_stream_; 209 return received_end_of_stream_ && rendered_end_of_stream_;
142 } 210 }
143 211
144 void AudioRendererBase::ResumeAfterUnderflow(bool buffer_more_audio) { 212 void AudioRendererBase::ResumeAfterUnderflow(bool buffer_more_audio) {
145 base::AutoLock auto_lock(lock_); 213 base::AutoLock auto_lock(lock_);
146 if (state_ == kUnderflow) { 214 if (state_ == kUnderflow) {
147 if (buffer_more_audio) 215 if (buffer_more_audio)
148 algorithm_->IncreaseQueueCapacity(); 216 algorithm_->IncreaseQueueCapacity();
149 217
150 state_ = kRebuffering; 218 state_ = kRebuffering;
151 } 219 }
152 } 220 }
153 221
222 void AudioRendererBase::SetVolume(float volume) {
223 if (stopped_)
224 return;
225 DCHECK(sink_.get());
scherkus (not reviewing) 2012/03/23 15:24:52 ditto
vrk (LEFT CHROMIUM) 2012/04/02 21:17:54 Done.
226 sink_->SetVolume(volume);
227 }
228
154 void AudioRendererBase::DecodedAudioReady(scoped_refptr<Buffer> buffer) { 229 void AudioRendererBase::DecodedAudioReady(scoped_refptr<Buffer> buffer) {
155 base::AutoLock auto_lock(lock_); 230 base::AutoLock auto_lock(lock_);
156 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || 231 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying ||
157 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped); 232 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped);
158 233
159 CHECK(pending_read_); 234 CHECK(pending_read_);
160 pending_read_ = false; 235 pending_read_ = false;
161 236
162 if (buffer && buffer->IsEndOfStream()) { 237 if (buffer && buffer->IsEndOfStream()) {
163 received_end_of_stream_ = true; 238 received_end_of_stream_ = true;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 algorithm_->EnqueueBuffer(buffer); 273 algorithm_->EnqueueBuffer(buffer);
199 return; 274 return;
200 case kStopped: 275 case kStopped:
201 return; 276 return;
202 } 277 }
203 } 278 }
204 279
205 uint32 AudioRendererBase::FillBuffer(uint8* dest, 280 uint32 AudioRendererBase::FillBuffer(uint8* dest,
206 uint32 requested_frames, 281 uint32 requested_frames,
207 const base::TimeDelta& playback_delay) { 282 const base::TimeDelta& playback_delay) {
208 // The timestamp of the last buffer written during the last call to 283 // The |audio_time_buffered_| is the ending timestamp of the last frame
209 // FillBuffer(). 284 // buffered at the audio device. |playback_delay| is the amount of time
210 base::TimeDelta last_fill_buffer_time; 285 // buffered at the audio device. The current time can be computed by their
286 // difference.
287 base::TimeDelta current_time = audio_time_buffered_ - playback_delay;
288
211 size_t frames_written = 0; 289 size_t frames_written = 0;
212 base::Closure underflow_cb; 290 base::Closure underflow_cb;
213 { 291 {
214 base::AutoLock auto_lock(lock_); 292 base::AutoLock auto_lock(lock_);
215 293
216 if (state_ == kRebuffering && algorithm_->IsQueueFull()) 294 if (state_ == kRebuffering && algorithm_->IsQueueFull())
217 state_ = kPlaying; 295 state_ = kPlaying;
218 296
219 // Mute audio by returning 0 when not playing. 297 // Mute audio by returning 0 when not playing.
220 if (state_ != kPlaying) { 298 if (state_ != kPlaying) {
221 // TODO(scherkus): To keep the audio hardware busy we write at most 8k of 299 // TODO(scherkus): To keep the audio hardware busy we write at most 8k of
222 // zeros. This gets around the tricky situation of pausing and resuming 300 // zeros. This gets around the tricky situation of pausing and resuming
223 // the audio IPC layer in Chrome. Ideally, we should return zero and then 301 // the audio IPC layer in Chrome. Ideally, we should return zero and then
224 // the subclass can restart the conversation. 302 // the subclass can restart the conversation.
225 // 303 //
226 // This should get handled by the subclass http://crbug.com/106600 304 // This should get handled by the subclass http://crbug.com/106600
227 const uint32 kZeroLength = 8192; 305 const uint32 kZeroLength = 8192;
228 size_t zeros_to_write = 306 size_t zeros_to_write =
229 std::min(kZeroLength, requested_frames * bytes_per_frame_); 307 std::min(kZeroLength, requested_frames * bytes_per_frame_);
230 memset(dest, 0, zeros_to_write); 308 memset(dest, 0, zeros_to_write);
231 return zeros_to_write / bytes_per_frame_; 309 return zeros_to_write / bytes_per_frame_;
232 } 310 }
233 311
234 // Save a local copy of last fill buffer time and reset the member.
235 last_fill_buffer_time = last_fill_buffer_time_;
236 last_fill_buffer_time_ = base::TimeDelta();
237
238 // Use three conditions to determine the end of playback: 312 // Use three conditions to determine the end of playback:
239 // 1. Algorithm needs more audio data. 313 // 1. Algorithm needs more audio data.
240 // 2. We've received an end of stream buffer. 314 // 2. We've received an end of stream buffer.
241 // (received_end_of_stream_ == true) 315 // (received_end_of_stream_ == true)
242 // 3. Browser process has no audio data being played. 316 // 3. Browser process has no audio data being played.
243 // There is no way to check that condition that would work for all 317 // There is no way to check that condition that would work for all
244 // derived classes, so call virtual method that would either render 318 // derived classes, so call virtual method that would either render
245 // end of stream or schedule such rendering. 319 // end of stream or schedule such rendering.
246 // 320 //
247 // Three conditions determine when an underflow occurs: 321 // Three conditions determine when an underflow occurs:
248 // 1. Algorithm has no audio data. 322 // 1. Algorithm has no audio data.
249 // 2. Currently in the kPlaying state. 323 // 2. Currently in the kPlaying state.
250 // 3. Have not received an end of stream buffer. 324 // 3. Have not received an end of stream buffer.
251 if (algorithm_->NeedsMoreData()) { 325 if (algorithm_->NeedsMoreData()) {
252 if (received_end_of_stream_) { 326 if (received_end_of_stream_) {
253 OnRenderEndOfStream(); 327 // TODO(enal): schedule callback instead of polling.
328 if (base::Time::Now() >= earliest_end_time_)
329 SignalEndOfStream();
254 } else if (state_ == kPlaying) { 330 } else if (state_ == kPlaying) {
255 state_ = kUnderflow; 331 state_ = kUnderflow;
256 underflow_cb = underflow_cb_; 332 underflow_cb = underflow_cb_;
257 } 333 }
258 } else { 334 } else {
259 // Otherwise fill the buffer. 335 // Otherwise fill the buffer.
260 frames_written = algorithm_->FillBuffer(dest, requested_frames); 336 frames_written = algorithm_->FillBuffer(dest, requested_frames);
261 } 337 }
262
263 // Get the current time.
264 last_fill_buffer_time_ = algorithm_->GetTime();
265 } 338 }
266 339
267 // Update the pipeline's time if it was set last time. 340 base::TimeDelta previous_time_buffered = audio_time_buffered_;
268 base::TimeDelta new_current_time = last_fill_buffer_time - playback_delay; 341 // The call to FillBuffer() on |algorithm_| has increased the amount of
269 if (last_fill_buffer_time.InMicroseconds() > 0 && 342 // buffered audio data. Update the new amount of time buffered.
270 (last_fill_buffer_time != last_fill_buffer_time_ || 343 audio_time_buffered_ = algorithm_->GetTime();
271 new_current_time > host()->GetTime())) { 344
272 time_cb_.Run(new_current_time, last_fill_buffer_time); 345 if (previous_time_buffered.InMicroseconds() > 0 &&
vrk (LEFT CHROMIUM) 2012/03/22 21:28:53 acolwell: The bug for crbug.com/119549 is here: th
346 (previous_time_buffered != audio_time_buffered_ ||
347 current_time > host()->GetTime())) {
348 time_cb_.Run(current_time, audio_time_buffered_);
273 } 349 }
274 350
275 if (!underflow_cb.is_null()) 351 if (!underflow_cb.is_null())
276 underflow_cb.Run(); 352 underflow_cb.Run();
277 353
278 return frames_written; 354 return frames_written;
279 } 355 }
280 356
281 void AudioRendererBase::SignalEndOfStream() { 357 void AudioRendererBase::SignalEndOfStream() {
282 DCHECK(received_end_of_stream_); 358 DCHECK(received_end_of_stream_);
283 if (!rendered_end_of_stream_) { 359 if (!rendered_end_of_stream_) {
284 rendered_end_of_stream_ = true; 360 rendered_end_of_stream_ = true;
285 host()->NotifyEnded(); 361 host()->NotifyEnded();
286 } 362 }
287 } 363 }
288 364
289 void AudioRendererBase::ScheduleRead_Locked() { 365 void AudioRendererBase::ScheduleRead_Locked() {
290 lock_.AssertAcquired(); 366 lock_.AssertAcquired();
291 if (pending_read_ || state_ == kPaused) 367 if (pending_read_ || state_ == kPaused)
292 return; 368 return;
293 pending_read_ = true; 369 pending_read_ = true;
294 decoder_->Read(read_cb_); 370 decoder_->Read(read_cb_);
295 } 371 }
296 372
297 void AudioRendererBase::SetPlaybackRate(float playback_rate) { 373 void AudioRendererBase::SetPlaybackRate(float playback_rate) {
374 DCHECK_LE(0.0f, playback_rate);
375
376 if (!stopped_) {
377 // Notify sink of new playback rate.
378 sink_->SetPlaybackRate(playback_rate);
379
380 // We have two cases here:
381 // Play: GetPlaybackRate() == 0.0 && playback_rate != 0.0
382 // Pause: GetPlaybackRate() != 0.0 && playback_rate == 0.0
383 if (GetPlaybackRate() == 0.0f && playback_rate != 0.0f) {
384 DoPlay();
385 } else if (GetPlaybackRate() != 0.0f && playback_rate == 0.0f) {
386 // Pause is easy, we can always pause.
387 DoPause();
388 }
389 }
390
298 base::AutoLock auto_lock(lock_); 391 base::AutoLock auto_lock(lock_);
299 algorithm_->SetPlaybackRate(playback_rate); 392 algorithm_->SetPlaybackRate(playback_rate);
300 } 393 }
301 394
302 float AudioRendererBase::GetPlaybackRate() { 395 float AudioRendererBase::GetPlaybackRate() {
303 base::AutoLock auto_lock(lock_); 396 base::AutoLock auto_lock(lock_);
304 return algorithm_->playback_rate(); 397 return algorithm_->playback_rate();
305 } 398 }
306 399
307 bool AudioRendererBase::IsBeforeSeekTime(const scoped_refptr<Buffer>& buffer) { 400 bool AudioRendererBase::IsBeforeSeekTime(const scoped_refptr<Buffer>& buffer) {
308 return (state_ == kSeeking) && buffer && !buffer->IsEndOfStream() && 401 return (state_ == kSeeking) && buffer && !buffer->IsEndOfStream() &&
309 (buffer->GetTimestamp() + buffer->GetDuration()) < seek_timestamp_; 402 (buffer->GetTimestamp() + buffer->GetDuration()) < seek_timestamp_;
310 } 403 }
311 404
405 int AudioRendererBase::Render(const std::vector<float*>& audio_data,
406 int number_of_frames,
407 int audio_delay_milliseconds) {
408 if (stopped_ || GetPlaybackRate() == 0.0f) {
409 // Output silence if stopped.
410 for (size_t i = 0; i < audio_data.size(); ++i)
411 memset(audio_data[i], 0, sizeof(float) * number_of_frames);
412 return 0;
413 }
414
415 // Adjust the playback delay.
416 base::TimeDelta request_delay =
417 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
418
419 // Finally we need to adjust the delay according to playback rate.
420 if (GetPlaybackRate() != 1.0f) {
421 request_delay = base::TimeDelta::FromMicroseconds(
422 static_cast<int64>(ceil(request_delay.InMicroseconds() *
423 GetPlaybackRate())));
424 }
425
426 int bytes_per_frame = audio_parameters_.GetBytesPerFrame();
427
428 const int buf_size = number_of_frames * bytes_per_frame;
429 scoped_array<uint8> buf(new uint8[buf_size]);
430
431 int frames_filled = FillBuffer(buf.get(), number_of_frames, request_delay);
432 int bytes_filled = frames_filled * bytes_per_frame;
433 DCHECK_LE(bytes_filled, buf_size);
434 UpdateEarliestEndTime(bytes_filled, request_delay, base::Time::Now());
435
436 // Deinterleave each audio channel.
437 int channels = audio_data.size();
438 for (int channel_index = 0; channel_index < channels; ++channel_index) {
439 media::DeinterleaveAudioChannel(buf.get(),
440 audio_data[channel_index],
441 channels,
442 channel_index,
443 bytes_per_frame / channels,
444 frames_filled);
445
446 // If FillBuffer() didn't give us enough data then zero out the remainder.
447 if (frames_filled < number_of_frames) {
448 int frames_to_zero = number_of_frames - frames_filled;
449 memset(audio_data[channel_index] + frames_filled,
450 0,
451 sizeof(float) * frames_to_zero);
452 }
453 }
454 return frames_filled;
455 }
456
457 void AudioRendererBase::UpdateEarliestEndTime(int bytes_filled,
458 base::TimeDelta request_delay,
459 base::Time time_now) {
460 if (bytes_filled != 0) {
461 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled);
462 float playback_rate = GetPlaybackRate();
463 if (playback_rate != 1.0f) {
464 predicted_play_time = base::TimeDelta::FromMicroseconds(
465 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() *
466 playback_rate)));
467 }
468 earliest_end_time_ =
469 std::max(earliest_end_time_,
470 time_now + request_delay + predicted_play_time);
471 }
472 }
473
474 base::TimeDelta AudioRendererBase::ConvertToDuration(int bytes) {
475 if (bytes_per_second_) {
476 return base::TimeDelta::FromMicroseconds(
477 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_);
478 }
479 return base::TimeDelta();
480 }
481
482 void AudioRendererBase::OnRenderError() {
483 host()->DisableAudioRenderer();
484 }
485
312 } // namespace media 486 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698