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_input_controller.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/threading/thread_restrictions.h"
      9 #include "media/base/limits.h"
     10 #include "media/base/scoped_histogram_timer.h"
     11 
     12 namespace {
     13 const int kMaxInputChannels = 2;
     14 
     15 // TODO(henrika): remove usage of timers and add support for proper
     16 // notification of when the input device is removed.  This was originally added
     17 // to resolve http://crbug.com/79936 for Windows platforms.  This then caused
     18 // breakage (very hard to repro bugs!) on other platforms: See
     19 // http://crbug.com/226327 and http://crbug.com/230972.
     20 const int kTimerResetIntervalSeconds = 1;
     21 #if defined(OS_IOS)
     22 // The first callback on iOS is received after the current background
     23 // audio has faded away.
     24 const int kTimerInitialIntervalSeconds = 4;
     25 #else
     26 // We have received reports that the timer can be too trigger happy on some
     27 // Mac devices and the initial timer interval has therefore been increased
     28 // from 1 second to 5 seconds.
     29 const int kTimerInitialIntervalSeconds = 5;
     30 #endif  // defined(OS_IOS)
     31 }
     32 
     33 namespace media {
     34 
     35 // static
     36 AudioInputController::Factory* AudioInputController::factory_ = NULL;
     37 
     38 AudioInputController::AudioInputController(EventHandler* handler,
     39                                            SyncWriter* sync_writer)
     40     : creator_loop_(base::MessageLoopProxy::current()),
     41       handler_(handler),
     42       stream_(NULL),
     43       data_is_active_(false),
     44       state_(kEmpty),
     45       sync_writer_(sync_writer),
     46       max_volume_(0.0) {
     47   DCHECK(creator_loop_.get());
     48 }
     49 
     50 AudioInputController::~AudioInputController() {
     51   DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_);
     52 }
     53 
     54 // static
     55 scoped_refptr<AudioInputController> AudioInputController::Create(
     56     AudioManager* audio_manager,
     57     EventHandler* event_handler,
     58     const AudioParameters& params,
     59     const std::string& device_id) {
     60   DCHECK(audio_manager);
     61 
     62   if (!params.IsValid() || (params.channels() > kMaxInputChannels))
     63     return NULL;
     64 
     65   if (factory_)
     66     return factory_->Create(audio_manager, event_handler, params);
     67 
     68   scoped_refptr<AudioInputController> controller(new AudioInputController(
     69       event_handler, NULL));
     70 
     71   controller->message_loop_ = audio_manager->GetMessageLoop();
     72 
     73   // Create and open a new audio input stream from the existing
     74   // audio-device thread.
     75   if (!controller->message_loop_->PostTask(FROM_HERE,
     76           base::Bind(&AudioInputController::DoCreate, controller,
     77                      base::Unretained(audio_manager), params, device_id))) {
     78     controller = NULL;
     79   }
     80 
     81   return controller;
     82 }
     83 
     84 // static
     85 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
     86     AudioManager* audio_manager,
     87     EventHandler* event_handler,
     88     const AudioParameters& params,
     89     const std::string& device_id,
     90     SyncWriter* sync_writer) {
     91   DCHECK(audio_manager);
     92   DCHECK(sync_writer);
     93 
     94   if (!params.IsValid() || (params.channels() > kMaxInputChannels))
     95     return NULL;
     96 
     97   // Create the AudioInputController object and ensure that it runs on
     98   // the audio-manager thread.
     99   scoped_refptr<AudioInputController> controller(new AudioInputController(
    100       event_handler, sync_writer));
    101   controller->message_loop_ = audio_manager->GetMessageLoop();
    102 
    103   // Create and open a new audio input stream from the existing
    104   // audio-device thread. Use the provided audio-input device.
    105   if (!controller->message_loop_->PostTask(FROM_HERE,
    106           base::Bind(&AudioInputController::DoCreate, controller,
    107                      base::Unretained(audio_manager), params, device_id))) {
    108     controller = NULL;
    109   }
    110 
    111   return controller;
    112 }
    113 
    114 // static
    115 scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
    116     const scoped_refptr<base::MessageLoopProxy>& message_loop,
    117     EventHandler* event_handler,
    118     AudioInputStream* stream,
    119     SyncWriter* sync_writer) {
    120   DCHECK(sync_writer);
    121   DCHECK(stream);
    122 
    123   // Create the AudioInputController object and ensure that it runs on
    124   // the audio-manager thread.
    125   scoped_refptr<AudioInputController> controller(new AudioInputController(
    126       event_handler, sync_writer));
    127   controller->message_loop_ = message_loop;
    128 
    129   // TODO(miu): See TODO at top of file.  Until that's resolved, we need to
    130   // disable the error auto-detection here (since the audio mirroring
    131   // implementation will reliably report error and close events).  Note, of
    132   // course, that we're assuming CreateForStream() has been called for the audio
    133   // mirroring use case only.
    134   if (!controller->message_loop_->PostTask(
    135           FROM_HERE,
    136           base::Bind(&AudioInputController::DoCreateForStream, controller,
    137                      stream, false))) {
    138     controller = NULL;
    139   }
    140 
    141   return controller;
    142 }
    143 
    144 void AudioInputController::Record() {
    145   message_loop_->PostTask(FROM_HERE, base::Bind(
    146       &AudioInputController::DoRecord, this));
    147 }
    148 
    149 void AudioInputController::Close(const base::Closure& closed_task) {
    150   DCHECK(!closed_task.is_null());
    151   DCHECK(creator_loop_->BelongsToCurrentThread());
    152 
    153   message_loop_->PostTaskAndReply(
    154       FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task);
    155 }
    156 
    157 void AudioInputController::SetVolume(double volume) {
    158   message_loop_->PostTask(FROM_HERE, base::Bind(
    159       &AudioInputController::DoSetVolume, this, volume));
    160 }
    161 
    162 void AudioInputController::SetAutomaticGainControl(bool enabled) {
    163   message_loop_->PostTask(FROM_HERE, base::Bind(
    164       &AudioInputController::DoSetAutomaticGainControl, this, enabled));
    165 }
    166 
    167 void AudioInputController::DoCreate(AudioManager* audio_manager,
    168                                     const AudioParameters& params,
    169                                     const std::string& device_id) {
    170   DCHECK(message_loop_->BelongsToCurrentThread());
    171   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
    172   // TODO(miu): See TODO at top of file.  Until that's resolved, assume all
    173   // platform audio input requires the |no_data_timer_| be used to auto-detect
    174   // errors.  In reality, probably only Windows and IOS need to be treated as
    175   // unreliable here.
    176   DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id),
    177                     true);
    178 }
    179 
    180 void AudioInputController::DoCreateForStream(
    181     AudioInputStream* stream_to_control, bool enable_nodata_timer) {
    182   DCHECK(message_loop_->BelongsToCurrentThread());
    183 
    184   DCHECK(!stream_);
    185   stream_ = stream_to_control;
    186 
    187   if (!stream_) {
    188     handler_->OnError(this);
    189     return;
    190   }
    191 
    192   if (stream_ && !stream_->Open()) {
    193     stream_->Close();
    194     stream_ = NULL;
    195     handler_->OnError(this);
    196     return;
    197   }
    198 
    199   DCHECK(!no_data_timer_.get());
    200   if (enable_nodata_timer) {
    201     // Create the data timer which will call DoCheckForNoData(). The timer
    202     // is started in DoRecord() and restarted in each DoCheckForNoData()
    203     // callback.
    204     no_data_timer_.reset(new base::Timer(
    205         FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds),
    206         base::Bind(&AudioInputController::DoCheckForNoData,
    207                    base::Unretained(this)), false));
    208   } else {
    209     DVLOG(1) << "Disabled: timer check for no data.";
    210   }
    211 
    212   state_ = kCreated;
    213   handler_->OnCreated(this);
    214 }
    215 
    216 void AudioInputController::DoRecord() {
    217   DCHECK(message_loop_->BelongsToCurrentThread());
    218   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime");
    219 
    220   if (state_ != kCreated)
    221     return;
    222 
    223   {
    224     base::AutoLock auto_lock(lock_);
    225     state_ = kRecording;
    226   }
    227 
    228   if (no_data_timer_) {
    229     // Start the data timer. Once |kTimerResetIntervalSeconds| have passed,
    230     // a callback to DoCheckForNoData() is made.
    231     no_data_timer_->Reset();
    232   }
    233 
    234   stream_->Start(this);
    235   handler_->OnRecording(this);
    236 }
    237 
    238 void AudioInputController::DoClose() {
    239   DCHECK(message_loop_->BelongsToCurrentThread());
    240   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
    241 
    242   // Delete the timer on the same thread that created it.
    243   no_data_timer_.reset();
    244 
    245   if (state_ != kClosed) {
    246     DoStopCloseAndClearStream(NULL);
    247     SetDataIsActive(false);
    248 
    249     if (LowLatencyMode()) {
    250       sync_writer_->Close();
    251     }
    252 
    253     state_ = kClosed;
    254   }
    255 }
    256 
    257 void AudioInputController::DoReportError() {
    258   DCHECK(message_loop_->BelongsToCurrentThread());
    259   handler_->OnError(this);
    260 }
    261 
    262 void AudioInputController::DoSetVolume(double volume) {
    263   DCHECK(message_loop_->BelongsToCurrentThread());
    264   DCHECK_GE(volume, 0);
    265   DCHECK_LE(volume, 1.0);
    266 
    267   if (state_ != kCreated && state_ != kRecording)
    268     return;
    269 
    270   // Only ask for the maximum volume at first call and use cached value
    271   // for remaining function calls.
    272   if (!max_volume_) {
    273     max_volume_ = stream_->GetMaxVolume();
    274   }
    275 
    276   if (max_volume_ == 0.0) {
    277     DLOG(WARNING) << "Failed to access input volume control";
    278     return;
    279   }
    280 
    281   // Set the stream volume and scale to a range matched to the platform.
    282   stream_->SetVolume(max_volume_ * volume);
    283 }
    284 
    285 void AudioInputController::DoSetAutomaticGainControl(bool enabled) {
    286   DCHECK(message_loop_->BelongsToCurrentThread());
    287   DCHECK_NE(state_, kRecording);
    288 
    289   // Ensure that the AGC state only can be modified before streaming starts.
    290   if (state_ != kCreated || state_ == kRecording)
    291     return;
    292 
    293   stream_->SetAutomaticGainControl(enabled);
    294 }
    295 
    296 void AudioInputController::DoCheckForNoData() {
    297   DCHECK(message_loop_->BelongsToCurrentThread());
    298 
    299   if (!GetDataIsActive()) {
    300     // The data-is-active marker will be false only if it has been more than
    301     // one second since a data packet was recorded. This can happen if a
    302     // capture device has been removed or disabled.
    303     handler_->OnError(this);
    304     return;
    305   }
    306 
    307   // Mark data as non-active. The flag will be re-enabled in OnData() each
    308   // time a data packet is received. Hence, under normal conditions, the
    309   // flag will only be disabled during a very short period.
    310   SetDataIsActive(false);
    311 
    312   // Restart the timer to ensure that we check the flag again in
    313   // |kTimerResetIntervalSeconds|.
    314   no_data_timer_->Start(
    315       FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds),
    316       base::Bind(&AudioInputController::DoCheckForNoData,
    317       base::Unretained(this)));
    318 }
    319 
    320 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
    321                                   uint32 size, uint32 hardware_delay_bytes,
    322                                   double volume) {
    323   {
    324     base::AutoLock auto_lock(lock_);
    325     if (state_ != kRecording)
    326       return;
    327   }
    328 
    329   // Mark data as active to ensure that the periodic calls to
    330   // DoCheckForNoData() does not report an error to the event handler.
    331   SetDataIsActive(true);
    332 
    333   // Use SyncSocket if we are in a low-latency mode.
    334   if (LowLatencyMode()) {
    335     sync_writer_->Write(data, size, volume);
    336     sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
    337     return;
    338   }
    339 
    340   handler_->OnData(this, data, size);
    341 }
    342 
    343 void AudioInputController::OnClose(AudioInputStream* stream) {
    344   DVLOG(1) << "AudioInputController::OnClose()";
    345   // TODO(satish): Sometimes the device driver closes the input stream without
    346   // us asking for it (may be if the device was unplugged?). Check how to handle
    347   // such cases here.
    348 }
    349 
    350 void AudioInputController::OnError(AudioInputStream* stream) {
    351   // Handle error on the audio-manager thread.
    352   message_loop_->PostTask(FROM_HERE, base::Bind(
    353       &AudioInputController::DoReportError, this));
    354 }
    355 
    356 void AudioInputController::DoStopCloseAndClearStream(
    357     base::WaitableEvent *done) {
    358   DCHECK(message_loop_->BelongsToCurrentThread());
    359 
    360   // Allow calling unconditionally and bail if we don't have a stream to close.
    361   if (stream_ != NULL) {
    362     stream_->Stop();
    363     stream_->Close();
    364     stream_ = NULL;
    365   }
    366 
    367   // Should be last in the method, do not touch "this" from here on.
    368   if (done != NULL)
    369     done->Signal();
    370 }
    371 
    372 void AudioInputController::SetDataIsActive(bool enabled) {
    373   base::subtle::Release_Store(&data_is_active_, enabled);
    374 }
    375 
    376 bool AudioInputController::GetDataIsActive() {
    377   return (base::subtle::Acquire_Load(&data_is_active_) != false);
    378 }
    379 
    380 }  // namespace media
    381