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/message_loop/message_loop.h"
10 #include "base/metrics/histogram.h"
11 #include "base/threading/platform_thread.h"
12 #include "base/time/time.h"
13 #include "build/build_config.h"
14 #include "media/audio/audio_util.h"
15 #include "media/audio/shared_memory_util.h"
16 #include "media/base/scoped_histogram_timer.h"
19 using base::TimeDelta
;
23 // Time constant for AudioPowerMonitor. See AudioPowerMonitor ctor comments for
24 // semantics. This value was arbitrarily chosen, but seems to work well.
25 static const int kPowerMeasurementTimeConstantMillis
= 10;
27 // Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting
28 // power levels in the audio signal.
29 static const int kPowerMeasurementsPerSecond
= 30;
31 // Polling-related constants.
32 const int AudioOutputController::kPollNumAttempts
= 3;
33 const int AudioOutputController::kPollPauseInMilliseconds
= 3;
35 AudioOutputController::AudioOutputController(AudioManager
* audio_manager
,
36 EventHandler
* handler
,
37 const AudioParameters
& params
,
38 const std::string
& input_device_id
,
39 SyncReader
* sync_reader
)
40 : audio_manager_(audio_manager
),
43 input_device_id_(input_device_id
),
45 diverting_to_stream_(NULL
),
49 sync_reader_(sync_reader
),
50 message_loop_(audio_manager
->GetMessageLoop()),
51 number_polling_attempts_left_(0),
54 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis
)) {
55 DCHECK(audio_manager
);
58 DCHECK(message_loop_
.get());
61 AudioOutputController::~AudioOutputController() {
62 DCHECK_EQ(kClosed
, state_
);
66 scoped_refptr
<AudioOutputController
> AudioOutputController::Create(
67 AudioManager
* audio_manager
,
68 EventHandler
* event_handler
,
69 const AudioParameters
& params
,
70 const std::string
& input_device_id
,
71 SyncReader
* sync_reader
) {
72 DCHECK(audio_manager
);
75 if (!params
.IsValid() || !audio_manager
)
78 scoped_refptr
<AudioOutputController
> controller(new AudioOutputController(
79 audio_manager
, event_handler
, params
, input_device_id
, sync_reader
));
80 controller
->message_loop_
->PostTask(FROM_HERE
, base::Bind(
81 &AudioOutputController::DoCreate
, controller
, false));
85 void AudioOutputController::Play() {
86 message_loop_
->PostTask(FROM_HERE
, base::Bind(
87 &AudioOutputController::DoPlay
, this));
90 void AudioOutputController::Pause() {
91 message_loop_
->PostTask(FROM_HERE
, base::Bind(
92 &AudioOutputController::DoPause
, this));
95 void AudioOutputController::Close(const base::Closure
& closed_task
) {
96 DCHECK(!closed_task
.is_null());
97 message_loop_
->PostTaskAndReply(FROM_HERE
, base::Bind(
98 &AudioOutputController::DoClose
, this), closed_task
);
101 void AudioOutputController::SetVolume(double volume
) {
102 message_loop_
->PostTask(FROM_HERE
, base::Bind(
103 &AudioOutputController::DoSetVolume
, this, volume
));
106 void AudioOutputController::DoCreate(bool is_for_device_change
) {
107 DCHECK(message_loop_
->BelongsToCurrentThread());
108 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
110 // Close() can be called before DoCreate() is executed.
111 if (state_
== kClosed
)
114 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener().
115 DCHECK_EQ(kEmpty
, state_
);
117 stream_
= diverting_to_stream_
? diverting_to_stream_
:
118 audio_manager_
->MakeAudioOutputStreamProxy(params_
, input_device_id_
);
125 if (!stream_
->Open()) {
126 DoStopCloseAndClearStream();
132 // Everything started okay, so re-register for state change callbacks if
133 // stream_ was created via AudioManager.
134 if (stream_
!= diverting_to_stream_
)
135 audio_manager_
->AddOutputDeviceChangeListener(this);
137 // We have successfully opened the stream. Set the initial volume.
138 stream_
->SetVolume(volume_
);
140 // Finally set the state to kCreated.
143 // And then report we have been created if we haven't done so already.
144 if (!is_for_device_change
)
145 handler_
->OnCreated();
148 void AudioOutputController::DoPlay() {
149 DCHECK(message_loop_
->BelongsToCurrentThread());
150 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
152 // We can start from created or paused state.
153 if (state_
!= kCreated
&& state_
!= kPaused
)
156 // Ask for first packet.
157 sync_reader_
->UpdatePendingBytes(0);
161 power_monitor_
.Reset();
162 power_poll_callback_
.Reset(
163 base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically
,
165 // Run the callback to send an initial notification that we're starting in
166 // silence, and to schedule periodic callbacks.
167 power_poll_callback_
.callback().Run();
169 // We start the AudioOutputStream lazily.
170 AllowEntryToOnMoreIOData();
171 stream_
->Start(this);
173 handler_
->OnPlaying();
176 void AudioOutputController::ReportPowerMeasurementPeriodically() {
177 DCHECK(message_loop_
->BelongsToCurrentThread());
178 const std::pair
<float, bool>& reading
=
179 power_monitor_
.ReadCurrentPowerAndClip();
180 handler_
->OnPowerMeasured(reading
.first
, reading
.second
);
181 message_loop_
->PostDelayedTask(
182 FROM_HERE
, power_poll_callback_
.callback(),
183 TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond
);
186 void AudioOutputController::StopStream() {
187 DCHECK(message_loop_
->BelongsToCurrentThread());
189 if (state_
== kPlaying
) {
191 DisallowEntryToOnMoreIOData();
193 power_poll_callback_
.Cancel();
199 void AudioOutputController::DoPause() {
200 DCHECK(message_loop_
->BelongsToCurrentThread());
201 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
205 if (state_
!= kPaused
)
208 // Send a special pause mark to the low-latency audio thread.
209 sync_reader_
->UpdatePendingBytes(kPauseMark
);
211 // Paused means silence follows.
212 handler_
->OnPowerMeasured(AudioPowerMonitor::zero_power(), false);
214 handler_
->OnPaused();
217 void AudioOutputController::DoClose() {
218 DCHECK(message_loop_
->BelongsToCurrentThread());
219 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
221 if (state_
!= kClosed
) {
222 DoStopCloseAndClearStream();
223 sync_reader_
->Close();
228 void AudioOutputController::DoSetVolume(double volume
) {
229 DCHECK(message_loop_
->BelongsToCurrentThread());
231 // Saves the volume to a member first. We may not be able to set the volume
232 // right away but when the stream is created we'll set the volume.
239 stream_
->SetVolume(volume_
);
246 void AudioOutputController::DoReportError() {
247 DCHECK(message_loop_
->BelongsToCurrentThread());
248 if (state_
!= kClosed
)
252 int AudioOutputController::OnMoreData(AudioBus
* dest
,
253 AudioBuffersState buffers_state
) {
254 return OnMoreIOData(NULL
, dest
, buffers_state
);
257 int AudioOutputController::OnMoreIOData(AudioBus
* source
,
259 AudioBuffersState buffers_state
) {
260 DisallowEntryToOnMoreIOData();
261 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
263 // The OS level audio APIs on Linux and Windows all have problems requesting
264 // data on a fixed interval. Sometimes they will issue calls back to back
265 // which can cause glitching, so wait until the renderer is ready.
267 // We also need to wait when diverting since the virtual stream will call this
268 // multiple times without waiting.
270 // NEVER wait on OSX unless a virtual stream is connected, otherwise we can
271 // end up hanging the entire OS.
273 // See many bugs for context behind this decision: http://crbug.com/170498,
274 // http://crbug.com/171651, http://crbug.com/174985, and more.
275 #if defined(OS_WIN) || defined(OS_LINUX)
276 const bool kShouldBlock
= true;
278 const bool kShouldBlock
= diverting_to_stream_
!= NULL
;
281 const int frames
= sync_reader_
->Read(kShouldBlock
, source
, dest
);
282 DCHECK_LE(0, frames
);
283 sync_reader_
->UpdatePendingBytes(
284 buffers_state
.total_bytes() + frames
* params_
.GetBytesPerFrame());
286 power_monitor_
.Scan(*dest
, frames
);
288 AllowEntryToOnMoreIOData();
292 void AudioOutputController::OnError(AudioOutputStream
* stream
) {
293 // Handle error on the audio controller thread.
294 message_loop_
->PostTask(FROM_HERE
, base::Bind(
295 &AudioOutputController::DoReportError
, this));
298 void AudioOutputController::DoStopCloseAndClearStream() {
299 DCHECK(message_loop_
->BelongsToCurrentThread());
301 // Allow calling unconditionally and bail if we don't have a stream_ to close.
303 // De-register from state change callbacks if stream_ was created via
305 if (stream_
!= diverting_to_stream_
)
306 audio_manager_
->RemoveOutputDeviceChangeListener(this);
310 if (stream_
== diverting_to_stream_
)
311 diverting_to_stream_
= NULL
;
318 void AudioOutputController::OnDeviceChange() {
319 DCHECK(message_loop_
->BelongsToCurrentThread());
320 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
322 // TODO(dalecurtis): Notify the renderer side that a device change has
323 // occurred. Currently querying the hardware information here will lead to
324 // crashes on OSX. See http://crbug.com/158170.
326 // Recreate the stream (DoCreate() will first shut down an existing stream).
327 // Exit if we ran into an error.
328 const State original_state
= state_
;
330 if (!stream_
|| state_
== kError
)
333 // Get us back to the original state or an equivalent state.
334 switch (original_state
) {
340 // From the outside these two states are equivalent.
343 NOTREACHED() << "Invalid original state.";
347 const AudioParameters
& AudioOutputController::GetAudioParameters() {
351 void AudioOutputController::StartDiverting(AudioOutputStream
* to_stream
) {
352 message_loop_
->PostTask(
354 base::Bind(&AudioOutputController::DoStartDiverting
, this, to_stream
));
357 void AudioOutputController::StopDiverting() {
358 message_loop_
->PostTask(
359 FROM_HERE
, base::Bind(&AudioOutputController::DoStopDiverting
, this));
362 void AudioOutputController::DoStartDiverting(AudioOutputStream
* to_stream
) {
363 DCHECK(message_loop_
->BelongsToCurrentThread());
365 if (state_
== kClosed
)
368 DCHECK(!diverting_to_stream_
);
369 diverting_to_stream_
= to_stream
;
370 // Note: OnDeviceChange() will engage the "re-create" process, which will
371 // detect and use the alternate AudioOutputStream rather than create a new one
376 void AudioOutputController::DoStopDiverting() {
377 DCHECK(message_loop_
->BelongsToCurrentThread());
379 if (state_
== kClosed
)
382 // Note: OnDeviceChange() will cause the existing stream (the consumer of the
383 // diverted audio data) to be closed, and diverting_to_stream_ will be set
386 DCHECK(!diverting_to_stream_
);
389 void AudioOutputController::AllowEntryToOnMoreIOData() {
390 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_
));
391 base::AtomicRefCountInc(&num_allowed_io_
);
394 void AudioOutputController::DisallowEntryToOnMoreIOData() {
395 const bool is_zero
= !base::AtomicRefCountDec(&num_allowed_io_
);