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 |