| 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 <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <limits> | 10 #include <limits> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
| 14 #include "base/numerics/safe_conversions.h" | 14 #include "base/numerics/safe_conversions.h" |
| 15 #include "base/task_runner_util.h" | 15 #include "base/task_runner_util.h" |
| 16 #include "base/threading/platform_thread.h" | 16 #include "base/threading/platform_thread.h" |
| 17 #include "base/time/time.h" | 17 #include "base/time/time.h" |
| 18 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
| 19 | 19 |
| 20 using base::TimeDelta; | 20 using base::TimeDelta; |
| 21 | 21 |
| 22 namespace media { | 22 namespace media { |
| 23 | 23 |
| 24 AudioOutputController::AudioOutputController( | 24 AudioOutputController::AudioOutputController( |
| 25 AudioManager* audio_manager, | 25 AudioManager* audio_manager, |
| 26 EventHandler* handler, | 26 EventHandler* handler, |
| 27 const AudioParameters& params, | 27 const AudioParameters& params, |
| 28 const std::string& output_device_id, | 28 const std::string& output_device_id, |
| 29 SyncReader* sync_reader) | 29 std::unique_ptr<SyncReader> sync_reader) |
| 30 : audio_manager_(audio_manager), | 30 : audio_manager_(audio_manager), |
| 31 params_(params), | 31 params_(params), |
| 32 handler_(handler), | 32 handler_(handler), |
| 33 output_device_id_(output_device_id), | 33 output_device_id_(output_device_id), |
| 34 stream_(NULL), | 34 stream_(NULL), |
| 35 diverting_to_stream_(NULL), | 35 diverting_to_stream_(NULL), |
| 36 volume_(1.0), | 36 volume_(1.0), |
| 37 state_(kEmpty), | 37 state_(kEmpty), |
| 38 sync_reader_(sync_reader), | 38 sync_reader_(std::move(sync_reader)), |
| 39 message_loop_(audio_manager->GetTaskRunner()), | 39 message_loop_(audio_manager->GetTaskRunner()), |
| 40 power_monitor_( | 40 power_monitor_( |
| 41 params.sample_rate(), | 41 params.sample_rate(), |
| 42 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)), | 42 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)), |
| 43 on_more_io_data_called_(0), | 43 on_more_io_data_called_(0), |
| 44 ignore_errors_during_stop_close_(false) { | 44 ignore_errors_during_stop_close_(false) { |
| 45 DCHECK(audio_manager); | 45 DCHECK(audio_manager); |
| 46 DCHECK(handler_); | 46 DCHECK(handler_); |
| 47 DCHECK(sync_reader_); | 47 DCHECK(sync_reader_); |
| 48 DCHECK(message_loop_.get()); | 48 DCHECK(message_loop_.get()); |
| 49 } | 49 } |
| 50 | 50 |
| 51 AudioOutputController::~AudioOutputController() { | 51 AudioOutputController::~AudioOutputController() { |
| 52 CHECK_EQ(kClosed, state_); | 52 CHECK_EQ(kClosed, state_); |
| 53 CHECK_EQ(nullptr, stream_); | 53 CHECK_EQ(nullptr, stream_); |
| 54 CHECK(duplication_targets_.empty()); | 54 CHECK(duplication_targets_.empty()); |
| 55 } | 55 } |
| 56 | 56 |
| 57 // static | 57 // static |
| 58 scoped_refptr<AudioOutputController> AudioOutputController::Create( | 58 scoped_refptr<AudioOutputController> AudioOutputController::Create( |
| 59 AudioManager* audio_manager, | 59 AudioManager* audio_manager, |
| 60 EventHandler* event_handler, | 60 EventHandler* event_handler, |
| 61 const AudioParameters& params, | 61 const AudioParameters& params, |
| 62 const std::string& output_device_id, | 62 const std::string& output_device_id, |
| 63 SyncReader* sync_reader) { | 63 std::unique_ptr<SyncReader> sync_reader) { |
| 64 CHECK(audio_manager); | 64 CHECK(audio_manager); |
| 65 CHECK_EQ(AudioManager::Get(), audio_manager); | 65 CHECK_EQ(AudioManager::Get(), audio_manager); |
| 66 DCHECK(sync_reader); | 66 DCHECK(sync_reader); |
| 67 | 67 |
| 68 if (!params.IsValid()) | 68 if (!params.IsValid()) |
| 69 return NULL; | 69 return NULL; |
| 70 | 70 |
| 71 scoped_refptr<AudioOutputController> controller(new AudioOutputController( | 71 scoped_refptr<AudioOutputController> controller( |
| 72 audio_manager, event_handler, params, output_device_id, sync_reader)); | 72 new AudioOutputController(audio_manager, event_handler, params, |
| 73 output_device_id, std::move(sync_reader))); |
| 73 controller->message_loop_->PostTask(FROM_HERE, base::Bind( | 74 controller->message_loop_->PostTask(FROM_HERE, base::Bind( |
| 74 &AudioOutputController::DoCreate, controller, false)); | 75 &AudioOutputController::DoCreate, controller, false)); |
| 75 return controller; | 76 return controller; |
| 76 } | 77 } |
| 77 | 78 |
| 78 void AudioOutputController::Play() { | 79 void AudioOutputController::Play() { |
| 79 CHECK_EQ(AudioManager::Get(), audio_manager_); | 80 CHECK_EQ(AudioManager::Get(), audio_manager_); |
| 80 message_loop_->PostTask(FROM_HERE, base::Bind( | 81 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 81 &AudioOutputController::DoPlay, this)); | 82 &AudioOutputController::DoPlay, this)); |
| 82 } | 83 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 return; | 131 return; |
| 131 | 132 |
| 132 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener(). | 133 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener(). |
| 133 DCHECK_EQ(kEmpty, state_); | 134 DCHECK_EQ(kEmpty, state_); |
| 134 | 135 |
| 135 stream_ = diverting_to_stream_ ? | 136 stream_ = diverting_to_stream_ ? |
| 136 diverting_to_stream_ : | 137 diverting_to_stream_ : |
| 137 audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_); | 138 audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_); |
| 138 if (!stream_) { | 139 if (!stream_) { |
| 139 state_ = kError; | 140 state_ = kError; |
| 140 handler_->OnError(); | 141 handler_->OnControllerError(); |
| 141 return; | 142 return; |
| 142 } | 143 } |
| 143 | 144 |
| 144 if (!stream_->Open()) { | 145 if (!stream_->Open()) { |
| 145 DoStopCloseAndClearStream(); | 146 DoStopCloseAndClearStream(); |
| 146 state_ = kError; | 147 state_ = kError; |
| 147 handler_->OnError(); | 148 handler_->OnControllerError(); |
| 148 return; | 149 return; |
| 149 } | 150 } |
| 150 | 151 |
| 151 // Everything started okay, so re-register for state change callbacks if | 152 // Everything started okay, so re-register for state change callbacks if |
| 152 // stream_ was created via AudioManager. | 153 // stream_ was created via AudioManager. |
| 153 if (stream_ != diverting_to_stream_) | 154 if (stream_ != diverting_to_stream_) |
| 154 audio_manager_->AddOutputDeviceChangeListener(this); | 155 audio_manager_->AddOutputDeviceChangeListener(this); |
| 155 | 156 |
| 156 // We have successfully opened the stream. Set the initial volume. | 157 // We have successfully opened the stream. Set the initial volume. |
| 157 stream_->SetVolume(volume_); | 158 stream_->SetVolume(volume_); |
| 158 | 159 |
| 159 // Finally set the state to kCreated. | 160 // Finally set the state to kCreated. |
| 160 state_ = kCreated; | 161 state_ = kCreated; |
| 161 | 162 |
| 162 // And then report we have been created if we haven't done so already. | 163 // And then report we have been created if we haven't done so already. |
| 163 if (!is_for_device_change) | 164 if (!is_for_device_change) |
| 164 handler_->OnCreated(); | 165 handler_->OnControllerCreated(); |
| 165 } | 166 } |
| 166 | 167 |
| 167 void AudioOutputController::DoPlay() { | 168 void AudioOutputController::DoPlay() { |
| 168 DCHECK(message_loop_->BelongsToCurrentThread()); | 169 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 169 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); | 170 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); |
| 170 TRACE_EVENT0("audio", "AudioOutputController::DoPlay"); | 171 TRACE_EVENT0("audio", "AudioOutputController::DoPlay"); |
| 171 | 172 |
| 172 // We can start from created or paused state. | 173 // We can start from created or paused state. |
| 173 if (state_ != kCreated && state_ != kPaused) | 174 if (state_ != kCreated && state_ != kPaused) |
| 174 return; | 175 return; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 189 // it. | 190 // it. |
| 190 // | 191 // |
| 191 // Timer self-manages its lifetime and WedgeCheck() will only record the UMA | 192 // Timer self-manages its lifetime and WedgeCheck() will only record the UMA |
| 192 // statistic if state is still kPlaying. Additional Start() calls will | 193 // statistic if state is still kPlaying. Additional Start() calls will |
| 193 // invalidate the previous timer. | 194 // invalidate the previous timer. |
| 194 wedge_timer_.reset(new base::OneShotTimer()); | 195 wedge_timer_.reset(new base::OneShotTimer()); |
| 195 wedge_timer_->Start( | 196 wedge_timer_->Start( |
| 196 FROM_HERE, TimeDelta::FromSeconds(5), this, | 197 FROM_HERE, TimeDelta::FromSeconds(5), this, |
| 197 &AudioOutputController::WedgeCheck); | 198 &AudioOutputController::WedgeCheck); |
| 198 | 199 |
| 199 handler_->OnPlaying(); | 200 handler_->OnControllerPlaying(); |
| 200 } | 201 } |
| 201 | 202 |
| 202 void AudioOutputController::StopStream() { | 203 void AudioOutputController::StopStream() { |
| 203 DCHECK(message_loop_->BelongsToCurrentThread()); | 204 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 204 | 205 |
| 205 if (state_ == kPlaying) { | 206 if (state_ == kPlaying) { |
| 206 wedge_timer_.reset(); | 207 wedge_timer_.reset(); |
| 207 stream_->Stop(); | 208 stream_->Stop(); |
| 208 | 209 |
| 209 // A stopped stream is silent, and power_montior_.Scan() is no longer being | 210 // A stopped stream is silent, and power_montior_.Scan() is no longer being |
| (...skipping 12 matching lines...) Expand all Loading... |
| 222 StopStream(); | 223 StopStream(); |
| 223 | 224 |
| 224 if (state_ != kPaused) | 225 if (state_ != kPaused) |
| 225 return; | 226 return; |
| 226 | 227 |
| 227 // Let the renderer know we've stopped. Necessary to let PPAPI clients know | 228 // Let the renderer know we've stopped. Necessary to let PPAPI clients know |
| 228 // audio has been shutdown. TODO(dalecurtis): This stinks. PPAPI should have | 229 // audio has been shutdown. TODO(dalecurtis): This stinks. PPAPI should have |
| 229 // a better way to know when it should exit PPB_Audio_Shared::Run(). | 230 // a better way to know when it should exit PPB_Audio_Shared::Run(). |
| 230 sync_reader_->UpdatePendingBytes(std::numeric_limits<uint32_t>::max(), 0); | 231 sync_reader_->UpdatePendingBytes(std::numeric_limits<uint32_t>::max(), 0); |
| 231 | 232 |
| 232 handler_->OnPaused(); | 233 handler_->OnControllerPaused(); |
| 233 } | 234 } |
| 234 | 235 |
| 235 void AudioOutputController::DoClose() { | 236 void AudioOutputController::DoClose() { |
| 236 DCHECK(message_loop_->BelongsToCurrentThread()); | 237 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 237 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime"); | 238 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime"); |
| 238 TRACE_EVENT0("audio", "AudioOutputController::DoClose"); | 239 TRACE_EVENT0("audio", "AudioOutputController::DoClose"); |
| 239 | 240 |
| 240 if (state_ != kClosed) { | 241 if (state_ != kClosed) { |
| 241 DoStopCloseAndClearStream(); | 242 DoStopCloseAndClearStream(); |
| 242 sync_reader_->Close(); | 243 sync_reader_->Close(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 // since it would break the diverted setup. Once diversion is | 284 // since it would break the diverted setup. Once diversion is |
| 284 // finished using StopDiverting() the output will switch to the new | 285 // finished using StopDiverting() the output will switch to the new |
| 285 // device ID. | 286 // device ID. |
| 286 if (stream_ != diverting_to_stream_) | 287 if (stream_ != diverting_to_stream_) |
| 287 OnDeviceChange(); | 288 OnDeviceChange(); |
| 288 } | 289 } |
| 289 | 290 |
| 290 void AudioOutputController::DoReportError() { | 291 void AudioOutputController::DoReportError() { |
| 291 DCHECK(message_loop_->BelongsToCurrentThread()); | 292 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 292 if (state_ != kClosed) | 293 if (state_ != kClosed) |
| 293 handler_->OnError(); | 294 handler_->OnControllerError(); |
| 294 } | 295 } |
| 295 | 296 |
| 296 int AudioOutputController::OnMoreData(base::TimeDelta delay, | 297 int AudioOutputController::OnMoreData(base::TimeDelta delay, |
| 297 base::TimeTicks delay_timestamp, | 298 base::TimeTicks delay_timestamp, |
| 298 int prior_frames_skipped, | 299 int prior_frames_skipped, |
| 299 AudioBus* dest) { | 300 AudioBus* dest) { |
| 300 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); | 301 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); |
| 301 | 302 |
| 302 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() | 303 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() |
| 303 // may have already fired if OnMoreData() took an abnormal amount of time). | 304 // may have already fired if OnMoreData() took an abnormal amount of time). |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 DCHECK(message_loop_->BelongsToCurrentThread()); | 507 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 507 | 508 |
| 508 // If we should be playing and we haven't, that's a wedge. | 509 // If we should be playing and we haven't, that's a wedge. |
| 509 if (state_ == kPlaying) { | 510 if (state_ == kPlaying) { |
| 510 UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess", | 511 UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess", |
| 511 base::AtomicRefCountIsOne(&on_more_io_data_called_)); | 512 base::AtomicRefCountIsOne(&on_more_io_data_called_)); |
| 512 } | 513 } |
| 513 } | 514 } |
| 514 | 515 |
| 515 } // namespace media | 516 } // namespace media |
| OLD | NEW |