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.
5 #include "media/audio/audio_output_controller.h"
8 #include "base/debug/trace_event.h"
9 #include "base/metrics/histogram.h"
10 #include "base/task_runner_util.h"
11 #include "base/threading/platform_thread.h"
12 #include "base/time/time.h"
13 #include "build/build_config.h"
14 #include "media/base/scoped_histogram_timer.h"
16 using base::TimeDelta;
20 #if defined(AUDIO_POWER_MONITORING)
21 // Time constant for AudioPowerMonitor. See AudioPowerMonitor ctor comments for
22 // semantics. This value was arbitrarily chosen, but seems to work well.
23 static const int kPowerMeasurementTimeConstantMillis = 10;
25 // Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting
26 // power levels in the audio signal.
27 static const int kPowerMeasurementsPerSecond = 4;
30 // Polling-related constants.
31 const int AudioOutputController::kPollNumAttempts = 3;
32 const int AudioOutputController::kPollPauseInMilliseconds = 3;
34 AudioOutputController::AudioOutputController(
35 AudioManager* audio_manager,
36 EventHandler* handler,
37 const AudioParameters& params,
38 const std::string& output_device_id,
39 const std::string& input_device_id,
40 SyncReader* sync_reader)
41 : audio_manager_(audio_manager),
44 output_device_id_(output_device_id),
45 input_device_id_(input_device_id),
47 diverting_to_stream_(NULL),
51 sync_reader_(sync_reader),
52 message_loop_(audio_manager->GetTaskRunner()),
53 #if defined(AUDIO_POWER_MONITORING)
56 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
58 on_more_io_data_called_(0) {
59 DCHECK(audio_manager);
62 DCHECK(message_loop_.get());
65 AudioOutputController::~AudioOutputController() {
66 DCHECK_EQ(kClosed, state_);
70 scoped_refptr<AudioOutputController> AudioOutputController::Create(
71 AudioManager* audio_manager,
72 EventHandler* event_handler,
73 const AudioParameters& params,
74 const std::string& output_device_id,
75 const std::string& input_device_id,
76 SyncReader* sync_reader) {
77 DCHECK(audio_manager);
80 if (!params.IsValid() || !audio_manager)
83 scoped_refptr<AudioOutputController> controller(new AudioOutputController(
84 audio_manager, event_handler, params, output_device_id, input_device_id,
86 controller->message_loop_->PostTask(FROM_HERE, base::Bind(
87 &AudioOutputController::DoCreate, controller, false));
91 void AudioOutputController::Play() {
92 message_loop_->PostTask(FROM_HERE, base::Bind(
93 &AudioOutputController::DoPlay, this));
96 void AudioOutputController::Pause() {
97 message_loop_->PostTask(FROM_HERE, base::Bind(
98 &AudioOutputController::DoPause, this));
101 void AudioOutputController::Close(const base::Closure& closed_task) {
102 DCHECK(!closed_task.is_null());
103 message_loop_->PostTaskAndReply(FROM_HERE, base::Bind(
104 &AudioOutputController::DoClose, this), closed_task);
107 void AudioOutputController::SetVolume(double volume) {
108 message_loop_->PostTask(FROM_HERE, base::Bind(
109 &AudioOutputController::DoSetVolume, this, volume));
112 void AudioOutputController::GetOutputDeviceId(
113 base::Callback<void(const std::string&)> callback) const {
114 base::PostTaskAndReplyWithResult(
117 base::Bind(&AudioOutputController::DoGetOutputDeviceId, this),
121 void AudioOutputController::SwitchOutputDevice(
122 const std::string& output_device_id, const base::Closure& callback) {
123 message_loop_->PostTaskAndReply(
125 base::Bind(&AudioOutputController::DoSwitchOutputDevice, this,
130 void AudioOutputController::DoCreate(bool is_for_device_change) {
131 DCHECK(message_loop_->BelongsToCurrentThread());
132 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
133 TRACE_EVENT0("audio", "AudioOutputController::DoCreate");
135 // Close() can be called before DoCreate() is executed.
136 if (state_ == kClosed)
139 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener().
140 DCHECK_EQ(kEmpty, state_);
142 stream_ = diverting_to_stream_ ?
143 diverting_to_stream_ :
144 audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_,
152 if (!stream_->Open()) {
153 DoStopCloseAndClearStream();
159 // Everything started okay, so re-register for state change callbacks if
160 // stream_ was created via AudioManager.
161 if (stream_ != diverting_to_stream_)
162 audio_manager_->AddOutputDeviceChangeListener(this);
164 // We have successfully opened the stream. Set the initial volume.
165 stream_->SetVolume(volume_);
167 // Finally set the state to kCreated.
170 // And then report we have been created if we haven't done so already.
171 if (!is_for_device_change)
172 handler_->OnCreated();
175 void AudioOutputController::DoPlay() {
176 DCHECK(message_loop_->BelongsToCurrentThread());
177 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
178 TRACE_EVENT0("audio", "AudioOutputController::DoPlay");
180 // We can start from created or paused state.
181 if (state_ != kCreated && state_ != kPaused)
184 // Ask for first packet.
185 sync_reader_->UpdatePendingBytes(0);
189 #if defined(AUDIO_POWER_MONITORING)
190 power_monitor_.Reset();
191 power_poll_callback_.Reset(
192 base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically,
194 // Run the callback to send an initial notification that we're starting in
195 // silence, and to schedule periodic callbacks.
196 power_poll_callback_.callback().Run();
199 on_more_io_data_called_ = 0;
200 AllowEntryToOnMoreIOData();
201 stream_->Start(this);
203 // For UMA tracking purposes, start the wedge detection timer. This allows us
204 // to record statistics about the number of wedged playbacks in the field.
206 // WedgeCheck() will look to see if |on_more_io_data_called_| is true after
207 // the timeout expires. Care must be taken to ensure the wedge check delay is
208 // large enough that the value isn't queried while OnMoreDataIO() is setting
211 // Timer self-manages its lifetime and WedgeCheck() will only record the UMA
212 // statistic if state is still kPlaying. Additional Start() calls will
213 // invalidate the previous timer.
214 wedge_timer_.reset(new base::OneShotTimer<AudioOutputController>());
216 FROM_HERE, TimeDelta::FromSeconds(5), this,
217 &AudioOutputController::WedgeCheck);
219 handler_->OnPlaying();
222 #if defined(AUDIO_POWER_MONITORING)
223 void AudioOutputController::ReportPowerMeasurementPeriodically() {
224 DCHECK(message_loop_->BelongsToCurrentThread());
225 const std::pair<float, bool>& reading =
226 power_monitor_.ReadCurrentPowerAndClip();
227 handler_->OnPowerMeasured(reading.first, reading.second);
228 message_loop_->PostDelayedTask(
229 FROM_HERE, power_poll_callback_.callback(),
230 TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond);
234 void AudioOutputController::StopStream() {
235 DCHECK(message_loop_->BelongsToCurrentThread());
237 if (state_ == kPlaying) {
238 wedge_timer_.reset();
240 DisallowEntryToOnMoreIOData();
242 #if defined(AUDIO_POWER_MONITORING)
243 power_poll_callback_.Cancel();
250 void AudioOutputController::DoPause() {
251 DCHECK(message_loop_->BelongsToCurrentThread());
252 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
253 TRACE_EVENT0("audio", "AudioOutputController::DoPause");
257 if (state_ != kPaused)
260 // Let the renderer know we've stopped. Necessary to let PPAPI clients know
261 // audio has been shutdown. TODO(dalecurtis): This stinks. PPAPI should have
262 // a better way to know when it should exit PPB_Audio_Shared::Run().
263 sync_reader_->UpdatePendingBytes(-1);
265 #if defined(AUDIO_POWER_MONITORING)
266 // Paused means silence follows.
267 handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false);
270 handler_->OnPaused();
273 void AudioOutputController::DoClose() {
274 DCHECK(message_loop_->BelongsToCurrentThread());
275 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
276 TRACE_EVENT0("audio", "AudioOutputController::DoClose");
278 if (state_ != kClosed) {
279 DoStopCloseAndClearStream();
280 sync_reader_->Close();
285 void AudioOutputController::DoSetVolume(double volume) {
286 DCHECK(message_loop_->BelongsToCurrentThread());
288 // Saves the volume to a member first. We may not be able to set the volume
289 // right away but when the stream is created we'll set the volume.
296 stream_->SetVolume(volume_);
303 std::string AudioOutputController::DoGetOutputDeviceId() const {
304 DCHECK(message_loop_->BelongsToCurrentThread());
305 return output_device_id_;
308 void AudioOutputController::DoSwitchOutputDevice(
309 const std::string& output_device_id) {
310 DCHECK(message_loop_->BelongsToCurrentThread());
312 if (state_ == kClosed)
315 if (output_device_id == output_device_id_)
318 output_device_id_ = output_device_id;
320 // If output is currently diverted, we must not call OnDeviceChange
321 // since it would break the diverted setup. Once diversion is
322 // finished using StopDiverting() the output will switch to the new
324 if (stream_ != diverting_to_stream_)
328 void AudioOutputController::DoReportError() {
329 DCHECK(message_loop_->BelongsToCurrentThread());
330 if (state_ != kClosed)
334 int AudioOutputController::OnMoreData(AudioBus* dest,
335 AudioBuffersState buffers_state) {
336 return OnMoreIOData(NULL, dest, buffers_state);
339 int AudioOutputController::OnMoreIOData(AudioBus* source,
341 AudioBuffersState buffers_state) {
342 DisallowEntryToOnMoreIOData();
343 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
345 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
346 // may have already fired if OnMoreIOData() took an abnormal amount of time).
347 // Since this thread is the only writer of |on_more_io_data_called_| once the
348 // thread starts, its safe to compare and then increment.
349 if (base::AtomicRefCountIsZero(&on_more_io_data_called_))
350 base::AtomicRefCountInc(&on_more_io_data_called_);
352 sync_reader_->Read(source, dest);
354 const int frames = dest->frames();
355 sync_reader_->UpdatePendingBytes(
356 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
358 #if defined(AUDIO_POWER_MONITORING)
359 power_monitor_.Scan(*dest, frames);
362 AllowEntryToOnMoreIOData();
366 void AudioOutputController::OnError(AudioOutputStream* stream) {
367 // Handle error on the audio controller thread.
368 message_loop_->PostTask(FROM_HERE, base::Bind(
369 &AudioOutputController::DoReportError, this));
372 void AudioOutputController::DoStopCloseAndClearStream() {
373 DCHECK(message_loop_->BelongsToCurrentThread());
375 // Allow calling unconditionally and bail if we don't have a stream_ to close.
377 // De-register from state change callbacks if stream_ was created via
379 if (stream_ != diverting_to_stream_)
380 audio_manager_->RemoveOutputDeviceChangeListener(this);
384 if (stream_ == diverting_to_stream_)
385 diverting_to_stream_ = NULL;
392 void AudioOutputController::OnDeviceChange() {
393 DCHECK(message_loop_->BelongsToCurrentThread());
394 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
395 TRACE_EVENT0("audio", "AudioOutputController::OnDeviceChange");
397 // TODO(dalecurtis): Notify the renderer side that a device change has
398 // occurred. Currently querying the hardware information here will lead to
399 // crashes on OSX. See http://crbug.com/158170.
401 // Recreate the stream (DoCreate() will first shut down an existing stream).
402 // Exit if we ran into an error.
403 const State original_state = state_;
405 if (!stream_ || state_ == kError)
408 // Get us back to the original state or an equivalent state.
409 switch (original_state) {
415 // From the outside these two states are equivalent.
418 NOTREACHED() << "Invalid original state.";
422 const AudioParameters& AudioOutputController::GetAudioParameters() {
426 void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
427 message_loop_->PostTask(
429 base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream));
432 void AudioOutputController::StopDiverting() {
433 message_loop_->PostTask(
434 FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
437 void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
438 DCHECK(message_loop_->BelongsToCurrentThread());
440 if (state_ == kClosed)
443 DCHECK(!diverting_to_stream_);
444 diverting_to_stream_ = to_stream;
445 // Note: OnDeviceChange() will engage the "re-create" process, which will
446 // detect and use the alternate AudioOutputStream rather than create a new one
451 void AudioOutputController::DoStopDiverting() {
452 DCHECK(message_loop_->BelongsToCurrentThread());
454 if (state_ == kClosed)
457 // Note: OnDeviceChange() will cause the existing stream (the consumer of the
458 // diverted audio data) to be closed, and diverting_to_stream_ will be set
461 DCHECK(!diverting_to_stream_);
464 void AudioOutputController::AllowEntryToOnMoreIOData() {
465 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
466 base::AtomicRefCountInc(&num_allowed_io_);
469 void AudioOutputController::DisallowEntryToOnMoreIOData() {
470 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
474 void AudioOutputController::WedgeCheck() {
475 DCHECK(message_loop_->BelongsToCurrentThread());
477 // If we should be playing and we haven't, that's a wedge.
478 if (state_ == kPlaying) {
479 const bool playback_success =
480 base::AtomicRefCountIsOne(&on_more_io_data_called_);
482 UMA_HISTOGRAM_BOOLEAN(
483 "Media.AudioOutputControllerPlaybackStartupSuccess", playback_success);
485 // Let the AudioManager try and fix it.
486 if (!playback_success)
487 audio_manager_->FixWedgedAudio();