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