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/task_runner_util.h" 12 #include "base/threading/platform_thread.h" 13 #include "base/time/time.h" 14 #include "build/build_config.h" 15 #include "media/base/scoped_histogram_timer.h" 16 17 using base::Time; 18 using base::TimeDelta; 19 20 namespace media { 21 22 #if defined(AUDIO_POWER_MONITORING) 23 // Time constant for AudioPowerMonitor. See AudioPowerMonitor ctor comments for 24 // semantics. This value was arbitrarily chosen, but seems to work well. 25 static const int kPowerMeasurementTimeConstantMillis = 10; 26 27 // Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting 28 // power levels in the audio signal. 29 static const int kPowerMeasurementsPerSecond = 4; 30 #endif 31 32 // Polling-related constants. 33 const int AudioOutputController::kPollNumAttempts = 3; 34 const int AudioOutputController::kPollPauseInMilliseconds = 3; 35 36 AudioOutputController::AudioOutputController( 37 AudioManager* audio_manager, 38 EventHandler* handler, 39 const AudioParameters& params, 40 const std::string& output_device_id, 41 const std::string& input_device_id, 42 SyncReader* sync_reader) 43 : audio_manager_(audio_manager), 44 params_(params), 45 handler_(handler), 46 output_device_id_(output_device_id), 47 input_device_id_(input_device_id), 48 stream_(NULL), 49 diverting_to_stream_(NULL), 50 volume_(1.0), 51 state_(kEmpty), 52 num_allowed_io_(0), 53 sync_reader_(sync_reader), 54 message_loop_(audio_manager->GetMessageLoop()), 55 #if defined(AUDIO_POWER_MONITORING) 56 power_monitor_( 57 params.sample_rate(), 58 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)), 59 #endif 60 on_more_io_data_called_(0) { 61 DCHECK(audio_manager); 62 DCHECK(handler_); 63 DCHECK(sync_reader_); 64 DCHECK(message_loop_.get()); 65 } 66 67 AudioOutputController::~AudioOutputController() { 68 DCHECK_EQ(kClosed, state_); 69 } 70 71 // static 72 scoped_refptr<AudioOutputController> AudioOutputController::Create( 73 AudioManager* audio_manager, 74 EventHandler* event_handler, 75 const AudioParameters& params, 76 const std::string& output_device_id, 77 const std::string& input_device_id, 78 SyncReader* sync_reader) { 79 DCHECK(audio_manager); 80 DCHECK(sync_reader); 81 82 if (!params.IsValid() || !audio_manager) 83 return NULL; 84 85 scoped_refptr<AudioOutputController> controller(new AudioOutputController( 86 audio_manager, event_handler, params, output_device_id, input_device_id, 87 sync_reader)); 88 controller->message_loop_->PostTask(FROM_HERE, base::Bind( 89 &AudioOutputController::DoCreate, controller, false)); 90 return controller; 91 } 92 93 void AudioOutputController::Play() { 94 message_loop_->PostTask(FROM_HERE, base::Bind( 95 &AudioOutputController::DoPlay, this)); 96 } 97 98 void AudioOutputController::Pause() { 99 message_loop_->PostTask(FROM_HERE, base::Bind( 100 &AudioOutputController::DoPause, this)); 101 } 102 103 void AudioOutputController::Close(const base::Closure& closed_task) { 104 DCHECK(!closed_task.is_null()); 105 message_loop_->PostTaskAndReply(FROM_HERE, base::Bind( 106 &AudioOutputController::DoClose, this), closed_task); 107 } 108 109 void AudioOutputController::SetVolume(double volume) { 110 message_loop_->PostTask(FROM_HERE, base::Bind( 111 &AudioOutputController::DoSetVolume, this, volume)); 112 } 113 114 void AudioOutputController::GetOutputDeviceId( 115 base::Callback<void(const std::string&)> callback) const { 116 base::PostTaskAndReplyWithResult( 117 message_loop_.get(), 118 FROM_HERE, 119 base::Bind(&AudioOutputController::DoGetOutputDeviceId, this), 120 callback); 121 } 122 123 void AudioOutputController::SwitchOutputDevice( 124 const std::string& output_device_id, const base::Closure& callback) { 125 message_loop_->PostTaskAndReply( 126 FROM_HERE, 127 base::Bind(&AudioOutputController::DoSwitchOutputDevice, this, 128 output_device_id), 129 callback); 130 } 131 132 void AudioOutputController::DoCreate(bool is_for_device_change) { 133 DCHECK(message_loop_->BelongsToCurrentThread()); 134 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime"); 135 TRACE_EVENT0("audio", "AudioOutputController::DoCreate"); 136 137 // Close() can be called before DoCreate() is executed. 138 if (state_ == kClosed) 139 return; 140 141 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener(). 142 DCHECK_EQ(kEmpty, state_); 143 144 stream_ = diverting_to_stream_ ? 145 diverting_to_stream_ : 146 audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_, 147 input_device_id_); 148 if (!stream_) { 149 state_ = kError; 150 handler_->OnError(); 151 return; 152 } 153 154 if (!stream_->Open()) { 155 DoStopCloseAndClearStream(); 156 state_ = kError; 157 handler_->OnError(); 158 return; 159 } 160 161 // Everything started okay, so re-register for state change callbacks if 162 // stream_ was created via AudioManager. 163 if (stream_ != diverting_to_stream_) 164 audio_manager_->AddOutputDeviceChangeListener(this); 165 166 // We have successfully opened the stream. Set the initial volume. 167 stream_->SetVolume(volume_); 168 169 // Finally set the state to kCreated. 170 state_ = kCreated; 171 172 // And then report we have been created if we haven't done so already. 173 if (!is_for_device_change) 174 handler_->OnCreated(); 175 } 176 177 void AudioOutputController::DoPlay() { 178 DCHECK(message_loop_->BelongsToCurrentThread()); 179 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); 180 TRACE_EVENT0("audio", "AudioOutputController::DoPlay"); 181 182 // We can start from created or paused state. 183 if (state_ != kCreated && state_ != kPaused) 184 return; 185 186 // Ask for first packet. 187 sync_reader_->UpdatePendingBytes(0); 188 189 state_ = kPlaying; 190 191 #if defined(AUDIO_POWER_MONITORING) 192 power_monitor_.Reset(); 193 power_poll_callback_.Reset( 194 base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically, 195 this)); 196 // Run the callback to send an initial notification that we're starting in 197 // silence, and to schedule periodic callbacks. 198 power_poll_callback_.callback().Run(); 199 #endif 200 201 on_more_io_data_called_ = 0; 202 AllowEntryToOnMoreIOData(); 203 stream_->Start(this); 204 205 // For UMA tracking purposes, start the wedge detection timer. This allows us 206 // to record statistics about the number of wedged playbacks in the field. 207 // 208 // WedgeCheck() will look to see if |on_more_io_data_called_| is true after 209 // the timeout expires. Care must be taken to ensure the wedge check delay is 210 // large enough that the value isn't queried while OnMoreDataIO() is setting 211 // it. 212 // 213 // Timer self-manages its lifetime and WedgeCheck() will only record the UMA 214 // statistic if state is still kPlaying. Additional Start() calls will 215 // invalidate the previous timer. 216 wedge_timer_.reset(new base::OneShotTimer<AudioOutputController>()); 217 wedge_timer_->Start( 218 FROM_HERE, TimeDelta::FromSeconds(5), this, 219 &AudioOutputController::WedgeCheck); 220 221 handler_->OnPlaying(); 222 } 223 224 #if defined(AUDIO_POWER_MONITORING) 225 void AudioOutputController::ReportPowerMeasurementPeriodically() { 226 DCHECK(message_loop_->BelongsToCurrentThread()); 227 const std::pair<float, bool>& reading = 228 power_monitor_.ReadCurrentPowerAndClip(); 229 handler_->OnPowerMeasured(reading.first, reading.second); 230 message_loop_->PostDelayedTask( 231 FROM_HERE, power_poll_callback_.callback(), 232 TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond); 233 } 234 #endif 235 236 void AudioOutputController::StopStream() { 237 DCHECK(message_loop_->BelongsToCurrentThread()); 238 239 if (state_ == kPlaying) { 240 wedge_timer_.reset(); 241 stream_->Stop(); 242 DisallowEntryToOnMoreIOData(); 243 244 #if defined(AUDIO_POWER_MONITORING) 245 power_poll_callback_.Cancel(); 246 #endif 247 248 state_ = kPaused; 249 } 250 } 251 252 void AudioOutputController::DoPause() { 253 DCHECK(message_loop_->BelongsToCurrentThread()); 254 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime"); 255 TRACE_EVENT0("audio", "AudioOutputController::DoPause"); 256 257 StopStream(); 258 259 if (state_ != kPaused) 260 return; 261 262 // Let the renderer know we've stopped. Necessary to let PPAPI clients know 263 // audio has been shutdown. TODO(dalecurtis): This stinks. PPAPI should have 264 // a better way to know when it should exit PPB_Audio_Shared::Run(). 265 sync_reader_->UpdatePendingBytes(-1); 266 267 #if defined(AUDIO_POWER_MONITORING) 268 // Paused means silence follows. 269 handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false); 270 #endif 271 272 handler_->OnPaused(); 273 } 274 275 void AudioOutputController::DoClose() { 276 DCHECK(message_loop_->BelongsToCurrentThread()); 277 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime"); 278 TRACE_EVENT0("audio", "AudioOutputController::DoClose"); 279 280 if (state_ != kClosed) { 281 DoStopCloseAndClearStream(); 282 sync_reader_->Close(); 283 state_ = kClosed; 284 } 285 } 286 287 void AudioOutputController::DoSetVolume(double volume) { 288 DCHECK(message_loop_->BelongsToCurrentThread()); 289 290 // Saves the volume to a member first. We may not be able to set the volume 291 // right away but when the stream is created we'll set the volume. 292 volume_ = volume; 293 294 switch (state_) { 295 case kCreated: 296 case kPlaying: 297 case kPaused: 298 stream_->SetVolume(volume_); 299 break; 300 default: 301 return; 302 } 303 } 304 305 std::string AudioOutputController::DoGetOutputDeviceId() const { 306 DCHECK(message_loop_->BelongsToCurrentThread()); 307 return output_device_id_; 308 } 309 310 void AudioOutputController::DoSwitchOutputDevice( 311 const std::string& output_device_id) { 312 DCHECK(message_loop_->BelongsToCurrentThread()); 313 314 if (state_ == kClosed) 315 return; 316 317 if (output_device_id == output_device_id_) 318 return; 319 320 output_device_id_ = output_device_id; 321 322 // If output is currently diverted, we must not call OnDeviceChange 323 // since it would break the diverted setup. Once diversion is 324 // finished using StopDiverting() the output will switch to the new 325 // device ID. 326 if (stream_ != diverting_to_stream_) 327 OnDeviceChange(); 328 } 329 330 void AudioOutputController::DoReportError() { 331 DCHECK(message_loop_->BelongsToCurrentThread()); 332 if (state_ != kClosed) 333 handler_->OnError(); 334 } 335 336 int AudioOutputController::OnMoreData(AudioBus* dest, 337 AudioBuffersState buffers_state) { 338 return OnMoreIOData(NULL, dest, buffers_state); 339 } 340 341 int AudioOutputController::OnMoreIOData(AudioBus* source, 342 AudioBus* dest, 343 AudioBuffersState buffers_state) { 344 DisallowEntryToOnMoreIOData(); 345 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); 346 347 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() 348 // may have already fired if OnMoreIOData() took an abnormal amount of time). 349 // Since this thread is the only writer of |on_more_io_data_called_| once the 350 // thread starts, its safe to compare and then increment. 351 if (base::AtomicRefCountIsZero(&on_more_io_data_called_)) 352 base::AtomicRefCountInc(&on_more_io_data_called_); 353 354 sync_reader_->Read(source, dest); 355 356 const int frames = dest->frames(); 357 sync_reader_->UpdatePendingBytes( 358 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); 359 360 #if defined(AUDIO_POWER_MONITORING) 361 power_monitor_.Scan(*dest, frames); 362 #endif 363 364 AllowEntryToOnMoreIOData(); 365 return frames; 366 } 367 368 void AudioOutputController::OnError(AudioOutputStream* stream) { 369 // Handle error on the audio controller thread. 370 message_loop_->PostTask(FROM_HERE, base::Bind( 371 &AudioOutputController::DoReportError, this)); 372 } 373 374 void AudioOutputController::DoStopCloseAndClearStream() { 375 DCHECK(message_loop_->BelongsToCurrentThread()); 376 377 // Allow calling unconditionally and bail if we don't have a stream_ to close. 378 if (stream_) { 379 // De-register from state change callbacks if stream_ was created via 380 // AudioManager. 381 if (stream_ != diverting_to_stream_) 382 audio_manager_->RemoveOutputDeviceChangeListener(this); 383 384 StopStream(); 385 stream_->Close(); 386 if (stream_ == diverting_to_stream_) 387 diverting_to_stream_ = NULL; 388 stream_ = NULL; 389 } 390 391 state_ = kEmpty; 392 } 393 394 void AudioOutputController::OnDeviceChange() { 395 DCHECK(message_loop_->BelongsToCurrentThread()); 396 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime"); 397 TRACE_EVENT0("audio", "AudioOutputController::OnDeviceChange"); 398 399 // TODO(dalecurtis): Notify the renderer side that a device change has 400 // occurred. Currently querying the hardware information here will lead to 401 // crashes on OSX. See http://crbug.com/158170. 402 403 // Recreate the stream (DoCreate() will first shut down an existing stream). 404 // Exit if we ran into an error. 405 const State original_state = state_; 406 DoCreate(true); 407 if (!stream_ || state_ == kError) 408 return; 409 410 // Get us back to the original state or an equivalent state. 411 switch (original_state) { 412 case kPlaying: 413 DoPlay(); 414 return; 415 case kCreated: 416 case kPaused: 417 // From the outside these two states are equivalent. 418 return; 419 default: 420 NOTREACHED() << "Invalid original state."; 421 } 422 } 423 424 const AudioParameters& AudioOutputController::GetAudioParameters() { 425 return params_; 426 } 427 428 void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) { 429 message_loop_->PostTask( 430 FROM_HERE, 431 base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream)); 432 } 433 434 void AudioOutputController::StopDiverting() { 435 message_loop_->PostTask( 436 FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this)); 437 } 438 439 void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) { 440 DCHECK(message_loop_->BelongsToCurrentThread()); 441 442 if (state_ == kClosed) 443 return; 444 445 DCHECK(!diverting_to_stream_); 446 diverting_to_stream_ = to_stream; 447 // Note: OnDeviceChange() will engage the "re-create" process, which will 448 // detect and use the alternate AudioOutputStream rather than create a new one 449 // via AudioManager. 450 OnDeviceChange(); 451 } 452 453 void AudioOutputController::DoStopDiverting() { 454 DCHECK(message_loop_->BelongsToCurrentThread()); 455 456 if (state_ == kClosed) 457 return; 458 459 // Note: OnDeviceChange() will cause the existing stream (the consumer of the 460 // diverted audio data) to be closed, and diverting_to_stream_ will be set 461 // back to NULL. 462 OnDeviceChange(); 463 DCHECK(!diverting_to_stream_); 464 } 465 466 void AudioOutputController::AllowEntryToOnMoreIOData() { 467 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); 468 base::AtomicRefCountInc(&num_allowed_io_); 469 } 470 471 void AudioOutputController::DisallowEntryToOnMoreIOData() { 472 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); 473 DCHECK(is_zero); 474 } 475 476 void AudioOutputController::WedgeCheck() { 477 DCHECK(message_loop_->BelongsToCurrentThread()); 478 479 // If we should be playing and we haven't, that's a wedge. 480 if (state_ == kPlaying) { 481 const bool playback_success = 482 base::AtomicRefCountIsOne(&on_more_io_data_called_); 483 484 UMA_HISTOGRAM_BOOLEAN( 485 "Media.AudioOutputControllerPlaybackStartupSuccess", playback_success); 486 487 // Let the AudioManager try and fix it. 488 if (!playback_success) 489 audio_manager_->FixWedgedAudio(); 490 } 491 } 492 493 } // namespace media 494