Chromium Code Reviews| 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_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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |