| 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/audio/audio_output_resampler.h" | 5 #include "media/audio/audio_output_resampler.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/message_loop/message_loop.h" | |
| 11 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 11 #include "base/single_thread_task_runner.h" |
| 12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
| 14 #include "media/audio/audio_io.h" | 14 #include "media/audio/audio_io.h" |
| 15 #include "media/audio/audio_output_dispatcher_impl.h" | 15 #include "media/audio/audio_output_dispatcher_impl.h" |
| 16 #include "media/audio/audio_output_proxy.h" | 16 #include "media/audio/audio_output_proxy.h" |
| 17 #include "media/audio/sample_rates.h" | 17 #include "media/audio/sample_rates.h" |
| 18 #include "media/base/audio_converter.h" | 18 #include "media/base/audio_converter.h" |
| 19 #include "media/base/limits.h" | 19 #include "media/base/limits.h" |
| 20 | 20 |
| 21 namespace media { | 21 namespace media { |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 | 167 |
| 168 void AudioOutputResampler::Initialize() { | 168 void AudioOutputResampler::Initialize() { |
| 169 DCHECK(!streams_opened_); | 169 DCHECK(!streams_opened_); |
| 170 DCHECK(callbacks_.empty()); | 170 DCHECK(callbacks_.empty()); |
| 171 dispatcher_ = new AudioOutputDispatcherImpl( | 171 dispatcher_ = new AudioOutputDispatcherImpl( |
| 172 audio_manager_, output_params_, output_device_id_, input_device_id_, | 172 audio_manager_, output_params_, output_device_id_, input_device_id_, |
| 173 close_delay_); | 173 close_delay_); |
| 174 } | 174 } |
| 175 | 175 |
| 176 bool AudioOutputResampler::OpenStream() { | 176 bool AudioOutputResampler::OpenStream() { |
| 177 DCHECK(message_loop_->BelongsToCurrentThread()); | 177 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 178 | 178 |
| 179 if (dispatcher_->OpenStream()) { | 179 if (dispatcher_->OpenStream()) { |
| 180 // Only record the UMA statistic if we didn't fallback during construction | 180 // Only record the UMA statistic if we didn't fallback during construction |
| 181 // and only for the first stream we open. | 181 // and only for the first stream we open. |
| 182 if (!streams_opened_ && | 182 if (!streams_opened_ && |
| 183 output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) { | 183 output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) { |
| 184 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false); | 184 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false); |
| 185 } | 185 } |
| 186 streams_opened_ = true; | 186 streams_opened_ = true; |
| 187 return true; | 187 return true; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 streams_opened_ = true; | 226 streams_opened_ = true; |
| 227 return true; | 227 return true; |
| 228 } | 228 } |
| 229 | 229 |
| 230 return false; | 230 return false; |
| 231 } | 231 } |
| 232 | 232 |
| 233 bool AudioOutputResampler::StartStream( | 233 bool AudioOutputResampler::StartStream( |
| 234 AudioOutputStream::AudioSourceCallback* callback, | 234 AudioOutputStream::AudioSourceCallback* callback, |
| 235 AudioOutputProxy* stream_proxy) { | 235 AudioOutputProxy* stream_proxy) { |
| 236 DCHECK(message_loop_->BelongsToCurrentThread()); | 236 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 237 | 237 |
| 238 OnMoreDataConverter* resampler_callback = NULL; | 238 OnMoreDataConverter* resampler_callback = NULL; |
| 239 CallbackMap::iterator it = callbacks_.find(stream_proxy); | 239 CallbackMap::iterator it = callbacks_.find(stream_proxy); |
| 240 if (it == callbacks_.end()) { | 240 if (it == callbacks_.end()) { |
| 241 resampler_callback = new OnMoreDataConverter(params_, output_params_); | 241 resampler_callback = new OnMoreDataConverter(params_, output_params_); |
| 242 callbacks_[stream_proxy] = resampler_callback; | 242 callbacks_[stream_proxy] = resampler_callback; |
| 243 } else { | 243 } else { |
| 244 resampler_callback = it->second; | 244 resampler_callback = it->second; |
| 245 } | 245 } |
| 246 | 246 |
| 247 resampler_callback->Start(callback); | 247 resampler_callback->Start(callback); |
| 248 bool result = dispatcher_->StartStream(resampler_callback, stream_proxy); | 248 bool result = dispatcher_->StartStream(resampler_callback, stream_proxy); |
| 249 if (!result) | 249 if (!result) |
| 250 resampler_callback->Stop(); | 250 resampler_callback->Stop(); |
| 251 return result; | 251 return result; |
| 252 } | 252 } |
| 253 | 253 |
| 254 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy, | 254 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy, |
| 255 double volume) { | 255 double volume) { |
| 256 DCHECK(message_loop_->BelongsToCurrentThread()); | 256 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 257 dispatcher_->StreamVolumeSet(stream_proxy, volume); | 257 dispatcher_->StreamVolumeSet(stream_proxy, volume); |
| 258 } | 258 } |
| 259 | 259 |
| 260 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) { | 260 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) { |
| 261 DCHECK(message_loop_->BelongsToCurrentThread()); | 261 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 262 dispatcher_->StopStream(stream_proxy); | 262 dispatcher_->StopStream(stream_proxy); |
| 263 | 263 |
| 264 // Now that StopStream() has completed the underlying physical stream should | 264 // Now that StopStream() has completed the underlying physical stream should |
| 265 // be stopped and no longer calling OnMoreData(), making it safe to Stop() the | 265 // be stopped and no longer calling OnMoreData(), making it safe to Stop() the |
| 266 // OnMoreDataConverter. | 266 // OnMoreDataConverter. |
| 267 CallbackMap::iterator it = callbacks_.find(stream_proxy); | 267 CallbackMap::iterator it = callbacks_.find(stream_proxy); |
| 268 if (it != callbacks_.end()) | 268 if (it != callbacks_.end()) |
| 269 it->second->Stop(); | 269 it->second->Stop(); |
| 270 } | 270 } |
| 271 | 271 |
| 272 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) { | 272 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) { |
| 273 DCHECK(message_loop_->BelongsToCurrentThread()); | 273 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 274 dispatcher_->CloseStream(stream_proxy); | 274 dispatcher_->CloseStream(stream_proxy); |
| 275 | 275 |
| 276 // We assume that StopStream() is always called prior to CloseStream(), so | 276 // We assume that StopStream() is always called prior to CloseStream(), so |
| 277 // that it is safe to delete the OnMoreDataConverter here. | 277 // that it is safe to delete the OnMoreDataConverter here. |
| 278 CallbackMap::iterator it = callbacks_.find(stream_proxy); | 278 CallbackMap::iterator it = callbacks_.find(stream_proxy); |
| 279 if (it != callbacks_.end()) { | 279 if (it != callbacks_.end()) { |
| 280 delete it->second; | 280 delete it->second; |
| 281 callbacks_.erase(it); | 281 callbacks_.erase(it); |
| 282 } | 282 } |
| 283 } | 283 } |
| 284 | 284 |
| 285 void AudioOutputResampler::Shutdown() { | 285 void AudioOutputResampler::Shutdown() { |
| 286 DCHECK(message_loop_->BelongsToCurrentThread()); | 286 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 287 | 287 |
| 288 // No AudioOutputProxy objects should hold a reference to us when we get | 288 // No AudioOutputProxy objects should hold a reference to us when we get |
| 289 // to this stage. | 289 // to this stage. |
| 290 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; | 290 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; |
| 291 | 291 |
| 292 dispatcher_->Shutdown(); | 292 dispatcher_->Shutdown(); |
| 293 DCHECK(callbacks_.empty()); | 293 DCHECK(callbacks_.empty()); |
| 294 } | 294 } |
| 295 | 295 |
| 296 void AudioOutputResampler::CloseStreamsForWedgeFix() { | 296 void AudioOutputResampler::CloseStreamsForWedgeFix() { |
| 297 DCHECK(message_loop_->BelongsToCurrentThread()); | 297 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 298 | 298 |
| 299 // Stop and close all active streams. Once all streams across all dispatchers | 299 // Stop and close all active streams. Once all streams across all dispatchers |
| 300 // have been closed the AudioManager will call RestartStreamsForWedgeFix(). | 300 // have been closed the AudioManager will call RestartStreamsForWedgeFix(). |
| 301 for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end(); | 301 for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end(); |
| 302 ++it) { | 302 ++it) { |
| 303 if (it->second->started()) | 303 if (it->second->started()) |
| 304 dispatcher_->StopStream(it->first); | 304 dispatcher_->StopStream(it->first); |
| 305 dispatcher_->CloseStream(it->first); | 305 dispatcher_->CloseStream(it->first); |
| 306 } | 306 } |
| 307 | 307 |
| 308 // Close all idle streams as well. | 308 // Close all idle streams as well. |
| 309 dispatcher_->CloseStreamsForWedgeFix(); | 309 dispatcher_->CloseStreamsForWedgeFix(); |
| 310 } | 310 } |
| 311 | 311 |
| 312 void AudioOutputResampler::RestartStreamsForWedgeFix() { | 312 void AudioOutputResampler::RestartStreamsForWedgeFix() { |
| 313 DCHECK(message_loop_->BelongsToCurrentThread()); | 313 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 314 // By opening all streams first and then starting them one by one we ensure | 314 // By opening all streams first and then starting them one by one we ensure |
| 315 // the dispatcher only opens streams for those which will actually be used. | 315 // the dispatcher only opens streams for those which will actually be used. |
| 316 for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end(); | 316 for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end(); |
| 317 ++it) { | 317 ++it) { |
| 318 dispatcher_->OpenStream(); | 318 dispatcher_->OpenStream(); |
| 319 } | 319 } |
| 320 for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end(); | 320 for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end(); |
| 321 ++it) { | 321 ++it) { |
| 322 if (it->second->started()) | 322 if (it->second->started()) |
| 323 dispatcher_->StartStream(it->second, it->first); | 323 dispatcher_->StartStream(it->second, it->first); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 if (frames > 0 && frames < dest->frames()) | 394 if (frames > 0 && frames < dest->frames()) |
| 395 dest->ZeroFramesPartial(frames, dest->frames() - frames); | 395 dest->ZeroFramesPartial(frames, dest->frames() - frames); |
| 396 return frames > 0 ? 1 : 0; | 396 return frames > 0 ? 1 : 0; |
| 397 } | 397 } |
| 398 | 398 |
| 399 void OnMoreDataConverter::OnError(AudioOutputStream* stream) { | 399 void OnMoreDataConverter::OnError(AudioOutputStream* stream) { |
| 400 source_callback_->OnError(stream); | 400 source_callback_->OnError(stream); |
| 401 } | 401 } |
| 402 | 402 |
| 403 } // namespace media | 403 } // namespace media |
| OLD | NEW |