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 }