audio_output_controller.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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 3// found in the LICENSE file. 4 5#include "media/audio/audio_output_controller.h" 6 7#include "base/bind.h" 8#include "base/debug/trace_event.h" 9#include "base/message_loop/message_loop.h" 10#include "base/metrics/histogram.h" 11#include "base/threading/platform_thread.h" 12#include "base/time/time.h" 13#include "build/build_config.h" 14#include "media/audio/audio_util.h" 15#include "media/audio/shared_memory_util.h" 16#include "media/base/scoped_histogram_timer.h" 17 18using base::Time; 19using base::TimeDelta; 20 21namespace media { 22 23// Time constant for AudioPowerMonitor. See AudioPowerMonitor ctor comments for 24// semantics. This value was arbitrarily chosen, but seems to work well. 25static const int kPowerMeasurementTimeConstantMillis = 10; 26 27// Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting 28// power levels in the audio signal. 29static const int kPowerMeasurementsPerSecond = 30; 30 31// Polling-related constants. 32const int AudioOutputController::kPollNumAttempts = 3; 33const int AudioOutputController::kPollPauseInMilliseconds = 3; 34 35AudioOutputController::AudioOutputController( 36 AudioManager* audio_manager, 37 EventHandler* handler, 38 const AudioParameters& params, 39 const std::string& output_device_id, 40 const std::string& input_device_id, 41 SyncReader* sync_reader) 42 : audio_manager_(audio_manager), 43 params_(params), 44 handler_(handler), 45 output_device_id_(output_device_id), 46 input_device_id_(input_device_id), 47 stream_(NULL), 48 diverting_to_stream_(NULL), 49 volume_(1.0), 50 state_(kEmpty), 51 num_allowed_io_(0), 52 sync_reader_(sync_reader), 53 message_loop_(audio_manager->GetMessageLoop()), 54 number_polling_attempts_left_(0), 55 power_monitor_( 56 params.sample_rate(), 57 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)) { 58 DCHECK(audio_manager); 59 DCHECK(handler_); 60 DCHECK(sync_reader_); 61 DCHECK(message_loop_.get()); 62} 63 64AudioOutputController::~AudioOutputController() { 65 DCHECK_EQ(kClosed, state_); 66} 67 68// static 69scoped_refptr<AudioOutputController> AudioOutputController::Create( 70 AudioManager* audio_manager, 71 EventHandler* event_handler, 72 const AudioParameters& params, 73 const std::string& output_device_id, 74 const std::string& input_device_id, 75 SyncReader* sync_reader) { 76 DCHECK(audio_manager); 77 DCHECK(sync_reader); 78 79 if (!params.IsValid() || !audio_manager) 80 return NULL; 81 82 scoped_refptr<AudioOutputController> controller(new AudioOutputController( 83 audio_manager, event_handler, params, output_device_id, input_device_id, 84 sync_reader)); 85 controller->message_loop_->PostTask(FROM_HERE, base::Bind( 86 &AudioOutputController::DoCreate, controller, false)); 87 return controller; 88} 89 90void AudioOutputController::Play() { 91 message_loop_->PostTask(FROM_HERE, base::Bind( 92 &AudioOutputController::DoPlay, this)); 93} 94 95void AudioOutputController::Pause() { 96 message_loop_->PostTask(FROM_HERE, base::Bind( 97 &AudioOutputController::DoPause, this)); 98} 99 100void AudioOutputController::Close(const base::Closure& closed_task) { 101 DCHECK(!closed_task.is_null()); 102 message_loop_->PostTaskAndReply(FROM_HERE, base::Bind( 103 &AudioOutputController::DoClose, this), closed_task); 104} 105 106void AudioOutputController::SetVolume(double volume) { 107 message_loop_->PostTask(FROM_HERE, base::Bind( 108 &AudioOutputController::DoSetVolume, this, volume)); 109} 110 111void AudioOutputController::DoCreate(bool is_for_device_change) { 112 DCHECK(message_loop_->BelongsToCurrentThread()); 113 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime"); 114 115 // Close() can be called before DoCreate() is executed. 116 if (state_ == kClosed) 117 return; 118 119 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener(). 120 DCHECK_EQ(kEmpty, state_); 121 122 stream_ = diverting_to_stream_ ? 123 diverting_to_stream_ : 124 audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_, 125 input_device_id_); 126 if (!stream_) { 127 state_ = kError; 128 handler_->OnError(); 129 return; 130 } 131 132 if (!stream_->Open()) { 133 DoStopCloseAndClearStream(); 134 state_ = kError; 135 handler_->OnError(); 136 return; 137 } 138 139 // Everything started okay, so re-register for state change callbacks if 140 // stream_ was created via AudioManager. 141 if (stream_ != diverting_to_stream_) 142 audio_manager_->AddOutputDeviceChangeListener(this); 143 144 // We have successfully opened the stream. Set the initial volume. 145 stream_->SetVolume(volume_); 146 147 // Finally set the state to kCreated. 148 state_ = kCreated; 149 150 // And then report we have been created if we haven't done so already. 151 if (!is_for_device_change) 152 handler_->OnCreated(); 153} 154 155void AudioOutputController::DoPlay() { 156 DCHECK(message_loop_->BelongsToCurrentThread()); 157 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); 158 159 // We can start from created or paused state. 160 if (state_ != kCreated && state_ != kPaused) 161 return; 162 163 // Ask for first packet. 164 sync_reader_->UpdatePendingBytes(0); 165 166 state_ = kPlaying; 167 168 power_monitor_.Reset(); 169 power_poll_callback_.Reset( 170 base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically, 171 this)); 172 // Run the callback to send an initial notification that we're starting in 173 // silence, and to schedule periodic callbacks. 174 power_poll_callback_.callback().Run(); 175 176 // We start the AudioOutputStream lazily. 177 AllowEntryToOnMoreIOData(); 178 stream_->Start(this); 179 180 handler_->OnPlaying(); 181} 182 183void AudioOutputController::ReportPowerMeasurementPeriodically() { 184 DCHECK(message_loop_->BelongsToCurrentThread()); 185 const std::pair<float, bool>& reading = 186 power_monitor_.ReadCurrentPowerAndClip(); 187 handler_->OnPowerMeasured(reading.first, reading.second); 188 message_loop_->PostDelayedTask( 189 FROM_HERE, power_poll_callback_.callback(), 190 TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond); 191} 192 193void AudioOutputController::StopStream() { 194 DCHECK(message_loop_->BelongsToCurrentThread()); 195 196 if (state_ == kPlaying) { 197 stream_->Stop(); 198 DisallowEntryToOnMoreIOData(); 199 200 power_poll_callback_.Cancel(); 201 202 state_ = kPaused; 203 } 204} 205 206void AudioOutputController::DoPause() { 207 DCHECK(message_loop_->BelongsToCurrentThread()); 208 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime"); 209 210 StopStream(); 211 212 if (state_ != kPaused) 213 return; 214 215 // Send a special pause mark to the low-latency audio thread. 216 sync_reader_->UpdatePendingBytes(kPauseMark); 217 218 // Paused means silence follows. 219 handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false); 220 221 handler_->OnPaused(); 222} 223 224void AudioOutputController::DoClose() { 225 DCHECK(message_loop_->BelongsToCurrentThread()); 226 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime"); 227 228 if (state_ != kClosed) { 229 DoStopCloseAndClearStream(); 230 sync_reader_->Close(); 231 state_ = kClosed; 232 } 233} 234 235void AudioOutputController::DoSetVolume(double volume) { 236 DCHECK(message_loop_->BelongsToCurrentThread()); 237 238 // Saves the volume to a member first. We may not be able to set the volume 239 // right away but when the stream is created we'll set the volume. 240 volume_ = volume; 241 242 switch (state_) { 243 case kCreated: 244 case kPlaying: 245 case kPaused: 246 stream_->SetVolume(volume_); 247 break; 248 default: 249 return; 250 } 251} 252 253void AudioOutputController::DoReportError() { 254 DCHECK(message_loop_->BelongsToCurrentThread()); 255 if (state_ != kClosed) 256 handler_->OnError(); 257} 258 259int AudioOutputController::OnMoreData(AudioBus* dest, 260 AudioBuffersState buffers_state) { 261 return OnMoreIOData(NULL, dest, buffers_state); 262} 263 264int AudioOutputController::OnMoreIOData(AudioBus* source, 265 AudioBus* dest, 266 AudioBuffersState buffers_state) { 267 DisallowEntryToOnMoreIOData(); 268 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); 269 270 // The OS level audio APIs on Linux and Windows all have problems requesting 271 // data on a fixed interval. Sometimes they will issue calls back to back 272 // which can cause glitching, so wait until the renderer is ready. 273 // 274 // We also need to wait when diverting since the virtual stream will call this 275 // multiple times without waiting. 276 // 277 // NEVER wait on OSX unless a virtual stream is connected, otherwise we can 278 // end up hanging the entire OS. 279 // 280 // See many bugs for context behind this decision: http://crbug.com/170498, 281 // http://crbug.com/171651, http://crbug.com/174985, and more. 282#if defined(OS_WIN) || defined(OS_LINUX) 283 const bool kShouldBlock = true; 284#else 285 const bool kShouldBlock = diverting_to_stream_ != NULL; 286#endif 287 288 const int frames = sync_reader_->Read(kShouldBlock, source, dest); 289 DCHECK_LE(0, frames); 290 sync_reader_->UpdatePendingBytes( 291 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); 292 293 power_monitor_.Scan(*dest, frames); 294 295 AllowEntryToOnMoreIOData(); 296 return frames; 297} 298 299void AudioOutputController::OnError(AudioOutputStream* stream) { 300 // Handle error on the audio controller thread. 301 message_loop_->PostTask(FROM_HERE, base::Bind( 302 &AudioOutputController::DoReportError, this)); 303} 304 305void AudioOutputController::DoStopCloseAndClearStream() { 306 DCHECK(message_loop_->BelongsToCurrentThread()); 307 308 // Allow calling unconditionally and bail if we don't have a stream_ to close. 309 if (stream_) { 310 // De-register from state change callbacks if stream_ was created via 311 // AudioManager. 312 if (stream_ != diverting_to_stream_) 313 audio_manager_->RemoveOutputDeviceChangeListener(this); 314 315 StopStream(); 316 stream_->Close(); 317 if (stream_ == diverting_to_stream_) 318 diverting_to_stream_ = NULL; 319 stream_ = NULL; 320 } 321 322 state_ = kEmpty; 323} 324 325void AudioOutputController::OnDeviceChange() { 326 DCHECK(message_loop_->BelongsToCurrentThread()); 327 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime"); 328 329 // TODO(dalecurtis): Notify the renderer side that a device change has 330 // occurred. Currently querying the hardware information here will lead to 331 // crashes on OSX. See http://crbug.com/158170. 332 333 // Recreate the stream (DoCreate() will first shut down an existing stream). 334 // Exit if we ran into an error. 335 const State original_state = state_; 336 DoCreate(true); 337 if (!stream_ || state_ == kError) 338 return; 339 340 // Get us back to the original state or an equivalent state. 341 switch (original_state) { 342 case kPlaying: 343 DoPlay(); 344 return; 345 case kCreated: 346 case kPaused: 347 // From the outside these two states are equivalent. 348 return; 349 default: 350 NOTREACHED() << "Invalid original state."; 351 } 352} 353 354const AudioParameters& AudioOutputController::GetAudioParameters() { 355 return params_; 356} 357 358void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) { 359 message_loop_->PostTask( 360 FROM_HERE, 361 base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream)); 362} 363 364void AudioOutputController::StopDiverting() { 365 message_loop_->PostTask( 366 FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this)); 367} 368 369void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) { 370 DCHECK(message_loop_->BelongsToCurrentThread()); 371 372 if (state_ == kClosed) 373 return; 374 375 DCHECK(!diverting_to_stream_); 376 diverting_to_stream_ = to_stream; 377 // Note: OnDeviceChange() will engage the "re-create" process, which will 378 // detect and use the alternate AudioOutputStream rather than create a new one 379 // via AudioManager. 380 OnDeviceChange(); 381} 382 383void AudioOutputController::DoStopDiverting() { 384 DCHECK(message_loop_->BelongsToCurrentThread()); 385 386 if (state_ == kClosed) 387 return; 388 389 // Note: OnDeviceChange() will cause the existing stream (the consumer of the 390 // diverted audio data) to be closed, and diverting_to_stream_ will be set 391 // back to NULL. 392 OnDeviceChange(); 393 DCHECK(!diverting_to_stream_); 394} 395 396void AudioOutputController::AllowEntryToOnMoreIOData() { 397 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); 398 base::AtomicRefCountInc(&num_allowed_io_); 399} 400 401void AudioOutputController::DisallowEntryToOnMoreIOData() { 402 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); 403 DCHECK(is_zero); 404} 405 406} // namespace media 407