Panda3D
|
00001 // Filename: microphoneAudioDS.cxx 00002 // Created by: jyelon (01Nov2007) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 // 00015 // It goes against Panda3D coding style conventions to hide an 00016 // entire class in a C++ file and not expose it through header 00017 // files at all. However, in this case, these classes are so full 00018 // of OS-specific junk that I feel it is better to hide them 00019 // entirely. - Josh 00020 // 00021 //////////////////////////////////////////////////////////////////// 00022 00023 #ifdef HAVE_DIRECTCAM 00024 00025 #define WIN32_LEAN_AND_MEAN 00026 00027 #undef Configure 00028 00029 #include <windows.h> 00030 #include <mmsystem.h> 00031 00032 //////////////////////////////////////////////////////////////////// 00033 // Class : MicrophoneAudioDS 00034 // Description : The directshow implementation of microphones. 00035 //////////////////////////////////////////////////////////////////// 00036 00037 class MicrophoneAudioDS : public MicrophoneAudio 00038 { 00039 public: 00040 static void find_all_microphones_ds(); 00041 friend void find_all_microphones_ds(); 00042 00043 private: 00044 virtual PT(MovieAudioCursor) open(); 00045 00046 int _device_id; 00047 int _manufacturer_id; 00048 int _product_id; 00049 00050 struct AudioBuf { 00051 HGLOBAL _storage_gh; 00052 HGLOBAL _header_gh; 00053 LPSTR _storage; 00054 LPWAVEHDR _header; 00055 }; 00056 typedef pvector <AudioBuf> AudioBuffers; 00057 00058 static void delete_buffers(AudioBuffers &buffers); 00059 00060 friend class MicrophoneAudioCursorDS; 00061 00062 public: 00063 static TypeHandle get_class_type() { 00064 return _type_handle; 00065 } 00066 static void init_type() { 00067 MicrophoneAudio::init_type(); 00068 register_type(_type_handle, "MicrophoneAudioDS", 00069 MicrophoneAudio::get_class_type()); 00070 } 00071 virtual TypeHandle get_type() const { 00072 return get_class_type(); 00073 } 00074 virtual TypeHandle force_init_type() {init_type(); return get_class_type();} 00075 00076 private: 00077 static TypeHandle _type_handle; 00078 }; 00079 00080 TypeHandle MicrophoneAudioDS::_type_handle; 00081 00082 //////////////////////////////////////////////////////////////////// 00083 // Class : MicrophoneAudioCursorDS 00084 // Description : The directshow implementation of microphones. 00085 //////////////////////////////////////////////////////////////////// 00086 00087 class MicrophoneAudioCursorDS : public MovieAudioCursor 00088 { 00089 public: 00090 typedef MicrophoneAudioDS::AudioBuffers AudioBuffers; 00091 MicrophoneAudioCursorDS(MicrophoneAudioDS *src, AudioBuffers &bufs, HWAVEIN hwav); 00092 virtual ~MicrophoneAudioCursorDS(); 00093 00094 AudioBuffers _buffers; 00095 HWAVEIN _hwavein; 00096 int _samples_per_buffer; 00097 00098 public: 00099 virtual void read_samples(int n, PN_int16 *data); 00100 virtual int ready() const; 00101 00102 public: 00103 void cleanup(); 00104 00105 HWAVEIN _handle; 00106 int _next; // Which buffer is the next one to read from. 00107 int _offset; // How many samples to skip in the buffer. 00108 00109 public: 00110 static TypeHandle get_class_type() { 00111 return _type_handle; 00112 } 00113 static void init_type() { 00114 MovieAudioCursor::init_type(); 00115 register_type(_type_handle, "MicrophoneAudioCursorDS", 00116 MovieAudioCursor::get_class_type()); 00117 } 00118 virtual TypeHandle get_type() const { 00119 return get_class_type(); 00120 } 00121 virtual TypeHandle force_init_type() {init_type(); return get_class_type();} 00122 00123 private: 00124 static TypeHandle _type_handle; 00125 }; 00126 00127 TypeHandle MicrophoneAudioCursorDS::_type_handle; 00128 00129 //////////////////////////////////////////////////////////////////// 00130 // Function: MicrophoneAudioDS::find_all_microphones_ds 00131 // Access: Public, Static 00132 // Description: Finds all DirectShow microphones and adds them to 00133 // the global list _all_microphones. 00134 //////////////////////////////////////////////////////////////////// 00135 void MicrophoneAudioDS:: 00136 find_all_microphones_ds() { 00137 MMRESULT stat; 00138 static int freqs[] = { 11025, 22050, 44100, 48000, 0 }; 00139 00140 int ndevs = waveInGetNumDevs(); 00141 for (int i=0; i<ndevs; i++) { 00142 WAVEINCAPS caps; 00143 stat = waveInGetDevCaps(i, &caps, sizeof(caps)); 00144 if (stat != MMSYSERR_NOERROR) continue; 00145 for (int chan=1; chan<=2; chan++) { 00146 for (int fselect=0; freqs[fselect]; fselect++) { 00147 WAVEFORMATEX format; 00148 int freq = freqs[fselect]; 00149 format.wFormatTag = WAVE_FORMAT_PCM; 00150 format.nChannels = chan; 00151 format.nSamplesPerSec = freq; 00152 format.nAvgBytesPerSec = freq * chan * 2; 00153 format.nBlockAlign = 2 * chan; 00154 format.wBitsPerSample = 16; 00155 format.cbSize = 0; 00156 stat = waveInOpen(NULL, i, &format, NULL, NULL, WAVE_FORMAT_QUERY); 00157 if (stat == MMSYSERR_NOERROR) { 00158 PT(MicrophoneAudioDS) p = new MicrophoneAudioDS(); 00159 ostringstream name; 00160 name << "WaveIn: " << caps.szPname << " Chan:" << chan << " HZ:" << freq; 00161 p->set_name(name.str()); 00162 p->_device_id = i; 00163 p->_manufacturer_id = caps.wMid; 00164 p->_product_id = caps.wPid; 00165 p->_rate = freq; 00166 p->_channels = chan; 00167 _all_microphones.push_back((MicrophoneAudioDS*)p); 00168 } 00169 } 00170 } 00171 } 00172 } 00173 00174 void find_all_microphones_ds() { 00175 MicrophoneAudioDS::init_type(); 00176 // MicrophoneAudioCursorDS::init_type(); 00177 MicrophoneAudioDS::find_all_microphones_ds(); 00178 } 00179 00180 //////////////////////////////////////////////////////////////////// 00181 // Function: MicrophoneAudioDS::delete_buffers 00182 // Access: Private, Static 00183 // Description: Delete a set of audio buffers. 00184 //////////////////////////////////////////////////////////////////// 00185 void MicrophoneAudioDS:: 00186 delete_buffers(AudioBuffers &buffers) { 00187 for (int i=0; i<(int)buffers.size(); i++) { 00188 AudioBuf &buf = buffers[i]; 00189 if (buf._header_gh) { 00190 GlobalUnlock(buf._header_gh); 00191 GlobalFree(buf._header_gh); 00192 } 00193 if (buf._storage_gh) { 00194 GlobalUnlock(buf._storage_gh); 00195 GlobalFree(buf._storage_gh); 00196 } 00197 } 00198 buffers.clear(); 00199 } 00200 00201 //////////////////////////////////////////////////////////////////// 00202 // Function: MicrophoneAudioDS::open 00203 // Access: Published, Virtual 00204 // Description: Open this video, returning a MovieVideoCursor. 00205 //////////////////////////////////////////////////////////////////// 00206 PT(MovieAudioCursor) MicrophoneAudioDS:: 00207 open() { 00208 00209 // Allocate the buffers. 64 buffers, not quite 1/20 sec each. 00210 int samples; 00211 switch (_rate) { 00212 case 11025: samples=512; break; 00213 case 22050: samples=1024; break; 00214 case 44100: samples=2048; break; 00215 } 00216 int bytes = _channels * samples * 2; 00217 00218 bool failed = false; 00219 AudioBuffers buffers; 00220 for (int i=0; i<64; i++) { 00221 AudioBuf buf; 00222 buf._storage_gh = 0; 00223 buf._header_gh = 0; 00224 buf._storage = 0; 00225 buf._header = 0; 00226 00227 buf._storage_gh = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, bytes); 00228 buf._header_gh = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR)); 00229 if (buf._storage_gh != 0) { 00230 buf._storage = (LPSTR)GlobalLock(buf._storage_gh); 00231 } 00232 if (buf._header_gh != 0) { 00233 buf._header = (LPWAVEHDR)GlobalLock(buf._header_gh); 00234 } 00235 if (buf._storage && buf._header) { 00236 ZeroMemory(buf._header, sizeof(WAVEHDR)); 00237 buf._header->lpData = buf._storage; 00238 buf._header->dwBufferLength = bytes; 00239 } else { 00240 failed = true; 00241 } 00242 buffers.push_back(buf); 00243 if (failed) break; 00244 } 00245 00246 if (failed) { 00247 delete_buffers(buffers); 00248 nassert_raise("Could not allocate audio input buffers."); 00249 return NULL; 00250 } 00251 00252 WAVEFORMATEX format; 00253 format.wFormatTag = WAVE_FORMAT_PCM; 00254 format.nChannels = _channels; 00255 format.nSamplesPerSec = _rate; 00256 format.nAvgBytesPerSec = _rate * _channels * 2; 00257 format.nBlockAlign = 2 * _channels; 00258 format.wBitsPerSample = 16; 00259 format.cbSize = 0; 00260 00261 HWAVEIN hwav; 00262 MMRESULT stat = waveInOpen(&hwav, _device_id, &format, NULL, NULL, CALLBACK_NULL); 00263 00264 if (stat != MMSYSERR_NOERROR) { 00265 delete_buffers(buffers); 00266 nassert_raise("Could not open audio input device."); 00267 return NULL; 00268 } 00269 00270 for (int i=0; i<(int)buffers.size(); i++) { 00271 stat = waveInPrepareHeader(hwav, buffers[i]._header, sizeof(WAVEHDR)); 00272 if (stat == MMSYSERR_NOERROR) { 00273 stat = waveInAddBuffer(hwav, buffers[i]._header, sizeof(WAVEHDR)); 00274 } 00275 if (stat != MMSYSERR_NOERROR) { 00276 waveInClose(hwav); 00277 delete_buffers(buffers); 00278 nassert_raise("Could not queue buffers for audio input device."); 00279 return NULL; 00280 } 00281 } 00282 stat = waveInStart(hwav); 00283 if (stat != MMSYSERR_NOERROR) { 00284 waveInClose(hwav); 00285 delete_buffers(buffers); 00286 nassert_raise("Could not start recording on input device."); 00287 return NULL; 00288 } 00289 return new MicrophoneAudioCursorDS(this, buffers, hwav); 00290 } 00291 00292 //////////////////////////////////////////////////////////////////// 00293 // Function: MicrophoneAudioCursorDS::Constructor 00294 // Access: Published 00295 // Description: 00296 //////////////////////////////////////////////////////////////////// 00297 MicrophoneAudioCursorDS:: 00298 MicrophoneAudioCursorDS(MicrophoneAudioDS *src, AudioBuffers &bufs, HWAVEIN hwav) : 00299 MovieAudioCursor(src), 00300 _buffers(bufs), 00301 _handle(hwav), 00302 _next(0), 00303 _offset(0) 00304 { 00305 _audio_rate = src->get_rate(); 00306 _audio_channels = src->get_channels(); 00307 _length = 1.0E10; 00308 _can_seek = false; 00309 _can_seek_fast = false; 00310 _aborted = false; 00311 _samples_per_buffer = bufs[0]._header->dwBufferLength / (2 * _audio_channels); 00312 } 00313 00314 //////////////////////////////////////////////////////////////////// 00315 // Function: MicrophoneAudioCursorDS::cleanup 00316 // Access: Published 00317 // Description: 00318 //////////////////////////////////////////////////////////////////// 00319 void MicrophoneAudioCursorDS:: 00320 cleanup() { 00321 if (_handle) { 00322 waveInClose(_handle); 00323 _handle = 0; 00324 } 00325 MicrophoneAudioDS::delete_buffers(_buffers); 00326 _next = 0; 00327 _offset = 0; 00328 } 00329 00330 //////////////////////////////////////////////////////////////////// 00331 // Function: MicrophoneAudioCursorDS::Destructor 00332 // Access: Published 00333 // Description: 00334 //////////////////////////////////////////////////////////////////// 00335 MicrophoneAudioCursorDS:: 00336 ~MicrophoneAudioCursorDS() { 00337 cleanup(); 00338 } 00339 00340 //////////////////////////////////////////////////////////////////// 00341 // Function: MicrophoneAudioCursorDS::read_samples 00342 // Access: Published 00343 // Description: 00344 //////////////////////////////////////////////////////////////////// 00345 void MicrophoneAudioCursorDS:: 00346 read_samples(int n, PN_int16 *data) { 00347 int orign = n; 00348 if (_handle) { 00349 while (1) { 00350 int index = _next % _buffers.size(); 00351 if ((_buffers[index]._header->dwFlags & WHDR_DONE)==0) { 00352 break; 00353 } 00354 00355 // Find start of data in buffer. 00356 PN_int16 *src = (PN_int16*)(_buffers[index]._storage); 00357 src += (_offset * _audio_channels); 00358 00359 // Decide how many samples to extract from this buffer. 00360 int samples = _samples_per_buffer; 00361 samples -= _offset; 00362 if (samples > n) samples = n; 00363 00364 // Copy data to output buffer. 00365 memcpy(data, src, samples * 2 * _audio_channels); 00366 00367 // Advance pointers. 00368 data += samples * _audio_channels; 00369 n -= samples; 00370 _offset += samples; 00371 _samples_read += samples; 00372 if (_offset != _samples_per_buffer) { 00373 break; 00374 } 00375 _buffers[index]._header->dwFlags &= ~(WHDR_DONE); 00376 MMRESULT stat = waveInUnprepareHeader(_handle, _buffers[index]._header, sizeof(WAVEHDR)); 00377 if (stat == MMSYSERR_NOERROR) { 00378 stat = waveInPrepareHeader(_handle, _buffers[index]._header, sizeof(WAVEHDR)); 00379 } 00380 if (stat == MMSYSERR_NOERROR) { 00381 stat = waveInAddBuffer(_handle, _buffers[index]._header, sizeof(WAVEHDR)); 00382 } 00383 if (stat != MMSYSERR_NOERROR) { 00384 movies_cat.error() << "Could not requeue audio buffers, closing microphone.\n"; 00385 cleanup(); 00386 break; 00387 } 00388 _next += 1; 00389 _offset = 0; 00390 } 00391 } 00392 if (n > 0) { 00393 memcpy(data, 0, n*2*_audio_channels); 00394 } 00395 } 00396 00397 //////////////////////////////////////////////////////////////////// 00398 // Function: MicrophoneAudioCursorDS::ready 00399 // Access: Published 00400 // Description: 00401 //////////////////////////////////////////////////////////////////// 00402 int MicrophoneAudioCursorDS:: 00403 ready() const { 00404 if (_handle == 0) return 0; 00405 int total = 0; 00406 for (int i=0; i<(int)_buffers.size(); i++) { 00407 int index = (_next + i) % (_buffers.size()); 00408 if ((_buffers[index]._header->dwFlags & WHDR_DONE)==0) { 00409 break; 00410 } 00411 total += _samples_per_buffer; 00412 } 00413 total -= _offset; 00414 return total; 00415 } 00416 00417 00418 #endif // HAVE_DIRECTSHOW