winmm.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17. * Boston, MA 02111-1307, USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <memory.h>
  24. #include <windows.h>
  25. #include <mmsystem.h>
  26. #include "alMain.h"
  27. #include "AL/al.h"
  28. #include "AL/alc.h"
  29. #ifndef WAVE_FORMAT_IEEE_FLOAT
  30. #define WAVE_FORMAT_IEEE_FLOAT 0x0003
  31. #endif
  32. typedef struct {
  33. // MMSYSTEM Device
  34. volatile ALboolean bWaveShutdown;
  35. HANDLE hWaveThreadEvent;
  36. HANDLE hWaveThread;
  37. DWORD ulWaveThreadID;
  38. volatile LONG lWaveBuffersCommitted;
  39. WAVEHDR WaveBuffer[4];
  40. union {
  41. HWAVEIN In;
  42. HWAVEOUT Out;
  43. } hWaveHandle;
  44. WAVEFORMATEX wfexFormat;
  45. RingBuffer *pRing;
  46. } WinMMData;
  47. static ALCchar **PlaybackDeviceList;
  48. static ALuint NumPlaybackDevices;
  49. static ALCchar **CaptureDeviceList;
  50. static ALuint NumCaptureDevices;
  51. static void ProbePlaybackDevices(void)
  52. {
  53. ALuint i;
  54. for(i = 0;i < NumPlaybackDevices;i++)
  55. free(PlaybackDeviceList[i]);
  56. NumPlaybackDevices = waveOutGetNumDevs();
  57. PlaybackDeviceList = realloc(PlaybackDeviceList, sizeof(ALCchar*) * NumPlaybackDevices);
  58. for(i = 0;i < NumPlaybackDevices;i++)
  59. {
  60. WAVEOUTCAPS WaveCaps;
  61. PlaybackDeviceList[i] = NULL;
  62. if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
  63. {
  64. char name[1024];
  65. ALuint count, j;
  66. count = 0;
  67. do {
  68. if(count == 0)
  69. snprintf(name, sizeof(name), "%s", WaveCaps.szPname);
  70. else
  71. snprintf(name, sizeof(name), "%s #%d", WaveCaps.szPname, count+1);
  72. count++;
  73. for(j = 0;j < i;j++)
  74. {
  75. if(strcmp(name, PlaybackDeviceList[j]) == 0)
  76. break;
  77. }
  78. } while(j != i);
  79. PlaybackDeviceList[i] = strdup(name);
  80. }
  81. }
  82. }
  83. static void ProbeCaptureDevices(void)
  84. {
  85. ALuint i;
  86. for(i = 0;i < NumCaptureDevices;i++)
  87. free(CaptureDeviceList[i]);
  88. NumCaptureDevices = waveInGetNumDevs();
  89. CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices);
  90. for(i = 0;i < NumCaptureDevices;i++)
  91. {
  92. WAVEINCAPS WaveInCaps;
  93. CaptureDeviceList[i] = NULL;
  94. if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
  95. {
  96. char name[1024];
  97. ALuint count, j;
  98. count = 0;
  99. do {
  100. if(count == 0)
  101. snprintf(name, sizeof(name), "%s", WaveInCaps.szPname);
  102. else
  103. snprintf(name, sizeof(name), "%s #%d", WaveInCaps.szPname, count+1);
  104. count++;
  105. for(j = 0;j < i;j++)
  106. {
  107. if(strcmp(name, CaptureDeviceList[j]) == 0)
  108. break;
  109. }
  110. } while(j != i);
  111. CaptureDeviceList[i] = strdup(name);
  112. }
  113. }
  114. }
  115. /*
  116. WaveOutProc
  117. Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and
  118. returns to the application (for more data)
  119. */
  120. static void CALLBACK WaveOutProc(HWAVEOUT hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
  121. {
  122. ALCdevice *pDevice = (ALCdevice*)dwInstance;
  123. WinMMData *pData = pDevice->ExtraData;
  124. (void)hDevice;
  125. (void)dwParam2;
  126. if(uMsg != WOM_DONE)
  127. return;
  128. InterlockedDecrement(&pData->lWaveBuffersCommitted);
  129. PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1);
  130. }
  131. /*
  132. PlaybackThreadProc
  133. Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its
  134. audio data.
  135. */
  136. static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)
  137. {
  138. ALCdevice *pDevice = (ALCdevice*)lpParameter;
  139. WinMMData *pData = pDevice->ExtraData;
  140. LPWAVEHDR pWaveHdr;
  141. ALuint FrameSize;
  142. MSG msg;
  143. FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
  144. SetRTPriority();
  145. while(GetMessage(&msg, NULL, 0, 0))
  146. {
  147. if(msg.message != WOM_DONE)
  148. continue;
  149. if(pData->bWaveShutdown)
  150. {
  151. if(pData->lWaveBuffersCommitted == 0)
  152. break;
  153. continue;
  154. }
  155. pWaveHdr = ((LPWAVEHDR)msg.lParam);
  156. aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize);
  157. // Send buffer back to play more data
  158. waveOutWrite(pData->hWaveHandle.Out, pWaveHdr, sizeof(WAVEHDR));
  159. InterlockedIncrement(&pData->lWaveBuffersCommitted);
  160. }
  161. // Signal Wave Thread completed event
  162. if(pData->hWaveThreadEvent)
  163. SetEvent(pData->hWaveThreadEvent);
  164. ExitThread(0);
  165. return 0;
  166. }
  167. /*
  168. WaveInProc
  169. Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
  170. returns to the application (with more data)
  171. */
  172. static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
  173. {
  174. ALCdevice *pDevice = (ALCdevice*)dwInstance;
  175. WinMMData *pData = pDevice->ExtraData;
  176. (void)hDevice;
  177. (void)dwParam2;
  178. if(uMsg != WIM_DATA)
  179. return;
  180. InterlockedDecrement(&pData->lWaveBuffersCommitted);
  181. PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);
  182. }
  183. /*
  184. CaptureThreadProc
  185. Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new
  186. audio data.
  187. */
  188. static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
  189. {
  190. ALCdevice *pDevice = (ALCdevice*)lpParameter;
  191. WinMMData *pData = pDevice->ExtraData;
  192. LPWAVEHDR pWaveHdr;
  193. ALuint FrameSize;
  194. MSG msg;
  195. FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
  196. while(GetMessage(&msg, NULL, 0, 0))
  197. {
  198. if(msg.message != WIM_DATA)
  199. continue;
  200. /* Don't wait for other buffers to finish before quitting. We're
  201. * closing so we don't need them. */
  202. if(pData->bWaveShutdown)
  203. break;
  204. pWaveHdr = ((LPWAVEHDR)msg.lParam);
  205. WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData,
  206. pWaveHdr->dwBytesRecorded/FrameSize);
  207. // Send buffer back to capture more data
  208. waveInAddBuffer(pData->hWaveHandle.In,pWaveHdr,sizeof(WAVEHDR));
  209. InterlockedIncrement(&pData->lWaveBuffersCommitted);
  210. }
  211. // Signal Wave Thread completed event
  212. if(pData->hWaveThreadEvent)
  213. SetEvent(pData->hWaveThreadEvent);
  214. ExitThread(0);
  215. return 0;
  216. }
  217. static ALCenum WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)
  218. {
  219. WinMMData *pData = NULL;
  220. UINT lDeviceID = 0;
  221. MMRESULT res;
  222. ALuint i = 0;
  223. if(!PlaybackDeviceList)
  224. ProbePlaybackDevices();
  225. // Find the Device ID matching the deviceName if valid
  226. for(i = 0;i < NumPlaybackDevices;i++)
  227. {
  228. if(PlaybackDeviceList[i] &&
  229. (!deviceName || strcmp(deviceName, PlaybackDeviceList[i]) == 0))
  230. {
  231. lDeviceID = i;
  232. break;
  233. }
  234. }
  235. if(i == NumPlaybackDevices)
  236. return ALC_INVALID_VALUE;
  237. pData = calloc(1, sizeof(*pData));
  238. if(!pData)
  239. return ALC_OUT_OF_MEMORY;
  240. pDevice->ExtraData = pData;
  241. retry_open:
  242. memset(&pData->wfexFormat, 0, sizeof(WAVEFORMATEX));
  243. if(pDevice->FmtType == DevFmtFloat)
  244. {
  245. pData->wfexFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
  246. pData->wfexFormat.wBitsPerSample = 32;
  247. }
  248. else
  249. {
  250. pData->wfexFormat.wFormatTag = WAVE_FORMAT_PCM;
  251. if(pDevice->FmtType == DevFmtUByte || pDevice->FmtType == DevFmtByte)
  252. pData->wfexFormat.wBitsPerSample = 8;
  253. else
  254. pData->wfexFormat.wBitsPerSample = 16;
  255. }
  256. pData->wfexFormat.nChannels = ((pDevice->FmtChans == DevFmtMono) ? 1 : 2);
  257. pData->wfexFormat.nBlockAlign = pData->wfexFormat.wBitsPerSample *
  258. pData->wfexFormat.nChannels / 8;
  259. pData->wfexFormat.nSamplesPerSec = pDevice->Frequency;
  260. pData->wfexFormat.nAvgBytesPerSec = pData->wfexFormat.nSamplesPerSec *
  261. pData->wfexFormat.nBlockAlign;
  262. pData->wfexFormat.cbSize = 0;
  263. if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &pData->wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
  264. {
  265. if(pDevice->FmtType == DevFmtFloat)
  266. {
  267. pDevice->FmtType = DevFmtShort;
  268. goto retry_open;
  269. }
  270. ERR("waveOutOpen failed: %u\n", res);
  271. goto failure;
  272. }
  273. pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  274. if(pData->hWaveThreadEvent == NULL)
  275. {
  276. ERR("CreateEvent failed: %lu\n", GetLastError());
  277. goto failure;
  278. }
  279. pDevice->szDeviceName = strdup(PlaybackDeviceList[lDeviceID]);
  280. return ALC_NO_ERROR;
  281. failure:
  282. if(pData->hWaveThreadEvent)
  283. CloseHandle(pData->hWaveThreadEvent);
  284. if(pData->hWaveHandle.Out)
  285. waveOutClose(pData->hWaveHandle.Out);
  286. free(pData);
  287. pDevice->ExtraData = NULL;
  288. return ALC_INVALID_VALUE;
  289. }
  290. static void WinMMClosePlayback(ALCdevice *device)
  291. {
  292. WinMMData *pData = (WinMMData*)device->ExtraData;
  293. // Close the Wave device
  294. CloseHandle(pData->hWaveThreadEvent);
  295. pData->hWaveThreadEvent = 0;
  296. waveOutClose(pData->hWaveHandle.Out);
  297. pData->hWaveHandle.Out = 0;
  298. free(pData);
  299. device->ExtraData = NULL;
  300. }
  301. static ALCboolean WinMMResetPlayback(ALCdevice *device)
  302. {
  303. WinMMData *data = (WinMMData*)device->ExtraData;
  304. device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
  305. data->wfexFormat.nSamplesPerSec /
  306. device->Frequency);
  307. device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4;
  308. device->NumUpdates = 4;
  309. device->Frequency = data->wfexFormat.nSamplesPerSec;
  310. if(data->wfexFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
  311. {
  312. if(data->wfexFormat.wBitsPerSample == 32)
  313. device->FmtType = DevFmtFloat;
  314. else
  315. {
  316. ERR("Unhandled IEEE float sample depth: %d\n", data->wfexFormat.wBitsPerSample);
  317. return ALC_FALSE;
  318. }
  319. }
  320. else if(data->wfexFormat.wFormatTag == WAVE_FORMAT_PCM)
  321. {
  322. if(data->wfexFormat.wBitsPerSample == 16)
  323. device->FmtType = DevFmtShort;
  324. else if(data->wfexFormat.wBitsPerSample == 8)
  325. device->FmtType = DevFmtUByte;
  326. else
  327. {
  328. ERR("Unhandled PCM sample depth: %d\n", data->wfexFormat.wBitsPerSample);
  329. return ALC_FALSE;
  330. }
  331. }
  332. else
  333. {
  334. ERR("Unhandled format tag: 0x%04x\n", data->wfexFormat.wFormatTag);
  335. return ALC_FALSE;
  336. }
  337. if(data->wfexFormat.nChannels == 2)
  338. device->FmtChans = DevFmtStereo;
  339. else if(data->wfexFormat.nChannels == 1)
  340. device->FmtChans = DevFmtMono;
  341. else
  342. {
  343. ERR("Unhandled channel count: %d\n", data->wfexFormat.nChannels);
  344. return ALC_FALSE;
  345. }
  346. SetDefaultWFXChannelOrder(device);
  347. return ALC_TRUE;
  348. }
  349. static ALCboolean WinMMStartPlayback(ALCdevice *device)
  350. {
  351. WinMMData *pData = (WinMMData*)device->ExtraData;
  352. ALbyte *BufferData;
  353. ALint lBufferSize;
  354. ALuint i;
  355. pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);
  356. if(pData->hWaveThread == NULL)
  357. return ALC_FALSE;
  358. pData->lWaveBuffersCommitted = 0;
  359. // Create 4 Buffers
  360. lBufferSize = device->UpdateSize*device->NumUpdates / 4;
  361. lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
  362. BufferData = calloc(4, lBufferSize);
  363. for(i = 0;i < 4;i++)
  364. {
  365. memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
  366. pData->WaveBuffer[i].dwBufferLength = lBufferSize;
  367. pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
  368. (pData->WaveBuffer[i-1].lpData +
  369. pData->WaveBuffer[i-1].dwBufferLength));
  370. waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
  371. waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
  372. InterlockedIncrement(&pData->lWaveBuffersCommitted);
  373. }
  374. return ALC_TRUE;
  375. }
  376. static void WinMMStopPlayback(ALCdevice *device)
  377. {
  378. WinMMData *pData = (WinMMData*)device->ExtraData;
  379. void *buffer = NULL;
  380. int i;
  381. if(pData->hWaveThread == NULL)
  382. return;
  383. // Set flag to stop processing headers
  384. pData->bWaveShutdown = AL_TRUE;
  385. // Wait for signal that Wave Thread has been destroyed
  386. WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
  387. CloseHandle(pData->hWaveThread);
  388. pData->hWaveThread = 0;
  389. pData->bWaveShutdown = AL_FALSE;
  390. // Release the wave buffers
  391. for(i = 0;i < 4;i++)
  392. {
  393. waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
  394. if(i == 0) buffer = pData->WaveBuffer[i].lpData;
  395. pData->WaveBuffer[i].lpData = NULL;
  396. }
  397. free(buffer);
  398. }
  399. static ALCenum WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
  400. {
  401. ALbyte *BufferData = NULL;
  402. DWORD ulCapturedDataSize;
  403. WinMMData *pData = NULL;
  404. UINT lDeviceID = 0;
  405. ALint lBufferSize;
  406. MMRESULT res;
  407. ALuint i;
  408. if(!CaptureDeviceList)
  409. ProbeCaptureDevices();
  410. // Find the Device ID matching the deviceName if valid
  411. for(i = 0;i < NumCaptureDevices;i++)
  412. {
  413. if(CaptureDeviceList[i] &&
  414. (!deviceName || strcmp(deviceName, CaptureDeviceList[i]) == 0))
  415. {
  416. lDeviceID = i;
  417. break;
  418. }
  419. }
  420. if(i == NumCaptureDevices)
  421. return ALC_INVALID_VALUE;
  422. switch(pDevice->FmtChans)
  423. {
  424. case DevFmtMono:
  425. case DevFmtStereo:
  426. break;
  427. case DevFmtQuad:
  428. case DevFmtX51:
  429. case DevFmtX51Side:
  430. case DevFmtX61:
  431. case DevFmtX71:
  432. return ALC_INVALID_ENUM;
  433. }
  434. switch(pDevice->FmtType)
  435. {
  436. case DevFmtUByte:
  437. case DevFmtShort:
  438. case DevFmtInt:
  439. case DevFmtFloat:
  440. break;
  441. case DevFmtByte:
  442. case DevFmtUShort:
  443. case DevFmtUInt:
  444. return ALC_INVALID_ENUM;
  445. }
  446. pData = calloc(1, sizeof(*pData));
  447. if(!pData)
  448. return ALC_OUT_OF_MEMORY;
  449. pDevice->ExtraData = pData;
  450. memset(&pData->wfexFormat, 0, sizeof(WAVEFORMATEX));
  451. pData->wfexFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
  452. WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
  453. pData->wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
  454. pData->wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
  455. pData->wfexFormat.nBlockAlign = pData->wfexFormat.wBitsPerSample *
  456. pData->wfexFormat.nChannels / 8;
  457. pData->wfexFormat.nSamplesPerSec = pDevice->Frequency;
  458. pData->wfexFormat.nAvgBytesPerSec = pData->wfexFormat.nSamplesPerSec *
  459. pData->wfexFormat.nBlockAlign;
  460. pData->wfexFormat.cbSize = 0;
  461. if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &pData->wfexFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
  462. {
  463. ERR("waveInOpen failed: %u\n", res);
  464. goto failure;
  465. }
  466. pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  467. if(pData->hWaveThreadEvent == NULL)
  468. {
  469. ERR("CreateEvent failed: %lu\n", GetLastError());
  470. goto failure;
  471. }
  472. // Allocate circular memory buffer for the captured audio
  473. ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;
  474. // Make sure circular buffer is at least 100ms in size
  475. if(ulCapturedDataSize < (pData->wfexFormat.nSamplesPerSec / 10))
  476. ulCapturedDataSize = pData->wfexFormat.nSamplesPerSec / 10;
  477. pData->pRing = CreateRingBuffer(pData->wfexFormat.nBlockAlign, ulCapturedDataSize);
  478. if(!pData->pRing)
  479. goto failure;
  480. pData->lWaveBuffersCommitted = 0;
  481. // Create 4 Buffers of 50ms each
  482. lBufferSize = pData->wfexFormat.nAvgBytesPerSec / 20;
  483. lBufferSize -= (lBufferSize % pData->wfexFormat.nBlockAlign);
  484. BufferData = calloc(4, lBufferSize);
  485. if(!BufferData)
  486. goto failure;
  487. for(i = 0;i < 4;i++)
  488. {
  489. memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
  490. pData->WaveBuffer[i].dwBufferLength = lBufferSize;
  491. pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
  492. (pData->WaveBuffer[i-1].lpData +
  493. pData->WaveBuffer[i-1].dwBufferLength));
  494. pData->WaveBuffer[i].dwFlags = 0;
  495. pData->WaveBuffer[i].dwLoops = 0;
  496. waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
  497. waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
  498. InterlockedIncrement(&pData->lWaveBuffersCommitted);
  499. }
  500. pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID);
  501. if (pData->hWaveThread == NULL)
  502. goto failure;
  503. pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
  504. return ALC_NO_ERROR;
  505. failure:
  506. if(pData->hWaveThread)
  507. CloseHandle(pData->hWaveThread);
  508. if(BufferData)
  509. {
  510. for(i = 0;i < 4;i++)
  511. waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
  512. free(BufferData);
  513. }
  514. if(pData->pRing)
  515. DestroyRingBuffer(pData->pRing);
  516. if(pData->hWaveThreadEvent)
  517. CloseHandle(pData->hWaveThreadEvent);
  518. if(pData->hWaveHandle.In)
  519. waveInClose(pData->hWaveHandle.In);
  520. free(pData);
  521. pDevice->ExtraData = NULL;
  522. return ALC_INVALID_VALUE;
  523. }
  524. static void WinMMCloseCapture(ALCdevice *pDevice)
  525. {
  526. WinMMData *pData = (WinMMData*)pDevice->ExtraData;
  527. void *buffer = NULL;
  528. int i;
  529. /* Tell the processing thread to quit and wait for it to do so. */
  530. pData->bWaveShutdown = AL_TRUE;
  531. PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
  532. WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
  533. /* Make sure capture is stopped and all pending buffers are flushed. */
  534. waveInReset(pData->hWaveHandle.In);
  535. CloseHandle(pData->hWaveThread);
  536. pData->hWaveThread = 0;
  537. // Release the wave buffers
  538. for(i = 0;i < 4;i++)
  539. {
  540. waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
  541. if(i == 0) buffer = pData->WaveBuffer[i].lpData;
  542. pData->WaveBuffer[i].lpData = NULL;
  543. }
  544. free(buffer);
  545. DestroyRingBuffer(pData->pRing);
  546. pData->pRing = NULL;
  547. // Close the Wave device
  548. CloseHandle(pData->hWaveThreadEvent);
  549. pData->hWaveThreadEvent = 0;
  550. waveInClose(pData->hWaveHandle.In);
  551. pData->hWaveHandle.In = 0;
  552. free(pData);
  553. pDevice->ExtraData = NULL;
  554. }
  555. static void WinMMStartCapture(ALCdevice *pDevice)
  556. {
  557. WinMMData *pData = (WinMMData*)pDevice->ExtraData;
  558. waveInStart(pData->hWaveHandle.In);
  559. }
  560. static void WinMMStopCapture(ALCdevice *pDevice)
  561. {
  562. WinMMData *pData = (WinMMData*)pDevice->ExtraData;
  563. waveInStop(pData->hWaveHandle.In);
  564. }
  565. static ALCenum WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
  566. {
  567. WinMMData *pData = (WinMMData*)pDevice->ExtraData;
  568. ReadRingBuffer(pData->pRing, pBuffer, lSamples);
  569. return ALC_NO_ERROR;
  570. }
  571. static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
  572. {
  573. WinMMData *pData = (WinMMData*)pDevice->ExtraData;
  574. return RingBufferSize(pData->pRing);
  575. }
  576. static const BackendFuncs WinMMFuncs = {
  577. WinMMOpenPlayback,
  578. WinMMClosePlayback,
  579. WinMMResetPlayback,
  580. WinMMStartPlayback,
  581. WinMMStopPlayback,
  582. WinMMOpenCapture,
  583. WinMMCloseCapture,
  584. WinMMStartCapture,
  585. WinMMStopCapture,
  586. WinMMCaptureSamples,
  587. WinMMAvailableSamples
  588. };
  589. ALCboolean alcWinMMInit(BackendFuncs *FuncList)
  590. {
  591. *FuncList = WinMMFuncs;
  592. return ALC_TRUE;
  593. }
  594. void alcWinMMDeinit()
  595. {
  596. ALuint lLoop;
  597. for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++)
  598. free(PlaybackDeviceList[lLoop]);
  599. free(PlaybackDeviceList);
  600. PlaybackDeviceList = NULL;
  601. NumPlaybackDevices = 0;
  602. for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
  603. free(CaptureDeviceList[lLoop]);
  604. free(CaptureDeviceList);
  605. CaptureDeviceList = NULL;
  606. NumCaptureDevices = 0;
  607. }
  608. void alcWinMMProbe(enum DevProbe type)
  609. {
  610. ALuint i;
  611. switch(type)
  612. {
  613. case ALL_DEVICE_PROBE:
  614. ProbePlaybackDevices();
  615. for(i = 0;i < NumPlaybackDevices;i++)
  616. {
  617. if(PlaybackDeviceList[i])
  618. AppendAllDeviceList(PlaybackDeviceList[i]);
  619. }
  620. break;
  621. case CAPTURE_DEVICE_PROBE:
  622. ProbeCaptureDevices();
  623. for(i = 0;i < NumCaptureDevices;i++)
  624. {
  625. if(CaptureDeviceList[i])
  626. AppendCaptureDeviceList(CaptureDeviceList[i]);
  627. }
  628. break;
  629. }
  630. }