audio_output_controller.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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.
4
5#include "media/audio/audio_output_controller.h"
6
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/shared_memory_util.h"
15#include "media/base/scoped_histogram_timer.h"
16
17using base::Time;
18using base::TimeDelta;
19
20namespace media {
21
22#if defined(AUDIO_POWER_MONITORING)
23// Time constant for AudioPowerMonitor.  See AudioPowerMonitor ctor comments for
24// semantics.  This value was arbitrarily chosen, but seems to work well.
25static const int kPowerMeasurementTimeConstantMillis = 10;
26
27// Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting
28// power levels in the audio signal.
29static const int kPowerMeasurementsPerSecond = 4;
30#endif
31
32// Polling-related constants.
33const int AudioOutputController::kPollNumAttempts = 3;
34const int AudioOutputController::kPollPauseInMilliseconds = 3;
35
36AudioOutputController::AudioOutputController(
37    AudioManager* audio_manager,
38    EventHandler* handler,
39    const AudioParameters& params,
40    const std::string& output_device_id,
41    const std::string& input_device_id,
42    SyncReader* sync_reader)
43    : audio_manager_(audio_manager),
44      params_(params),
45      handler_(handler),
46      output_device_id_(output_device_id),
47      input_device_id_(input_device_id),
48      stream_(NULL),
49      diverting_to_stream_(NULL),
50      volume_(1.0),
51      state_(kEmpty),
52      num_allowed_io_(0),
53      sync_reader_(sync_reader),
54      message_loop_(audio_manager->GetMessageLoop()),
55#if defined(AUDIO_POWER_MONITORING)
56      power_monitor_(
57          params.sample_rate(),
58          TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
59#endif
60      number_polling_attempts_left_(0) {
61  DCHECK(audio_manager);
62  DCHECK(handler_);
63  DCHECK(sync_reader_);
64  DCHECK(message_loop_.get());
65}
66
67AudioOutputController::~AudioOutputController() {
68  DCHECK_EQ(kClosed, state_);
69}
70
71// static
72scoped_refptr<AudioOutputController> AudioOutputController::Create(
73    AudioManager* audio_manager,
74    EventHandler* event_handler,
75    const AudioParameters& params,
76    const std::string& output_device_id,
77    const std::string& input_device_id,
78    SyncReader* sync_reader) {
79  DCHECK(audio_manager);
80  DCHECK(sync_reader);
81
82  if (!params.IsValid() || !audio_manager)
83    return NULL;
84
85  scoped_refptr<AudioOutputController> controller(new AudioOutputController(
86      audio_manager, event_handler, params, output_device_id, input_device_id,
87      sync_reader));
88  controller->message_loop_->PostTask(FROM_HERE, base::Bind(
89      &AudioOutputController::DoCreate, controller, false));
90  return controller;
91}
92
93void AudioOutputController::Play() {
94  message_loop_->PostTask(FROM_HERE, base::Bind(
95      &AudioOutputController::DoPlay, this));
96}
97
98void AudioOutputController::Pause() {
99  message_loop_->PostTask(FROM_HERE, base::Bind(
100      &AudioOutputController::DoPause, this));
101}
102
103void AudioOutputController::Close(const base::Closure& closed_task) {
104  DCHECK(!closed_task.is_null());
105  message_loop_->PostTaskAndReply(FROM_HERE, base::Bind(
106      &AudioOutputController::DoClose, this), closed_task);
107}
108
109void AudioOutputController::SetVolume(double volume) {
110  message_loop_->PostTask(FROM_HERE, base::Bind(
111      &AudioOutputController::DoSetVolume, this, volume));
112}
113
114void AudioOutputController::DoCreate(bool is_for_device_change) {
115  DCHECK(message_loop_->BelongsToCurrentThread());
116  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
117
118  // Close() can be called before DoCreate() is executed.
119  if (state_ == kClosed)
120    return;
121
122  DoStopCloseAndClearStream();  // Calls RemoveOutputDeviceChangeListener().
123  DCHECK_EQ(kEmpty, state_);
124
125  stream_ = diverting_to_stream_ ?
126      diverting_to_stream_ :
127      audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_,
128                                                 input_device_id_);
129  if (!stream_) {
130    state_ = kError;
131    handler_->OnError();
132    return;
133  }
134
135  if (!stream_->Open()) {
136    DoStopCloseAndClearStream();
137    state_ = kError;
138    handler_->OnError();
139    return;
140  }
141
142  // Everything started okay, so re-register for state change callbacks if
143  // stream_ was created via AudioManager.
144  if (stream_ != diverting_to_stream_)
145    audio_manager_->AddOutputDeviceChangeListener(this);
146
147  // We have successfully opened the stream. Set the initial volume.
148  stream_->SetVolume(volume_);
149
150  // Finally set the state to kCreated.
151  state_ = kCreated;
152
153  // And then report we have been created if we haven't done so already.
154  if (!is_for_device_change)
155    handler_->OnCreated();
156}
157
158void AudioOutputController::DoPlay() {
159  DCHECK(message_loop_->BelongsToCurrentThread());
160  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
161
162  // We can start from created or paused state.
163  if (state_ != kCreated && state_ != kPaused)
164    return;
165
166  // Ask for first packet.
167  sync_reader_->UpdatePendingBytes(0);
168
169  state_ = kPlaying;
170
171#if defined(AUDIO_POWER_MONITORING)
172  power_monitor_.Reset();
173  power_poll_callback_.Reset(
174      base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically,
175                 this));
176  // Run the callback to send an initial notification that we're starting in
177  // silence, and to schedule periodic callbacks.
178  power_poll_callback_.callback().Run();
179#endif
180
181  // We start the AudioOutputStream lazily.
182  AllowEntryToOnMoreIOData();
183  stream_->Start(this);
184
185  handler_->OnPlaying();
186}
187
188#if defined(AUDIO_POWER_MONITORING)
189void AudioOutputController::ReportPowerMeasurementPeriodically() {
190  DCHECK(message_loop_->BelongsToCurrentThread());
191  const std::pair<float, bool>& reading =
192      power_monitor_.ReadCurrentPowerAndClip();
193  handler_->OnPowerMeasured(reading.first, reading.second);
194  message_loop_->PostDelayedTask(
195      FROM_HERE, power_poll_callback_.callback(),
196      TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond);
197}
198#endif
199
200void AudioOutputController::StopStream() {
201  DCHECK(message_loop_->BelongsToCurrentThread());
202
203  if (state_ == kPlaying) {
204    stream_->Stop();
205    DisallowEntryToOnMoreIOData();
206
207#if defined(AUDIO_POWER_MONITORING)
208    power_poll_callback_.Cancel();
209#endif
210
211    state_ = kPaused;
212  }
213}
214
215void AudioOutputController::DoPause() {
216  DCHECK(message_loop_->BelongsToCurrentThread());
217  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
218
219  StopStream();
220
221  if (state_ != kPaused)
222    return;
223
224  // Send a special pause mark to the low-latency audio thread.
225  sync_reader_->UpdatePendingBytes(kPauseMark);
226
227#if defined(AUDIO_POWER_MONITORING)
228  // Paused means silence follows.
229  handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false);
230#endif
231
232  handler_->OnPaused();
233}
234
235void AudioOutputController::DoClose() {
236  DCHECK(message_loop_->BelongsToCurrentThread());
237  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
238
239  if (state_ != kClosed) {
240    DoStopCloseAndClearStream();
241    sync_reader_->Close();
242    state_ = kClosed;
243  }
244}
245
246void AudioOutputController::DoSetVolume(double volume) {
247  DCHECK(message_loop_->BelongsToCurrentThread());
248
249  // Saves the volume to a member first. We may not be able to set the volume
250  // right away but when the stream is created we'll set the volume.
251  volume_ = volume;
252
253  switch (state_) {
254    case kCreated:
255    case kPlaying:
256    case kPaused:
257      stream_->SetVolume(volume_);
258      break;
259    default:
260      return;
261  }
262}
263
264void AudioOutputController::DoReportError() {
265  DCHECK(message_loop_->BelongsToCurrentThread());
266  if (state_ != kClosed)
267    handler_->OnError();
268}
269
270int AudioOutputController::OnMoreData(AudioBus* dest,
271                                      AudioBuffersState buffers_state) {
272  return OnMoreIOData(NULL, dest, buffers_state);
273}
274
275int AudioOutputController::OnMoreIOData(AudioBus* source,
276                                        AudioBus* dest,
277                                        AudioBuffersState buffers_state) {
278  DisallowEntryToOnMoreIOData();
279  TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
280
281  // The OS level audio APIs on Linux and Windows all have problems requesting
282  // data on a fixed interval.  Sometimes they will issue calls back to back
283  // which can cause glitching, so wait until the renderer is ready.
284  //
285  // We also need to wait when diverting since the virtual stream will call this
286  // multiple times without waiting.
287  //
288  // NEVER wait on OSX unless a virtual stream is connected, otherwise we can
289  // end up hanging the entire OS.
290  //
291  // See many bugs for context behind this decision: http://crbug.com/170498,
292  // http://crbug.com/171651, http://crbug.com/174985, and more.
293#if defined(OS_WIN) || defined(OS_LINUX)
294    const bool kShouldBlock = true;
295#else
296    const bool kShouldBlock = diverting_to_stream_ != NULL;
297#endif
298
299  const int frames = sync_reader_->Read(kShouldBlock, source, dest);
300  DCHECK_LE(0, frames);
301  sync_reader_->UpdatePendingBytes(
302      buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
303
304#if defined(AUDIO_POWER_MONITORING)
305  power_monitor_.Scan(*dest, frames);
306#endif
307
308  AllowEntryToOnMoreIOData();
309  return frames;
310}
311
312void AudioOutputController::OnError(AudioOutputStream* stream) {
313  // Handle error on the audio controller thread.
314  message_loop_->PostTask(FROM_HERE, base::Bind(
315      &AudioOutputController::DoReportError, this));
316}
317
318void AudioOutputController::DoStopCloseAndClearStream() {
319  DCHECK(message_loop_->BelongsToCurrentThread());
320
321  // Allow calling unconditionally and bail if we don't have a stream_ to close.
322  if (stream_) {
323    // De-register from state change callbacks if stream_ was created via
324    // AudioManager.
325    if (stream_ != diverting_to_stream_)
326      audio_manager_->RemoveOutputDeviceChangeListener(this);
327
328    StopStream();
329    stream_->Close();
330    if (stream_ == diverting_to_stream_)
331      diverting_to_stream_ = NULL;
332    stream_ = NULL;
333  }
334
335  state_ = kEmpty;
336}
337
338void AudioOutputController::OnDeviceChange() {
339  DCHECK(message_loop_->BelongsToCurrentThread());
340  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
341
342  // TODO(dalecurtis): Notify the renderer side that a device change has
343  // occurred.  Currently querying the hardware information here will lead to
344  // crashes on OSX.  See http://crbug.com/158170.
345
346  // Recreate the stream (DoCreate() will first shut down an existing stream).
347  // Exit if we ran into an error.
348  const State original_state = state_;
349  DoCreate(true);
350  if (!stream_ || state_ == kError)
351    return;
352
353  // Get us back to the original state or an equivalent state.
354  switch (original_state) {
355    case kPlaying:
356      DoPlay();
357      return;
358    case kCreated:
359    case kPaused:
360      // From the outside these two states are equivalent.
361      return;
362    default:
363      NOTREACHED() << "Invalid original state.";
364  }
365}
366
367const AudioParameters& AudioOutputController::GetAudioParameters() {
368  return params_;
369}
370
371void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
372  message_loop_->PostTask(
373      FROM_HERE,
374      base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream));
375}
376
377void AudioOutputController::StopDiverting() {
378  message_loop_->PostTask(
379      FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
380}
381
382void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
383  DCHECK(message_loop_->BelongsToCurrentThread());
384
385  if (state_ == kClosed)
386    return;
387
388  DCHECK(!diverting_to_stream_);
389  diverting_to_stream_ = to_stream;
390  // Note: OnDeviceChange() will engage the "re-create" process, which will
391  // detect and use the alternate AudioOutputStream rather than create a new one
392  // via AudioManager.
393  OnDeviceChange();
394}
395
396void AudioOutputController::DoStopDiverting() {
397  DCHECK(message_loop_->BelongsToCurrentThread());
398
399  if (state_ == kClosed)
400    return;
401
402  // Note: OnDeviceChange() will cause the existing stream (the consumer of the
403  // diverted audio data) to be closed, and diverting_to_stream_ will be set
404  // back to NULL.
405  OnDeviceChange();
406  DCHECK(!diverting_to_stream_);
407}
408
409void AudioOutputController::AllowEntryToOnMoreIOData() {
410  DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
411  base::AtomicRefCountInc(&num_allowed_io_);
412}
413
414void AudioOutputController::DisallowEntryToOnMoreIOData() {
415  const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
416  DCHECK(is_zero);
417}
418
419}  // namespace media
420