Home | History | Annotate | Download | only in win
      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/win/wavein_input_win.h"
      6 
      7 #pragma comment(lib, "winmm.lib")
      8 
      9 #include "base/logging.h"
     10 #include "media/audio/audio_io.h"
     11 #include "media/audio/win/audio_manager_win.h"
     12 #include "media/audio/win/device_enumeration_win.h"
     13 #include "media/base/audio_bus.h"
     14 
     15 namespace media {
     16 
     17 // Our sound buffers are allocated once and kept in a linked list using the
     18 // the WAVEHDR::dwUser variable. The last buffer points to the first buffer.
     19 static WAVEHDR* GetNextBuffer(WAVEHDR* current) {
     20   return reinterpret_cast<WAVEHDR*>(current->dwUser);
     21 }
     22 
     23 PCMWaveInAudioInputStream::PCMWaveInAudioInputStream(
     24     AudioManagerWin* manager,
     25     const AudioParameters& params,
     26     int num_buffers,
     27     const std::string& device_id)
     28     : state_(kStateEmpty),
     29       manager_(manager),
     30       device_id_(device_id),
     31       wavein_(NULL),
     32       callback_(NULL),
     33       num_buffers_(num_buffers),
     34       buffer_(NULL),
     35       channels_(params.channels()),
     36       audio_bus_(media::AudioBus::Create(params)) {
     37   DCHECK_GT(num_buffers_, 0);
     38   format_.wFormatTag = WAVE_FORMAT_PCM;
     39   format_.nChannels = params.channels() > 2 ? 2 : params.channels();
     40   format_.nSamplesPerSec = params.sample_rate();
     41   format_.wBitsPerSample = params.bits_per_sample();
     42   format_.cbSize = 0;
     43   format_.nBlockAlign = (format_.nChannels * format_.wBitsPerSample) / 8;
     44   format_.nAvgBytesPerSec = format_.nBlockAlign * format_.nSamplesPerSec;
     45   buffer_size_ = params.frames_per_buffer() * format_.nBlockAlign;
     46   // If we don't have a packet size we use 100ms.
     47   if (!buffer_size_)
     48     buffer_size_ = format_.nAvgBytesPerSec / 10;
     49   // The event is auto-reset.
     50   stopped_event_.Set(::CreateEventW(NULL, FALSE, FALSE, NULL));
     51 }
     52 
     53 PCMWaveInAudioInputStream::~PCMWaveInAudioInputStream() {
     54   DCHECK(NULL == wavein_);
     55 }
     56 
     57 bool PCMWaveInAudioInputStream::Open() {
     58   DCHECK(thread_checker_.CalledOnValidThread());
     59   if (state_ != kStateEmpty)
     60     return false;
     61   if (num_buffers_ < 2 || num_buffers_ > 10)
     62     return false;
     63 
     64   // Convert the stored device id string into an unsigned integer
     65   // corresponding to the selected device.
     66   UINT device_id = WAVE_MAPPER;
     67   if (!GetDeviceId(&device_id)) {
     68     return false;
     69   }
     70 
     71   // Open the specified input device for recording.
     72   MMRESULT result = MMSYSERR_NOERROR;
     73   result = ::waveInOpen(&wavein_, device_id, &format_,
     74                         reinterpret_cast<DWORD_PTR>(WaveCallback),
     75                         reinterpret_cast<DWORD_PTR>(this),
     76                         CALLBACK_FUNCTION);
     77   if (result != MMSYSERR_NOERROR)
     78     return false;
     79 
     80   SetupBuffers();
     81   state_ = kStateReady;
     82   return true;
     83 }
     84 
     85 void PCMWaveInAudioInputStream::SetupBuffers() {
     86   WAVEHDR* last = NULL;
     87   WAVEHDR* first = NULL;
     88   for (int ix = 0; ix != num_buffers_; ++ix) {
     89     uint32 sz = sizeof(WAVEHDR) + buffer_size_;
     90     buffer_ =  reinterpret_cast<WAVEHDR*>(new char[sz]);
     91     buffer_->lpData = reinterpret_cast<char*>(buffer_) + sizeof(WAVEHDR);
     92     buffer_->dwBufferLength = buffer_size_;
     93     buffer_->dwBytesRecorded = 0;
     94     buffer_->dwUser = reinterpret_cast<DWORD_PTR>(last);
     95     buffer_->dwFlags = WHDR_DONE;
     96     buffer_->dwLoops = 0;
     97     if (ix == 0)
     98       first = buffer_;
     99     last = buffer_;
    100     ::waveInPrepareHeader(wavein_, buffer_, sizeof(WAVEHDR));
    101   }
    102   // Fix the first buffer to point to the last one.
    103   first->dwUser = reinterpret_cast<DWORD_PTR>(last);
    104 }
    105 
    106 void PCMWaveInAudioInputStream::FreeBuffers() {
    107   WAVEHDR* current = buffer_;
    108   for (int ix = 0; ix != num_buffers_; ++ix) {
    109     WAVEHDR* next = GetNextBuffer(current);
    110     if (current->dwFlags & WHDR_PREPARED)
    111       ::waveInUnprepareHeader(wavein_, current, sizeof(WAVEHDR));
    112     delete[] reinterpret_cast<char*>(current);
    113     current = next;
    114   }
    115   buffer_ = NULL;
    116 }
    117 
    118 void PCMWaveInAudioInputStream::Start(AudioInputCallback* callback) {
    119   DCHECK(thread_checker_.CalledOnValidThread());
    120   if (state_ != kStateReady)
    121     return;
    122 
    123   DCHECK(!callback_);
    124   callback_ = callback;
    125   state_ = kStateRecording;
    126 
    127   WAVEHDR* buffer = buffer_;
    128   for (int ix = 0; ix != num_buffers_; ++ix) {
    129     QueueNextPacket(buffer);
    130     buffer = GetNextBuffer(buffer);
    131   }
    132   buffer = buffer_;
    133 
    134   MMRESULT result = ::waveInStart(wavein_);
    135   if (result != MMSYSERR_NOERROR) {
    136     HandleError(result);
    137     state_ = kStateReady;
    138     callback_ = NULL;
    139   }
    140 }
    141 
    142 // Stopping is tricky. First, no buffer should be locked by the audio driver
    143 // or else the waveInReset() will deadlock and secondly, the callback should
    144 // not be inside the AudioInputCallback's OnData because waveInReset()
    145 // forcefully kills the callback thread.
    146 void PCMWaveInAudioInputStream::Stop() {
    147   DVLOG(1) << "PCMWaveInAudioInputStream::Stop()";
    148   DCHECK(thread_checker_.CalledOnValidThread());
    149   if (state_ != kStateRecording)
    150     return;
    151 
    152   bool already_stopped = false;
    153   {
    154     // Tell the callback that we're stopping.
    155     // As a result, |stopped_event_| will be signaled in callback method.
    156     base::AutoLock auto_lock(lock_);
    157     already_stopped = (callback_ == NULL);
    158     callback_ = NULL;
    159   }
    160 
    161   if (already_stopped)
    162     return;
    163 
    164   // Wait for the callback to finish, it will signal us when ready to be reset.
    165   DWORD wait = ::WaitForSingleObject(stopped_event_, INFINITE);
    166   DCHECK_EQ(wait, WAIT_OBJECT_0);
    167 
    168   // Stop input and reset the current position to zero for |wavein_|.
    169   // All pending buffers are marked as done and returned to the application.
    170   MMRESULT res = ::waveInReset(wavein_);
    171   DCHECK_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR));
    172 
    173   state_ = kStateReady;
    174 }
    175 
    176 void PCMWaveInAudioInputStream::Close() {
    177   DVLOG(1) << "PCMWaveInAudioInputStream::Close()";
    178   DCHECK(thread_checker_.CalledOnValidThread());
    179 
    180   // We should not call Close() while recording. Catch it with DCHECK and
    181   // implement auto-stop just in case.
    182   DCHECK_NE(state_, kStateRecording);
    183   Stop();
    184 
    185   if (wavein_) {
    186     FreeBuffers();
    187 
    188     // waveInClose() generates a WIM_CLOSE callback.  In case Start() was never
    189     // called, force a reset to ensure close succeeds.
    190     MMRESULT res = ::waveInReset(wavein_);
    191     DCHECK_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR));
    192     res = ::waveInClose(wavein_);
    193     DCHECK_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR));
    194     state_ = kStateClosed;
    195     wavein_ = NULL;
    196   }
    197 
    198   // Tell the audio manager that we have been released. This can result in
    199   // the manager destroying us in-place so this needs to be the last thing
    200   // we do on this function.
    201   manager_->ReleaseInputStream(this);
    202 }
    203 
    204 double PCMWaveInAudioInputStream::GetMaxVolume() {
    205   // TODO(henrika): Add volume support using the Audio Mixer API.
    206   return 0.0;
    207 }
    208 
    209 void PCMWaveInAudioInputStream::SetVolume(double volume) {
    210   // TODO(henrika): Add volume support using the Audio Mixer API.
    211 }
    212 
    213 double PCMWaveInAudioInputStream::GetVolume() {
    214   // TODO(henrika): Add volume support using the Audio Mixer API.
    215   return 0.0;
    216 }
    217 
    218 void PCMWaveInAudioInputStream::SetAutomaticGainControl(bool enabled) {
    219   // TODO(henrika): Add AGC support when volume control has been added.
    220   NOTIMPLEMENTED();
    221 }
    222 
    223 bool PCMWaveInAudioInputStream::GetAutomaticGainControl() {
    224   // TODO(henrika): Add AGC support when volume control has been added.
    225   NOTIMPLEMENTED();
    226   return false;
    227 }
    228 
    229 void PCMWaveInAudioInputStream::HandleError(MMRESULT error) {
    230   DLOG(WARNING) << "PCMWaveInAudio error " << error;
    231   if (callback_)
    232     callback_->OnError(this);
    233 }
    234 
    235 void PCMWaveInAudioInputStream::QueueNextPacket(WAVEHDR *buffer) {
    236   MMRESULT res = ::waveInAddBuffer(wavein_, buffer, sizeof(WAVEHDR));
    237   if (res != MMSYSERR_NOERROR)
    238     HandleError(res);
    239 }
    240 
    241 bool PCMWaveInAudioInputStream::GetDeviceId(UINT* device_index) {
    242   // Deliver the default input device id (WAVE_MAPPER) if the default
    243   // device has been selected.
    244   if (device_id_ == AudioManagerBase::kDefaultDeviceId) {
    245     *device_index = WAVE_MAPPER;
    246     return true;
    247   }
    248 
    249   // Get list of all available and active devices.
    250   AudioDeviceNames device_names;
    251   if (!media::GetInputDeviceNamesWinXP(&device_names))
    252     return false;
    253 
    254   if (device_names.empty())
    255     return false;
    256 
    257   // Search the full list of devices and compare with the specified
    258   // device id which was specified in the constructor. Stop comparing
    259   // when a match is found and return the corresponding index.
    260   UINT index = 0;
    261   bool found_device = false;
    262   AudioDeviceNames::const_iterator it = device_names.begin();
    263   while (it != device_names.end()) {
    264     if (it->unique_id.compare(device_id_) == 0) {
    265       *device_index = index;
    266       found_device = true;
    267       break;
    268     }
    269     ++index;
    270     ++it;
    271   }
    272 
    273   return found_device;
    274 }
    275 
    276 // Windows calls us back in this function when some events happen. Most notably
    277 // when it has an audio buffer with recorded data.
    278 void PCMWaveInAudioInputStream::WaveCallback(HWAVEIN hwi, UINT msg,
    279                                              DWORD_PTR instance,
    280                                              DWORD_PTR param1, DWORD_PTR) {
    281   PCMWaveInAudioInputStream* obj =
    282       reinterpret_cast<PCMWaveInAudioInputStream*>(instance);
    283 
    284   // The lock ensures that Stop() can't be called during a callback.
    285   base::AutoLock auto_lock(obj->lock_);
    286 
    287   if (msg == WIM_DATA) {
    288     // The WIM_DATA message is sent when waveform-audio data is present in
    289     // the input buffer and the buffer is being returned to the application.
    290     // The message can be sent when the buffer is full or after the
    291     // waveInReset function is called.
    292     if (obj->callback_) {
    293       // TODO(henrika): the |volume| parameter is always set to zero since
    294       // there is currently no support for controlling the microphone volume
    295       // level.
    296       WAVEHDR* buffer = reinterpret_cast<WAVEHDR*>(param1);
    297       obj->audio_bus_->FromInterleaved(reinterpret_cast<uint8*>(buffer->lpData),
    298                                        obj->audio_bus_->frames(),
    299                                        obj->format_.wBitsPerSample / 8);
    300       obj->callback_->OnData(
    301           obj, obj->audio_bus_.get(), buffer->dwBytesRecorded, 0.0);
    302 
    303       // Queue the finished buffer back with the audio driver. Since we are
    304       // reusing the same buffers we can get away without calling
    305       // waveInPrepareHeader.
    306       obj->QueueNextPacket(buffer);
    307     } else {
    308       // Main thread has called Stop() and set |callback_| to NULL and is
    309       // now waiting to issue waveInReset which will kill this thread.
    310       // We should not call AudioSourceCallback code anymore.
    311       ::SetEvent(obj->stopped_event_);
    312     }
    313   } else if (msg == WIM_CLOSE) {
    314     // Intentionaly no-op for now.
    315   } else if (msg == WIM_OPEN) {
    316     // Intentionaly no-op for now.
    317   }
    318 }
    319 
    320 }  // namespace media
    321