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
= aluFrameSizeFromFormat(pDevice
->Format
);
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
= aluFrameSizeFromFormat(pDevice
->Format
);
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(aluChannelsFromFormat(pDevice
->Format
) >= 2)
341 if(aluBytesFromFormat(pDevice
->Format
) >= 2)
342 pDevice
->Format
= AL_FORMAT_STEREO16
;
344 pDevice
->Format
= AL_FORMAT_STEREO8
;
348 if(aluBytesFromFormat(pDevice
->Format
) >= 2)
349 pDevice
->Format
= AL_FORMAT_MONO16
;
351 pDevice
->Format
= AL_FORMAT_MONO8
;
354 memset(&wfexFormat
, 0, sizeof(WAVEFORMATEX
));
355 wfexFormat
.wFormatTag
= WAVE_FORMAT_PCM
;
356 wfexFormat
.nChannels
= aluChannelsFromFormat(pDevice
->Format
);
357 wfexFormat
.wBitsPerSample
= aluBytesFromFormat(pDevice
->Format
) * 8;
358 wfexFormat
.nBlockAlign
= wfexFormat
.wBitsPerSample
*
359 wfexFormat
.nChannels
/ 8;
360 wfexFormat
.nSamplesPerSec
= pDevice
->Frequency
;
361 wfexFormat
.nAvgBytesPerSec
= wfexFormat
.nSamplesPerSec
*
362 wfexFormat
.nBlockAlign
;
363 wfexFormat
.cbSize
= 0;
365 if((res
=waveOutOpen(&pData
->hWaveHandle
.Out
, lDeviceID
, &wfexFormat
, (DWORD_PTR
)&WaveOutProc
, (DWORD_PTR
)pDevice
, CALLBACK_FUNCTION
)) != MMSYSERR_NOERROR
)
367 AL_PRINT("waveInOpen failed: %u\n", res
);
371 pData
->hWaveHdrEvent
= CreateEvent(NULL
, AL_TRUE
, AL_FALSE
, "WaveOutAllHeadersReturned");
372 pData
->hWaveThreadEvent
= CreateEvent(NULL
, AL_TRUE
, AL_FALSE
, "WaveOutThreadDestroyed");
373 if(pData
->hWaveHdrEvent
== NULL
|| pData
->hWaveThreadEvent
== NULL
)
375 AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
379 pData
->Frequency
= pDevice
->Frequency
;
381 pDevice
->szDeviceName
= strdup((lDeviceID
==WAVE_MAPPER
) ? woDefault
:
382 PlaybackDeviceList
[lDeviceID
]);
386 if(pData
->hWaveThreadEvent
)
387 CloseHandle(pData
->hWaveThreadEvent
);
388 if(pData
->hWaveHdrEvent
)
389 CloseHandle(pData
->hWaveHdrEvent
);
391 if(pData
->hWaveHandle
.Out
)
392 waveOutClose(pData
->hWaveHandle
.Out
);
395 pDevice
->ExtraData
= NULL
;
399 static void WinMMClosePlayback(ALCdevice
*device
)
401 WinMMData
*pData
= (WinMMData
*)device
->ExtraData
;
403 // Close the Wave device
404 CloseHandle(pData
->hWaveThreadEvent
);
405 pData
->hWaveThreadEvent
= 0;
407 CloseHandle(pData
->hWaveHdrEvent
);
408 pData
->hWaveHdrEvent
= 0;
410 waveInClose(pData
->hWaveHandle
.In
);
411 pData
->hWaveHandle
.In
= 0;
414 device
->ExtraData
= NULL
;
417 static ALCboolean
WinMMResetPlayback(ALCdevice
*device
)
419 WinMMData
*pData
= (WinMMData
*)device
->ExtraData
;
424 pData
->hWaveThread
= CreateThread(NULL
, 0, (LPTHREAD_START_ROUTINE
)PlaybackThreadProc
, (LPVOID
)device
, 0, &pData
->ulWaveThreadID
);
425 if(pData
->hWaveThread
== NULL
)
428 device
->UpdateSize
= (ALuint
)((ALuint64
)device
->UpdateSize
*
429 pData
->Frequency
/ device
->Frequency
);
430 device
->Frequency
= pData
->Frequency
;
432 pData
->lWaveBuffersCommitted
= 0;
435 lBufferSize
= device
->UpdateSize
*device
->NumUpdates
/ 4;
436 lBufferSize
*= aluFrameSizeFromFormat(device
->Format
);
438 BufferData
= calloc(4, lBufferSize
);
441 memset(&pData
->WaveBuffer
[i
], 0, sizeof(WAVEHDR
));
442 pData
->WaveBuffer
[i
].dwBufferLength
= lBufferSize
;
443 pData
->WaveBuffer
[i
].lpData
= ((i
==0) ? (LPSTR
)BufferData
:
444 (pData
->WaveBuffer
[i
-1].lpData
+
445 pData
->WaveBuffer
[i
-1].dwBufferLength
));
446 waveOutPrepareHeader(pData
->hWaveHandle
.Out
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
447 waveOutWrite(pData
->hWaveHandle
.Out
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
448 InterlockedIncrement(&pData
->lWaveBuffersCommitted
);
454 static void WinMMStopPlayback(ALCdevice
*device
)
456 WinMMData
*pData
= (WinMMData
*)device
->ExtraData
;
459 if(pData
->hWaveThread
== NULL
)
462 // Set flag to stop processing headers
463 pData
->bWaveShutdown
= AL_TRUE
;
465 // Wait for signal that all Wave Buffers have returned
466 WaitForSingleObjectEx(pData
->hWaveHdrEvent
, 5000, FALSE
);
468 // Wait for signal that Wave Thread has been destroyed
469 WaitForSingleObjectEx(pData
->hWaveThreadEvent
, 5000, FALSE
);
471 CloseHandle(pData
->hWaveThread
);
472 pData
->hWaveThread
= 0;
474 pData
->bWaveShutdown
= AL_FALSE
;
476 // Release the wave buffers
479 waveOutUnprepareHeader(pData
->hWaveHandle
.Out
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
481 free(pData
->WaveBuffer
[i
].lpData
);
482 pData
->WaveBuffer
[i
].lpData
= NULL
;
487 static ALCboolean
WinMMOpenCapture(ALCdevice
*pDevice
, const ALCchar
*deviceName
)
489 WAVEFORMATEX wfexCaptureFormat
;
490 DWORD ulCapturedDataSize
;
491 WinMMData
*pData
= NULL
;
498 if(!CaptureDeviceList
)
499 ProbeCaptureDevices();
501 // Find the Device ID matching the deviceName if valid
504 for(i
= 0;i
< NumCaptureDevices
;i
++)
506 if(CaptureDeviceList
[i
] &&
507 strcmp(deviceName
, CaptureDeviceList
[i
]) == 0)
516 for(i
= 0;i
< NumCaptureDevices
;i
++)
518 if(CaptureDeviceList
[i
])
525 if(i
== NumCaptureDevices
)
528 pData
= calloc(1, sizeof(*pData
));
531 alcSetError(pDevice
, ALC_OUT_OF_MEMORY
);
534 pDevice
->ExtraData
= pData
;
536 memset(&wfexCaptureFormat
, 0, sizeof(WAVEFORMATEX
));
537 wfexCaptureFormat
.wFormatTag
= WAVE_FORMAT_PCM
;
538 wfexCaptureFormat
.nChannels
= aluChannelsFromFormat(pDevice
->Format
);
539 wfexCaptureFormat
.wBitsPerSample
= aluBytesFromFormat(pDevice
->Format
) * 8;
540 wfexCaptureFormat
.nBlockAlign
= wfexCaptureFormat
.wBitsPerSample
*
541 wfexCaptureFormat
.nChannels
/ 8;
542 wfexCaptureFormat
.nSamplesPerSec
= pDevice
->Frequency
;
543 wfexCaptureFormat
.nAvgBytesPerSec
= wfexCaptureFormat
.nSamplesPerSec
*
544 wfexCaptureFormat
.nBlockAlign
;
545 wfexCaptureFormat
.cbSize
= 0;
547 if((res
=waveInOpen(&pData
->hWaveHandle
.In
, lDeviceID
, &wfexCaptureFormat
, (DWORD_PTR
)&WaveInProc
, (DWORD_PTR
)pDevice
, CALLBACK_FUNCTION
)) != MMSYSERR_NOERROR
)
549 AL_PRINT("waveInOpen failed: %u\n", res
);
553 pData
->hWaveHdrEvent
= CreateEvent(NULL
, AL_TRUE
, AL_FALSE
, "WaveInAllHeadersReturned");
554 pData
->hWaveThreadEvent
= CreateEvent(NULL
, AL_TRUE
, AL_FALSE
, "WaveInThreadDestroyed");
555 if(pData
->hWaveHdrEvent
== NULL
|| pData
->hWaveThreadEvent
== NULL
)
557 AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
561 pData
->Frequency
= pDevice
->Frequency
;
563 // Allocate circular memory buffer for the captured audio
564 ulCapturedDataSize
= pDevice
->UpdateSize
*pDevice
->NumUpdates
;
566 // Make sure circular buffer is at least 100ms in size
567 if(ulCapturedDataSize
< (wfexCaptureFormat
.nSamplesPerSec
/ 10))
568 ulCapturedDataSize
= wfexCaptureFormat
.nSamplesPerSec
/ 10;
570 pData
->pRing
= CreateRingBuffer(wfexCaptureFormat
.nBlockAlign
, ulCapturedDataSize
);
574 pData
->lWaveBuffersCommitted
= 0;
576 // Create 4 Buffers of 50ms each
577 lBufferSize
= wfexCaptureFormat
.nAvgBytesPerSec
/ 20;
578 lBufferSize
-= (lBufferSize
% wfexCaptureFormat
.nBlockAlign
);
580 BufferData
= calloc(4, lBufferSize
);
586 memset(&pData
->WaveBuffer
[i
], 0, sizeof(WAVEHDR
));
587 pData
->WaveBuffer
[i
].dwBufferLength
= lBufferSize
;
588 pData
->WaveBuffer
[i
].lpData
= ((i
==0) ? (LPSTR
)BufferData
:
589 (pData
->WaveBuffer
[i
-1].lpData
+
590 pData
->WaveBuffer
[i
-1].dwBufferLength
));
591 pData
->WaveBuffer
[i
].dwFlags
= 0;
592 pData
->WaveBuffer
[i
].dwLoops
= 0;
593 waveInPrepareHeader(pData
->hWaveHandle
.In
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
594 waveInAddBuffer(pData
->hWaveHandle
.In
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
595 InterlockedIncrement(&pData
->lWaveBuffersCommitted
);
598 pData
->hWaveThread
= CreateThread(NULL
, 0, (LPTHREAD_START_ROUTINE
)CaptureThreadProc
, (LPVOID
)pDevice
, 0, &pData
->ulWaveThreadID
);
599 if (pData
->hWaveThread
== NULL
)
602 pDevice
->szDeviceName
= strdup(CaptureDeviceList
[lDeviceID
]);
606 if(pData
->hWaveThread
)
607 CloseHandle(pData
->hWaveThread
);
611 if(pData
->WaveBuffer
[i
].lpData
)
613 waveInUnprepareHeader(pData
->hWaveHandle
.In
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
615 free(pData
->WaveBuffer
[i
].lpData
);
620 DestroyRingBuffer(pData
->pRing
);
622 if(pData
->hWaveThreadEvent
)
623 CloseHandle(pData
->hWaveThreadEvent
);
624 if(pData
->hWaveHdrEvent
)
625 CloseHandle(pData
->hWaveHdrEvent
);
627 if(pData
->hWaveHandle
.In
)
628 waveInClose(pData
->hWaveHandle
.In
);
631 pDevice
->ExtraData
= NULL
;
635 static void WinMMCloseCapture(ALCdevice
*pDevice
)
637 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
640 // Call waveOutReset to shutdown wave device
641 pData
->bWaveShutdown
= AL_TRUE
;
642 waveInReset(pData
->hWaveHandle
.In
);
644 // Wait for signal that all Wave Buffers have returned
645 WaitForSingleObjectEx(pData
->hWaveHdrEvent
, 5000, FALSE
);
647 // Wait for signal that Wave Thread has been destroyed
648 WaitForSingleObjectEx(pData
->hWaveThreadEvent
, 5000, FALSE
);
650 CloseHandle(pData
->hWaveThread
);
651 pData
->hWaveThread
= 0;
653 // Release the wave buffers
656 waveInUnprepareHeader(pData
->hWaveHandle
.In
, &pData
->WaveBuffer
[i
], sizeof(WAVEHDR
));
658 free(pData
->WaveBuffer
[i
].lpData
);
659 pData
->WaveBuffer
[i
].lpData
= NULL
;
662 DestroyRingBuffer(pData
->pRing
);
665 // Close the Wave device
666 CloseHandle(pData
->hWaveThreadEvent
);
667 pData
->hWaveThreadEvent
= 0;
669 CloseHandle(pData
->hWaveHdrEvent
);
670 pData
->hWaveHdrEvent
= 0;
672 waveInClose(pData
->hWaveHandle
.In
);
673 pData
->hWaveHandle
.In
= 0;
676 pDevice
->ExtraData
= NULL
;
679 static void WinMMStartCapture(ALCdevice
*pDevice
)
681 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
682 waveInStart(pData
->hWaveHandle
.In
);
685 static void WinMMStopCapture(ALCdevice
*pDevice
)
687 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
688 waveInStop(pData
->hWaveHandle
.In
);
691 static ALCuint
WinMMAvailableSamples(ALCdevice
*pDevice
)
693 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
694 return RingBufferSize(pData
->pRing
);
697 static void WinMMCaptureSamples(ALCdevice
*pDevice
, ALCvoid
*pBuffer
, ALCuint lSamples
)
699 WinMMData
*pData
= (WinMMData
*)pDevice
->ExtraData
;
701 if(WinMMAvailableSamples(pDevice
) >= lSamples
)
702 ReadRingBuffer(pData
->pRing
, pBuffer
, lSamples
);
704 alcSetError(pDevice
, ALC_INVALID_VALUE
);
708 static BackendFuncs WinMMFuncs
= {
718 WinMMAvailableSamples
721 void alcWinMMInit(BackendFuncs
*FuncList
)
723 *FuncList
= WinMMFuncs
;
726 void alcWinMMDeinit()
730 for(lLoop
= 0;lLoop
< NumPlaybackDevices
;lLoop
++)
731 free(PlaybackDeviceList
[lLoop
]);
732 free(PlaybackDeviceList
);
733 PlaybackDeviceList
= NULL
;
735 NumPlaybackDevices
= 0;
738 for(lLoop
= 0; lLoop
< NumCaptureDevices
; lLoop
++)
739 free(CaptureDeviceList
[lLoop
]);
740 free(CaptureDeviceList
);
741 CaptureDeviceList
= NULL
;
743 NumCaptureDevices
= 0;
746 void alcWinMMProbe(int type
)
750 if(type
== DEVICE_PROBE
)
752 ProbePlaybackDevices();
753 if(NumPlaybackDevices
> 0)
754 AppendDeviceList(woDefault
);
756 else if(type
== ALL_DEVICE_PROBE
)
758 ProbePlaybackDevices();
759 if(NumPlaybackDevices
> 0)
760 AppendAllDeviceList(woDefault
);
761 for(i
= 0;i
< NumPlaybackDevices
;i
++)
763 if(PlaybackDeviceList
[i
])
764 AppendAllDeviceList(PlaybackDeviceList
[i
]);
767 else if(type
== CAPTURE_DEVICE_PROBE
)
769 ProbeCaptureDevices();
770 for(i
= 0;i
< NumCaptureDevices
;i
++)
772 if(CaptureDeviceList
[i
])
773 AppendCaptureDeviceList(CaptureDeviceList
[i
]);