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