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_device.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/bind.h"
      9 #include "base/memory/scoped_vector.h"
     10 #include "base/threading/thread_restrictions.h"
     11 #include "base/time/time.h"
     12 #include "media/audio/audio_manager_base.h"
     13 #include "media/base/audio_bus.h"
     14 
     15 namespace media {
     16 
     17 // The number of shared memory buffer segments indicated to browser process
     18 // in order to avoid data overwriting. This number can be any positive number,
     19 // dependent how fast the renderer process can pick up captured data from
     20 // shared memory.
     21 static const int kRequestedSharedMemoryCount = 10;
     22 
     23 // Takes care of invoking the capture callback on the audio thread.
     24 // An instance of this class is created for each capture stream in
     25 // OnLowLatencyCreated().
     26 class AudioInputDevice::AudioThreadCallback
     27     : public AudioDeviceThread::Callback {
     28  public:
     29   AudioThreadCallback(const AudioParameters& audio_parameters,
     30                       base::SharedMemoryHandle memory,
     31                       int memory_length,
     32                       int total_segments,
     33                       CaptureCallback* capture_callback);
     34   virtual ~AudioThreadCallback();
     35 
     36   virtual void MapSharedMemory() OVERRIDE;
     37 
     38   // Called whenever we receive notifications about pending data.
     39   virtual void Process(int pending_data) OVERRIDE;
     40 
     41  private:
     42   int current_segment_id_;
     43   ScopedVector<media::AudioBus> audio_buses_;
     44   CaptureCallback* capture_callback_;
     45 
     46   DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
     47 };
     48 
     49 AudioInputDevice::AudioInputDevice(
     50     scoped_ptr<AudioInputIPC> ipc,
     51     const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
     52     : ScopedTaskRunnerObserver(io_task_runner),
     53       callback_(NULL),
     54       ipc_(ipc.Pass()),
     55       state_(IDLE),
     56       session_id_(0),
     57       agc_is_enabled_(false),
     58       stopping_hack_(false) {
     59   CHECK(ipc_);
     60 
     61   // The correctness of the code depends on the relative values assigned in the
     62   // State enum.
     63   COMPILE_ASSERT(IPC_CLOSED < IDLE, invalid_enum_value_assignment_0);
     64   COMPILE_ASSERT(IDLE < CREATING_STREAM, invalid_enum_value_assignment_1);
     65   COMPILE_ASSERT(CREATING_STREAM < RECORDING, invalid_enum_value_assignment_2);
     66 }
     67 
     68 void AudioInputDevice::Initialize(const AudioParameters& params,
     69                                   CaptureCallback* callback,
     70                                   int session_id) {
     71   DCHECK(params.IsValid());
     72   DCHECK(!callback_);
     73   DCHECK_EQ(0, session_id_);
     74   audio_parameters_ = params;
     75   callback_ = callback;
     76   session_id_ = session_id;
     77 }
     78 
     79 void AudioInputDevice::Start() {
     80   DCHECK(callback_) << "Initialize hasn't been called";
     81   DVLOG(1) << "Start()";
     82   task_runner()->PostTask(FROM_HERE,
     83       base::Bind(&AudioInputDevice::StartUpOnIOThread, this));
     84 }
     85 
     86 void AudioInputDevice::Stop() {
     87   DVLOG(1) << "Stop()";
     88 
     89   {
     90     base::AutoLock auto_lock(audio_thread_lock_);
     91     audio_thread_.Stop(base::MessageLoop::current());
     92     stopping_hack_ = true;
     93   }
     94 
     95   task_runner()->PostTask(FROM_HERE,
     96       base::Bind(&AudioInputDevice::ShutDownOnIOThread, this));
     97 }
     98 
     99 void AudioInputDevice::SetVolume(double volume) {
    100   if (volume < 0 || volume > 1.0) {
    101     DLOG(ERROR) << "Invalid volume value specified";
    102     return;
    103   }
    104 
    105   task_runner()->PostTask(FROM_HERE,
    106       base::Bind(&AudioInputDevice::SetVolumeOnIOThread, this, volume));
    107 }
    108 
    109 void AudioInputDevice::SetAutomaticGainControl(bool enabled) {
    110   DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")";
    111   task_runner()->PostTask(FROM_HERE,
    112       base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread,
    113           this, enabled));
    114 }
    115 
    116 void AudioInputDevice::OnStreamCreated(
    117     base::SharedMemoryHandle handle,
    118     base::SyncSocket::Handle socket_handle,
    119     int length,
    120     int total_segments) {
    121   DCHECK(task_runner()->BelongsToCurrentThread());
    122 #if defined(OS_WIN)
    123   DCHECK(handle);
    124   DCHECK(socket_handle);
    125 #else
    126   DCHECK_GE(handle.fd, 0);
    127   DCHECK_GE(socket_handle, 0);
    128 #endif
    129   DCHECK_GT(length, 0);
    130 
    131   if (state_ != CREATING_STREAM)
    132     return;
    133 
    134   base::AutoLock auto_lock(audio_thread_lock_);
    135   // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice.
    136   // Interface changes need to be made; likely, after AudioInputDevice is merged
    137   // into AudioOutputDevice (http://crbug.com/179597).
    138   if (stopping_hack_)
    139     return;
    140 
    141   DCHECK(audio_thread_.IsStopped());
    142   audio_callback_.reset(new AudioInputDevice::AudioThreadCallback(
    143       audio_parameters_, handle, length, total_segments, callback_));
    144   audio_thread_.Start(
    145       audio_callback_.get(), socket_handle, "AudioInputDevice", false);
    146 
    147   state_ = RECORDING;
    148   ipc_->RecordStream();
    149 }
    150 
    151 void AudioInputDevice::OnVolume(double volume) {
    152   NOTIMPLEMENTED();
    153 }
    154 
    155 void AudioInputDevice::OnStateChanged(
    156     AudioInputIPCDelegate::State state) {
    157   DCHECK(task_runner()->BelongsToCurrentThread());
    158 
    159   // Do nothing if the stream has been closed.
    160   if (state_ < CREATING_STREAM)
    161     return;
    162 
    163   // TODO(miu): Clean-up inconsistent and incomplete handling here.
    164   // http://crbug.com/180640
    165   switch (state) {
    166     case AudioInputIPCDelegate::kStopped:
    167       ShutDownOnIOThread();
    168       break;
    169     case AudioInputIPCDelegate::kRecording:
    170       NOTIMPLEMENTED();
    171       break;
    172     case AudioInputIPCDelegate::kError:
    173       DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)";
    174       // Don't dereference the callback object if the audio thread
    175       // is stopped or stopping.  That could mean that the callback
    176       // object has been deleted.
    177       // TODO(tommi): Add an explicit contract for clearing the callback
    178       // object.  Possibly require calling Initialize again or provide
    179       // a callback object via Start() and clear it in Stop().
    180       if (!audio_thread_.IsStopped())
    181         callback_->OnCaptureError();
    182       break;
    183     default:
    184       NOTREACHED();
    185       break;
    186   }
    187 }
    188 
    189 void AudioInputDevice::OnIPCClosed() {
    190   DCHECK(task_runner()->BelongsToCurrentThread());
    191   state_ = IPC_CLOSED;
    192   ipc_.reset();
    193 }
    194 
    195 AudioInputDevice::~AudioInputDevice() {
    196   // TODO(henrika): The current design requires that the user calls
    197   // Stop before deleting this class.
    198   DCHECK(audio_thread_.IsStopped());
    199 }
    200 
    201 void AudioInputDevice::StartUpOnIOThread() {
    202   DCHECK(task_runner()->BelongsToCurrentThread());
    203 
    204   // Make sure we don't call Start() more than once.
    205   if (state_ != IDLE)
    206     return;
    207 
    208   if (session_id_ <= 0) {
    209     DLOG(WARNING) << "Invalid session id for the input stream " << session_id_;
    210     return;
    211   }
    212 
    213   state_ = CREATING_STREAM;
    214   ipc_->CreateStream(this, session_id_, audio_parameters_,
    215                      agc_is_enabled_, kRequestedSharedMemoryCount);
    216 }
    217 
    218 void AudioInputDevice::ShutDownOnIOThread() {
    219   DCHECK(task_runner()->BelongsToCurrentThread());
    220 
    221   // Close the stream, if we haven't already.
    222   if (state_ >= CREATING_STREAM) {
    223     ipc_->CloseStream();
    224     state_ = IDLE;
    225     agc_is_enabled_ = false;
    226   }
    227 
    228   // We can run into an issue where ShutDownOnIOThread is called right after
    229   // OnStreamCreated is called in cases where Start/Stop are called before we
    230   // get the OnStreamCreated callback.  To handle that corner case, we call
    231   // Stop(). In most cases, the thread will already be stopped.
    232   //
    233   // Another situation is when the IO thread goes away before Stop() is called
    234   // in which case, we cannot use the message loop to close the thread handle
    235   // and can't not rely on the main thread existing either.
    236   base::AutoLock auto_lock_(audio_thread_lock_);
    237   base::ThreadRestrictions::ScopedAllowIO allow_io;
    238   audio_thread_.Stop(NULL);
    239   audio_callback_.reset();
    240   stopping_hack_ = false;
    241 }
    242 
    243 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
    244   DCHECK(task_runner()->BelongsToCurrentThread());
    245   if (state_ >= CREATING_STREAM)
    246     ipc_->SetVolume(volume);
    247 }
    248 
    249 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) {
    250   DCHECK(task_runner()->BelongsToCurrentThread());
    251 
    252   if (state_ >= CREATING_STREAM) {
    253     DLOG(WARNING) << "The AGC state can not be modified after starting.";
    254     return;
    255   }
    256 
    257   // We simply store the new AGC setting here. This value will be used when
    258   // a new stream is initialized and by GetAutomaticGainControl().
    259   agc_is_enabled_ = enabled;
    260 }
    261 
    262 void AudioInputDevice::WillDestroyCurrentMessageLoop() {
    263   LOG(ERROR) << "IO loop going away before the input device has been stopped";
    264   ShutDownOnIOThread();
    265 }
    266 
    267 // AudioInputDevice::AudioThreadCallback
    268 AudioInputDevice::AudioThreadCallback::AudioThreadCallback(
    269     const AudioParameters& audio_parameters,
    270     base::SharedMemoryHandle memory,
    271     int memory_length,
    272     int total_segments,
    273     CaptureCallback* capture_callback)
    274     : AudioDeviceThread::Callback(audio_parameters, memory, memory_length,
    275                                   total_segments),
    276       current_segment_id_(0),
    277       capture_callback_(capture_callback) {
    278 }
    279 
    280 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() {
    281 }
    282 
    283 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() {
    284   shared_memory_.Map(memory_length_);
    285 
    286   // Create vector of audio buses by wrapping existing blocks of memory.
    287   uint8* ptr = static_cast<uint8*>(shared_memory_.memory());
    288   for (int i = 0; i < total_segments_; ++i) {
    289     media::AudioInputBuffer* buffer =
    290         reinterpret_cast<media::AudioInputBuffer*>(ptr);
    291     scoped_ptr<media::AudioBus> audio_bus =
    292         media::AudioBus::WrapMemory(audio_parameters_, buffer->audio);
    293     audio_buses_.push_back(audio_bus.release());
    294     ptr += segment_length_;
    295   }
    296 }
    297 
    298 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) {
    299   // The shared memory represents parameters, size of the data buffer and the
    300   // actual data buffer containing audio data. Map the memory into this
    301   // structure and parse out parameters and the data area.
    302   uint8* ptr = static_cast<uint8*>(shared_memory_.memory());
    303   ptr += current_segment_id_ * segment_length_;
    304   AudioInputBuffer* buffer = reinterpret_cast<AudioInputBuffer*>(ptr);
    305   // Usually this will be equal but in the case of low sample rate (e.g. 8kHz,
    306   // the buffer may be bigger (on mac at least)).
    307   DCHECK_GE(buffer->params.size,
    308             segment_length_ - sizeof(AudioInputBufferParameters));
    309   double volume = buffer->params.volume;
    310   bool key_pressed = buffer->params.key_pressed;
    311 
    312   // Use pre-allocated audio bus wrapping existing block of shared memory.
    313   media::AudioBus* audio_bus = audio_buses_[current_segment_id_];
    314 
    315   // Deliver captured data to the client in floating point format
    316   // and update the audio-delay measurement.
    317   int audio_delay_milliseconds = pending_data / bytes_per_ms_;
    318   capture_callback_->Capture(
    319       audio_bus, audio_delay_milliseconds, volume, key_pressed);
    320 
    321   if (++current_segment_id_ >= total_segments_)
    322     current_segment_id_ = 0;
    323 }
    324 
    325 }  // namespace media
    326