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