cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / media / audio / audio_output_controller.cc
blobf7f4cf8240b79e1b539913c4d1eea618b75541be
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"
7 #include "base/bind.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"
18 using base::Time;
19 using base::TimeDelta;
21 namespace media {
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),
41 params_(params),
42 handler_(handler),
43 input_device_id_(input_device_id),
44 stream_(NULL),
45 diverting_to_stream_(NULL),
46 volume_(1.0),
47 state_(kEmpty),
48 num_allowed_io_(0),
49 sync_reader_(sync_reader),
50 message_loop_(audio_manager->GetMessageLoop()),
51 number_polling_attempts_left_(0),
52 power_monitor_(
53 params.sample_rate(),
54 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)) {
55 DCHECK(audio_manager);
56 DCHECK(handler_);
57 DCHECK(sync_reader_);
58 DCHECK(message_loop_.get());
61 AudioOutputController::~AudioOutputController() {
62 DCHECK_EQ(kClosed, state_);
65 // static
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);
73 DCHECK(sync_reader);
75 if (!params.IsValid() || !audio_manager)
76 return NULL;
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));
82 return controller;
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)
112 return;
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_);
119 if (!stream_) {
120 state_ = kError;
121 handler_->OnError();
122 return;
125 if (!stream_->Open()) {
126 DoStopCloseAndClearStream();
127 state_ = kError;
128 handler_->OnError();
129 return;
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.
141 state_ = 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)
154 return;
156 // Ask for first packet.
157 sync_reader_->UpdatePendingBytes(0);
159 state_ = kPlaying;
161 power_monitor_.Reset();
162 power_poll_callback_.Reset(
163 base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically,
164 this));
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) {
190 stream_->Stop();
191 DisallowEntryToOnMoreIOData();
193 power_poll_callback_.Cancel();
195 state_ = kPaused;
199 void AudioOutputController::DoPause() {
200 DCHECK(message_loop_->BelongsToCurrentThread());
201 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
203 StopStream();
205 if (state_ != kPaused)
206 return;
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();
224 state_ = kClosed;
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.
233 volume_ = volume;
235 switch (state_) {
236 case kCreated:
237 case kPlaying:
238 case kPaused:
239 stream_->SetVolume(volume_);
240 break;
241 default:
242 return;
246 void AudioOutputController::DoReportError() {
247 DCHECK(message_loop_->BelongsToCurrentThread());
248 if (state_ != kClosed)
249 handler_->OnError();
252 int AudioOutputController::OnMoreData(AudioBus* dest,
253 AudioBuffersState buffers_state) {
254 return OnMoreIOData(NULL, dest, buffers_state);
257 int AudioOutputController::OnMoreIOData(AudioBus* source,
258 AudioBus* dest,
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;
277 #else
278 const bool kShouldBlock = diverting_to_stream_ != NULL;
279 #endif
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();
289 return frames;
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.
302 if (stream_) {
303 // De-register from state change callbacks if stream_ was created via
304 // AudioManager.
305 if (stream_ != diverting_to_stream_)
306 audio_manager_->RemoveOutputDeviceChangeListener(this);
308 StopStream();
309 stream_->Close();
310 if (stream_ == diverting_to_stream_)
311 diverting_to_stream_ = NULL;
312 stream_ = NULL;
315 state_ = kEmpty;
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_;
329 DoCreate(true);
330 if (!stream_ || state_ == kError)
331 return;
333 // Get us back to the original state or an equivalent state.
334 switch (original_state) {
335 case kPlaying:
336 DoPlay();
337 return;
338 case kCreated:
339 case kPaused:
340 // From the outside these two states are equivalent.
341 return;
342 default:
343 NOTREACHED() << "Invalid original state.";
347 const AudioParameters& AudioOutputController::GetAudioParameters() {
348 return params_;
351 void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
352 message_loop_->PostTask(
353 FROM_HERE,
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)
366 return;
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
372 // via AudioManager.
373 OnDeviceChange();
376 void AudioOutputController::DoStopDiverting() {
377 DCHECK(message_loop_->BelongsToCurrentThread());
379 if (state_ == kClosed)
380 return;
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
384 // back to NULL.
385 OnDeviceChange();
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_);
396 DCHECK(is_zero);
399 } // namespace media