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