audio_output_controller.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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.h" 10#include "base/metrics/histogram.h" 11#include "base/threading/platform_thread.h" 12#include "base/time.h" 13#include "build/build_config.h" 14#include "media/audio/audio_silence_detector.h" 15#include "media/audio/audio_util.h" 16#include "media/audio/shared_memory_util.h" 17 18using base::Time; 19using base::TimeDelta; 20 21namespace media { 22 23// Amount of contiguous time where all audio is silent before considering the 24// stream to have transitioned and EventHandler::OnAudible() should be called. 25static const int kQuestionableSilencePeriodMillis = 50; 26 27// Sample value range below which audio is considered indistinguishably silent. 28// 29// TODO(miu): This value should be specified in dbFS units rather than full 30// scale. See TODO in audio_silence_detector.h. 31static const float kIndistinguishableSilenceThreshold = 32 1.0f / 4096.0f; // Note: This is approximately -72 dbFS. 33 34// Polling-related constants. 35const int AudioOutputController::kPollNumAttempts = 3; 36const int AudioOutputController::kPollPauseInMilliseconds = 3; 37 38AudioOutputController::AudioOutputController(AudioManager* audio_manager, 39 EventHandler* handler, 40 const AudioParameters& params, 41 SyncReader* sync_reader) 42 : audio_manager_(audio_manager), 43 params_(params), 44 handler_(handler), 45 stream_(NULL), 46 diverting_to_stream_(NULL), 47 volume_(1.0), 48 state_(kEmpty), 49 num_allowed_io_(0), 50 sync_reader_(sync_reader), 51 message_loop_(audio_manager->GetMessageLoop()), 52 number_polling_attempts_left_(0), 53 weak_this_(this) { 54 DCHECK(audio_manager); 55 DCHECK(handler_); 56 DCHECK(sync_reader_); 57 DCHECK(message_loop_); 58} 59 60AudioOutputController::~AudioOutputController() { 61 DCHECK_EQ(kClosed, state_); 62} 63 64// static 65scoped_refptr<AudioOutputController> AudioOutputController::Create( 66 AudioManager* audio_manager, 67 EventHandler* event_handler, 68 const AudioParameters& params, 69 SyncReader* sync_reader) { 70 DCHECK(audio_manager); 71 DCHECK(sync_reader); 72 73 if (!params.IsValid() || !audio_manager) 74 return NULL; 75 76 scoped_refptr<AudioOutputController> controller(new AudioOutputController( 77 audio_manager, event_handler, params, sync_reader)); 78 controller->message_loop_->PostTask(FROM_HERE, base::Bind( 79 &AudioOutputController::DoCreate, controller, false)); 80 return controller; 81} 82 83void AudioOutputController::Play() { 84 message_loop_->PostTask(FROM_HERE, base::Bind( 85 &AudioOutputController::DoPlay, this)); 86} 87 88void AudioOutputController::Pause() { 89 message_loop_->PostTask(FROM_HERE, base::Bind( 90 &AudioOutputController::DoPause, this)); 91} 92 93void AudioOutputController::Close(const base::Closure& closed_task) { 94 DCHECK(!closed_task.is_null()); 95 message_loop_->PostTaskAndReply(FROM_HERE, base::Bind( 96 &AudioOutputController::DoClose, this), closed_task); 97} 98 99void AudioOutputController::SetVolume(double volume) { 100 message_loop_->PostTask(FROM_HERE, base::Bind( 101 &AudioOutputController::DoSetVolume, this, volume)); 102} 103 104void AudioOutputController::DoCreate(bool is_for_device_change) { 105 DCHECK(message_loop_->BelongsToCurrentThread()); 106 107 // Close() can be called before DoCreate() is executed. 108 if (state_ == kClosed) 109 return; 110 111 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener(). 112 DCHECK_EQ(kEmpty, state_); 113 114 stream_ = diverting_to_stream_ ? diverting_to_stream_ : 115 audio_manager_->MakeAudioOutputStreamProxy(params_); 116 if (!stream_) { 117 state_ = kError; 118 handler_->OnError(); 119 return; 120 } 121 122 if (!stream_->Open()) { 123 DoStopCloseAndClearStream(); 124 state_ = kError; 125 handler_->OnError(); 126 return; 127 } 128 129 // Everything started okay, so re-register for state change callbacks if 130 // stream_ was created via AudioManager. 131 if (stream_ != diverting_to_stream_) 132 audio_manager_->AddOutputDeviceChangeListener(this); 133 134 // We have successfully opened the stream. Set the initial volume. 135 stream_->SetVolume(volume_); 136 137 // Finally set the state to kCreated. 138 state_ = kCreated; 139 140 // And then report we have been created if we haven't done so already. 141 if (!is_for_device_change) 142 handler_->OnCreated(); 143} 144 145void AudioOutputController::DoPlay() { 146 DCHECK(message_loop_->BelongsToCurrentThread()); 147 148 // We can start from created or paused state. 149 if (state_ != kCreated && state_ != kPaused) 150 return; 151 152 state_ = kStarting; 153 154 // Ask for first packet. 155 sync_reader_->UpdatePendingBytes(0); 156 157 // Cannot start stream immediately, should give renderer some time 158 // to deliver data. 159 // TODO(vrk): The polling here and in WaitTillDataReady() is pretty clunky. 160 // Refine the API such that polling is no longer needed. (crbug.com/112196) 161 number_polling_attempts_left_ = kPollNumAttempts; 162 DCHECK(!weak_this_.HasWeakPtrs()); 163 message_loop_->PostDelayedTask( 164 FROM_HERE, 165 base::Bind(&AudioOutputController::PollAndStartIfDataReady, 166 weak_this_.GetWeakPtr()), 167 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds)); 168} 169 170void AudioOutputController::PollAndStartIfDataReady() { 171 DCHECK(message_loop_->BelongsToCurrentThread()); 172 173 DCHECK_EQ(kStarting, state_); 174 175 // If we are ready to start the stream, start it. 176 if (--number_polling_attempts_left_ == 0 || 177 sync_reader_->DataReady()) { 178 StartStream(); 179 } else { 180 message_loop_->PostDelayedTask( 181 FROM_HERE, 182 base::Bind(&AudioOutputController::PollAndStartIfDataReady, 183 weak_this_.GetWeakPtr()), 184 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds)); 185 } 186} 187 188void AudioOutputController::StartStream() { 189 DCHECK(message_loop_->BelongsToCurrentThread()); 190 state_ = kPlaying; 191 192 silence_detector_.reset(new AudioSilenceDetector( 193 params_.sample_rate(), 194 TimeDelta::FromMilliseconds(kQuestionableSilencePeriodMillis), 195 kIndistinguishableSilenceThreshold)); 196 197 // We start the AudioOutputStream lazily. 198 AllowEntryToOnMoreIOData(); 199 stream_->Start(this); 200 201 // Tell the event handler that we are now playing, and also start the silence 202 // detection notifications. 203 handler_->OnPlaying(); 204 silence_detector_->Start( 205 base::Bind(&EventHandler::OnAudible, base::Unretained(handler_))); 206} 207 208void AudioOutputController::StopStream() { 209 DCHECK(message_loop_->BelongsToCurrentThread()); 210 211 if (state_ == kStarting) { 212 // Cancel in-progress polling start. 213 weak_this_.InvalidateWeakPtrs(); 214 state_ = kPaused; 215 } else if (state_ == kPlaying) { 216 stream_->Stop(); 217 DisallowEntryToOnMoreIOData(); 218 silence_detector_->Stop(true); 219 silence_detector_.reset(); 220 state_ = kPaused; 221 } 222} 223 224void AudioOutputController::DoPause() { 225 DCHECK(message_loop_->BelongsToCurrentThread()); 226 227 StopStream(); 228 229 if (state_ != kPaused) 230 return; 231 232 // Send a special pause mark to the low-latency audio thread. 233 sync_reader_->UpdatePendingBytes(kPauseMark); 234 235 handler_->OnPaused(); 236} 237 238void AudioOutputController::DoClose() { 239 DCHECK(message_loop_->BelongsToCurrentThread()); 240 241 if (state_ != kClosed) { 242 DoStopCloseAndClearStream(); 243 sync_reader_->Close(); 244 state_ = kClosed; 245 } 246} 247 248void AudioOutputController::DoSetVolume(double volume) { 249 DCHECK(message_loop_->BelongsToCurrentThread()); 250 251 // Saves the volume to a member first. We may not be able to set the volume 252 // right away but when the stream is created we'll set the volume. 253 volume_ = volume; 254 255 switch (state_) { 256 case kCreated: 257 case kStarting: 258 case kPlaying: 259 case kPaused: 260 stream_->SetVolume(volume_); 261 break; 262 default: 263 return; 264 } 265} 266 267void AudioOutputController::DoReportError() { 268 DCHECK(message_loop_->BelongsToCurrentThread()); 269 if (state_ != kClosed) 270 handler_->OnError(); 271} 272 273int AudioOutputController::OnMoreData(AudioBus* dest, 274 AudioBuffersState buffers_state) { 275 return OnMoreIOData(NULL, dest, buffers_state); 276} 277 278int AudioOutputController::OnMoreIOData(AudioBus* source, 279 AudioBus* dest, 280 AudioBuffersState buffers_state) { 281 DisallowEntryToOnMoreIOData(); 282 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); 283 284 // The OS level audio APIs on Linux and Windows all have problems requesting 285 // data on a fixed interval. Sometimes they will issue calls back to back 286 // which can cause glitching, so wait until the renderer is ready for Read(). 287 // 288 // See many bugs for context behind this decision: http://crbug.com/170498, 289 // http://crbug.com/171651, http://crbug.com/174985, and more. 290#if defined(OS_WIN) || defined(OS_LINUX) 291 WaitTillDataReady(); 292#endif 293 294 const int frames = sync_reader_->Read(source, dest); 295 DCHECK_LE(0, frames); 296 sync_reader_->UpdatePendingBytes( 297 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); 298 299 silence_detector_->Scan(dest, frames); 300 301 AllowEntryToOnMoreIOData(); 302 return frames; 303} 304 305void AudioOutputController::WaitTillDataReady() { 306 // Most of the time the data is ready already. 307 if (sync_reader_->DataReady()) 308 return; 309 310 base::TimeTicks start = base::TimeTicks::Now(); 311#if defined(OS_WIN) 312 // Wait for up to 683ms for DataReady(). 683ms was chosen because it's larger 313 // than the playback time of the WaveOut buffer size using the minimum 314 // supported sample rate: 2048 / 3000 = ~683ms. 315 // TODO(davemoore): We think this can be reduced to 20ms based on 316 // http://crrev.com/180102 but will do that in separate cl for mergability. 317 const base::TimeDelta kMaxWait = base::TimeDelta::FromMilliseconds(683); 318 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(0); 319#else 320 const base::TimeDelta kMaxWait = base::TimeDelta::FromMilliseconds(20); 321 // We want to sleep for a bit here, as otherwise a backgrounded renderer won't 322 // get enough cpu to send the data and the high priority thread in the browser 323 // will use up a core causing even more skips. 324 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(2); 325#endif 326 base::TimeDelta time_since_start; 327 do { 328 base::PlatformThread::Sleep(kSleep); 329 time_since_start = base::TimeTicks::Now() - start; 330 } while (!sync_reader_->DataReady() && (time_since_start < kMaxWait)); 331 UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady", 332 time_since_start, 333 base::TimeDelta::FromMilliseconds(1), 334 base::TimeDelta::FromMilliseconds(1000), 335 50); 336} 337 338void AudioOutputController::OnError(AudioOutputStream* stream) { 339 // Handle error on the audio controller thread. 340 message_loop_->PostTask(FROM_HERE, base::Bind( 341 &AudioOutputController::DoReportError, this)); 342} 343 344void AudioOutputController::DoStopCloseAndClearStream() { 345 DCHECK(message_loop_->BelongsToCurrentThread()); 346 347 // Allow calling unconditionally and bail if we don't have a stream_ to close. 348 if (stream_) { 349 // De-register from state change callbacks if stream_ was created via 350 // AudioManager. 351 if (stream_ != diverting_to_stream_) 352 audio_manager_->RemoveOutputDeviceChangeListener(this); 353 354 StopStream(); 355 stream_->Close(); 356 if (stream_ == diverting_to_stream_) 357 diverting_to_stream_ = NULL; 358 stream_ = NULL; 359 } 360 361 state_ = kEmpty; 362} 363 364void AudioOutputController::OnDeviceChange() { 365 DCHECK(message_loop_->BelongsToCurrentThread()); 366 367 // TODO(dalecurtis): Notify the renderer side that a device change has 368 // occurred. Currently querying the hardware information here will lead to 369 // crashes on OSX. See http://crbug.com/158170. 370 371 // Recreate the stream (DoCreate() will first shut down an existing stream). 372 // Exit if we ran into an error. 373 const State original_state = state_; 374 DoCreate(true); 375 if (!stream_ || state_ == kError) 376 return; 377 378 // Get us back to the original state or an equivalent state. 379 switch (original_state) { 380 case kStarting: 381 case kPlaying: 382 DoPlay(); 383 return; 384 case kCreated: 385 case kPaused: 386 // From the outside these two states are equivalent. 387 return; 388 default: 389 NOTREACHED() << "Invalid original state."; 390 } 391} 392 393const AudioParameters& AudioOutputController::GetAudioParameters() { 394 return params_; 395} 396 397void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) { 398 message_loop_->PostTask( 399 FROM_HERE, 400 base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream)); 401} 402 403void AudioOutputController::StopDiverting() { 404 message_loop_->PostTask( 405 FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this)); 406} 407 408void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) { 409 DCHECK(message_loop_->BelongsToCurrentThread()); 410 411 if (state_ == kClosed) 412 return; 413 414 DCHECK(!diverting_to_stream_); 415 diverting_to_stream_ = to_stream; 416 // Note: OnDeviceChange() will engage the "re-create" process, which will 417 // detect and use the alternate AudioOutputStream rather than create a new one 418 // via AudioManager. 419 OnDeviceChange(); 420} 421 422void AudioOutputController::DoStopDiverting() { 423 DCHECK(message_loop_->BelongsToCurrentThread()); 424 425 if (state_ == kClosed) 426 return; 427 428 // Note: OnDeviceChange() will cause the existing stream (the consumer of the 429 // diverted audio data) to be closed, and diverting_to_stream_ will be set 430 // back to NULL. 431 OnDeviceChange(); 432 DCHECK(!diverting_to_stream_); 433} 434 435void AudioOutputController::AllowEntryToOnMoreIOData() { 436 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); 437 base::AtomicRefCountInc(&num_allowed_io_); 438} 439 440void AudioOutputController::DisallowEntryToOnMoreIOData() { 441 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); 442 DCHECK(is_zero); 443} 444 445} // namespace media 446