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 <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <string> | 10 #include <string> |
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 const base::TimeDelta& close_delay) | 222 const base::TimeDelta& close_delay) |
223 : AudioOutputDispatcher(audio_manager, input_params, output_device_id), | 223 : AudioOutputDispatcher(audio_manager, input_params, output_device_id), |
224 close_delay_(close_delay), | 224 close_delay_(close_delay), |
225 output_params_(output_params), | 225 output_params_(output_params), |
226 original_output_params_(output_params), | 226 original_output_params_(output_params), |
227 streams_opened_(false), | 227 streams_opened_(false), |
228 reinitialize_timer_(FROM_HERE, | 228 reinitialize_timer_(FROM_HERE, |
229 close_delay_, | 229 close_delay_, |
230 base::Bind(&AudioOutputResampler::Reinitialize, | 230 base::Bind(&AudioOutputResampler::Reinitialize, |
231 base::Unretained(this)), | 231 base::Unretained(this)), |
232 false) { | 232 false), |
| 233 weak_factory_(this) { |
233 DCHECK(input_params.IsValid()); | 234 DCHECK(input_params.IsValid()); |
234 DCHECK(output_params.IsValid()); | 235 DCHECK(output_params.IsValid()); |
235 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); | 236 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); |
236 | 237 |
237 // Record UMA statistics for the hardware configuration. | 238 // Record UMA statistics for the hardware configuration. |
238 RecordStats(output_params); | 239 RecordStats(output_params); |
239 | 240 |
240 Initialize(); | 241 Initialize(); |
241 } | 242 } |
242 | 243 |
243 AudioOutputResampler::~AudioOutputResampler() { | 244 AudioOutputResampler::~AudioOutputResampler() { |
244 DCHECK(callbacks_.empty()); | 245 for (auto& iter : callbacks_) { |
| 246 StopStream(iter.first); |
| 247 } |
245 } | 248 } |
246 | 249 |
247 void AudioOutputResampler::Reinitialize() { | 250 void AudioOutputResampler::Reinitialize() { |
248 DCHECK(task_runner_->BelongsToCurrentThread()); | 251 DCHECK(task_runner_->BelongsToCurrentThread()); |
249 DCHECK(streams_opened_); | 252 DCHECK(streams_opened_); |
250 | 253 |
251 // We can only reinitialize the dispatcher if it has no active proxies. Check | 254 // We can only reinitialize the dispatcher if it has no active proxies. Check |
252 // if one has been created since the reinitialization timer was started. | 255 // if one has been created since the reinitialization timer was started. |
253 if (dispatcher_->HasOutputProxies()) | 256 if (dispatcher_->HasOutputProxies()) |
254 return; | 257 return; |
255 | 258 |
256 // Log a trace event so we can get feedback in the field when this happens. | 259 // Log a trace event so we can get feedback in the field when this happens. |
257 TRACE_EVENT0("audio", "AudioOutputResampler::Reinitialize"); | 260 TRACE_EVENT0("audio", "AudioOutputResampler::Reinitialize"); |
258 | 261 |
259 output_params_ = original_output_params_; | 262 output_params_ = original_output_params_; |
260 streams_opened_ = false; | 263 streams_opened_ = false; |
261 Initialize(); | 264 Initialize(); |
262 } | 265 } |
263 | 266 |
264 void AudioOutputResampler::Initialize() { | 267 void AudioOutputResampler::Initialize() { |
265 DCHECK(!streams_opened_); | 268 DCHECK(!streams_opened_); |
266 DCHECK(callbacks_.empty()); | 269 DCHECK(callbacks_.empty()); |
267 dispatcher_ = base::MakeUnique<AudioOutputDispatcherImpl>( | 270 dispatcher_ = base::MakeUnique<AudioOutputDispatcherImpl>( |
268 audio_manager_, output_params_, device_id_, close_delay_); | 271 audio_manager_, output_params_, device_id_, close_delay_); |
269 } | 272 } |
270 | 273 |
| 274 AudioOutputProxy* AudioOutputResampler::CreateStreamProxy() { |
| 275 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 276 return new AudioOutputProxy(weak_factory_.GetWeakPtr()); |
| 277 } |
| 278 |
271 bool AudioOutputResampler::OpenStream() { | 279 bool AudioOutputResampler::OpenStream() { |
272 DCHECK(task_runner_->BelongsToCurrentThread()); | 280 DCHECK(task_runner_->BelongsToCurrentThread()); |
273 | 281 |
274 if (dispatcher_->OpenStream()) { | 282 if (dispatcher_->OpenStream()) { |
275 // Only record the UMA statistic if we didn't fallback during construction | 283 // Only record the UMA statistic if we didn't fallback during construction |
276 // and only for the first stream we open. | 284 // and only for the first stream we open. |
277 if (!streams_opened_ && | 285 if (!streams_opened_ && |
278 output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) { | 286 output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) { |
279 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false); | 287 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false); |
280 } | 288 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 | 334 |
327 bool AudioOutputResampler::StartStream( | 335 bool AudioOutputResampler::StartStream( |
328 AudioOutputStream::AudioSourceCallback* callback, | 336 AudioOutputStream::AudioSourceCallback* callback, |
329 AudioOutputProxy* stream_proxy) { | 337 AudioOutputProxy* stream_proxy) { |
330 DCHECK(task_runner_->BelongsToCurrentThread()); | 338 DCHECK(task_runner_->BelongsToCurrentThread()); |
331 | 339 |
332 OnMoreDataConverter* resampler_callback = nullptr; | 340 OnMoreDataConverter* resampler_callback = nullptr; |
333 CallbackMap::iterator it = callbacks_.find(stream_proxy); | 341 CallbackMap::iterator it = callbacks_.find(stream_proxy); |
334 if (it == callbacks_.end()) { | 342 if (it == callbacks_.end()) { |
335 resampler_callback = new OnMoreDataConverter(params_, output_params_); | 343 resampler_callback = new OnMoreDataConverter(params_, output_params_); |
336 callbacks_[stream_proxy] = resampler_callback; | 344 callbacks_[stream_proxy] = |
| 345 base::WrapUnique<OnMoreDataConverter>(resampler_callback); |
337 } else { | 346 } else { |
338 resampler_callback = it->second; | 347 resampler_callback = it->second.get(); |
339 } | 348 } |
340 | 349 |
341 resampler_callback->Start(callback); | 350 resampler_callback->Start(callback); |
342 bool result = dispatcher_->StartStream(resampler_callback, stream_proxy); | 351 bool result = dispatcher_->StartStream(resampler_callback, stream_proxy); |
343 if (!result) | 352 if (!result) |
344 resampler_callback->Stop(); | 353 resampler_callback->Stop(); |
345 return result; | 354 return result; |
346 } | 355 } |
347 | 356 |
348 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy, | 357 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy, |
(...skipping 20 matching lines...) Expand all Loading... |
369 dispatcher_->CloseAllIdleStreams(); | 378 dispatcher_->CloseAllIdleStreams(); |
370 } | 379 } |
371 } | 380 } |
372 | 381 |
373 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) { | 382 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) { |
374 DCHECK(task_runner_->BelongsToCurrentThread()); | 383 DCHECK(task_runner_->BelongsToCurrentThread()); |
375 dispatcher_->CloseStream(stream_proxy); | 384 dispatcher_->CloseStream(stream_proxy); |
376 | 385 |
377 // We assume that StopStream() is always called prior to CloseStream(), so | 386 // We assume that StopStream() is always called prior to CloseStream(), so |
378 // that it is safe to delete the OnMoreDataConverter here. | 387 // that it is safe to delete the OnMoreDataConverter here. |
379 CallbackMap::iterator it = callbacks_.find(stream_proxy); | 388 callbacks_.erase(stream_proxy); |
380 if (it != callbacks_.end()) { | |
381 delete it->second; | |
382 callbacks_.erase(it); | |
383 } | |
384 | 389 |
385 // Start the reinitialization timer if there are no active proxies and we're | 390 // Start the reinitialization timer if there are no active proxies and we're |
386 // not using the originally requested output parameters. This allows us to | 391 // not using the originally requested output parameters. This allows us to |
387 // recover from transient output creation errors. | 392 // recover from transient output creation errors. |
388 if (!dispatcher_->HasOutputProxies() && callbacks_.empty() && | 393 if (!dispatcher_->HasOutputProxies() && callbacks_.empty() && |
389 !output_params_.Equals(original_output_params_)) { | 394 !output_params_.Equals(original_output_params_)) { |
390 reinitialize_timer_.Reset(); | 395 reinitialize_timer_.Reset(); |
391 } | 396 } |
392 } | 397 } |
393 | 398 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 dest->ZeroFramesPartial(frames, dest->frames() - frames); | 462 dest->ZeroFramesPartial(frames, dest->frames() - frames); |
458 return frames > 0 ? 1 : 0; | 463 return frames > 0 ? 1 : 0; |
459 } | 464 } |
460 | 465 |
461 void OnMoreDataConverter::OnError(AudioOutputStream* stream) { | 466 void OnMoreDataConverter::OnError(AudioOutputStream* stream) { |
462 error_occurred_ = true; | 467 error_occurred_ = true; |
463 source_callback_->OnError(stream); | 468 source_callback_->OnError(stream); |
464 } | 469 } |
465 | 470 |
466 } // namespace media | 471 } // namespace media |
OLD | NEW |