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 "content/renderer/media/audio_renderer_impl.h" | 5 #include "content/renderer/media/audio_renderer_impl.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 if (sample_rate <= 48000) | 32 if (sample_rate <= 48000) |
| 33 return kNominalBufferSize; | 33 return kNominalBufferSize; |
| 34 else if (sample_rate <= 96000) | 34 else if (sample_rate <= 96000) |
| 35 return kNominalBufferSize * 2; | 35 return kNominalBufferSize * 2; |
| 36 return kNominalBufferSize * 4; | 36 return kNominalBufferSize * 4; |
| 37 } | 37 } |
| 38 | 38 |
| 39 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) | 39 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) |
| 40 : AudioRendererBase(), | 40 : AudioRendererBase(), |
| 41 bytes_per_second_(0), | 41 bytes_per_second_(0), |
| 42 stopped_(false), | 42 state_(NOT_PLAYING), |
| 43 sink_(sink), | 43 sink_(sink), |
| 44 is_initialized_(false) { | 44 is_initialized_(false) { |
| 45 } | 45 } |
| 46 | 46 |
| 47 AudioRendererImpl::~AudioRendererImpl() { | 47 AudioRendererImpl::~AudioRendererImpl() { |
| 48 DCHECK(signal_end_of_stream_callback_.IsCancelled()); | |
| 49 if (!signal_end_of_stream_callback_.IsCancelled()) | |
| 50 signal_end_of_stream_callback_.Cancel(); | |
| 48 } | 51 } |
| 49 | 52 |
| 50 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { | 53 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { |
| 51 if (bytes_per_second_) { | 54 if (bytes_per_second_) { |
| 52 return base::TimeDelta::FromMicroseconds( | 55 return base::TimeDelta::FromMicroseconds( |
| 53 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); | 56 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); |
| 54 } | 57 } |
| 55 return base::TimeDelta(); | 58 return base::TimeDelta(); |
| 56 } | 59 } |
| 57 | 60 |
| 58 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled, | 61 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled, |
| 59 base::TimeDelta request_delay, | 62 base::TimeDelta request_delay, |
| 60 base::Time time_now) { | 63 base::Time time_now) { |
| 61 if (bytes_filled != 0) { | 64 if (bytes_filled != 0) { |
| 62 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled); | 65 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled); |
| 63 float playback_rate = GetPlaybackRate(); | 66 float playback_rate = GetPlaybackRate(); |
| 64 if (playback_rate != 1.0f) { | 67 if (playback_rate != 1.0f) { |
| 65 predicted_play_time = base::TimeDelta::FromMicroseconds( | 68 predicted_play_time = base::TimeDelta::FromMicroseconds( |
| 66 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * | 69 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * |
| 67 playback_rate))); | 70 playback_rate))); |
| 68 } | 71 } |
| 69 earliest_end_time_ = | 72 base::AutoLock auto_lock(audio_renderer_impl_lock_); |
| 73 set_earliest_end_time( | |
| 70 std::max(earliest_end_time_, | 74 std::max(earliest_end_time_, |
| 71 time_now + request_delay + predicted_play_time); | 75 time_now + request_delay + predicted_play_time)); |
| 72 } | 76 } |
| 73 } | 77 } |
| 74 | 78 |
| 75 bool AudioRendererImpl::OnInitialize(int bits_per_channel, | 79 bool AudioRendererImpl::OnInitialize(int bits_per_channel, |
| 76 ChannelLayout channel_layout, | 80 ChannelLayout channel_layout, |
| 77 int sample_rate) { | 81 int sample_rate) { |
| 78 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY | 82 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY |
| 79 // does not currently support all the sample-rates that we require. | 83 // does not currently support all the sample-rates that we require. |
| 80 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 | 84 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 |
| 81 // for more details. | 85 // for more details. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 99 | 103 |
| 100 sink_->Start(); | 104 sink_->Start(); |
| 101 is_initialized_ = true; | 105 is_initialized_ = true; |
| 102 return true; | 106 return true; |
| 103 } | 107 } |
| 104 | 108 |
| 105 return false; | 109 return false; |
| 106 } | 110 } |
| 107 | 111 |
| 108 void AudioRendererImpl::OnStop() { | 112 void AudioRendererImpl::OnStop() { |
| 109 if (stopped_) | 113 base::AutoLock auto_lock(audio_renderer_impl_lock_); |
| 114 if (state_ == STOPPED) | |
| 110 return; | 115 return; |
| 111 | 116 signal_end_of_stream_callback_.Cancel(); |
| 112 DCHECK(sink_.get()); | 117 DCHECK(sink_.get()); |
| 113 sink_->Stop(); | 118 sink_->Stop(); |
| 114 | 119 state_ = STOPPED; |
| 115 stopped_ = true; | |
| 116 } | 120 } |
| 117 | 121 |
| 118 void AudioRendererImpl::SetPlaybackRate(float rate) { | 122 void AudioRendererImpl::SetPlaybackRate(float rate) { |
| 119 DCHECK_LE(0.0f, rate); | 123 DCHECK_LE(0.0f, rate); |
| 120 | 124 |
| 121 // Handle the case where we stopped due to IO message loop dying. | 125 // Handle the case where we stopped due to IO message loop dying. |
| 122 if (stopped_) { | 126 if (stopped()) { |
| 123 AudioRendererBase::SetPlaybackRate(rate); | 127 AudioRendererBase::SetPlaybackRate(rate); |
| 124 return; | 128 return; |
| 125 } | 129 } |
| 126 | 130 |
| 127 // We have two cases here: | 131 // We have two cases here: |
| 128 // Play: GetPlaybackRate() == 0.0 && rate != 0.0 | 132 // Play: GetPlaybackRate() == 0.0 && rate != 0.0 |
| 129 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 | 133 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 |
| 130 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { | 134 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { |
| 131 DoPlay(); | 135 DoPlay(); |
| 132 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { | 136 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { |
| 133 // Pause is easy, we can always pause. | 137 // Pause is easy, we can always pause. |
| 134 DoPause(); | 138 DoPause(); |
| 135 } | 139 } |
| 136 AudioRendererBase::SetPlaybackRate(rate); | 140 AudioRendererBase::SetPlaybackRate(rate); |
| 137 } | 141 } |
| 138 | 142 |
| 139 void AudioRendererImpl::Pause(const base::Closure& callback) { | 143 void AudioRendererImpl::Pause(const base::Closure& callback) { |
| 140 AudioRendererBase::Pause(callback); | 144 AudioRendererBase::Pause(callback); |
| 141 if (stopped_) | 145 if (stopped()) |
| 142 return; | 146 return; |
| 143 | 147 |
| 144 DoPause(); | 148 DoPause(); |
| 145 } | 149 } |
| 146 | 150 |
| 147 void AudioRendererImpl::Seek(base::TimeDelta time, | 151 void AudioRendererImpl::Seek(base::TimeDelta time, |
| 148 const media::FilterStatusCB& cb) { | 152 const media::FilterStatusCB& cb) { |
| 149 AudioRendererBase::Seek(time, cb); | 153 AudioRendererBase::Seek(time, cb); |
| 150 if (stopped_) | 154 if (stopped()) |
| 151 return; | 155 return; |
| 152 | 156 |
| 153 DoSeek(); | 157 DoSeek(); |
| 154 } | 158 } |
| 155 | 159 |
| 156 void AudioRendererImpl::Play(const base::Closure& callback) { | 160 void AudioRendererImpl::Play(const base::Closure& callback) { |
| 157 AudioRendererBase::Play(callback); | 161 AudioRendererBase::Play(callback); |
| 158 if (stopped_) | 162 if (stopped()) |
| 159 return; | 163 return; |
| 160 | 164 |
| 161 if (GetPlaybackRate() != 0.0f) { | 165 if (GetPlaybackRate() != 0.0f) { |
| 162 DoPlay(); | 166 DoPlay(); |
| 163 } else { | 167 } else { |
| 164 DoPause(); | 168 DoPause(); |
| 165 } | 169 } |
| 166 } | 170 } |
| 167 | 171 |
| 168 void AudioRendererImpl::SetVolume(float volume) { | 172 void AudioRendererImpl::SetVolume(float volume) { |
| 169 if (stopped_) | 173 if (stopped()) |
| 170 return; | 174 return; |
| 175 | |
| 171 DCHECK(sink_.get()); | 176 DCHECK(sink_.get()); |
| 172 sink_->SetVolume(volume); | 177 sink_->SetVolume(volume); |
| 173 } | 178 } |
| 174 | 179 |
| 180 void AudioRendererImpl::DoSetOrCheckMessageLoopProxy() { | |
| 181 if (pipeline_message_loop_proxy_.get() == NULL) { | |
| 182 pipeline_message_loop_proxy_ = current_message_loop_proxy(); | |
| 183 } else { | |
| 184 DCHECK_EQ(pipeline_message_loop_proxy_.get(), current_message_loop_proxy()); | |
| 185 } | |
| 186 } | |
| 187 | |
| 175 void AudioRendererImpl::DoPlay() { | 188 void AudioRendererImpl::DoPlay() { |
| 176 earliest_end_time_ = base::Time::Now(); | 189 DoSetOrCheckMessageLoopProxy(); |
| 190 base::AutoLock auto_lock(audio_renderer_impl_lock_); | |
| 191 set_earliest_end_time(base::Time::Now()); | |
| 192 signal_end_of_stream_callback_.Reset( | |
| 193 base::Bind(&AudioRendererImpl::DoSignalEndOfStream, AsWeakPtr())); | |
|
scherkus (not reviewing)
2012/03/03 02:24:32
are weak pointers enforced by cancellable callback
| |
| 194 state_ = PLAYING; | |
| 177 DCHECK(sink_.get()); | 195 DCHECK(sink_.get()); |
| 178 sink_->Play(); | 196 sink_->Play(); |
| 179 } | 197 } |
| 180 | 198 |
| 181 void AudioRendererImpl::DoPause() { | 199 void AudioRendererImpl::DoPause() { |
| 200 DoSetOrCheckMessageLoopProxy(); | |
|
scherkus (not reviewing)
2012/03/03 02:24:32
I would strongly prefer having pipeline set the me
| |
| 201 base::AutoLock auto_lock(audio_renderer_impl_lock_); | |
| 202 signal_end_of_stream_callback_.Cancel(); | |
| 203 state_ = NOT_PLAYING; | |
| 182 DCHECK(sink_.get()); | 204 DCHECK(sink_.get()); |
| 183 sink_->Pause(false); | 205 sink_->Pause(false); |
| 184 } | 206 } |
| 185 | 207 |
| 186 void AudioRendererImpl::DoSeek() { | 208 void AudioRendererImpl::DoSeek() { |
| 187 earliest_end_time_ = base::Time::Now(); | 209 DoSetOrCheckMessageLoopProxy(); |
| 210 base::AutoLock auto_lock(audio_renderer_impl_lock_); | |
| 211 signal_end_of_stream_callback_.Cancel(); | |
| 212 state_ = NOT_PLAYING; | |
| 213 set_earliest_end_time(base::Time::Now()); | |
| 188 | 214 |
| 189 // Pause and flush the stream when we seek to a new location. | 215 // Pause and flush the stream when we seek to a new location. |
| 190 DCHECK(sink_.get()); | 216 DCHECK(sink_.get()); |
| 191 sink_->Pause(true); | 217 sink_->Pause(true); |
| 192 } | 218 } |
| 193 | 219 |
| 194 size_t AudioRendererImpl::Render(const std::vector<float*>& audio_data, | 220 size_t AudioRendererImpl::Render(const std::vector<float*>& audio_data, |
| 195 size_t number_of_frames, | 221 size_t number_of_frames, |
| 196 size_t audio_delay_milliseconds) { | 222 size_t audio_delay_milliseconds) { |
| 197 if (stopped_ || GetPlaybackRate() == 0.0f) { | 223 if (state_ == STOPPED || GetPlaybackRate() == 0.0f) { |
| 198 // Output silence if stopped. | 224 // Output silence if stopped. |
| 199 for (size_t i = 0; i < audio_data.size(); ++i) | 225 for (size_t i = 0; i < audio_data.size(); ++i) |
| 200 memset(audio_data[i], 0, sizeof(float) * number_of_frames); | 226 memset(audio_data[i], 0, sizeof(audio_data[i][0]) * number_of_frames); |
| 201 return 0; | 227 return 0; |
| 202 } | 228 } |
| 203 | 229 |
| 204 // Adjust the playback delay. | 230 // Adjust the playback delay. |
| 205 base::TimeDelta request_delay = | 231 base::TimeDelta request_delay = |
| 206 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); | 232 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); |
| 207 | 233 |
| 208 // Finally we need to adjust the delay according to playback rate. | 234 // Finally we need to adjust the delay according to playback rate. |
| 209 if (GetPlaybackRate() != 1.0f) { | 235 if (GetPlaybackRate() != 1.0f) { |
| 210 request_delay = base::TimeDelta::FromMicroseconds( | 236 request_delay = base::TimeDelta::FromMicroseconds( |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 232 channels, | 258 channels, |
| 233 channel_index, | 259 channel_index, |
| 234 bytes_per_frame / channels, | 260 bytes_per_frame / channels, |
| 235 filled_frames); | 261 filled_frames); |
| 236 | 262 |
| 237 // If FillBuffer() didn't give us enough data then zero out the remainder. | 263 // If FillBuffer() didn't give us enough data then zero out the remainder. |
| 238 if (filled_frames < number_of_frames) { | 264 if (filled_frames < number_of_frames) { |
| 239 int frames_to_zero = number_of_frames - filled_frames; | 265 int frames_to_zero = number_of_frames - filled_frames; |
| 240 memset(audio_data[channel_index] + filled_frames, | 266 memset(audio_data[channel_index] + filled_frames, |
| 241 0, | 267 0, |
| 242 sizeof(float) * frames_to_zero); | 268 sizeof(audio_data[channel_index][0]) * frames_to_zero); |
| 243 } | 269 } |
| 244 } | 270 } |
| 245 return filled_frames; | 271 return filled_frames; |
| 246 } | 272 } |
| 247 | 273 |
| 248 void AudioRendererImpl::OnRenderError() { | 274 void AudioRendererImpl::OnRenderError() { |
| 249 host()->DisableAudioRenderer(); | 275 host()->DisableAudioRenderer(); |
| 250 } | 276 } |
| 251 | 277 |
| 278 int64 AudioRendererImpl::OnRenderEndOfStreamDelay() { | |
| 279 audio_renderer_impl_lock_.AssertAcquired(); | |
| 280 return (earliest_end_time() - base::Time::Now()).InMilliseconds(); | |
| 281 } | |
| 282 | |
| 252 void AudioRendererImpl::OnRenderEndOfStream() { | 283 void AudioRendererImpl::OnRenderEndOfStream() { |
| 253 // TODO(enal): schedule callback instead of polling. | 284 base::AutoLock auto_lock(audio_renderer_impl_lock_); |
| 254 if (base::Time::Now() >= earliest_end_time_) | 285 if (state_ == PLAYING) { |
| 255 SignalEndOfStream(); | 286 state_ = ENDED_EVENT_SCHEDULED; |
| 287 int64 delay_ms = OnRenderEndOfStreamDelay(); | |
| 288 if (delay_ms <= 0) { | |
|
scherkus (not reviewing)
2012/03/03 02:24:32
if the delay time was calculated to be <=0 wouldn'
| |
| 289 pipeline_message_loop_proxy_->PostTask( | |
| 290 FROM_HERE, | |
| 291 signal_end_of_stream_callback_.callback()); | |
| 292 } else { | |
| 293 pipeline_message_loop_proxy_->PostDelayedTask( | |
| 294 FROM_HERE, | |
| 295 signal_end_of_stream_callback_.callback(), | |
| 296 delay_ms); | |
| 297 } | |
| 298 } | |
| 256 } | 299 } |
| 300 | |
| 301 void AudioRendererImpl::DoSignalEndOfStream() { | |
| 302 DCHECK_EQ(pipeline_message_loop_proxy_.get(), current_message_loop_proxy()); | |
| 303 SignalEndOfStream(); | |
| 304 signal_end_of_stream_callback_.Cancel(); | |
| 305 } | |
| OLD | NEW |