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_.Get(), 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 bool PCMWaveInAudioInputStream::IsMuted() { 230 NOTIMPLEMENTED(); 231 return false; 232 } 233 234 void PCMWaveInAudioInputStream::HandleError(MMRESULT error) { 235 DLOG(WARNING) << "PCMWaveInAudio error " << error; 236 if (callback_) 237 callback_->OnError(this); 238 } 239 240 void PCMWaveInAudioInputStream::QueueNextPacket(WAVEHDR *buffer) { 241 MMRESULT res = ::waveInAddBuffer(wavein_, buffer, sizeof(WAVEHDR)); 242 if (res != MMSYSERR_NOERROR) 243 HandleError(res); 244 } 245 246 bool PCMWaveInAudioInputStream::GetDeviceId(UINT* device_index) { 247 // Deliver the default input device id (WAVE_MAPPER) if the default 248 // device has been selected. 249 if (device_id_ == AudioManagerBase::kDefaultDeviceId) { 250 *device_index = WAVE_MAPPER; 251 return true; 252 } 253 254 // Get list of all available and active devices. 255 AudioDeviceNames device_names; 256 if (!media::GetInputDeviceNamesWinXP(&device_names)) 257 return false; 258 259 if (device_names.empty()) 260 return false; 261 262 // Search the full list of devices and compare with the specified 263 // device id which was specified in the constructor. Stop comparing 264 // when a match is found and return the corresponding index. 265 UINT index = 0; 266 bool found_device = false; 267 AudioDeviceNames::const_iterator it = device_names.begin(); 268 while (it != device_names.end()) { 269 if (it->unique_id.compare(device_id_) == 0) { 270 *device_index = index; 271 found_device = true; 272 break; 273 } 274 ++index; 275 ++it; 276 } 277 278 return found_device; 279 } 280 281 // Windows calls us back in this function when some events happen. Most notably 282 // when it has an audio buffer with recorded data. 283 void PCMWaveInAudioInputStream::WaveCallback(HWAVEIN hwi, UINT msg, 284 DWORD_PTR instance, 285 DWORD_PTR param1, DWORD_PTR) { 286 PCMWaveInAudioInputStream* obj = 287 reinterpret_cast<PCMWaveInAudioInputStream*>(instance); 288 289 // The lock ensures that Stop() can't be called during a callback. 290 base::AutoLock auto_lock(obj->lock_); 291 292 if (msg == WIM_DATA) { 293 // The WIM_DATA message is sent when waveform-audio data is present in 294 // the input buffer and the buffer is being returned to the application. 295 // The message can be sent when the buffer is full or after the 296 // waveInReset function is called. 297 if (obj->callback_) { 298 // TODO(henrika): the |volume| parameter is always set to zero since 299 // there is currently no support for controlling the microphone volume 300 // level. 301 WAVEHDR* buffer = reinterpret_cast<WAVEHDR*>(param1); 302 obj->audio_bus_->FromInterleaved(reinterpret_cast<uint8*>(buffer->lpData), 303 obj->audio_bus_->frames(), 304 obj->format_.wBitsPerSample / 8); 305 obj->callback_->OnData( 306 obj, obj->audio_bus_.get(), buffer->dwBytesRecorded, 0.0); 307 308 // Queue the finished buffer back with the audio driver. Since we are 309 // reusing the same buffers we can get away without calling 310 // waveInPrepareHeader. 311 obj->QueueNextPacket(buffer); 312 } else { 313 // Main thread has called Stop() and set |callback_| to NULL and is 314 // now waiting to issue waveInReset which will kill this thread. 315 // We should not call AudioSourceCallback code anymore. 316 ::SetEvent(obj->stopped_event_.Get()); 317 } 318 } else if (msg == WIM_CLOSE) { 319 // Intentionaly no-op for now. 320 } else if (msg == WIM_OPEN) { 321 // Intentionaly no-op for now. 322 } 323 } 324 325 } // namespace media 326