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/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/task_runner_util.h" | 10 #include "base/task_runner_util.h" |
(...skipping 27 matching lines...) Expand all Loading... | |
38 const std::string& output_device_id, | 38 const std::string& output_device_id, |
39 SyncReader* sync_reader) | 39 SyncReader* sync_reader) |
40 : audio_manager_(audio_manager), | 40 : audio_manager_(audio_manager), |
41 params_(params), | 41 params_(params), |
42 handler_(handler), | 42 handler_(handler), |
43 output_device_id_(output_device_id), | 43 output_device_id_(output_device_id), |
44 stream_(NULL), | 44 stream_(NULL), |
45 diverting_to_stream_(NULL), | 45 diverting_to_stream_(NULL), |
46 volume_(1.0), | 46 volume_(1.0), |
47 state_(kEmpty), | 47 state_(kEmpty), |
48 num_allowed_io_(0), | 48 currently_in_on_more_io_data_(0), |
49 sync_reader_(sync_reader), | 49 sync_reader_(sync_reader), |
50 message_loop_(audio_manager->GetTaskRunner()), | 50 message_loop_(audio_manager->GetTaskRunner()), |
51 #if defined(AUDIO_POWER_MONITORING) | 51 #if defined(AUDIO_POWER_MONITORING) |
52 power_monitor_( | 52 power_monitor_( |
53 params.sample_rate(), | 53 params.sample_rate(), |
54 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)), | 54 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)), |
55 #endif | 55 #endif |
56 on_more_io_data_called_(0) { | 56 on_more_io_data_called_(0) { |
57 DCHECK(audio_manager); | 57 DCHECK(audio_manager); |
58 DCHECK(handler_); | 58 DCHECK(handler_); |
59 DCHECK(sync_reader_); | 59 DCHECK(sync_reader_); |
60 DCHECK(message_loop_.get()); | 60 DCHECK(message_loop_.get()); |
61 } | 61 } |
62 | 62 |
63 AudioOutputController::~AudioOutputController() { | 63 AudioOutputController::~AudioOutputController() { |
64 DCHECK_EQ(kClosed, state_); | 64 DCHECK_EQ(kClosed, state_); |
65 // TODO(dalecurtis): Remove debugging for http://crbug.com/349651 | |
66 CHECK(base::AtomicRefCountIsZero(¤tly_in_on_more_io_data_)); | |
acolwell GONE FROM CHROMIUM
2014/03/06 20:54:10
I'm a little unclear why we need this. Who owns th
DaleCurtis
2014/03/06 21:21:11
See audio_io.h and the AudioSourceCallback interfa
| |
65 } | 67 } |
66 | 68 |
67 // static | 69 // static |
68 scoped_refptr<AudioOutputController> AudioOutputController::Create( | 70 scoped_refptr<AudioOutputController> AudioOutputController::Create( |
69 AudioManager* audio_manager, | 71 AudioManager* audio_manager, |
70 EventHandler* event_handler, | 72 EventHandler* event_handler, |
71 const AudioParameters& params, | 73 const AudioParameters& params, |
72 const std::string& output_device_id, | 74 const std::string& output_device_id, |
73 SyncReader* sync_reader) { | 75 SyncReader* sync_reader) { |
74 DCHECK(audio_manager); | 76 DCHECK(audio_manager); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
184 #if defined(AUDIO_POWER_MONITORING) | 186 #if defined(AUDIO_POWER_MONITORING) |
185 power_monitor_.Reset(); | 187 power_monitor_.Reset(); |
186 power_poll_callback_.Reset( | 188 power_poll_callback_.Reset( |
187 base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically, | 189 base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically, |
188 this)); | 190 this)); |
189 // Run the callback to send an initial notification that we're starting in | 191 // Run the callback to send an initial notification that we're starting in |
190 // silence, and to schedule periodic callbacks. | 192 // silence, and to schedule periodic callbacks. |
191 power_poll_callback_.callback().Run(); | 193 power_poll_callback_.callback().Run(); |
192 #endif | 194 #endif |
193 | 195 |
194 on_more_io_data_called_ = 0; | |
195 AllowEntryToOnMoreIOData(); | |
196 stream_->Start(this); | 196 stream_->Start(this); |
197 | 197 |
198 // For UMA tracking purposes, start the wedge detection timer. This allows us | 198 // For UMA tracking purposes, start the wedge detection timer. This allows us |
199 // to record statistics about the number of wedged playbacks in the field. | 199 // to record statistics about the number of wedged playbacks in the field. |
200 // | 200 // |
201 // WedgeCheck() will look to see if |on_more_io_data_called_| is true after | 201 // WedgeCheck() will look to see if |on_more_io_data_called_| is true after |
202 // the timeout expires. Care must be taken to ensure the wedge check delay is | 202 // the timeout expires. Care must be taken to ensure the wedge check delay is |
203 // large enough that the value isn't queried while OnMoreDataIO() is setting | 203 // large enough that the value isn't queried while OnMoreDataIO() is setting |
204 // it. | 204 // it. |
205 // | 205 // |
(...skipping 19 matching lines...) Expand all Loading... | |
225 TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond); | 225 TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond); |
226 } | 226 } |
227 #endif | 227 #endif |
228 | 228 |
229 void AudioOutputController::StopStream() { | 229 void AudioOutputController::StopStream() { |
230 DCHECK(message_loop_->BelongsToCurrentThread()); | 230 DCHECK(message_loop_->BelongsToCurrentThread()); |
231 | 231 |
232 if (state_ == kPlaying) { | 232 if (state_ == kPlaying) { |
233 wedge_timer_.reset(); | 233 wedge_timer_.reset(); |
234 stream_->Stop(); | 234 stream_->Stop(); |
235 DisallowEntryToOnMoreIOData(); | |
236 | 235 |
237 #if defined(AUDIO_POWER_MONITORING) | 236 #if defined(AUDIO_POWER_MONITORING) |
238 power_poll_callback_.Cancel(); | 237 power_poll_callback_.Cancel(); |
239 #endif | 238 #endif |
240 | 239 |
241 state_ = kPaused; | 240 state_ = kPaused; |
242 } | 241 } |
243 } | 242 } |
244 | 243 |
245 void AudioOutputController::DoPause() { | 244 void AudioOutputController::DoPause() { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
327 } | 326 } |
328 | 327 |
329 int AudioOutputController::OnMoreData(AudioBus* dest, | 328 int AudioOutputController::OnMoreData(AudioBus* dest, |
330 AudioBuffersState buffers_state) { | 329 AudioBuffersState buffers_state) { |
331 return OnMoreIOData(NULL, dest, buffers_state); | 330 return OnMoreIOData(NULL, dest, buffers_state); |
332 } | 331 } |
333 | 332 |
334 int AudioOutputController::OnMoreIOData(AudioBus* source, | 333 int AudioOutputController::OnMoreIOData(AudioBus* source, |
335 AudioBus* dest, | 334 AudioBus* dest, |
336 AudioBuffersState buffers_state) { | 335 AudioBuffersState buffers_state) { |
337 DisallowEntryToOnMoreIOData(); | 336 base::AtomicRefCountInc(¤tly_in_on_more_io_data_); |
acolwell GONE FROM CHROMIUM
2014/03/06 20:54:10
If you make the initial value 1 and dec instead of
DaleCurtis
2014/03/06 21:21:11
Done.
| |
338 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); | 337 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); |
339 | 338 |
340 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() | 339 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() |
341 // may have already fired if OnMoreIOData() took an abnormal amount of time). | 340 // may have already fired if OnMoreIOData() took an abnormal amount of time). |
342 // Since this thread is the only writer of |on_more_io_data_called_| once the | 341 // Since this thread is the only writer of |on_more_io_data_called_| once the |
343 // thread starts, its safe to compare and then increment. | 342 // thread starts, its safe to compare and then increment. |
344 if (base::AtomicRefCountIsZero(&on_more_io_data_called_)) | 343 if (base::AtomicRefCountIsZero(&on_more_io_data_called_)) |
345 base::AtomicRefCountInc(&on_more_io_data_called_); | 344 base::AtomicRefCountInc(&on_more_io_data_called_); |
346 | 345 |
347 sync_reader_->Read(source, dest); | 346 sync_reader_->Read(source, dest); |
348 | 347 |
349 const int frames = dest->frames(); | 348 const int frames = dest->frames(); |
350 sync_reader_->UpdatePendingBytes( | 349 sync_reader_->UpdatePendingBytes( |
351 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); | 350 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); |
352 | 351 |
353 #if defined(AUDIO_POWER_MONITORING) | 352 #if defined(AUDIO_POWER_MONITORING) |
354 power_monitor_.Scan(*dest, frames); | 353 power_monitor_.Scan(*dest, frames); |
355 #endif | 354 #endif |
356 | 355 |
357 AllowEntryToOnMoreIOData(); | 356 CHECK(!base::AtomicRefCountDec(¤tly_in_on_more_io_data_)); |
358 return frames; | 357 return frames; |
359 } | 358 } |
360 | 359 |
361 void AudioOutputController::OnError(AudioOutputStream* stream) { | 360 void AudioOutputController::OnError(AudioOutputStream* stream) { |
362 // Handle error on the audio controller thread. | 361 // Handle error on the audio controller thread. |
363 message_loop_->PostTask(FROM_HERE, base::Bind( | 362 message_loop_->PostTask(FROM_HERE, base::Bind( |
364 &AudioOutputController::DoReportError, this)); | 363 &AudioOutputController::DoReportError, this)); |
365 } | 364 } |
366 | 365 |
367 void AudioOutputController::DoStopCloseAndClearStream() { | 366 void AudioOutputController::DoStopCloseAndClearStream() { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
449 if (state_ == kClosed) | 448 if (state_ == kClosed) |
450 return; | 449 return; |
451 | 450 |
452 // Note: OnDeviceChange() will cause the existing stream (the consumer of the | 451 // Note: OnDeviceChange() will cause the existing stream (the consumer of the |
453 // diverted audio data) to be closed, and diverting_to_stream_ will be set | 452 // diverted audio data) to be closed, and diverting_to_stream_ will be set |
454 // back to NULL. | 453 // back to NULL. |
455 OnDeviceChange(); | 454 OnDeviceChange(); |
456 DCHECK(!diverting_to_stream_); | 455 DCHECK(!diverting_to_stream_); |
457 } | 456 } |
458 | 457 |
459 void AudioOutputController::AllowEntryToOnMoreIOData() { | |
460 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); | |
461 base::AtomicRefCountInc(&num_allowed_io_); | |
462 } | |
463 | |
464 void AudioOutputController::DisallowEntryToOnMoreIOData() { | |
465 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); | |
466 DCHECK(is_zero); | |
467 } | |
468 | |
469 void AudioOutputController::WedgeCheck() { | 458 void AudioOutputController::WedgeCheck() { |
470 DCHECK(message_loop_->BelongsToCurrentThread()); | 459 DCHECK(message_loop_->BelongsToCurrentThread()); |
471 | 460 |
472 // If we should be playing and we haven't, that's a wedge. | 461 // If we should be playing and we haven't, that's a wedge. |
473 if (state_ == kPlaying) { | 462 if (state_ == kPlaying) { |
474 const bool playback_success = | 463 const bool playback_success = |
475 base::AtomicRefCountIsOne(&on_more_io_data_called_); | 464 base::AtomicRefCountIsOne(&on_more_io_data_called_); |
476 | 465 |
477 UMA_HISTOGRAM_BOOLEAN( | 466 UMA_HISTOGRAM_BOOLEAN( |
478 "Media.AudioOutputControllerPlaybackStartupSuccess", playback_success); | 467 "Media.AudioOutputControllerPlaybackStartupSuccess", playback_success); |
479 | 468 |
480 // Let the AudioManager try and fix it. | 469 // Let the AudioManager try and fix it. |
481 if (!playback_success) | 470 if (!playback_success) |
482 audio_manager_->FixWedgedAudio(); | 471 audio_manager_->FixWedgedAudio(); |
483 } | 472 } |
484 } | 473 } |
485 | 474 |
486 } // namespace media | 475 } // namespace media |
OLD | NEW |