Mercurial > audio-send
comparison Alc/backends/winmm.c @ 0:f9476ff7637e
initial forking of open-al to create multiple listeners
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Tue, 25 Oct 2011 13:02:31 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f9476ff7637e |
---|---|
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 | |
21 #include "config.h" | |
22 | |
23 #define _WIN32_WINNT 0x0500 | |
24 #include <stdlib.h> | |
25 #include <stdio.h> | |
26 #include <memory.h> | |
27 | |
28 #include <windows.h> | |
29 #include <mmsystem.h> | |
30 | |
31 #include "alMain.h" | |
32 #include "AL/al.h" | |
33 #include "AL/alc.h" | |
34 | |
35 | |
36 typedef struct { | |
37 // MMSYSTEM Device | |
38 volatile ALboolean bWaveShutdown; | |
39 HANDLE hWaveThreadEvent; | |
40 HANDLE hWaveThread; | |
41 DWORD ulWaveThreadID; | |
42 LONG lWaveBuffersCommitted; | |
43 WAVEHDR WaveBuffer[4]; | |
44 | |
45 union { | |
46 HWAVEIN In; | |
47 HWAVEOUT Out; | |
48 } hWaveHandle; | |
49 | |
50 ALuint Frequency; | |
51 | |
52 RingBuffer *pRing; | |
53 } WinMMData; | |
54 | |
55 | |
56 static const ALCchar woDefault[] = "WaveOut Default"; | |
57 | |
58 static ALCchar **PlaybackDeviceList; | |
59 static ALuint NumPlaybackDevices; | |
60 static ALCchar **CaptureDeviceList; | |
61 static ALuint NumCaptureDevices; | |
62 | |
63 | |
64 static void ProbePlaybackDevices(void) | |
65 { | |
66 ALuint i; | |
67 | |
68 for(i = 0;i < NumPlaybackDevices;i++) | |
69 free(PlaybackDeviceList[i]); | |
70 | |
71 NumPlaybackDevices = waveOutGetNumDevs(); | |
72 PlaybackDeviceList = realloc(PlaybackDeviceList, sizeof(ALCchar*) * NumPlaybackDevices); | |
73 for(i = 0;i < NumPlaybackDevices;i++) | |
74 { | |
75 WAVEOUTCAPS WaveCaps; | |
76 | |
77 PlaybackDeviceList[i] = NULL; | |
78 if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) | |
79 { | |
80 char name[1024]; | |
81 ALuint count, j; | |
82 | |
83 count = 0; | |
84 do { | |
85 if(count == 0) | |
86 snprintf(name, sizeof(name), "%s", WaveCaps.szPname); | |
87 else | |
88 snprintf(name, sizeof(name), "%s #%d", WaveCaps.szPname, count+1); | |
89 count++; | |
90 | |
91 for(j = 0;j < i;j++) | |
92 { | |
93 if(strcmp(name, PlaybackDeviceList[j]) == 0) | |
94 break; | |
95 } | |
96 } while(j != i); | |
97 | |
98 PlaybackDeviceList[i] = strdup(name); | |
99 } | |
100 } | |
101 } | |
102 | |
103 static void ProbeCaptureDevices(void) | |
104 { | |
105 ALuint i; | |
106 | |
107 for(i = 0;i < NumCaptureDevices;i++) | |
108 free(CaptureDeviceList[i]); | |
109 | |
110 NumCaptureDevices = waveInGetNumDevs(); | |
111 CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices); | |
112 for(i = 0;i < NumCaptureDevices;i++) | |
113 { | |
114 WAVEINCAPS WaveInCaps; | |
115 | |
116 CaptureDeviceList[i] = NULL; | |
117 if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) | |
118 { | |
119 char name[1024]; | |
120 ALuint count, j; | |
121 | |
122 count = 0; | |
123 do { | |
124 if(count == 0) | |
125 snprintf(name, sizeof(name), "%s", WaveInCaps.szPname); | |
126 else | |
127 snprintf(name, sizeof(name), "%s #%d", WaveInCaps.szPname, count+1); | |
128 count++; | |
129 | |
130 for(j = 0;j < i;j++) | |
131 { | |
132 if(strcmp(name, CaptureDeviceList[j]) == 0) | |
133 break; | |
134 } | |
135 } while(j != i); | |
136 | |
137 CaptureDeviceList[i] = strdup(name); | |
138 } | |
139 } | |
140 } | |
141 | |
142 | |
143 /* | |
144 WaveOutProc | |
145 | |
146 Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and | |
147 returns to the application (for more data) | |
148 */ | |
149 static void CALLBACK WaveOutProc(HWAVEOUT hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2) | |
150 { | |
151 ALCdevice *pDevice = (ALCdevice*)dwInstance; | |
152 WinMMData *pData = pDevice->ExtraData; | |
153 | |
154 (void)hDevice; | |
155 (void)dwParam2; | |
156 | |
157 if(uMsg != WOM_DONE) | |
158 return; | |
159 | |
160 // Decrement number of buffers in use | |
161 InterlockedDecrement(&pData->lWaveBuffersCommitted); | |
162 | |
163 if(pData->bWaveShutdown == AL_FALSE) | |
164 { | |
165 // Notify Wave Processor Thread that a Wave Header has returned | |
166 PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1); | |
167 } | |
168 else | |
169 { | |
170 if(pData->lWaveBuffersCommitted == 0) | |
171 { | |
172 // Post 'Quit' Message to WaveOut Processor Thread | |
173 PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0); | |
174 } | |
175 } | |
176 } | |
177 | |
178 /* | |
179 PlaybackThreadProc | |
180 | |
181 Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its | |
182 audio data. | |
183 */ | |
184 static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter) | |
185 { | |
186 ALCdevice *pDevice = (ALCdevice*)lpParameter; | |
187 WinMMData *pData = pDevice->ExtraData; | |
188 LPWAVEHDR pWaveHdr; | |
189 ALuint FrameSize; | |
190 MSG msg; | |
191 | |
192 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); | |
193 | |
194 SetRTPriority(); | |
195 | |
196 while(GetMessage(&msg, NULL, 0, 0)) | |
197 { | |
198 if(msg.message != WOM_DONE || pData->bWaveShutdown) | |
199 continue; | |
200 | |
201 pWaveHdr = ((LPWAVEHDR)msg.lParam); | |
202 | |
203 aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize); | |
204 | |
205 // Send buffer back to play more data | |
206 waveOutWrite(pData->hWaveHandle.Out, pWaveHdr, sizeof(WAVEHDR)); | |
207 InterlockedIncrement(&pData->lWaveBuffersCommitted); | |
208 } | |
209 | |
210 // Signal Wave Thread completed event | |
211 if(pData->hWaveThreadEvent) | |
212 SetEvent(pData->hWaveThreadEvent); | |
213 | |
214 ExitThread(0); | |
215 | |
216 return 0; | |
217 } | |
218 | |
219 /* | |
220 WaveInProc | |
221 | |
222 Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and | |
223 returns to the application (with more data) | |
224 */ | |
225 static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2) | |
226 { | |
227 ALCdevice *pDevice = (ALCdevice*)dwInstance; | |
228 WinMMData *pData = pDevice->ExtraData; | |
229 | |
230 (void)hDevice; | |
231 (void)dwParam2; | |
232 | |
233 if(uMsg != WIM_DATA) | |
234 return; | |
235 | |
236 // Decrement number of buffers in use | |
237 InterlockedDecrement(&pData->lWaveBuffersCommitted); | |
238 | |
239 if(pData->bWaveShutdown == AL_FALSE) | |
240 { | |
241 // Notify Wave Processor Thread that a Wave Header has returned | |
242 PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1); | |
243 } | |
244 else | |
245 { | |
246 if(pData->lWaveBuffersCommitted == 0) | |
247 { | |
248 // Post 'Quit' Message to WaveIn Processor Thread | |
249 PostThreadMessage(pData->ulWaveThreadID,WM_QUIT,0,0); | |
250 } | |
251 } | |
252 } | |
253 | |
254 /* | |
255 CaptureThreadProc | |
256 | |
257 Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new | |
258 audio data. | |
259 */ | |
260 static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter) | |
261 { | |
262 ALCdevice *pDevice = (ALCdevice*)lpParameter; | |
263 WinMMData *pData = pDevice->ExtraData; | |
264 LPWAVEHDR pWaveHdr; | |
265 ALuint FrameSize; | |
266 MSG msg; | |
267 | |
268 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); | |
269 | |
270 while(GetMessage(&msg, NULL, 0, 0)) | |
271 { | |
272 if(msg.message != WIM_DATA || pData->bWaveShutdown) | |
273 continue; | |
274 | |
275 pWaveHdr = ((LPWAVEHDR)msg.lParam); | |
276 | |
277 WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData, | |
278 pWaveHdr->dwBytesRecorded/FrameSize); | |
279 | |
280 // Send buffer back to capture more data | |
281 waveInAddBuffer(pData->hWaveHandle.In,pWaveHdr,sizeof(WAVEHDR)); | |
282 InterlockedIncrement(&pData->lWaveBuffersCommitted); | |
283 } | |
284 | |
285 // Signal Wave Thread completed event | |
286 if(pData->hWaveThreadEvent) | |
287 SetEvent(pData->hWaveThreadEvent); | |
288 | |
289 ExitThread(0); | |
290 | |
291 return 0; | |
292 } | |
293 | |
294 | |
295 static ALCboolean WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName) | |
296 { | |
297 WAVEFORMATEX wfexFormat; | |
298 WinMMData *pData = NULL; | |
299 UINT lDeviceID = 0; | |
300 MMRESULT res; | |
301 ALuint i = 0; | |
302 | |
303 // Find the Device ID matching the deviceName if valid | |
304 if(!deviceName || strcmp(deviceName, woDefault) == 0) | |
305 lDeviceID = WAVE_MAPPER; | |
306 else | |
307 { | |
308 if(!PlaybackDeviceList) | |
309 ProbePlaybackDevices(); | |
310 | |
311 for(i = 0;i < NumPlaybackDevices;i++) | |
312 { | |
313 if(PlaybackDeviceList[i] && | |
314 strcmp(deviceName, PlaybackDeviceList[i]) == 0) | |
315 { | |
316 lDeviceID = i; | |
317 break; | |
318 } | |
319 } | |
320 if(i == NumPlaybackDevices) | |
321 return ALC_FALSE; | |
322 } | |
323 | |
324 pData = calloc(1, sizeof(*pData)); | |
325 if(!pData) | |
326 { | |
327 alcSetError(pDevice, ALC_OUT_OF_MEMORY); | |
328 return ALC_FALSE; | |
329 } | |
330 pDevice->ExtraData = pData; | |
331 | |
332 if(pDevice->FmtChans != DevFmtMono) | |
333 { | |
334 if((pDevice->Flags&DEVICE_CHANNELS_REQUEST) && | |
335 pDevice->FmtChans != DevFmtStereo) | |
336 { | |
337 ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(pDevice->FmtChans)); | |
338 pDevice->Flags &= ~DEVICE_CHANNELS_REQUEST; | |
339 } | |
340 pDevice->FmtChans = DevFmtStereo; | |
341 } | |
342 switch(pDevice->FmtType) | |
343 { | |
344 case DevFmtByte: | |
345 pDevice->FmtType = DevFmtUByte; | |
346 break; | |
347 case DevFmtUShort: | |
348 case DevFmtFloat: | |
349 pDevice->FmtType = DevFmtShort; | |
350 break; | |
351 case DevFmtUByte: | |
352 case DevFmtShort: | |
353 break; | |
354 } | |
355 | |
356 memset(&wfexFormat, 0, sizeof(WAVEFORMATEX)); | |
357 wfexFormat.wFormatTag = WAVE_FORMAT_PCM; | |
358 wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans); | |
359 wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8; | |
360 wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample * | |
361 wfexFormat.nChannels / 8; | |
362 wfexFormat.nSamplesPerSec = pDevice->Frequency; | |
363 wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec * | |
364 wfexFormat.nBlockAlign; | |
365 wfexFormat.cbSize = 0; | |
366 | |
367 if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) | |
368 { | |
369 ERR("waveOutOpen failed: %u\n", res); | |
370 goto failure; | |
371 } | |
372 | |
373 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); | |
374 if(pData->hWaveThreadEvent == NULL) | |
375 { | |
376 ERR("CreateEvent failed: %lu\n", GetLastError()); | |
377 goto failure; | |
378 } | |
379 | |
380 pData->Frequency = pDevice->Frequency; | |
381 | |
382 pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault : | |
383 PlaybackDeviceList[lDeviceID]); | |
384 return ALC_TRUE; | |
385 | |
386 failure: | |
387 if(pData->hWaveThreadEvent) | |
388 CloseHandle(pData->hWaveThreadEvent); | |
389 | |
390 if(pData->hWaveHandle.Out) | |
391 waveOutClose(pData->hWaveHandle.Out); | |
392 | |
393 free(pData); | |
394 pDevice->ExtraData = NULL; | |
395 return ALC_FALSE; | |
396 } | |
397 | |
398 static void WinMMClosePlayback(ALCdevice *device) | |
399 { | |
400 WinMMData *pData = (WinMMData*)device->ExtraData; | |
401 | |
402 // Close the Wave device | |
403 CloseHandle(pData->hWaveThreadEvent); | |
404 pData->hWaveThreadEvent = 0; | |
405 | |
406 waveOutClose(pData->hWaveHandle.Out); | |
407 pData->hWaveHandle.Out = 0; | |
408 | |
409 free(pData); | |
410 device->ExtraData = NULL; | |
411 } | |
412 | |
413 static ALCboolean WinMMResetPlayback(ALCdevice *device) | |
414 { | |
415 WinMMData *pData = (WinMMData*)device->ExtraData; | |
416 ALbyte *BufferData; | |
417 ALint lBufferSize; | |
418 ALuint i; | |
419 | |
420 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID); | |
421 if(pData->hWaveThread == NULL) | |
422 return ALC_FALSE; | |
423 | |
424 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * | |
425 pData->Frequency / device->Frequency); | |
426 if(device->Frequency != pData->Frequency) | |
427 { | |
428 if((device->Flags&DEVICE_FREQUENCY_REQUEST)) | |
429 ERR("WinMM does not support changing sample rates (wanted %dhz, got %dhz)\n", device->Frequency, pData->Frequency); | |
430 device->Flags &= ~DEVICE_FREQUENCY_REQUEST; | |
431 device->Frequency = pData->Frequency; | |
432 } | |
433 | |
434 SetDefaultWFXChannelOrder(device); | |
435 | |
436 pData->lWaveBuffersCommitted = 0; | |
437 | |
438 // Create 4 Buffers | |
439 lBufferSize = device->UpdateSize*device->NumUpdates / 4; | |
440 lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType); | |
441 | |
442 BufferData = calloc(4, lBufferSize); | |
443 for(i = 0;i < 4;i++) | |
444 { | |
445 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR)); | |
446 pData->WaveBuffer[i].dwBufferLength = lBufferSize; | |
447 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData : | |
448 (pData->WaveBuffer[i-1].lpData + | |
449 pData->WaveBuffer[i-1].dwBufferLength)); | |
450 waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR)); | |
451 waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR)); | |
452 InterlockedIncrement(&pData->lWaveBuffersCommitted); | |
453 } | |
454 | |
455 return ALC_TRUE; | |
456 } | |
457 | |
458 static void WinMMStopPlayback(ALCdevice *device) | |
459 { | |
460 WinMMData *pData = (WinMMData*)device->ExtraData; | |
461 void *buffer = NULL; | |
462 int i; | |
463 | |
464 if(pData->hWaveThread == NULL) | |
465 return; | |
466 | |
467 // Set flag to stop processing headers | |
468 pData->bWaveShutdown = AL_TRUE; | |
469 | |
470 // Wait for signal that Wave Thread has been destroyed | |
471 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE); | |
472 | |
473 CloseHandle(pData->hWaveThread); | |
474 pData->hWaveThread = 0; | |
475 | |
476 pData->bWaveShutdown = AL_FALSE; | |
477 | |
478 // Release the wave buffers | |
479 for(i = 0;i < 4;i++) | |
480 { | |
481 waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR)); | |
482 if(i == 0) buffer = pData->WaveBuffer[i].lpData; | |
483 pData->WaveBuffer[i].lpData = NULL; | |
484 } | |
485 free(buffer); | |
486 } | |
487 | |
488 | |
489 static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName) | |
490 { | |
491 WAVEFORMATEX wfexCaptureFormat; | |
492 DWORD ulCapturedDataSize; | |
493 WinMMData *pData = NULL; | |
494 UINT lDeviceID = 0; | |
495 ALbyte *BufferData; | |
496 ALint lBufferSize; | |
497 MMRESULT res; | |
498 ALuint i; | |
499 | |
500 if(!CaptureDeviceList) | |
501 ProbeCaptureDevices(); | |
502 | |
503 // Find the Device ID matching the deviceName if valid | |
504 if(deviceName) | |
505 { | |
506 for(i = 0;i < NumCaptureDevices;i++) | |
507 { | |
508 if(CaptureDeviceList[i] && | |
509 strcmp(deviceName, CaptureDeviceList[i]) == 0) | |
510 { | |
511 lDeviceID = i; | |
512 break; | |
513 } | |
514 } | |
515 } | |
516 else | |
517 { | |
518 for(i = 0;i < NumCaptureDevices;i++) | |
519 { | |
520 if(CaptureDeviceList[i]) | |
521 { | |
522 lDeviceID = i; | |
523 break; | |
524 } | |
525 } | |
526 } | |
527 if(i == NumCaptureDevices) | |
528 return ALC_FALSE; | |
529 | |
530 pData = calloc(1, sizeof(*pData)); | |
531 if(!pData) | |
532 { | |
533 alcSetError(pDevice, ALC_OUT_OF_MEMORY); | |
534 return ALC_FALSE; | |
535 } | |
536 pDevice->ExtraData = pData; | |
537 | |
538 if((pDevice->FmtChans != DevFmtMono && pDevice->FmtChans != DevFmtStereo) || | |
539 (pDevice->FmtType != DevFmtUByte && pDevice->FmtType != DevFmtShort)) | |
540 { | |
541 alcSetError(pDevice, ALC_INVALID_ENUM); | |
542 goto failure; | |
543 } | |
544 | |
545 memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX)); | |
546 wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM; | |
547 wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans); | |
548 wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8; | |
549 wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample * | |
550 wfexCaptureFormat.nChannels / 8; | |
551 wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency; | |
552 wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec * | |
553 wfexCaptureFormat.nBlockAlign; | |
554 wfexCaptureFormat.cbSize = 0; | |
555 | |
556 if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) | |
557 { | |
558 ERR("waveInOpen failed: %u\n", res); | |
559 goto failure; | |
560 } | |
561 | |
562 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); | |
563 if(pData->hWaveThreadEvent == NULL) | |
564 { | |
565 ERR("CreateEvent failed: %lu\n", GetLastError()); | |
566 goto failure; | |
567 } | |
568 | |
569 pData->Frequency = pDevice->Frequency; | |
570 | |
571 // Allocate circular memory buffer for the captured audio | |
572 ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates; | |
573 | |
574 // Make sure circular buffer is at least 100ms in size | |
575 if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10)) | |
576 ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10; | |
577 | |
578 pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize); | |
579 if(!pData->pRing) | |
580 goto failure; | |
581 | |
582 pData->lWaveBuffersCommitted = 0; | |
583 | |
584 // Create 4 Buffers of 50ms each | |
585 lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20; | |
586 lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign); | |
587 | |
588 BufferData = calloc(4, lBufferSize); | |
589 if(!BufferData) | |
590 goto failure; | |
591 | |
592 for(i = 0;i < 4;i++) | |
593 { | |
594 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR)); | |
595 pData->WaveBuffer[i].dwBufferLength = lBufferSize; | |
596 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData : | |
597 (pData->WaveBuffer[i-1].lpData + | |
598 pData->WaveBuffer[i-1].dwBufferLength)); | |
599 pData->WaveBuffer[i].dwFlags = 0; | |
600 pData->WaveBuffer[i].dwLoops = 0; | |
601 waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); | |
602 waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); | |
603 InterlockedIncrement(&pData->lWaveBuffersCommitted); | |
604 } | |
605 | |
606 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID); | |
607 if (pData->hWaveThread == NULL) | |
608 goto failure; | |
609 | |
610 pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]); | |
611 return ALC_TRUE; | |
612 | |
613 failure: | |
614 if(pData->hWaveThread) | |
615 CloseHandle(pData->hWaveThread); | |
616 | |
617 for(i = 0;i < 4;i++) | |
618 { | |
619 if(pData->WaveBuffer[i].lpData) | |
620 { | |
621 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); | |
622 if(i == 0) | |
623 free(pData->WaveBuffer[i].lpData); | |
624 } | |
625 } | |
626 | |
627 if(pData->pRing) | |
628 DestroyRingBuffer(pData->pRing); | |
629 | |
630 if(pData->hWaveThreadEvent) | |
631 CloseHandle(pData->hWaveThreadEvent); | |
632 | |
633 if(pData->hWaveHandle.In) | |
634 waveInClose(pData->hWaveHandle.In); | |
635 | |
636 free(pData); | |
637 pDevice->ExtraData = NULL; | |
638 return ALC_FALSE; | |
639 } | |
640 | |
641 static void WinMMCloseCapture(ALCdevice *pDevice) | |
642 { | |
643 WinMMData *pData = (WinMMData*)pDevice->ExtraData; | |
644 void *buffer = NULL; | |
645 int i; | |
646 | |
647 // Call waveOutReset to shutdown wave device | |
648 pData->bWaveShutdown = AL_TRUE; | |
649 waveInReset(pData->hWaveHandle.In); | |
650 | |
651 // Wait for signal that Wave Thread has been destroyed | |
652 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE); | |
653 | |
654 CloseHandle(pData->hWaveThread); | |
655 pData->hWaveThread = 0; | |
656 | |
657 // Release the wave buffers | |
658 for(i = 0;i < 4;i++) | |
659 { | |
660 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); | |
661 if(i == 0) buffer = pData->WaveBuffer[i].lpData; | |
662 pData->WaveBuffer[i].lpData = NULL; | |
663 } | |
664 free(buffer); | |
665 | |
666 DestroyRingBuffer(pData->pRing); | |
667 pData->pRing = NULL; | |
668 | |
669 // Close the Wave device | |
670 CloseHandle(pData->hWaveThreadEvent); | |
671 pData->hWaveThreadEvent = 0; | |
672 | |
673 waveInClose(pData->hWaveHandle.In); | |
674 pData->hWaveHandle.In = 0; | |
675 | |
676 free(pData); | |
677 pDevice->ExtraData = NULL; | |
678 } | |
679 | |
680 static void WinMMStartCapture(ALCdevice *pDevice) | |
681 { | |
682 WinMMData *pData = (WinMMData*)pDevice->ExtraData; | |
683 waveInStart(pData->hWaveHandle.In); | |
684 } | |
685 | |
686 static void WinMMStopCapture(ALCdevice *pDevice) | |
687 { | |
688 WinMMData *pData = (WinMMData*)pDevice->ExtraData; | |
689 waveInStop(pData->hWaveHandle.In); | |
690 } | |
691 | |
692 static ALCuint WinMMAvailableSamples(ALCdevice *pDevice) | |
693 { | |
694 WinMMData *pData = (WinMMData*)pDevice->ExtraData; | |
695 return RingBufferSize(pData->pRing); | |
696 } | |
697 | |
698 static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) | |
699 { | |
700 WinMMData *pData = (WinMMData*)pDevice->ExtraData; | |
701 | |
702 if(WinMMAvailableSamples(pDevice) >= lSamples) | |
703 ReadRingBuffer(pData->pRing, pBuffer, lSamples); | |
704 else | |
705 alcSetError(pDevice, ALC_INVALID_VALUE); | |
706 } | |
707 | |
708 | |
709 static const BackendFuncs WinMMFuncs = { | |
710 WinMMOpenPlayback, | |
711 WinMMClosePlayback, | |
712 WinMMResetPlayback, | |
713 WinMMStopPlayback, | |
714 WinMMOpenCapture, | |
715 WinMMCloseCapture, | |
716 WinMMStartCapture, | |
717 WinMMStopCapture, | |
718 WinMMCaptureSamples, | |
719 WinMMAvailableSamples | |
720 }; | |
721 | |
722 ALCboolean alcWinMMInit(BackendFuncs *FuncList) | |
723 { | |
724 *FuncList = WinMMFuncs; | |
725 return ALC_TRUE; | |
726 } | |
727 | |
728 void alcWinMMDeinit() | |
729 { | |
730 ALuint lLoop; | |
731 | |
732 for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++) | |
733 free(PlaybackDeviceList[lLoop]); | |
734 free(PlaybackDeviceList); | |
735 PlaybackDeviceList = NULL; | |
736 | |
737 NumPlaybackDevices = 0; | |
738 | |
739 | |
740 for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++) | |
741 free(CaptureDeviceList[lLoop]); | |
742 free(CaptureDeviceList); | |
743 CaptureDeviceList = NULL; | |
744 | |
745 NumCaptureDevices = 0; | |
746 } | |
747 | |
748 void alcWinMMProbe(enum DevProbe type) | |
749 { | |
750 ALuint i; | |
751 | |
752 switch(type) | |
753 { | |
754 case DEVICE_PROBE: | |
755 ProbePlaybackDevices(); | |
756 if(NumPlaybackDevices > 0) | |
757 AppendDeviceList(woDefault); | |
758 break; | |
759 | |
760 case ALL_DEVICE_PROBE: | |
761 ProbePlaybackDevices(); | |
762 if(NumPlaybackDevices > 0) | |
763 AppendAllDeviceList(woDefault); | |
764 for(i = 0;i < NumPlaybackDevices;i++) | |
765 { | |
766 if(PlaybackDeviceList[i]) | |
767 AppendAllDeviceList(PlaybackDeviceList[i]); | |
768 } | |
769 break; | |
770 | |
771 case CAPTURE_DEVICE_PROBE: | |
772 ProbeCaptureDevices(); | |
773 for(i = 0;i < NumCaptureDevices;i++) | |
774 { | |
775 if(CaptureDeviceList[i]) | |
776 AppendCaptureDeviceList(CaptureDeviceList[i]); | |
777 } | |
778 break; | |
779 } | |
780 } |