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/task_runner_util.h"
     12 #include "base/threading/platform_thread.h"
     13 #include "base/time/time.h"
     14 #include "build/build_config.h"
     15 #include "media/base/scoped_histogram_timer.h"
     16 
     17 using base::Time;
     18 using base::TimeDelta;
     19 
     20 namespace 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.
     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 = 4;
     30 #endif
     31 
     32 // Polling-related constants.
     33 const int AudioOutputController::kPollNumAttempts = 3;
     34 const int AudioOutputController::kPollPauseInMilliseconds = 3;
     35 
     36 AudioOutputController::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       on_more_io_data_called_(0) {
     61   DCHECK(audio_manager);
     62   DCHECK(handler_);
     63   DCHECK(sync_reader_);
     64   DCHECK(message_loop_.get());
     65 }
     66 
     67 AudioOutputController::~AudioOutputController() {
     68   DCHECK_EQ(kClosed, state_);
     69 }
     70 
     71 // static
     72 scoped_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 
     93 void AudioOutputController::Play() {
     94   message_loop_->PostTask(FROM_HERE, base::Bind(
     95       &AudioOutputController::DoPlay, this));
     96 }
     97 
     98 void AudioOutputController::Pause() {
     99   message_loop_->PostTask(FROM_HERE, base::Bind(
    100       &AudioOutputController::DoPause, this));
    101 }
    102 
    103 void 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 
    109 void AudioOutputController::SetVolume(double volume) {
    110   message_loop_->PostTask(FROM_HERE, base::Bind(
    111       &AudioOutputController::DoSetVolume, this, volume));
    112 }
    113 
    114 void AudioOutputController::GetOutputDeviceId(
    115     base::Callback<void(const std::string&)> callback) const {
    116   base::PostTaskAndReplyWithResult(
    117       message_loop_.get(),
    118       FROM_HERE,
    119       base::Bind(&AudioOutputController::DoGetOutputDeviceId, this),
    120       callback);
    121 }
    122 
    123 void AudioOutputController::SwitchOutputDevice(
    124     const std::string& output_device_id, const base::Closure& callback) {
    125   message_loop_->PostTaskAndReply(
    126       FROM_HERE,
    127       base::Bind(&AudioOutputController::DoSwitchOutputDevice, this,
    128                  output_device_id),
    129       callback);
    130 }
    131 
    132 void AudioOutputController::DoCreate(bool is_for_device_change) {
    133   DCHECK(message_loop_->BelongsToCurrentThread());
    134   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
    135   TRACE_EVENT0("audio", "AudioOutputController::DoCreate");
    136 
    137   // Close() can be called before DoCreate() is executed.
    138   if (state_ == kClosed)
    139     return;
    140 
    141   DoStopCloseAndClearStream();  // Calls RemoveOutputDeviceChangeListener().
    142   DCHECK_EQ(kEmpty, state_);
    143 
    144   stream_ = diverting_to_stream_ ?
    145       diverting_to_stream_ :
    146       audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_,
    147                                                  input_device_id_);
    148   if (!stream_) {
    149     state_ = kError;
    150     handler_->OnError();
    151     return;
    152   }
    153 
    154   if (!stream_->Open()) {
    155     DoStopCloseAndClearStream();
    156     state_ = kError;
    157     handler_->OnError();
    158     return;
    159   }
    160 
    161   // Everything started okay, so re-register for state change callbacks if
    162   // stream_ was created via AudioManager.
    163   if (stream_ != diverting_to_stream_)
    164     audio_manager_->AddOutputDeviceChangeListener(this);
    165 
    166   // We have successfully opened the stream. Set the initial volume.
    167   stream_->SetVolume(volume_);
    168 
    169   // Finally set the state to kCreated.
    170   state_ = kCreated;
    171 
    172   // And then report we have been created if we haven't done so already.
    173   if (!is_for_device_change)
    174     handler_->OnCreated();
    175 }
    176 
    177 void AudioOutputController::DoPlay() {
    178   DCHECK(message_loop_->BelongsToCurrentThread());
    179   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
    180   TRACE_EVENT0("audio", "AudioOutputController::DoPlay");
    181 
    182   // We can start from created or paused state.
    183   if (state_ != kCreated && state_ != kPaused)
    184     return;
    185 
    186   // Ask for first packet.
    187   sync_reader_->UpdatePendingBytes(0);
    188 
    189   state_ = kPlaying;
    190 
    191 #if defined(AUDIO_POWER_MONITORING)
    192   power_monitor_.Reset();
    193   power_poll_callback_.Reset(
    194       base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically,
    195                  this));
    196   // Run the callback to send an initial notification that we're starting in
    197   // silence, and to schedule periodic callbacks.
    198   power_poll_callback_.callback().Run();
    199 #endif
    200 
    201   on_more_io_data_called_ = 0;
    202   AllowEntryToOnMoreIOData();
    203   stream_->Start(this);
    204 
    205   // For UMA tracking purposes, start the wedge detection timer.  This allows us
    206   // to record statistics about the number of wedged playbacks in the field.
    207   //
    208   // WedgeCheck() will look to see if |on_more_io_data_called_| is true after
    209   // the timeout expires.  Care must be taken to ensure the wedge check delay is
    210   // large enough that the value isn't queried while OnMoreDataIO() is setting
    211   // it.
    212   //
    213   // Timer self-manages its lifetime and WedgeCheck() will only record the UMA
    214   // statistic if state is still kPlaying.  Additional Start() calls will
    215   // invalidate the previous timer.
    216   wedge_timer_.reset(new base::OneShotTimer<AudioOutputController>());
    217   wedge_timer_->Start(
    218       FROM_HERE, TimeDelta::FromSeconds(5), this,
    219       &AudioOutputController::WedgeCheck);
    220 
    221   handler_->OnPlaying();
    222 }
    223 
    224 #if defined(AUDIO_POWER_MONITORING)
    225 void AudioOutputController::ReportPowerMeasurementPeriodically() {
    226   DCHECK(message_loop_->BelongsToCurrentThread());
    227   const std::pair<float, bool>& reading =
    228       power_monitor_.ReadCurrentPowerAndClip();
    229   handler_->OnPowerMeasured(reading.first, reading.second);
    230   message_loop_->PostDelayedTask(
    231       FROM_HERE, power_poll_callback_.callback(),
    232       TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond);
    233 }
    234 #endif
    235 
    236 void AudioOutputController::StopStream() {
    237   DCHECK(message_loop_->BelongsToCurrentThread());
    238 
    239   if (state_ == kPlaying) {
    240     wedge_timer_.reset();
    241     stream_->Stop();
    242     DisallowEntryToOnMoreIOData();
    243 
    244 #if defined(AUDIO_POWER_MONITORING)
    245     power_poll_callback_.Cancel();
    246 #endif
    247 
    248     state_ = kPaused;
    249   }
    250 }
    251 
    252 void AudioOutputController::DoPause() {
    253   DCHECK(message_loop_->BelongsToCurrentThread());
    254   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
    255   TRACE_EVENT0("audio", "AudioOutputController::DoPause");
    256 
    257   StopStream();
    258 
    259   if (state_ != kPaused)
    260     return;
    261 
    262   // Let the renderer know we've stopped.  Necessary to let PPAPI clients know
    263   // audio has been shutdown.  TODO(dalecurtis): This stinks.  PPAPI should have
    264   // a better way to know when it should exit PPB_Audio_Shared::Run().
    265   sync_reader_->UpdatePendingBytes(-1);
    266 
    267 #if defined(AUDIO_POWER_MONITORING)
    268   // Paused means silence follows.
    269   handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false);
    270 #endif
    271 
    272   handler_->OnPaused();
    273 }
    274 
    275 void AudioOutputController::DoClose() {
    276   DCHECK(message_loop_->BelongsToCurrentThread());
    277   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
    278   TRACE_EVENT0("audio", "AudioOutputController::DoClose");
    279 
    280   if (state_ != kClosed) {
    281     DoStopCloseAndClearStream();
    282     sync_reader_->Close();
    283     state_ = kClosed;
    284   }
    285 }
    286 
    287 void AudioOutputController::DoSetVolume(double volume) {
    288   DCHECK(message_loop_->BelongsToCurrentThread());
    289 
    290   // Saves the volume to a member first. We may not be able to set the volume
    291   // right away but when the stream is created we'll set the volume.
    292   volume_ = volume;
    293 
    294   switch (state_) {
    295     case kCreated:
    296     case kPlaying:
    297     case kPaused:
    298       stream_->SetVolume(volume_);
    299       break;
    300     default:
    301       return;
    302   }
    303 }
    304 
    305 std::string AudioOutputController::DoGetOutputDeviceId() const {
    306   DCHECK(message_loop_->BelongsToCurrentThread());
    307   return output_device_id_;
    308 }
    309 
    310 void AudioOutputController::DoSwitchOutputDevice(
    311     const std::string& output_device_id) {
    312   DCHECK(message_loop_->BelongsToCurrentThread());
    313 
    314   if (state_ == kClosed)
    315     return;
    316 
    317   if (output_device_id == output_device_id_)
    318     return;
    319 
    320   output_device_id_ = output_device_id;
    321 
    322   // If output is currently diverted, we must not call OnDeviceChange
    323   // since it would break the diverted setup. Once diversion is
    324   // finished using StopDiverting() the output will switch to the new
    325   // device ID.
    326   if (stream_ != diverting_to_stream_)
    327     OnDeviceChange();
    328 }
    329 
    330 void AudioOutputController::DoReportError() {
    331   DCHECK(message_loop_->BelongsToCurrentThread());
    332   if (state_ != kClosed)
    333     handler_->OnError();
    334 }
    335 
    336 int AudioOutputController::OnMoreData(AudioBus* dest,
    337                                       AudioBuffersState buffers_state) {
    338   return OnMoreIOData(NULL, dest, buffers_state);
    339 }
    340 
    341 int AudioOutputController::OnMoreIOData(AudioBus* source,
    342                                         AudioBus* dest,
    343                                         AudioBuffersState buffers_state) {
    344   DisallowEntryToOnMoreIOData();
    345   TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
    346 
    347   // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
    348   // may have already fired if OnMoreIOData() took an abnormal amount of time).
    349   // Since this thread is the only writer of |on_more_io_data_called_| once the
    350   // thread starts, its safe to compare and then increment.
    351   if (base::AtomicRefCountIsZero(&on_more_io_data_called_))
    352     base::AtomicRefCountInc(&on_more_io_data_called_);
    353 
    354   sync_reader_->Read(source, dest);
    355 
    356   const int frames = dest->frames();
    357   sync_reader_->UpdatePendingBytes(
    358       buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
    359 
    360 #if defined(AUDIO_POWER_MONITORING)
    361   power_monitor_.Scan(*dest, frames);
    362 #endif
    363 
    364   AllowEntryToOnMoreIOData();
    365   return frames;
    366 }
    367 
    368 void AudioOutputController::OnError(AudioOutputStream* stream) {
    369   // Handle error on the audio controller thread.
    370   message_loop_->PostTask(FROM_HERE, base::Bind(
    371       &AudioOutputController::DoReportError, this));
    372 }
    373 
    374 void AudioOutputController::DoStopCloseAndClearStream() {
    375   DCHECK(message_loop_->BelongsToCurrentThread());
    376 
    377   // Allow calling unconditionally and bail if we don't have a stream_ to close.
    378   if (stream_) {
    379     // De-register from state change callbacks if stream_ was created via
    380     // AudioManager.
    381     if (stream_ != diverting_to_stream_)
    382       audio_manager_->RemoveOutputDeviceChangeListener(this);
    383 
    384     StopStream();
    385     stream_->Close();
    386     if (stream_ == diverting_to_stream_)
    387       diverting_to_stream_ = NULL;
    388     stream_ = NULL;
    389   }
    390 
    391   state_ = kEmpty;
    392 }
    393 
    394 void AudioOutputController::OnDeviceChange() {
    395   DCHECK(message_loop_->BelongsToCurrentThread());
    396   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
    397   TRACE_EVENT0("audio", "AudioOutputController::OnDeviceChange");
    398 
    399   // TODO(dalecurtis): Notify the renderer side that a device change has
    400   // occurred.  Currently querying the hardware information here will lead to
    401   // crashes on OSX.  See http://crbug.com/158170.
    402 
    403   // Recreate the stream (DoCreate() will first shut down an existing stream).
    404   // Exit if we ran into an error.
    405   const State original_state = state_;
    406   DoCreate(true);
    407   if (!stream_ || state_ == kError)
    408     return;
    409 
    410   // Get us back to the original state or an equivalent state.
    411   switch (original_state) {
    412     case kPlaying:
    413       DoPlay();
    414       return;
    415     case kCreated:
    416     case kPaused:
    417       // From the outside these two states are equivalent.
    418       return;
    419     default:
    420       NOTREACHED() << "Invalid original state.";
    421   }
    422 }
    423 
    424 const AudioParameters& AudioOutputController::GetAudioParameters() {
    425   return params_;
    426 }
    427 
    428 void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
    429   message_loop_->PostTask(
    430       FROM_HERE,
    431       base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream));
    432 }
    433 
    434 void AudioOutputController::StopDiverting() {
    435   message_loop_->PostTask(
    436       FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
    437 }
    438 
    439 void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
    440   DCHECK(message_loop_->BelongsToCurrentThread());
    441 
    442   if (state_ == kClosed)
    443     return;
    444 
    445   DCHECK(!diverting_to_stream_);
    446   diverting_to_stream_ = to_stream;
    447   // Note: OnDeviceChange() will engage the "re-create" process, which will
    448   // detect and use the alternate AudioOutputStream rather than create a new one
    449   // via AudioManager.
    450   OnDeviceChange();
    451 }
    452 
    453 void AudioOutputController::DoStopDiverting() {
    454   DCHECK(message_loop_->BelongsToCurrentThread());
    455 
    456   if (state_ == kClosed)
    457     return;
    458 
    459   // Note: OnDeviceChange() will cause the existing stream (the consumer of the
    460   // diverted audio data) to be closed, and diverting_to_stream_ will be set
    461   // back to NULL.
    462   OnDeviceChange();
    463   DCHECK(!diverting_to_stream_);
    464 }
    465 
    466 void AudioOutputController::AllowEntryToOnMoreIOData() {
    467   DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
    468   base::AtomicRefCountInc(&num_allowed_io_);
    469 }
    470 
    471 void AudioOutputController::DisallowEntryToOnMoreIOData() {
    472   const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
    473   DCHECK(is_zero);
    474 }
    475 
    476 void AudioOutputController::WedgeCheck() {
    477   DCHECK(message_loop_->BelongsToCurrentThread());
    478 
    479   // If we should be playing and we haven't, that's a wedge.
    480   if (state_ == kPlaying) {
    481     const bool playback_success =
    482         base::AtomicRefCountIsOne(&on_more_io_data_called_);
    483 
    484     UMA_HISTOGRAM_BOOLEAN(
    485         "Media.AudioOutputControllerPlaybackStartupSuccess", playback_success);
    486 
    487     // Let the AudioManager try and fix it.
    488     if (!playback_success)
    489       audio_manager_->FixWedgedAudio();
    490   }
    491 }
    492 
    493 }  // namespace media
    494