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.
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.
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
23 #define _WIN32_WINNT 0x0500
38 volatile ALboolean bWaveShutdown
;
40 HANDLE hWaveThreadEvent
;
43 LONG lWaveBuffersCommitted
;
44 WAVEHDR WaveBuffer
[4];
57 static const ALCchar woDefault
[] = "WaveOut Default";
59 static ALCchar
**PlaybackDeviceList
;
60 static ALuint NumPlaybackDevices
;
61 static ALCchar
**CaptureDeviceList
;
62 static ALuint NumCaptureDevices
;
65 static void ProbePlaybackDevices(void)
69 for(i
= 0;i
< NumPlaybackDevices
;i
++)
70 free(PlaybackDeviceList
[i
]);
72 NumPlaybackDevices
= waveOutGetNumDevs();
73 PlaybackDeviceList
= realloc(PlaybackDeviceList
, sizeof(ALCchar
*) * NumPlaybackDevices
);
74 for(i
= 0;i
< NumPlaybackDevices
;i
++)
78 PlaybackDeviceList
[i
] = NULL
;
79 if(waveOutGetDevCaps(i
, &WaveCaps
, sizeof(WaveCaps
)) == MMSYSERR_NOERROR
)
87 snprintf(name
, sizeof(name
), "%s via WaveOut", WaveCaps
.szPname
);
89 snprintf(name
, sizeof(name
), "%s #%d via WaveOut", WaveCaps
.szPname
, count
+1);
94 if(strcmp(name
, PlaybackDeviceList
[j
]) == 0)
99 PlaybackDeviceList
[i
] = strdup(name
);
104 static void ProbeCaptureDevices(void)
108 for(i
= 0;i
< NumCaptureDevices
;i
++)
109 free(CaptureDeviceList
[i
]);
111 NumCaptureDevices
= waveInGetNumDevs();
112 CaptureDeviceList
= realloc(CaptureDeviceList
, sizeof(ALCchar
*) * NumCaptureDevices
);
113 for(i
= 0;i
< NumCaptureDevices
;i
++)
115 WAVEINCAPS WaveInCaps
;
117 CaptureDeviceList
[i
] = NULL
;
118 if(waveInGetDevCaps(i
, &WaveInCaps
, sizeof(WAVEINCAPS
)) == MMSYSERR_NOERROR
)
126 snprintf(name
, sizeof(name
), "%s via WaveIn", WaveInCaps
.szPname
);
128 snprintf(name
, sizeof(name
), "%s #%d via WaveIn", WaveInCaps
.szPname
, count
+1);
133 if(strcmp(name
, CaptureDeviceList
[j
]) == 0)
138 CaptureDeviceList
[i
] = strdup(name
);
147 Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and
148 returns to the application (for more data)
150 static void CALLBACK
WaveOutProc(HWAVEOUT hDevice
,UINT uMsg
,DWORD_PTR dwInstance
,DWORD_PTR dwParam1
,DWORD_PTR dwParam2
)
152 ALCdevice
*pDevice
= (ALCdevice
*)dwInstance
;
153 WinMMData
*pData
= pDevice
->ExtraData
;
161 // Decrement number of buffers in use
162 InterlockedDecrement(&pData
->lWaveBuffersCommitted
);
164 if(pData
->bWaveShutdown
== AL_FALSE
)
166 // Notify Wave Processor Thread that a Wave Header has returned
167 PostThreadMessage(pData
->ulWaveThreadID
, uMsg
, 0, dwParam1
);
171 if(pData
->lWaveBuffersCommitted
== 0)
173 // Signal Wave Buffers Returned event
174 if(pData
->hWaveHdrEvent
)
175 SetEvent(pData
->hWaveHdrEvent
);
177 // Post 'Quit' Message to WaveOut Processor Thread
178 PostThreadMessage(pData
->ulWaveThreadID
, WM_QUIT
, 0, 0);
186 Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its
189 static DWORD WINAPI
PlaybackThreadProc(LPVOID lpParameter
)
191 ALCdevice
*pDevice
= (ALCdevice
*)lpParameter
;
192 WinMMData
*pData
= pDevice
->ExtraData
;
197 FrameSize
= FrameSizeFromDevFmt(pDevice
->FmtChans
, pDevice
->FmtType
);
199 while(GetMessage(&msg
, NULL
, 0, 0))
201 if(msg
.message
!= WOM_DONE
|| pData
->bWaveShutdown
)
204 pWaveHdr
= ((LPWAVEHDR
)msg
.lParam
);
206 aluMixData(pDevice
, pWaveHdr
->lpData
, pWaveHdr
->dwBufferLength
/FrameSize
);
208 // Send buffer back to play more data
209 waveOutWrite(pData
->hWaveHandle
.Out
, pWaveHdr
, sizeof(WAVEHDR
));
210 InterlockedIncrement(&pData
->lWaveBuffersCommitted
);
213 // Signal Wave Thread completed event
214 if(pData
->hWaveThreadEvent
)
215 SetEvent(pData
->hWaveThreadEvent
);
225 Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
226 returns to the application (with more data)
228 static void CALLBACK
WaveInProc(HWAVEIN hDevice
,UINT uMsg
,DWORD_PTR dwInstance
,DWORD_PTR dwParam1
,DWORD_PTR dwParam2
)
230 ALCdevice
*pDevice
= (ALCdevice
*)dwInstance
;
231 WinMMData
*pData
= pDevice
->ExtraData
;
239 // Decrement number of buffers in use
240 InterlockedDecrement(&pData
->lWaveBuffersCommitted
);
242 if(pData
->bWaveShutdown
== AL_FALSE
)
244 // Notify Wave Processor Thread that a Wave Header has returned
245 PostThreadMessage(pData
->ulWaveThreadID
,uMsg
,0,dwParam1
);
249 if(pData
->lWaveBuffersCommitted
== 0)
251 // Signal Wave Buffers Returned event
252 if(pData
->hWaveHdrEvent
)
253 SetEvent(pData
->hWaveHdrEvent
);
255 // Post 'Quit' Message to WaveIn Processor Thread
256 PostThreadMessage(pData
->ulWaveThreadID
,WM_QUIT
,0,0);
264 Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new
267 static DWORD WINAPI
CaptureThreadProc(LPVOID lpParameter
)
269 ALCdevice
*pDevice
= (ALCdevice
*)lpParameter
;
270 WinMMData
*pData
= pDevice
->ExtraData
;
275 FrameSize
= FrameSizeFromDevFmt(pDevice
->FmtChans
, pDevice
->FmtType
);
277 while(GetMessage(&msg
, NULL
, 0, 0))
279 if(msg
.message
!= WIM_DATA
|| pData
->bWaveShutdown
)
282 pWaveHdr
= ((LPWAVEHDR
)msg
.lParam
);
284 WriteRingBuffer(pData
->pRing
, (ALubyte
*)pWaveHdr
->lpData
,
285 pWaveHdr
->dwBytesRecorded
/FrameSize
);
287 // Send buffer back to capture more data
288 waveInAddBuffer(pData
->hWaveHandle
.In
,pWaveHdr
,sizeof(WAVEHDR
));
289 InterlockedIncrement(&pData
->lWaveBuffersCommitted
);
292 // Signal Wave Thread completed event
293 if(pData
->hWaveThreadEvent
)
294 SetEvent(pData
->hWaveThreadEvent
);
302 static ALCboolean
WinMMOpenPlayback(ALCdevice
*pDevice
, const ALCchar
*deviceName
)
304 WAVEFORMATEX wfexFormat
;
305 WinMMData
*pData
= NULL
;
306 UINT_PTR lDeviceID
= 0;
310 // Find the Device ID matching the deviceName if valid
311 if(!deviceName
|| strcmp(deviceName
, woDefault
) == 0)
312 lDeviceID
= WAVE_MAPPER
;
315 if(!PlaybackDeviceList
)
316 ProbePlaybackDevices();
318 for(i
= 0;i
< NumPlaybackDevices
;i
++)
320 if(PlaybackDeviceList
[i
] &&
321 strcmp(deviceName
, PlaybackDeviceList
[i
]) == 0)
327 if(i
== NumPlaybackDevices
)
331 pData
= calloc(1, sizeof(*pData
));
334 alcSetError(pDevice
, ALC_OUT_OF_MEMORY
);
337 pDevice
->ExtraData
= pData
;
339 if(pDevice
->FmtChans
!= DevFmtMono
)
340 pDevice
->FmtChans
= DevFmtStereo
;
341 switch(pDevice
->FmtType
)
344 pDevice
->FmtType
= DevFmtUByte
;
348 pDevice
->FmtType
= DevFmtShort
;
355 memset(&wfexFormat
, 0, sizeof(WAVEFORMATEX
));
356 wfexFormat
.wFormatTag
= WAVE_FORMAT_PCM
;
357 wfexFormat
.nChannels
= ChannelsFromDevFmt(pDevice
->FmtChans
);
358 wfexFormat
.wBitsPerSample
= BytesFromDevFmt(pDevice
->FmtType
) * 8;
359 wfexFormat
.nBlockAlign
= wfexFormat
.wBitsPerSample
*
360 wfexFormat
.nChannels
/ 8;
361 wfexFormat
.nSamplesPerSec
= pDevice
->Frequency
;
362 wfexFormat
.nAvgBytesPerSec
= wfexFormat
.nSamplesPerSec
*
363 wfexFormat
.nBlockAlign
;
364 wfexFormat
.cbSize
= 0;
366 if((res
=waveOutOpen(&pData
->hWaveHandle
.Out
, lDeviceID
, &wfexFormat
, (DWORD_PTR
)&WaveOutProc
, (DWORD_PTR
)pDevice
, CALLBACK_FUNCTION
)) != MMSYSERR_NOERROR
)
368 AL_PRINT("waveInOpen failed: %u\n", res
);
372 pData
->hWaveHdrEvent
= CreateEvent(NULL
, AL_TRUE
, AL_FALSE
, "WaveOutAllHeadersReturned");
373 pData
->hWaveThreadEvent
= CreateEvent(NULL
, AL_TRUE
, AL_FALSE
, "WaveOutThreadDestroyed");
374 if(pData
->hWaveHdrEvent
== NULL
|| pData
->hWaveThreadEvent
== NULL
)
376 AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
380 pData
->Frequency
= pDevice
->Frequency
;
382 pDevice
->szDeviceName
= strdup((lDeviceID
==WAVE_MAPPER
) ? woDefault
:
383 PlaybackDeviceList
[lDeviceID
]);
387 if(pData
->hWaveThreadEvent
)
388 CloseHandle(pData
->hWaveThreadEvent
);
389 if(pData
->hWaveHdrEvent
)
390 CloseHandle(pData
->hWaveHdrEvent
);
392 if(pData
->hWaveHandle
.Out
)
393 waveOutClose(pData
->hWaveHandle
.Out
);
396 pDevice
->ExtraData
= NULL
;
400 static void WinMMClosePlayback(ALCdevice
*device
)
402 WinMMData
*pData
= (WinMMData
*)device
->ExtraData
;
404 // Close the Wave device
405 CloseHandle(pData
->hWaveThreadEvent
);
406 pData
->hWaveThreadEvent
= 0;
408 CloseHandle(pData
->hWaveHdrEvent
);
409 pData
->hWaveHdrEvent
= 0;
411 waveInClose(pData
->hWaveHandle
.In
);
412 pData
->hWaveHandle
.In
= 0;
415 device
->ExtraData
= NULL
;
418 static ALCboolean
WinMMResetPlayback(ALCdevice
*device
)
420 WinMMData
*pData
= (WinMMData
*)device
->ExtraData
;
425 pData
->hWaveThread
= CreateThread(NULL
, 0, (LPTHREAD_START_ROUTINE
)PlaybackThreadProc
, (LPVOID
)device
, 0, &pData
->ulWaveThreadID
);
426 if(pData
->hWaveThread
== NULL
)
429 device
->UpdateSize
= (ALuint
)((ALuint64
)device
->UpdateSize
*
430 pData
->Frequency
/ device
->Frequency
);
431 device
->Frequency
= pData
->Frequency
;
433 pData
->lWaveBuffersCommitted
= 0;
436 lBufferSize
= device
->UpdateSize
*device
->NumUpdates
/ 4;
437 lBufferSize
*= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
439 BufferData
= calloc(4, lBufferSize
);
442 memset(&pData
->WaveBuffer
[i
], 0, sizeof(WAVEHDR
));
443 pData
->WaveBuffer
[i
].dwBufferLength
= lBufferSize
;
444 pData
->WaveBuffer
[i
].lpData
= ((i
==0) ? (LPSTR
)BufferData
:
445 (pData
->WaveBuffer
[i
-1].lpData
+
446 pData
->WaveBuffer
[i
-1].dwBufferLength
));
447 waveOutPrepareHeader(pData
->hWaveHandle
.Out
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
448 waveOutWrite(pData
->hWaveHandle
.Out
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
449 InterlockedIncrement(&pData
->lWaveBuffersCommitted
);
455 static void WinMMStopPlayback(ALCdevice
*device
)
457 WinMMData
*pData
= (WinMMData
*)device
->ExtraData
;
460 if(pData
->hWaveThread
== NULL
)
463 // Set flag to stop processing headers
464 pData
->bWaveShutdown
= AL_TRUE
;
466 // Wait for signal that all Wave Buffers have returned
467 WaitForSingleObjectEx(pData
->hWaveHdrEvent
, 5000, FALSE
);
469 // Wait for signal that Wave Thread has been destroyed
470 WaitForSingleObjectEx(pData
->hWaveThreadEvent
, 5000, FALSE
);
472 CloseHandle(pData
->hWaveThread
);
473 pData
->hWaveThread
= 0;
475 pData
->bWaveShutdown
= AL_FALSE
;
477 // Release the wave buffers
480 waveOutUnprepareHeader(pData
->hWaveHandle
.Out
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
482 free(pData
->WaveBuffer
[i
].lpData
);
483 pData
->WaveBuffer
[i
].lpData
= NULL
;
488 static ALCboolean
WinMMOpenCapture(ALCdevice
*pDevice
, const ALCchar
*deviceName
)
490 WAVEFORMATEX wfexCaptureFormat
;
491 DWORD ulCapturedDataSize
;
492 WinMMData
*pData
= NULL
;
499 if(!CaptureDeviceList
)
500 ProbeCaptureDevices();
502 // Find the Device ID matching the deviceName if valid
505 for(i
= 0;i
< NumCaptureDevices
;i
++)
507 if(CaptureDeviceList
[i
] &&
508 strcmp(deviceName
, CaptureDeviceList
[i
]) == 0)
517 for(i
= 0;i
< NumCaptureDevices
;i
++)
519 if(CaptureDeviceList
[i
])
526 if(i
== NumCaptureDevices
)
529 pData
= calloc(1, sizeof(*pData
));
532 alcSetError(pDevice
, ALC_OUT_OF_MEMORY
);
535 pDevice
->ExtraData
= pData
;
537 if((pDevice
->FmtChans
!= DevFmtMono
&& pDevice
->FmtChans
!= DevFmtStereo
) ||
538 (pDevice
->FmtType
!= DevFmtUByte
&& pDevice
->FmtType
!= DevFmtShort
))
540 alcSetError(pDevice
, ALC_INVALID_ENUM
);
544 memset(&wfexCaptureFormat
, 0, sizeof(WAVEFORMATEX
));
545 wfexCaptureFormat
.wFormatTag
= WAVE_FORMAT_PCM
;
546 wfexCaptureFormat
.nChannels
= ChannelsFromDevFmt(pDevice
->FmtChans
);
547 wfexCaptureFormat
.wBitsPerSample
= BytesFromDevFmt(pDevice
->FmtType
) * 8;
548 wfexCaptureFormat
.nBlockAlign
= wfexCaptureFormat
.wBitsPerSample
*
549 wfexCaptureFormat
.nChannels
/ 8;
550 wfexCaptureFormat
.nSamplesPerSec
= pDevice
->Frequency
;
551 wfexCaptureFormat
.nAvgBytesPerSec
= wfexCaptureFormat
.nSamplesPerSec
*
552 wfexCaptureFormat
.nBlockAlign
;
553 wfexCaptureFormat
.cbSize
= 0;
555 if((res
=waveInOpen(&pData
->hWaveHandle
.In
, lDeviceID
, &wfexCaptureFormat
, (DWORD_PTR
)&WaveInProc
, (DWORD_PTR
)pDevice
, CALLBACK_FUNCTION
)) != MMSYSERR_NOERROR
)
557 AL_PRINT("waveInOpen failed: %u\n", res
);
561 pData
->hWaveHdrEvent
= CreateEvent(NULL
, AL_TRUE
, AL_FALSE
, "WaveInAllHeadersReturned");
562 pData
->hWaveThreadEvent
= CreateEvent(NULL
, AL_TRUE
, AL_FALSE
, "WaveInThreadDestroyed");
563 if(pData
->hWaveHdrEvent
== NULL
|| pData
->hWaveThreadEvent
== NULL
)
565 AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
569 pData
->Frequency
= pDevice
->Frequency
;
571 // Allocate circular memory buffer for the captured audio
572 ulCapturedDataSize
= pDevice
->UpdateSize
*pDevice
->NumUpdates
;
574 // Make sure circular buffer is at least 100ms in size
575 if(ulCapturedDataSize
< (wfexCaptureFormat
.nSamplesPerSec
/ 10))
576 ulCapturedDataSize
= wfexCaptureFormat
.nSamplesPerSec
/ 10;
578 pData
->pRing
= CreateRingBuffer(wfexCaptureFormat
.nBlockAlign
, ulCapturedDataSize
);
582 pData
->lWaveBuffersCommitted
= 0;
584 // Create 4 Buffers of 50ms each
585 lBufferSize
= wfexCaptureFormat
.nAvgBytesPerSec
/ 20;
586 lBufferSize
-= (lBufferSize
% wfexCaptureFormat
.nBlockAlign
);
588 BufferData
= calloc(4, lBufferSize
);
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
);
606 pData
->hWaveThread
= CreateThread(NULL
, 0, (LPTHREAD_START_ROUTINE
)CaptureThreadProc
, (LPVOID
)pDevice
, 0, &pData
->ulWaveThreadID
);
607 if (pData
->hWaveThread
== NULL
)
610 pDevice
->szDeviceName
= strdup(CaptureDeviceList
[lDeviceID
]);
614 if(pData
->hWaveThread
)
615 CloseHandle(pData
->hWaveThread
);
619 if(pData
->WaveBuffer
[i
].lpData
)
621 waveInUnprepareHeader(pData
->hWaveHandle
.In
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
623 free(pData
->WaveBuffer
[i
].lpData
);
628 DestroyRingBuffer(pData
->pRing
);
630 if(pData
->hWaveThreadEvent
)
631 CloseHandle(pData
->hWaveThreadEvent
);
632 if(pData
->hWaveHdrEvent
)
633 CloseHandle(pData
->hWaveHdrEvent
);
635 if(pData
->hWaveHandle
.In
)
636 waveInClose(pData
->hWaveHandle
.In
);
639 pDevice
->ExtraData
= NULL
;
643 static void WinMMCloseCapture(ALCdevice
*pDevice
)
645 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
648 // Call waveOutReset to shutdown wave device
649 pData
->bWaveShutdown
= AL_TRUE
;
650 waveInReset(pData
->hWaveHandle
.In
);
652 // Wait for signal that all Wave Buffers have returned
653 WaitForSingleObjectEx(pData
->hWaveHdrEvent
, 5000, FALSE
);
655 // Wait for signal that Wave Thread has been destroyed
656 WaitForSingleObjectEx(pData
->hWaveThreadEvent
, 5000, FALSE
);
658 CloseHandle(pData
->hWaveThread
);
659 pData
->hWaveThread
= 0;
661 // Release the wave buffers
664 waveInUnprepareHeader(pData
->hWaveHandle
.In
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
666 free(pData
->WaveBuffer
[i
].lpData
);
667 pData
->WaveBuffer
[i
].lpData
= NULL
;
670 DestroyRingBuffer(pData
->pRing
);
673 // Close the Wave device
674 CloseHandle(pData
->hWaveThreadEvent
);
675 pData
->hWaveThreadEvent
= 0;
677 CloseHandle(pData
->hWaveHdrEvent
);
678 pData
->hWaveHdrEvent
= 0;
680 waveInClose(pData
->hWaveHandle
.In
);
681 pData
->hWaveHandle
.In
= 0;
684 pDevice
->ExtraData
= NULL
;
687 static void WinMMStartCapture(ALCdevice
*pDevice
)
689 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
690 waveInStart(pData
->hWaveHandle
.In
);
693 static void WinMMStopCapture(ALCdevice
*pDevice
)
695 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
696 waveInStop(pData
->hWaveHandle
.In
);
699 static ALCuint
WinMMAvailableSamples(ALCdevice
*pDevice
)
701 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
702 return RingBufferSize(pData
->pRing
);
705 static void WinMMCaptureSamples(ALCdevice
*pDevice
, ALCvoid
*pBuffer
, ALCuint lSamples
)
707 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
709 if(WinMMAvailableSamples(pDevice
) >= lSamples
)
710 ReadRingBuffer(pData
->pRing
, pBuffer
, lSamples
);
712 alcSetError(pDevice
, ALC_INVALID_VALUE
);
716 static BackendFuncs WinMMFuncs
= {
726 WinMMAvailableSamples
729 void alcWinMMInit(BackendFuncs
*FuncList
)
731 *FuncList
= WinMMFuncs
;
734 void alcWinMMDeinit()
738 for(lLoop
= 0;lLoop
< NumPlaybackDevices
;lLoop
++)
739 free(PlaybackDeviceList
[lLoop
]);
740 free(PlaybackDeviceList
);
741 PlaybackDeviceList
= NULL
;
743 NumPlaybackDevices
= 0;
746 for(lLoop
= 0; lLoop
< NumCaptureDevices
; lLoop
++)
747 free(CaptureDeviceList
[lLoop
]);
748 free(CaptureDeviceList
);
749 CaptureDeviceList
= NULL
;
751 NumCaptureDevices
= 0;
754 void alcWinMMProbe(int type
)
758 if(type
== DEVICE_PROBE
)
760 ProbePlaybackDevices();
761 if(NumPlaybackDevices
> 0)
762 AppendDeviceList(woDefault
);
764 else if(type
== ALL_DEVICE_PROBE
)
766 ProbePlaybackDevices();
767 if(NumPlaybackDevices
> 0)
768 AppendAllDeviceList(woDefault
);
769 for(i
= 0;i
< NumPlaybackDevices
;i
++)
771 if(PlaybackDeviceList
[i
])
772 AppendAllDeviceList(PlaybackDeviceList
[i
]);
775 else if(type
== CAPTURE_DEVICE_PROBE
)
777 ProbeCaptureDevices();
778 for(i
= 0;i
< NumCaptureDevices
;i
++)
780 if(CaptureDeviceList
[i
])
781 AppendCaptureDeviceList(CaptureDeviceList
[i
]);