Chromium Code Reviews| 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_controller.h" | 5 #include "media/audio/audio_output_controller.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/task_runner_util.h" | 10 #include "base/task_runner_util.h" |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 38 const std::string& output_device_id, | 38 const std::string& output_device_id, |
| 39 SyncReader* sync_reader) | 39 SyncReader* sync_reader) |
| 40 : audio_manager_(audio_manager), | 40 : audio_manager_(audio_manager), |
| 41 params_(params), | 41 params_(params), |
| 42 handler_(handler), | 42 handler_(handler), |
| 43 output_device_id_(output_device_id), | 43 output_device_id_(output_device_id), |
| 44 stream_(NULL), | 44 stream_(NULL), |
| 45 diverting_to_stream_(NULL), | 45 diverting_to_stream_(NULL), |
| 46 volume_(1.0), | 46 volume_(1.0), |
| 47 state_(kEmpty), | 47 state_(kEmpty), |
| 48 num_allowed_io_(0), | 48 currently_in_on_more_io_data_(0), |
| 49 sync_reader_(sync_reader), | 49 sync_reader_(sync_reader), |
| 50 message_loop_(audio_manager->GetTaskRunner()), | 50 message_loop_(audio_manager->GetTaskRunner()), |
| 51 #if defined(AUDIO_POWER_MONITORING) | 51 #if defined(AUDIO_POWER_MONITORING) |
| 52 power_monitor_( | 52 power_monitor_( |
| 53 params.sample_rate(), | 53 params.sample_rate(), |
| 54 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)), | 54 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)), |
| 55 #endif | 55 #endif |
| 56 on_more_io_data_called_(0) { | 56 on_more_io_data_called_(0) { |
| 57 DCHECK(audio_manager); | 57 DCHECK(audio_manager); |
| 58 DCHECK(handler_); | 58 DCHECK(handler_); |
| 59 DCHECK(sync_reader_); | 59 DCHECK(sync_reader_); |
| 60 DCHECK(message_loop_.get()); | 60 DCHECK(message_loop_.get()); |
| 61 } | 61 } |
| 62 | 62 |
| 63 AudioOutputController::~AudioOutputController() { | 63 AudioOutputController::~AudioOutputController() { |
| 64 DCHECK_EQ(kClosed, state_); | 64 DCHECK_EQ(kClosed, state_); |
| 65 // TODO(dalecurtis): Remove debugging for http://crbug.com/349651 | |
| 66 CHECK(base::AtomicRefCountIsZero(¤tly_in_on_more_io_data_)); | |
|
acolwell GONE FROM CHROMIUM
2014/03/06 20:54:10
I'm a little unclear why we need this. Who owns th
DaleCurtis
2014/03/06 21:21:11
See audio_io.h and the AudioSourceCallback interfa
| |
| 65 } | 67 } |
| 66 | 68 |
| 67 // static | 69 // static |
| 68 scoped_refptr<AudioOutputController> AudioOutputController::Create( | 70 scoped_refptr<AudioOutputController> AudioOutputController::Create( |
| 69 AudioManager* audio_manager, | 71 AudioManager* audio_manager, |
| 70 EventHandler* event_handler, | 72 EventHandler* event_handler, |
| 71 const AudioParameters& params, | 73 const AudioParameters& params, |
| 72 const std::string& output_device_id, | 74 const std::string& output_device_id, |
| 73 SyncReader* sync_reader) { | 75 SyncReader* sync_reader) { |
| 74 DCHECK(audio_manager); | 76 DCHECK(audio_manager); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 184 #if defined(AUDIO_POWER_MONITORING) | 186 #if defined(AUDIO_POWER_MONITORING) |
| 185 power_monitor_.Reset(); | 187 power_monitor_.Reset(); |
| 186 power_poll_callback_.Reset( | 188 power_poll_callback_.Reset( |
| 187 base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically, | 189 base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically, |
| 188 this)); | 190 this)); |
| 189 // Run the callback to send an initial notification that we're starting in | 191 // Run the callback to send an initial notification that we're starting in |
| 190 // silence, and to schedule periodic callbacks. | 192 // silence, and to schedule periodic callbacks. |
| 191 power_poll_callback_.callback().Run(); | 193 power_poll_callback_.callback().Run(); |
| 192 #endif | 194 #endif |
| 193 | 195 |
| 194 on_more_io_data_called_ = 0; | |
| 195 AllowEntryToOnMoreIOData(); | |
| 196 stream_->Start(this); | 196 stream_->Start(this); |
| 197 | 197 |
| 198 // For UMA tracking purposes, start the wedge detection timer. This allows us | 198 // For UMA tracking purposes, start the wedge detection timer. This allows us |
| 199 // to record statistics about the number of wedged playbacks in the field. | 199 // to record statistics about the number of wedged playbacks in the field. |
| 200 // | 200 // |
| 201 // WedgeCheck() will look to see if |on_more_io_data_called_| is true after | 201 // WedgeCheck() will look to see if |on_more_io_data_called_| is true after |
| 202 // the timeout expires. Care must be taken to ensure the wedge check delay is | 202 // the timeout expires. Care must be taken to ensure the wedge check delay is |
| 203 // large enough that the value isn't queried while OnMoreDataIO() is setting | 203 // large enough that the value isn't queried while OnMoreDataIO() is setting |
| 204 // it. | 204 // it. |
| 205 // | 205 // |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 225 TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond); | 225 TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond); |
| 226 } | 226 } |
| 227 #endif | 227 #endif |
| 228 | 228 |
| 229 void AudioOutputController::StopStream() { | 229 void AudioOutputController::StopStream() { |
| 230 DCHECK(message_loop_->BelongsToCurrentThread()); | 230 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 231 | 231 |
| 232 if (state_ == kPlaying) { | 232 if (state_ == kPlaying) { |
| 233 wedge_timer_.reset(); | 233 wedge_timer_.reset(); |
| 234 stream_->Stop(); | 234 stream_->Stop(); |
| 235 DisallowEntryToOnMoreIOData(); | |
| 236 | 235 |
| 237 #if defined(AUDIO_POWER_MONITORING) | 236 #if defined(AUDIO_POWER_MONITORING) |
| 238 power_poll_callback_.Cancel(); | 237 power_poll_callback_.Cancel(); |
| 239 #endif | 238 #endif |
| 240 | 239 |
| 241 state_ = kPaused; | 240 state_ = kPaused; |
| 242 } | 241 } |
| 243 } | 242 } |
| 244 | 243 |
| 245 void AudioOutputController::DoPause() { | 244 void AudioOutputController::DoPause() { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 } | 326 } |
| 328 | 327 |
| 329 int AudioOutputController::OnMoreData(AudioBus* dest, | 328 int AudioOutputController::OnMoreData(AudioBus* dest, |
| 330 AudioBuffersState buffers_state) { | 329 AudioBuffersState buffers_state) { |
| 331 return OnMoreIOData(NULL, dest, buffers_state); | 330 return OnMoreIOData(NULL, dest, buffers_state); |
| 332 } | 331 } |
| 333 | 332 |
| 334 int AudioOutputController::OnMoreIOData(AudioBus* source, | 333 int AudioOutputController::OnMoreIOData(AudioBus* source, |
| 335 AudioBus* dest, | 334 AudioBus* dest, |
| 336 AudioBuffersState buffers_state) { | 335 AudioBuffersState buffers_state) { |
| 337 DisallowEntryToOnMoreIOData(); | 336 base::AtomicRefCountInc(¤tly_in_on_more_io_data_); |
|
acolwell GONE FROM CHROMIUM
2014/03/06 20:54:10
If you make the initial value 1 and dec instead of
DaleCurtis
2014/03/06 21:21:11
Done.
| |
| 338 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); | 337 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); |
| 339 | 338 |
| 340 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() | 339 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() |
| 341 // may have already fired if OnMoreIOData() took an abnormal amount of time). | 340 // may have already fired if OnMoreIOData() took an abnormal amount of time). |
| 342 // Since this thread is the only writer of |on_more_io_data_called_| once the | 341 // Since this thread is the only writer of |on_more_io_data_called_| once the |
| 343 // thread starts, its safe to compare and then increment. | 342 // thread starts, its safe to compare and then increment. |
| 344 if (base::AtomicRefCountIsZero(&on_more_io_data_called_)) | 343 if (base::AtomicRefCountIsZero(&on_more_io_data_called_)) |
| 345 base::AtomicRefCountInc(&on_more_io_data_called_); | 344 base::AtomicRefCountInc(&on_more_io_data_called_); |
| 346 | 345 |
| 347 sync_reader_->Read(source, dest); | 346 sync_reader_->Read(source, dest); |
| 348 | 347 |
| 349 const int frames = dest->frames(); | 348 const int frames = dest->frames(); |
| 350 sync_reader_->UpdatePendingBytes( | 349 sync_reader_->UpdatePendingBytes( |
| 351 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); | 350 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); |
| 352 | 351 |
| 353 #if defined(AUDIO_POWER_MONITORING) | 352 #if defined(AUDIO_POWER_MONITORING) |
| 354 power_monitor_.Scan(*dest, frames); | 353 power_monitor_.Scan(*dest, frames); |
| 355 #endif | 354 #endif |
| 356 | 355 |
| 357 AllowEntryToOnMoreIOData(); | 356 CHECK(!base::AtomicRefCountDec(¤tly_in_on_more_io_data_)); |
| 358 return frames; | 357 return frames; |
| 359 } | 358 } |
| 360 | 359 |
| 361 void AudioOutputController::OnError(AudioOutputStream* stream) { | 360 void AudioOutputController::OnError(AudioOutputStream* stream) { |
| 362 // Handle error on the audio controller thread. | 361 // Handle error on the audio controller thread. |
| 363 message_loop_->PostTask(FROM_HERE, base::Bind( | 362 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 364 &AudioOutputController::DoReportError, this)); | 363 &AudioOutputController::DoReportError, this)); |
| 365 } | 364 } |
| 366 | 365 |
| 367 void AudioOutputController::DoStopCloseAndClearStream() { | 366 void AudioOutputController::DoStopCloseAndClearStream() { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 449 if (state_ == kClosed) | 448 if (state_ == kClosed) |
| 450 return; | 449 return; |
| 451 | 450 |
| 452 // Note: OnDeviceChange() will cause the existing stream (the consumer of the | 451 // Note: OnDeviceChange() will cause the existing stream (the consumer of the |
| 453 // diverted audio data) to be closed, and diverting_to_stream_ will be set | 452 // diverted audio data) to be closed, and diverting_to_stream_ will be set |
| 454 // back to NULL. | 453 // back to NULL. |
| 455 OnDeviceChange(); | 454 OnDeviceChange(); |
| 456 DCHECK(!diverting_to_stream_); | 455 DCHECK(!diverting_to_stream_); |
| 457 } | 456 } |
| 458 | 457 |
| 459 void AudioOutputController::AllowEntryToOnMoreIOData() { | |
| 460 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); | |
| 461 base::AtomicRefCountInc(&num_allowed_io_); | |
| 462 } | |
| 463 | |
| 464 void AudioOutputController::DisallowEntryToOnMoreIOData() { | |
| 465 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); | |
| 466 DCHECK(is_zero); | |
| 467 } | |
| 468 | |
| 469 void AudioOutputController::WedgeCheck() { | 458 void AudioOutputController::WedgeCheck() { |
| 470 DCHECK(message_loop_->BelongsToCurrentThread()); | 459 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 471 | 460 |
| 472 // If we should be playing and we haven't, that's a wedge. | 461 // If we should be playing and we haven't, that's a wedge. |
| 473 if (state_ == kPlaying) { | 462 if (state_ == kPlaying) { |
| 474 const bool playback_success = | 463 const bool playback_success = |
| 475 base::AtomicRefCountIsOne(&on_more_io_data_called_); | 464 base::AtomicRefCountIsOne(&on_more_io_data_called_); |
| 476 | 465 |
| 477 UMA_HISTOGRAM_BOOLEAN( | 466 UMA_HISTOGRAM_BOOLEAN( |
| 478 "Media.AudioOutputControllerPlaybackStartupSuccess", playback_success); | 467 "Media.AudioOutputControllerPlaybackStartupSuccess", playback_success); |
| 479 | 468 |
| 480 // Let the AudioManager try and fix it. | 469 // Let the AudioManager try and fix it. |
| 481 if (!playback_success) | 470 if (!playback_success) |
| 482 audio_manager_->FixWedgedAudio(); | 471 audio_manager_->FixWedgedAudio(); |
| 483 } | 472 } |
| 484 } | 473 } |
| 485 | 474 |
| 486 } // namespace media | 475 } // namespace media |
| OLD | NEW |