| 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 |