Home | History | Annotate | Download | only in audio
      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/audio_util.h"
     15 #include "media/audio/shared_memory_util.h"
     16 #include "media/base/scoped_histogram_timer.h"
     17 
     18 using base::Time;
     19 using base::TimeDelta;
     20 
     21 namespace media {
     22 
     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;
     26 
     27 // Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting
     28 // power levels in the audio signal.
     29 static const int kPowerMeasurementsPerSecond = 30;
     30 
     31 // Polling-related constants.
     32 const int AudioOutputController::kPollNumAttempts = 3;
     33 const int AudioOutputController::kPollPauseInMilliseconds = 3;
     34 
     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());
     59 }
     60 
     61 AudioOutputController::~AudioOutputController() {
     62   DCHECK_EQ(kClosed, state_);
     63 }
     64 
     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);
     74 
     75   if (!params.IsValid() || !audio_manager)
     76     return NULL;
     77 
     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;
     83 }
     84 
     85 void AudioOutputController::Play() {
     86   message_loop_->PostTask(FROM_HERE, base::Bind(
     87       &AudioOutputController::DoPlay, this));
     88 }
     89 
     90 void AudioOutputController::Pause() {
     91   message_loop_->PostTask(FROM_HERE, base::Bind(
     92       &AudioOutputController::DoPause, this));
     93 }
     94 
     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);
     99 }
    100 
    101 void AudioOutputController::SetVolume(double volume) {
    102   message_loop_->PostTask(FROM_HERE, base::Bind(
    103       &AudioOutputController::DoSetVolume, this, volume));
    104 }
    105 
    106 void AudioOutputController::DoCreate(bool is_for_device_change) {
    107   DCHECK(message_loop_->BelongsToCurrentThread());
    108   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
    109 
    110   // Close() can be called before DoCreate() is executed.
    111   if (state_ == kClosed)
    112     return;
    113 
    114   DoStopCloseAndClearStream();  // Calls RemoveOutputDeviceChangeListener().
    115   DCHECK_EQ(kEmpty, state_);
    116 
    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;
    123   }
    124 
    125   if (!stream_->Open()) {
    126     DoStopCloseAndClearStream();
    127     state_ = kError;
    128     handler_->OnError();
    129     return;
    130   }
    131 
    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);
    136 
    137   // We have successfully opened the stream. Set the initial volume.
    138   stream_->SetVolume(volume_);
    139 
    140   // Finally set the state to kCreated.
    141   state_ = kCreated;
    142 
    143   // And then report we have been created if we haven't done so already.
    144   if (!is_for_device_change)
    145     handler_->OnCreated();
    146 }
    147 
    148 void AudioOutputController::DoPlay() {
    149   DCHECK(message_loop_->BelongsToCurrentThread());
    150   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
    151 
    152   // We can start from created or paused state.
    153   if (state_ != kCreated && state_ != kPaused)
    154     return;
    155 
    156   // Ask for first packet.
    157   sync_reader_->UpdatePendingBytes(0);
    158 
    159   state_ = kPlaying;
    160 
    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();
    168 
    169   // We start the AudioOutputStream lazily.
    170   AllowEntryToOnMoreIOData();
    171   stream_->Start(this);
    172 
    173   handler_->OnPlaying();
    174 }
    175 
    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);
    184 }
    185 
    186 void AudioOutputController::StopStream() {
    187   DCHECK(message_loop_->BelongsToCurrentThread());
    188 
    189   if (state_ == kPlaying) {
    190     stream_->Stop();
    191     DisallowEntryToOnMoreIOData();
    192 
    193     power_poll_callback_.Cancel();
    194 
    195     state_ = kPaused;
    196   }
    197 }
    198 
    199 void AudioOutputController::DoPause() {
    200   DCHECK(message_loop_->BelongsToCurrentThread());
    201   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
    202 
    203   StopStream();
    204 
    205   if (state_ != kPaused)
    206     return;
    207 
    208   // Send a special pause mark to the low-latency audio thread.
    209   sync_reader_->UpdatePendingBytes(kPauseMark);
    210 
    211   // Paused means silence follows.
    212   handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false);
    213 
    214   handler_->OnPaused();
    215 }
    216 
    217 void AudioOutputController::DoClose() {
    218   DCHECK(message_loop_->BelongsToCurrentThread());
    219   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
    220 
    221   if (state_ != kClosed) {
    222     DoStopCloseAndClearStream();
    223     sync_reader_->Close();
    224     state_ = kClosed;
    225   }
    226 }
    227 
    228 void AudioOutputController::DoSetVolume(double volume) {
    229   DCHECK(message_loop_->BelongsToCurrentThread());
    230 
    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;
    234 
    235   switch (state_) {
    236     case kCreated:
    237     case kPlaying:
    238     case kPaused:
    239       stream_->SetVolume(volume_);
    240       break;
    241     default:
    242       return;
    243   }
    244 }
    245 
    246 void AudioOutputController::DoReportError() {
    247   DCHECK(message_loop_->BelongsToCurrentThread());
    248   if (state_ != kClosed)
    249     handler_->OnError();
    250 }
    251 
    252 int AudioOutputController::OnMoreData(AudioBus* dest,
    253                                       AudioBuffersState buffers_state) {
    254   return OnMoreIOData(NULL, dest, buffers_state);
    255 }
    256 
    257 int AudioOutputController::OnMoreIOData(AudioBus* source,
    258                                         AudioBus* dest,
    259                                         AudioBuffersState buffers_state) {
    260   DisallowEntryToOnMoreIOData();
    261   TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
    262 
    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.
    266   //
    267   // We also need to wait when diverting since the virtual stream will call this
    268   // multiple times without waiting.
    269   //
    270   // NEVER wait on OSX unless a virtual stream is connected, otherwise we can
    271   // end up hanging the entire OS.
    272   //
    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
    280 
    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());
    285 
    286   power_monitor_.Scan(*dest, frames);
    287 
    288   AllowEntryToOnMoreIOData();
    289   return frames;
    290 }
    291 
    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));
    296 }
    297 
    298 void AudioOutputController::DoStopCloseAndClearStream() {
    299   DCHECK(message_loop_->BelongsToCurrentThread());
    300 
    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);
    307 
    308     StopStream();
    309     stream_->Close();
    310     if (stream_ == diverting_to_stream_)
    311       diverting_to_stream_ = NULL;
    312     stream_ = NULL;
    313   }
    314 
    315   state_ = kEmpty;
    316 }
    317 
    318 void AudioOutputController::OnDeviceChange() {
    319   DCHECK(message_loop_->BelongsToCurrentThread());
    320   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
    321 
    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.
    325 
    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;
    332 
    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.";
    344   }
    345 }
    346 
    347 const AudioParameters& AudioOutputController::GetAudioParameters() {
    348   return params_;
    349 }
    350 
    351 void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
    352   message_loop_->PostTask(
    353       FROM_HERE,
    354       base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream));
    355 }
    356 
    357 void AudioOutputController::StopDiverting() {
    358   message_loop_->PostTask(
    359       FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
    360 }
    361 
    362 void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
    363   DCHECK(message_loop_->BelongsToCurrentThread());
    364 
    365   if (state_ == kClosed)
    366     return;
    367 
    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();
    374 }
    375 
    376 void AudioOutputController::DoStopDiverting() {
    377   DCHECK(message_loop_->BelongsToCurrentThread());
    378 
    379   if (state_ == kClosed)
    380     return;
    381 
    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_);
    387 }
    388 
    389 void AudioOutputController::AllowEntryToOnMoreIOData() {
    390   DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
    391   base::AtomicRefCountInc(&num_allowed_io_);
    392 }
    393 
    394 void AudioOutputController::DisallowEntryToOnMoreIOData() {
    395   const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
    396   DCHECK(is_zero);
    397 }
    398 
    399 }  // namespace media
    400