| 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 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "content/common/child_process.h" | 12 #include "content/common/child_process.h" |
| 13 #include "content/common/media/audio_messages.h" | 13 #include "content/common/media/audio_messages.h" |
| 14 #include "content/renderer/render_thread_impl.h" | 14 #include "content/renderer/render_thread_impl.h" |
| 15 #include "media/audio/audio_buffers_state.h" | 15 #include "media/audio/audio_buffers_state.h" |
| 16 #include "media/audio/audio_util.h" | 16 #include "media/audio/audio_util.h" |
| 17 #include "media/base/filter_host.h" | 17 #include "media/base/filter_host.h" |
| 18 | 18 |
| 19 using base::subtle::AtomicWord; |
| 20 |
| 19 // We define GetBufferSizeForSampleRate() instead of using | 21 // We define GetBufferSizeForSampleRate() instead of using |
| 20 // GetAudioHardwareBufferSize() in audio_util because we're using | 22 // GetAudioHardwareBufferSize() in audio_util because we're using |
| 21 // the AUDIO_PCM_LINEAR flag, instead of AUDIO_PCM_LOW_LATENCY, | 23 // the AUDIO_PCM_LINEAR flag, instead of AUDIO_PCM_LOW_LATENCY, |
| 22 // which the audio_util functions assume. | 24 // which the audio_util functions assume. |
| 23 // | 25 // |
| 24 // See: http://code.google.com/p/chromium/issues/detail?id=103627 | 26 // See: http://code.google.com/p/chromium/issues/detail?id=103627 |
| 25 // for a more detailed description of the subtleties. | 27 // for a more detailed description of the subtleties. |
| 26 static size_t GetBufferSizeForSampleRate(int sample_rate) { | 28 static size_t GetBufferSizeForSampleRate(int sample_rate) { |
| 27 // kNominalBufferSize has been tested on Windows, Mac OS X, and Linux | 29 // kNominalBufferSize has been tested on Windows, Mac OS X, and Linux |
| 28 // using the low-latency audio codepath (SyncSocket implementation) | 30 // using the low-latency audio codepath (SyncSocket implementation) |
| 29 // with the AUDIO_PCM_LINEAR flag. | 31 // with the AUDIO_PCM_LINEAR flag. |
| 30 const size_t kNominalBufferSize = 2048; | 32 const size_t kNominalBufferSize = 2048; |
| 31 | 33 |
| 32 if (sample_rate <= 48000) | 34 if (sample_rate <= 48000) |
| 33 return kNominalBufferSize; | 35 return kNominalBufferSize; |
| 34 else if (sample_rate <= 96000) | 36 else if (sample_rate <= 96000) |
| 35 return kNominalBufferSize * 2; | 37 return kNominalBufferSize * 2; |
| 36 return kNominalBufferSize * 4; | 38 return kNominalBufferSize * 4; |
| 37 } | 39 } |
| 38 | 40 |
| 39 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) | 41 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) |
| 40 : AudioRendererBase(), | 42 : AudioRendererBase(), |
| 41 bytes_per_second_(0), | 43 bytes_per_second_(0), |
| 42 stopped_(false), | 44 stopped_(false), |
| 43 sink_(sink), | 45 sink_(sink), |
| 44 is_initialized_(false) { | 46 is_initialized_(false), |
| 47 ended_event_scheduled_(false), |
| 48 io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()), |
| 49 stream_id_(0) { |
| 45 } | 50 } |
| 46 | 51 |
| 47 AudioRendererImpl::~AudioRendererImpl() { | 52 AudioRendererImpl::~AudioRendererImpl() { |
| 48 } | 53 } |
| 49 | 54 |
| 50 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { | 55 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { |
| 51 if (bytes_per_second_) { | 56 if (bytes_per_second_) { |
| 52 return base::TimeDelta::FromMicroseconds( | 57 return base::TimeDelta::FromMicroseconds( |
| 53 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); | 58 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); |
| 54 } | 59 } |
| 55 return base::TimeDelta(); | 60 return base::TimeDelta(); |
| 56 } | 61 } |
| 57 | 62 |
| 58 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled, | 63 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled, |
| 59 base::TimeDelta request_delay, | 64 base::TimeDelta request_delay, |
| 60 base::Time time_now) { | 65 base::Time time_now) { |
| 61 if (bytes_filled != 0) { | 66 if (bytes_filled != 0) { |
| 62 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled); | 67 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled); |
| 63 float playback_rate = GetPlaybackRate(); | 68 float playback_rate = GetPlaybackRate(); |
| 64 if (playback_rate != 1.0f) { | 69 if (playback_rate != 1.0f) { |
| 65 predicted_play_time = base::TimeDelta::FromMicroseconds( | 70 predicted_play_time = base::TimeDelta::FromMicroseconds( |
| 66 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * | 71 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * |
| 67 playback_rate))); | 72 playback_rate))); |
| 68 } | 73 } |
| 69 earliest_end_time_ = | 74 set_earliest_end_time( |
| 70 std::max(earliest_end_time_, | 75 std::max(earliest_end_time_, |
| 71 time_now + request_delay + predicted_play_time); | 76 time_now + request_delay + predicted_play_time)); |
| 72 } | 77 } |
| 73 } | 78 } |
| 74 | 79 |
| 75 bool AudioRendererImpl::OnInitialize(int bits_per_channel, | 80 bool AudioRendererImpl::OnInitialize(int bits_per_channel, |
| 76 ChannelLayout channel_layout, | 81 ChannelLayout channel_layout, |
| 77 int sample_rate) { | 82 int sample_rate) { |
| 78 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY | 83 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY |
| 79 // does not currently support all the sample-rates that we require. | 84 // does not currently support all the sample-rates that we require. |
| 80 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 | 85 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 |
| 81 // for more details. | 86 // for more details. |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 } | 171 } |
| 167 | 172 |
| 168 void AudioRendererImpl::SetVolume(float volume) { | 173 void AudioRendererImpl::SetVolume(float volume) { |
| 169 if (stopped_) | 174 if (stopped_) |
| 170 return; | 175 return; |
| 171 DCHECK(sink_.get()); | 176 DCHECK(sink_.get()); |
| 172 sink_->SetVolume(volume); | 177 sink_->SetVolume(volume); |
| 173 } | 178 } |
| 174 | 179 |
| 175 void AudioRendererImpl::DoPlay() { | 180 void AudioRendererImpl::DoPlay() { |
| 176 earliest_end_time_ = base::Time::Now(); | 181 set_earliest_end_time(base::Time::Now()); |
| 182 ended_event_scheduled_ = false; |
| 177 DCHECK(sink_.get()); | 183 DCHECK(sink_.get()); |
| 178 sink_->Play(); | 184 sink_->Play(); |
| 179 } | 185 } |
| 180 | 186 |
| 181 void AudioRendererImpl::DoPause() { | 187 void AudioRendererImpl::DoPause() { |
| 188 ++stream_id_; |
| 182 DCHECK(sink_.get()); | 189 DCHECK(sink_.get()); |
| 183 sink_->Pause(false); | 190 sink_->Pause(false); |
| 184 } | 191 } |
| 185 | 192 |
| 186 void AudioRendererImpl::DoSeek() { | 193 void AudioRendererImpl::DoSeek() { |
| 187 earliest_end_time_ = base::Time::Now(); | 194 set_earliest_end_time(base::Time::Now()); |
| 195 ended_event_scheduled_ = false; |
| 196 ++stream_id_; |
| 188 | 197 |
| 189 // Pause and flush the stream when we seek to a new location. | 198 // Pause and flush the stream when we seek to a new location. |
| 190 DCHECK(sink_.get()); | 199 DCHECK(sink_.get()); |
| 191 sink_->Pause(true); | 200 sink_->Pause(true); |
| 192 } | 201 } |
| 193 | 202 |
| 194 size_t AudioRendererImpl::Render(const std::vector<float*>& audio_data, | 203 size_t AudioRendererImpl::Render(const std::vector<float*>& audio_data, |
| 195 size_t number_of_frames, | 204 size_t number_of_frames, |
| 196 size_t audio_delay_milliseconds) { | 205 size_t audio_delay_milliseconds) { |
| 197 if (stopped_ || GetPlaybackRate() == 0.0f) { | 206 if (stopped_ || GetPlaybackRate() == 0.0f) { |
| 198 // Output silence if stopped. | 207 // Output silence if stopped. |
| 199 for (size_t i = 0; i < audio_data.size(); ++i) | 208 for (size_t i = 0; i < audio_data.size(); ++i) |
| 200 memset(audio_data[i], 0, sizeof(float) * number_of_frames); | 209 memset(audio_data[i], 0, sizeof(audio_data[i][0]) * number_of_frames); |
| 201 return 0; | 210 return 0; |
| 202 } | 211 } |
| 203 | 212 |
| 204 // Adjust the playback delay. | 213 // Adjust the playback delay. |
| 205 base::TimeDelta request_delay = | 214 base::TimeDelta request_delay = |
| 206 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); | 215 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); |
| 207 | 216 |
| 208 // Finally we need to adjust the delay according to playback rate. | 217 // Finally we need to adjust the delay according to playback rate. |
| 209 if (GetPlaybackRate() != 1.0f) { | 218 if (GetPlaybackRate() != 1.0f) { |
| 210 request_delay = base::TimeDelta::FromMicroseconds( | 219 request_delay = base::TimeDelta::FromMicroseconds( |
| (...skipping 21 matching lines...) Expand all Loading... |
| 232 channels, | 241 channels, |
| 233 channel_index, | 242 channel_index, |
| 234 bytes_per_frame / channels, | 243 bytes_per_frame / channels, |
| 235 filled_frames); | 244 filled_frames); |
| 236 | 245 |
| 237 // If FillBuffer() didn't give us enough data then zero out the remainder. | 246 // If FillBuffer() didn't give us enough data then zero out the remainder. |
| 238 if (filled_frames < number_of_frames) { | 247 if (filled_frames < number_of_frames) { |
| 239 int frames_to_zero = number_of_frames - filled_frames; | 248 int frames_to_zero = number_of_frames - filled_frames; |
| 240 memset(audio_data[channel_index] + filled_frames, | 249 memset(audio_data[channel_index] + filled_frames, |
| 241 0, | 250 0, |
| 242 sizeof(float) * frames_to_zero); | 251 sizeof(audio_data[channel_index][0]) * frames_to_zero); |
| 243 } | 252 } |
| 244 } | 253 } |
| 245 return filled_frames; | 254 return filled_frames; |
| 246 } | 255 } |
| 247 | 256 |
| 248 void AudioRendererImpl::OnError() { | 257 void AudioRendererImpl::OnError() { |
| 249 host()->DisableAudioRenderer(); | 258 host()->DisableAudioRenderer(); |
| 250 } | 259 } |
| 251 | 260 |
| 261 int64 AudioRendererImpl::OnRenderEndOfStreamDelay() { |
| 262 return (earliest_end_time() - base::Time::Now()).InMilliseconds(); |
| 263 } |
| 264 |
| 252 void AudioRendererImpl::OnRenderEndOfStream() { | 265 void AudioRendererImpl::OnRenderEndOfStream() { |
| 253 // TODO(enal): schedule callback instead of polling. | 266 if (!ended_event_scheduled_) { |
| 254 if (base::Time::Now() >= earliest_end_time_) | 267 ended_event_scheduled_ = true; |
| 268 int64 delay_ms = OnRenderEndOfStreamDelay(); |
| 269 if (delay_ms <= 0) { |
| 270 DoSignalEndOfStream(stream_id_); |
| 271 } else { |
| 272 io_message_loop_proxy_->PostDelayedTask( |
| 273 FROM_HERE, |
| 274 base::Bind(&AudioRendererImpl::DoSignalEndOfStream, this, stream_id_), |
| 275 delay_ms); |
| 276 } |
| 277 } |
| 278 } |
| 279 |
| 280 void AudioRendererImpl::DoSignalEndOfStream(AtomicWord stream_id) { |
| 281 // There is no way to cancel delayed task if we paused or seeked after task |
| 282 // was scheduled, use stream id to catch such case. |
| 283 if (stream_id == stream_id_) |
| 255 SignalEndOfStream(); | 284 SignalEndOfStream(); |
| 256 } | 285 } |
| OLD | NEW |