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 |