| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/audio_output_controller.h" | 5 #include "media/audio/audio_output_controller.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 params_(params), | 45 params_(params), |
| 46 handler_(handler), | 46 handler_(handler), |
| 47 input_device_id_(input_device_id), | 47 input_device_id_(input_device_id), |
| 48 stream_(NULL), | 48 stream_(NULL), |
| 49 diverting_to_stream_(NULL), | 49 diverting_to_stream_(NULL), |
| 50 volume_(1.0), | 50 volume_(1.0), |
| 51 state_(kEmpty), | 51 state_(kEmpty), |
| 52 num_allowed_io_(0), | 52 num_allowed_io_(0), |
| 53 sync_reader_(sync_reader), | 53 sync_reader_(sync_reader), |
| 54 message_loop_(audio_manager->GetMessageLoop()), | 54 message_loop_(audio_manager->GetMessageLoop()), |
| 55 number_polling_attempts_left_(0), | 55 number_polling_attempts_left_(0) { |
| 56 weak_this_(this) { | |
| 57 DCHECK(audio_manager); | 56 DCHECK(audio_manager); |
| 58 DCHECK(handler_); | 57 DCHECK(handler_); |
| 59 DCHECK(sync_reader_); | 58 DCHECK(sync_reader_); |
| 60 DCHECK(message_loop_.get()); | 59 DCHECK(message_loop_.get()); |
| 61 } | 60 } |
| 62 | 61 |
| 63 AudioOutputController::~AudioOutputController() { | 62 AudioOutputController::~AudioOutputController() { |
| 64 DCHECK_EQ(kClosed, state_); | 63 DCHECK_EQ(kClosed, state_); |
| 65 } | 64 } |
| 66 | 65 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 // Finally set the state to kCreated. | 141 // Finally set the state to kCreated. |
| 143 state_ = kCreated; | 142 state_ = kCreated; |
| 144 | 143 |
| 145 // And then report we have been created if we haven't done so already. | 144 // And then report we have been created if we haven't done so already. |
| 146 if (!is_for_device_change) | 145 if (!is_for_device_change) |
| 147 handler_->OnCreated(); | 146 handler_->OnCreated(); |
| 148 } | 147 } |
| 149 | 148 |
| 150 void AudioOutputController::DoPlay() { | 149 void AudioOutputController::DoPlay() { |
| 151 DCHECK(message_loop_->BelongsToCurrentThread()); | 150 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 151 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); |
| 152 | 152 |
| 153 // We can start from created or paused state. | 153 // We can start from created or paused state. |
| 154 if (state_ != kCreated && state_ != kPaused) | 154 if (state_ != kCreated && state_ != kPaused) |
| 155 return; | 155 return; |
| 156 | 156 |
| 157 state_ = kStarting; | |
| 158 | |
| 159 // Ask for first packet. | 157 // Ask for first packet. |
| 160 sync_reader_->UpdatePendingBytes(0); | 158 sync_reader_->UpdatePendingBytes(0); |
| 161 | 159 |
| 162 // Cannot start stream immediately, should give renderer some time | |
| 163 // to deliver data. | |
| 164 // TODO(vrk): The polling here and in WaitTillDataReady() is pretty clunky. | |
| 165 // Refine the API such that polling is no longer needed. (crbug.com/112196) | |
| 166 number_polling_attempts_left_ = kPollNumAttempts; | |
| 167 DCHECK(!weak_this_.HasWeakPtrs()); | |
| 168 message_loop_->PostDelayedTask( | |
| 169 FROM_HERE, | |
| 170 base::Bind(&AudioOutputController::PollAndStartIfDataReady, | |
| 171 weak_this_.GetWeakPtr()), | |
| 172 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds)); | |
| 173 } | |
| 174 | |
| 175 void AudioOutputController::PollAndStartIfDataReady() { | |
| 176 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 177 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); | |
| 178 | |
| 179 DCHECK_EQ(kStarting, state_); | |
| 180 | |
| 181 // If we are ready to start the stream, start it. | |
| 182 if (--number_polling_attempts_left_ == 0 || | |
| 183 sync_reader_->DataReady()) { | |
| 184 StartStream(); | |
| 185 } else { | |
| 186 message_loop_->PostDelayedTask( | |
| 187 FROM_HERE, | |
| 188 base::Bind(&AudioOutputController::PollAndStartIfDataReady, | |
| 189 weak_this_.GetWeakPtr()), | |
| 190 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds)); | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 void AudioOutputController::StartStream() { | |
| 195 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 196 state_ = kPlaying; | 160 state_ = kPlaying; |
| 197 | |
| 198 silence_detector_.reset(new AudioSilenceDetector( | 161 silence_detector_.reset(new AudioSilenceDetector( |
| 199 params_.sample_rate(), | 162 params_.sample_rate(), |
| 200 TimeDelta::FromMilliseconds(kQuestionableSilencePeriodMillis), | 163 TimeDelta::FromMilliseconds(kQuestionableSilencePeriodMillis), |
| 201 kIndistinguishableSilenceThreshold)); | 164 kIndistinguishableSilenceThreshold)); |
| 202 | 165 |
| 203 // We start the AudioOutputStream lazily. | 166 // We start the AudioOutputStream lazily. |
| 204 AllowEntryToOnMoreIOData(); | 167 AllowEntryToOnMoreIOData(); |
| 205 stream_->Start(this); | 168 stream_->Start(this); |
| 206 | 169 |
| 207 // Tell the event handler that we are now playing, and also start the silence | 170 // Tell the event handler that we are now playing, and also start the silence |
| 208 // detection notifications. | 171 // detection notifications. |
| 209 handler_->OnPlaying(); | 172 handler_->OnPlaying(); |
| 210 silence_detector_->Start( | 173 silence_detector_->Start( |
| 211 base::Bind(&EventHandler::OnAudible, base::Unretained(handler_))); | 174 base::Bind(&EventHandler::OnAudible, base::Unretained(handler_))); |
| 212 } | 175 } |
| 213 | 176 |
| 214 void AudioOutputController::StopStream() { | 177 void AudioOutputController::StopStream() { |
| 215 DCHECK(message_loop_->BelongsToCurrentThread()); | 178 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 216 | 179 |
| 217 if (state_ == kStarting) { | 180 if (state_ == kPlaying) { |
| 218 // Cancel in-progress polling start. | |
| 219 weak_this_.InvalidateWeakPtrs(); | |
| 220 state_ = kPaused; | |
| 221 } else if (state_ == kPlaying) { | |
| 222 stream_->Stop(); | 181 stream_->Stop(); |
| 223 DisallowEntryToOnMoreIOData(); | 182 DisallowEntryToOnMoreIOData(); |
| 224 silence_detector_->Stop(true); | 183 silence_detector_->Stop(true); |
| 225 silence_detector_.reset(); | 184 silence_detector_.reset(); |
| 226 state_ = kPaused; | 185 state_ = kPaused; |
| 227 } | 186 } |
| 228 } | 187 } |
| 229 | 188 |
| 230 void AudioOutputController::DoPause() { | 189 void AudioOutputController::DoPause() { |
| 231 DCHECK(message_loop_->BelongsToCurrentThread()); | 190 DCHECK(message_loop_->BelongsToCurrentThread()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 255 | 214 |
| 256 void AudioOutputController::DoSetVolume(double volume) { | 215 void AudioOutputController::DoSetVolume(double volume) { |
| 257 DCHECK(message_loop_->BelongsToCurrentThread()); | 216 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 258 | 217 |
| 259 // Saves the volume to a member first. We may not be able to set the volume | 218 // Saves the volume to a member first. We may not be able to set the volume |
| 260 // right away but when the stream is created we'll set the volume. | 219 // right away but when the stream is created we'll set the volume. |
| 261 volume_ = volume; | 220 volume_ = volume; |
| 262 | 221 |
| 263 switch (state_) { | 222 switch (state_) { |
| 264 case kCreated: | 223 case kCreated: |
| 265 case kStarting: | |
| 266 case kPlaying: | 224 case kPlaying: |
| 267 case kPaused: | 225 case kPaused: |
| 268 stream_->SetVolume(volume_); | 226 stream_->SetVolume(volume_); |
| 269 break; | 227 break; |
| 270 default: | 228 default: |
| 271 return; | 229 return; |
| 272 } | 230 } |
| 273 } | 231 } |
| 274 | 232 |
| 275 void AudioOutputController::DoReportError() { | 233 void AudioOutputController::DoReportError() { |
| 276 DCHECK(message_loop_->BelongsToCurrentThread()); | 234 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 277 if (state_ != kClosed) | 235 if (state_ != kClosed) |
| 278 handler_->OnError(); | 236 handler_->OnError(); |
| 279 } | 237 } |
| 280 | 238 |
| 281 int AudioOutputController::OnMoreData(AudioBus* dest, | 239 int AudioOutputController::OnMoreData(AudioBus* dest, |
| 282 AudioBuffersState buffers_state) { | 240 AudioBuffersState buffers_state) { |
| 283 return OnMoreIOData(NULL, dest, buffers_state); | 241 return OnMoreIOData(NULL, dest, buffers_state); |
| 284 } | 242 } |
| 285 | 243 |
| 286 int AudioOutputController::OnMoreIOData(AudioBus* source, | 244 int AudioOutputController::OnMoreIOData(AudioBus* source, |
| 287 AudioBus* dest, | 245 AudioBus* dest, |
| 288 AudioBuffersState buffers_state) { | 246 AudioBuffersState buffers_state) { |
| 289 DisallowEntryToOnMoreIOData(); | 247 DisallowEntryToOnMoreIOData(); |
| 290 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); | 248 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); |
| 291 | 249 |
| 292 // The OS level audio APIs on Linux and Windows all have problems requesting | 250 // The OS level audio APIs on Linux and Windows all have problems requesting |
| 293 // data on a fixed interval. Sometimes they will issue calls back to back | 251 // data on a fixed interval. Sometimes they will issue calls back to back |
| 294 // which can cause glitching, so wait until the renderer is ready for Read(). | 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. |
| 295 // | 259 // |
| 296 // See many bugs for context behind this decision: http://crbug.com/170498, | 260 // See many bugs for context behind this decision: http://crbug.com/170498, |
| 297 // http://crbug.com/171651, http://crbug.com/174985, and more. | 261 // http://crbug.com/171651, http://crbug.com/174985, and more. |
| 298 #if defined(OS_WIN) || defined(OS_LINUX) | 262 #if defined(OS_WIN) || defined(OS_LINUX) |
| 299 WaitTillDataReady(); | 263 const bool kShouldBlock = true; |
| 264 #else |
| 265 const bool kShouldBlock = diverting_to_stream_ != NULL; |
| 300 #endif | 266 #endif |
| 301 | 267 |
| 302 const int frames = sync_reader_->Read(source, dest); | 268 const int frames = sync_reader_->Read(kShouldBlock, source, dest); |
| 303 DCHECK_LE(0, frames); | 269 DCHECK_LE(0, frames); |
| 304 sync_reader_->UpdatePendingBytes( | 270 sync_reader_->UpdatePendingBytes( |
| 305 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); | 271 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); |
| 306 | 272 |
| 307 silence_detector_->Scan(dest, frames); | 273 silence_detector_->Scan(dest, frames); |
| 308 | 274 |
| 309 AllowEntryToOnMoreIOData(); | 275 AllowEntryToOnMoreIOData(); |
| 310 return frames; | 276 return frames; |
| 311 } | 277 } |
| 312 | 278 |
| 313 void AudioOutputController::WaitTillDataReady() { | |
| 314 // Most of the time the data is ready already. | |
| 315 if (sync_reader_->DataReady()) | |
| 316 return; | |
| 317 | |
| 318 base::TimeTicks start = base::TimeTicks::Now(); | |
| 319 const base::TimeDelta kMaxWait = base::TimeDelta::FromMilliseconds(20); | |
| 320 #if defined(OS_WIN) | |
| 321 // Sleep(0) on windows lets the other threads run. | |
| 322 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(0); | |
| 323 #else | |
| 324 // We want to sleep for a bit here, as otherwise a backgrounded renderer won't | |
| 325 // get enough cpu to send the data and the high priority thread in the browser | |
| 326 // will use up a core causing even more skips. | |
| 327 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(2); | |
| 328 #endif | |
| 329 base::TimeDelta time_since_start; | |
| 330 do { | |
| 331 base::PlatformThread::Sleep(kSleep); | |
| 332 time_since_start = base::TimeTicks::Now() - start; | |
| 333 } while (!sync_reader_->DataReady() && (time_since_start < kMaxWait)); | |
| 334 UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady", | |
| 335 time_since_start, | |
| 336 base::TimeDelta::FromMilliseconds(1), | |
| 337 base::TimeDelta::FromMilliseconds(1000), | |
| 338 50); | |
| 339 } | |
| 340 | |
| 341 void AudioOutputController::OnError(AudioOutputStream* stream) { | 279 void AudioOutputController::OnError(AudioOutputStream* stream) { |
| 342 // Handle error on the audio controller thread. | 280 // Handle error on the audio controller thread. |
| 343 message_loop_->PostTask(FROM_HERE, base::Bind( | 281 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 344 &AudioOutputController::DoReportError, this)); | 282 &AudioOutputController::DoReportError, this)); |
| 345 } | 283 } |
| 346 | 284 |
| 347 void AudioOutputController::DoStopCloseAndClearStream() { | 285 void AudioOutputController::DoStopCloseAndClearStream() { |
| 348 DCHECK(message_loop_->BelongsToCurrentThread()); | 286 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 349 | 287 |
| 350 // Allow calling unconditionally and bail if we don't have a stream_ to close. | 288 // Allow calling unconditionally and bail if we don't have a stream_ to close. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 374 | 312 |
| 375 // Recreate the stream (DoCreate() will first shut down an existing stream). | 313 // Recreate the stream (DoCreate() will first shut down an existing stream). |
| 376 // Exit if we ran into an error. | 314 // Exit if we ran into an error. |
| 377 const State original_state = state_; | 315 const State original_state = state_; |
| 378 DoCreate(true); | 316 DoCreate(true); |
| 379 if (!stream_ || state_ == kError) | 317 if (!stream_ || state_ == kError) |
| 380 return; | 318 return; |
| 381 | 319 |
| 382 // Get us back to the original state or an equivalent state. | 320 // Get us back to the original state or an equivalent state. |
| 383 switch (original_state) { | 321 switch (original_state) { |
| 384 case kStarting: | |
| 385 case kPlaying: | 322 case kPlaying: |
| 386 DoPlay(); | 323 DoPlay(); |
| 387 return; | 324 return; |
| 388 case kCreated: | 325 case kCreated: |
| 389 case kPaused: | 326 case kPaused: |
| 390 // From the outside these two states are equivalent. | 327 // From the outside these two states are equivalent. |
| 391 return; | 328 return; |
| 392 default: | 329 default: |
| 393 NOTREACHED() << "Invalid original state."; | 330 NOTREACHED() << "Invalid original state."; |
| 394 } | 331 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); | 377 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); |
| 441 base::AtomicRefCountInc(&num_allowed_io_); | 378 base::AtomicRefCountInc(&num_allowed_io_); |
| 442 } | 379 } |
| 443 | 380 |
| 444 void AudioOutputController::DisallowEntryToOnMoreIOData() { | 381 void AudioOutputController::DisallowEntryToOnMoreIOData() { |
| 445 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); | 382 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); |
| 446 DCHECK(is_zero); | 383 DCHECK(is_zero); |
| 447 } | 384 } |
| 448 | 385 |
| 449 } // namespace media | 386 } // namespace media |
| OLD | NEW |