| Index: media/audio/audio_output_controller.cc
|
| diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
|
| index 4f008c993db98b3527199fb0d6f0fa5b925c0407..4325a1b1ad290a78b1e815d05714563620e5064a 100644
|
| --- a/media/audio/audio_output_controller.cc
|
| +++ b/media/audio/audio_output_controller.cc
|
| @@ -57,7 +57,7 @@ AudioOutputController::AudioOutputController(
|
| params.sample_rate(),
|
| TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
|
| #endif
|
| - number_polling_attempts_left_(0) {
|
| + on_more_io_data_called_(0) {
|
| DCHECK(audio_manager);
|
| DCHECK(handler_);
|
| DCHECK(sync_reader_);
|
| @@ -132,6 +132,7 @@ void AudioOutputController::SwitchOutputDevice(
|
| void AudioOutputController::DoCreate(bool is_for_device_change) {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
|
| + TRACE_EVENT0("audio", "AudioOutputController::DoCreate");
|
|
|
| // Close() can be called before DoCreate() is executed.
|
| if (state_ == kClosed)
|
| @@ -176,6 +177,7 @@ void AudioOutputController::DoCreate(bool is_for_device_change) {
|
| void AudioOutputController::DoPlay() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
|
| + TRACE_EVENT0("audio", "AudioOutputController::DoPlay");
|
|
|
| // We can start from created or paused state.
|
| if (state_ != kCreated && state_ != kPaused)
|
| @@ -196,7 +198,23 @@ void AudioOutputController::DoPlay() {
|
| power_poll_callback_.callback().Run();
|
| #endif
|
|
|
| - // We start the AudioOutputStream lazily.
|
| + // For UMA tracking purposes, start the wedge detection timer. This allows us
|
| + // to record statistics about the number of wedged playbacks in the field.
|
| + //
|
| + // WedgeCheck() will look to see if |on_more_io_data_called_| is true after
|
| + // the timeout expires. Care must be taken to ensure the wedge check delay is
|
| + // large enough that the value isn't queried while OnMoreDataIO() is setting
|
| + // it.
|
| + //
|
| + // Timer self-manages its lifetime and WedgeCheck() will only record the UMA
|
| + // statistic if state is still kPlaying. Additional Start() calls will
|
| + // invalidate the previous timer.
|
| + wedge_timer_.reset(new base::OneShotTimer<AudioOutputController>());
|
| + wedge_timer_->Start(
|
| + FROM_HERE, TimeDelta::FromSeconds(3), this,
|
| + &AudioOutputController::WedgeCheck);
|
| + on_more_io_data_called_ = 0;
|
| +
|
| AllowEntryToOnMoreIOData();
|
| stream_->Start(this);
|
|
|
| @@ -219,6 +237,7 @@ void AudioOutputController::StopStream() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
|
|
| if (state_ == kPlaying) {
|
| + wedge_timer_.reset();
|
| stream_->Stop();
|
| DisallowEntryToOnMoreIOData();
|
|
|
| @@ -233,6 +252,7 @@ void AudioOutputController::StopStream() {
|
| void AudioOutputController::DoPause() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
|
| + TRACE_EVENT0("audio", "AudioOutputController::DoPause");
|
|
|
| StopStream();
|
|
|
| @@ -255,6 +275,7 @@ void AudioOutputController::DoPause() {
|
| void AudioOutputController::DoClose() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
|
| + TRACE_EVENT0("audio", "AudioOutputController::DoClose");
|
|
|
| if (state_ != kClosed) {
|
| DoStopCloseAndClearStream();
|
| @@ -320,6 +341,13 @@ int AudioOutputController::OnMoreIOData(AudioBus* source,
|
| DisallowEntryToOnMoreIOData();
|
| TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
|
|
|
| + // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
|
| + // may have already fired if OnMoreIOData() took an abnormal amount of time).
|
| + // Since this thread is the only writer of |on_more_io_data_called_| once the
|
| + // thread starts, its safe to compare and then increment.
|
| + if (base::AtomicRefCountIsZero(&on_more_io_data_called_))
|
| + base::AtomicRefCountInc(&on_more_io_data_called_);
|
| +
|
| sync_reader_->Read(source, dest);
|
|
|
| const int frames = dest->frames();
|
| @@ -363,6 +391,7 @@ void AudioOutputController::DoStopCloseAndClearStream() {
|
| void AudioOutputController::OnDeviceChange() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
|
| + TRACE_EVENT0("audio", "AudioOutputController::OnDeviceChange");
|
|
|
| // TODO(dalecurtis): Notify the renderer side that a device change has
|
| // occurred. Currently querying the hardware information here will lead to
|
| @@ -441,4 +470,14 @@ void AudioOutputController::DisallowEntryToOnMoreIOData() {
|
| DCHECK(is_zero);
|
| }
|
|
|
| +void AudioOutputController::WedgeCheck() {
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| +
|
| + // If we should be playing and we haven't, that's a wedge.
|
| + if (state_ == kPlaying) {
|
| + UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess",
|
| + base::AtomicRefCountIsOne(&on_more_io_data_called_));
|
| + }
|
| +}
|
| +
|
| } // namespace media
|
|
|