Pass the uncompressed sample count to LoadData and ConvertData for IMA4
[openal-soft/android.git] / Alc / backends / winmm.c
blobdf43a81de47d77483e9619fe994494b1063b1ebe
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.
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <memory.h>
27 #include <windows.h>
28 #include <mmsystem.h>
30 #include "alMain.h"
31 #include "AL/al.h"
32 #include "AL/alc.h"
34 #ifndef WAVE_FORMAT_IEEE_FLOAT
35 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
36 #endif
39 typedef struct {
40 // MMSYSTEM Device
41 volatile ALboolean bWaveShutdown;
42 HANDLE hWaveThreadEvent;
43 HANDLE hWaveThread;
44 DWORD ulWaveThreadID;
45 volatile LONG lWaveBuffersCommitted;
46 WAVEHDR WaveBuffer[4];
48 union {
49 HWAVEIN In;
50 HWAVEOUT Out;
51 } hWaveHandle;
53 ALuint Frequency;
55 RingBuffer *pRing;
56 } WinMMData;
59 static const ALCchar woDefault[] = "WaveOut Default";
61 static ALCchar **PlaybackDeviceList;
62 static ALuint NumPlaybackDevices;
63 static ALCchar **CaptureDeviceList;
64 static ALuint NumCaptureDevices;
67 static void ProbePlaybackDevices(void)
69 ALuint i;
71 for(i = 0;i < NumPlaybackDevices;i++)
72 free(PlaybackDeviceList[i]);
74 NumPlaybackDevices = waveOutGetNumDevs();
75 PlaybackDeviceList = realloc(PlaybackDeviceList, sizeof(ALCchar*) * NumPlaybackDevices);
76 for(i = 0;i < NumPlaybackDevices;i++)
78 WAVEOUTCAPS WaveCaps;
80 PlaybackDeviceList[i] = NULL;
81 if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
83 char name[1024];
84 ALuint count, j;
86 count = 0;
87 do {
88 if(count == 0)
89 snprintf(name, sizeof(name), "%s", WaveCaps.szPname);
90 else
91 snprintf(name, sizeof(name), "%s #%d", WaveCaps.szPname, count+1);
92 count++;
94 for(j = 0;j < i;j++)
96 if(strcmp(name, PlaybackDeviceList[j]) == 0)
97 break;
99 } while(j != i);
101 PlaybackDeviceList[i] = strdup(name);
106 static void ProbeCaptureDevices(void)
108 ALuint i;
110 for(i = 0;i < NumCaptureDevices;i++)
111 free(CaptureDeviceList[i]);
113 NumCaptureDevices = waveInGetNumDevs();
114 CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices);
115 for(i = 0;i < NumCaptureDevices;i++)
117 WAVEINCAPS WaveInCaps;
119 CaptureDeviceList[i] = NULL;
120 if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
122 char name[1024];
123 ALuint count, j;
125 count = 0;
126 do {
127 if(count == 0)
128 snprintf(name, sizeof(name), "%s", WaveInCaps.szPname);
129 else
130 snprintf(name, sizeof(name), "%s #%d", WaveInCaps.szPname, count+1);
131 count++;
133 for(j = 0;j < i;j++)
135 if(strcmp(name, CaptureDeviceList[j]) == 0)
136 break;
138 } while(j != i);
140 CaptureDeviceList[i] = strdup(name);
147 WaveOutProc
149 Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and
150 returns to the application (for more data)
152 static void CALLBACK WaveOutProc(HWAVEOUT hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
154 ALCdevice *pDevice = (ALCdevice*)dwInstance;
155 WinMMData *pData = pDevice->ExtraData;
157 (void)hDevice;
158 (void)dwParam2;
160 if(uMsg != WOM_DONE)
161 return;
163 InterlockedDecrement(&pData->lWaveBuffersCommitted);
164 PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1);
168 PlaybackThreadProc
170 Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its
171 audio data.
173 static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)
175 ALCdevice *pDevice = (ALCdevice*)lpParameter;
176 WinMMData *pData = pDevice->ExtraData;
177 LPWAVEHDR pWaveHdr;
178 ALuint FrameSize;
179 MSG msg;
181 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
183 SetRTPriority();
185 while(GetMessage(&msg, NULL, 0, 0))
187 if(msg.message != WOM_DONE)
188 continue;
190 if(pData->bWaveShutdown)
192 if(pData->lWaveBuffersCommitted == 0)
193 break;
194 continue;
197 pWaveHdr = ((LPWAVEHDR)msg.lParam);
199 aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize);
201 // Send buffer back to play more data
202 waveOutWrite(pData->hWaveHandle.Out, pWaveHdr, sizeof(WAVEHDR));
203 InterlockedIncrement(&pData->lWaveBuffersCommitted);
206 // Signal Wave Thread completed event
207 if(pData->hWaveThreadEvent)
208 SetEvent(pData->hWaveThreadEvent);
210 ExitThread(0);
212 return 0;
216 WaveInProc
218 Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
219 returns to the application (with more data)
221 static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
223 ALCdevice *pDevice = (ALCdevice*)dwInstance;
224 WinMMData *pData = pDevice->ExtraData;
226 (void)hDevice;
227 (void)dwParam2;
229 if(uMsg != WIM_DATA)
230 return;
232 InterlockedDecrement(&pData->lWaveBuffersCommitted);
233 PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);
237 CaptureThreadProc
239 Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new
240 audio data.
242 static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
244 ALCdevice *pDevice = (ALCdevice*)lpParameter;
245 WinMMData *pData = pDevice->ExtraData;
246 LPWAVEHDR pWaveHdr;
247 ALuint FrameSize;
248 MSG msg;
250 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
252 while(GetMessage(&msg, NULL, 0, 0))
254 if(msg.message != WIM_DATA)
255 continue;
256 /* Don't wait for other buffers to finish before quitting. We're
257 * closing so we don't need them. */
258 if(pData->bWaveShutdown)
259 break;
261 pWaveHdr = ((LPWAVEHDR)msg.lParam);
263 WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData,
264 pWaveHdr->dwBytesRecorded/FrameSize);
266 // Send buffer back to capture more data
267 waveInAddBuffer(pData->hWaveHandle.In,pWaveHdr,sizeof(WAVEHDR));
268 InterlockedIncrement(&pData->lWaveBuffersCommitted);
271 // Signal Wave Thread completed event
272 if(pData->hWaveThreadEvent)
273 SetEvent(pData->hWaveThreadEvent);
275 ExitThread(0);
277 return 0;
281 static ALCenum WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)
283 WAVEFORMATEX wfexFormat;
284 WinMMData *pData = NULL;
285 UINT lDeviceID = 0;
286 MMRESULT res;
287 ALuint i = 0;
289 // Find the Device ID matching the deviceName if valid
290 if(!deviceName || strcmp(deviceName, woDefault) == 0)
291 lDeviceID = WAVE_MAPPER;
292 else
294 if(!PlaybackDeviceList)
295 ProbePlaybackDevices();
297 for(i = 0;i < NumPlaybackDevices;i++)
299 if(PlaybackDeviceList[i] &&
300 strcmp(deviceName, PlaybackDeviceList[i]) == 0)
302 lDeviceID = i;
303 break;
306 if(i == NumPlaybackDevices)
307 return ALC_INVALID_VALUE;
310 pData = calloc(1, sizeof(*pData));
311 if(!pData)
312 return ALC_OUT_OF_MEMORY;
313 pDevice->ExtraData = pData;
315 if(pDevice->FmtChans != DevFmtMono)
317 if((pDevice->Flags&DEVICE_CHANNELS_REQUEST) &&
318 pDevice->FmtChans != DevFmtStereo)
320 ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(pDevice->FmtChans));
321 pDevice->Flags &= ~DEVICE_CHANNELS_REQUEST;
323 pDevice->FmtChans = DevFmtStereo;
325 switch(pDevice->FmtType)
327 case DevFmtByte:
328 pDevice->FmtType = DevFmtUByte;
329 break;
330 case DevFmtUShort:
331 pDevice->FmtType = DevFmtShort;
332 break;
333 case DevFmtUByte:
334 case DevFmtShort:
335 case DevFmtFloat:
336 break;
339 retry_open:
340 memset(&wfexFormat, 0, sizeof(WAVEFORMATEX));
341 wfexFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
342 WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
343 wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
344 wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
345 wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample *
346 wfexFormat.nChannels / 8;
347 wfexFormat.nSamplesPerSec = pDevice->Frequency;
348 wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec *
349 wfexFormat.nBlockAlign;
350 wfexFormat.cbSize = 0;
352 if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
354 if(pDevice->FmtType == DevFmtFloat)
356 pDevice->FmtType = DevFmtShort;
357 goto retry_open;
359 ERR("waveOutOpen failed: %u\n", res);
360 goto failure;
363 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
364 if(pData->hWaveThreadEvent == NULL)
366 ERR("CreateEvent failed: %lu\n", GetLastError());
367 goto failure;
370 pData->Frequency = pDevice->Frequency;
372 pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault :
373 PlaybackDeviceList[lDeviceID]);
374 return ALC_NO_ERROR;
376 failure:
377 if(pData->hWaveThreadEvent)
378 CloseHandle(pData->hWaveThreadEvent);
380 if(pData->hWaveHandle.Out)
381 waveOutClose(pData->hWaveHandle.Out);
383 free(pData);
384 pDevice->ExtraData = NULL;
385 return ALC_INVALID_VALUE;
388 static void WinMMClosePlayback(ALCdevice *device)
390 WinMMData *pData = (WinMMData*)device->ExtraData;
392 // Close the Wave device
393 CloseHandle(pData->hWaveThreadEvent);
394 pData->hWaveThreadEvent = 0;
396 waveOutClose(pData->hWaveHandle.Out);
397 pData->hWaveHandle.Out = 0;
399 free(pData);
400 device->ExtraData = NULL;
403 static ALCboolean WinMMResetPlayback(ALCdevice *device)
405 WinMMData *pData = (WinMMData*)device->ExtraData;
406 ALbyte *BufferData;
407 ALint lBufferSize;
408 ALuint i;
410 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);
411 if(pData->hWaveThread == NULL)
412 return ALC_FALSE;
414 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
415 pData->Frequency / device->Frequency);
416 device->Frequency = pData->Frequency;
418 SetDefaultWFXChannelOrder(device);
420 pData->lWaveBuffersCommitted = 0;
422 // Create 4 Buffers
423 lBufferSize = device->UpdateSize*device->NumUpdates / 4;
424 lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
426 BufferData = calloc(4, lBufferSize);
427 for(i = 0;i < 4;i++)
429 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
430 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
431 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
432 (pData->WaveBuffer[i-1].lpData +
433 pData->WaveBuffer[i-1].dwBufferLength));
434 waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
435 waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
436 InterlockedIncrement(&pData->lWaveBuffersCommitted);
439 return ALC_TRUE;
442 static void WinMMStopPlayback(ALCdevice *device)
444 WinMMData *pData = (WinMMData*)device->ExtraData;
445 void *buffer = NULL;
446 int i;
448 if(pData->hWaveThread == NULL)
449 return;
451 // Set flag to stop processing headers
452 pData->bWaveShutdown = AL_TRUE;
454 // Wait for signal that Wave Thread has been destroyed
455 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
457 CloseHandle(pData->hWaveThread);
458 pData->hWaveThread = 0;
460 pData->bWaveShutdown = AL_FALSE;
462 // Release the wave buffers
463 for(i = 0;i < 4;i++)
465 waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
466 if(i == 0) buffer = pData->WaveBuffer[i].lpData;
467 pData->WaveBuffer[i].lpData = NULL;
469 free(buffer);
473 static ALCenum WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
475 WAVEFORMATEX wfexCaptureFormat;
476 ALbyte *BufferData = NULL;
477 DWORD ulCapturedDataSize;
478 WinMMData *pData = NULL;
479 UINT lDeviceID = 0;
480 ALint lBufferSize;
481 MMRESULT res;
482 ALuint i;
484 if(!CaptureDeviceList)
485 ProbeCaptureDevices();
487 // Find the Device ID matching the deviceName if valid
488 if(deviceName)
490 for(i = 0;i < NumCaptureDevices;i++)
492 if(CaptureDeviceList[i] &&
493 strcmp(deviceName, CaptureDeviceList[i]) == 0)
495 lDeviceID = i;
496 break;
500 else
502 for(i = 0;i < NumCaptureDevices;i++)
504 if(CaptureDeviceList[i])
506 lDeviceID = i;
507 break;
511 if(i == NumCaptureDevices)
512 return ALC_INVALID_VALUE;
514 pData = calloc(1, sizeof(*pData));
515 if(!pData)
516 return ALC_OUT_OF_MEMORY;
517 pDevice->ExtraData = pData;
519 if((pDevice->FmtChans != DevFmtMono && pDevice->FmtChans != DevFmtStereo) ||
520 (pDevice->FmtType != DevFmtUByte && pDevice->FmtType != DevFmtShort &&
521 pDevice->FmtType != DevFmtFloat))
522 goto failure;
524 memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));
525 wfexCaptureFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
526 WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
527 wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
528 wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
529 wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
530 wfexCaptureFormat.nChannels / 8;
531 wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;
532 wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
533 wfexCaptureFormat.nBlockAlign;
534 wfexCaptureFormat.cbSize = 0;
536 if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
538 ERR("waveInOpen failed: %u\n", res);
539 goto failure;
542 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
543 if(pData->hWaveThreadEvent == NULL)
545 ERR("CreateEvent failed: %lu\n", GetLastError());
546 goto failure;
549 pData->Frequency = pDevice->Frequency;
551 // Allocate circular memory buffer for the captured audio
552 ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;
554 // Make sure circular buffer is at least 100ms in size
555 if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10))
556 ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10;
558 pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize);
559 if(!pData->pRing)
560 goto failure;
562 pData->lWaveBuffersCommitted = 0;
564 // Create 4 Buffers of 50ms each
565 lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20;
566 lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign);
568 BufferData = calloc(4, lBufferSize);
569 if(!BufferData)
570 goto failure;
572 for(i = 0;i < 4;i++)
574 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
575 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
576 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
577 (pData->WaveBuffer[i-1].lpData +
578 pData->WaveBuffer[i-1].dwBufferLength));
579 pData->WaveBuffer[i].dwFlags = 0;
580 pData->WaveBuffer[i].dwLoops = 0;
581 waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
582 waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
583 InterlockedIncrement(&pData->lWaveBuffersCommitted);
586 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID);
587 if (pData->hWaveThread == NULL)
588 goto failure;
590 pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
591 return ALC_NO_ERROR;
593 failure:
594 if(pData->hWaveThread)
595 CloseHandle(pData->hWaveThread);
597 if(BufferData)
599 for(i = 0;i < 4;i++)
600 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
601 free(BufferData);
604 if(pData->pRing)
605 DestroyRingBuffer(pData->pRing);
607 if(pData->hWaveThreadEvent)
608 CloseHandle(pData->hWaveThreadEvent);
610 if(pData->hWaveHandle.In)
611 waveInClose(pData->hWaveHandle.In);
613 free(pData);
614 pDevice->ExtraData = NULL;
615 return ALC_INVALID_VALUE;
618 static void WinMMCloseCapture(ALCdevice *pDevice)
620 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
621 void *buffer = NULL;
622 int i;
624 /* Tell the processing thread to quit and wait for it to do so. */
625 pData->bWaveShutdown = AL_TRUE;
626 PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
628 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
630 /* Make sure capture is stopped and all pending buffers are flushed. */
631 waveInReset(pData->hWaveHandle.In);
633 CloseHandle(pData->hWaveThread);
634 pData->hWaveThread = 0;
636 // Release the wave buffers
637 for(i = 0;i < 4;i++)
639 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
640 if(i == 0) buffer = pData->WaveBuffer[i].lpData;
641 pData->WaveBuffer[i].lpData = NULL;
643 free(buffer);
645 DestroyRingBuffer(pData->pRing);
646 pData->pRing = NULL;
648 // Close the Wave device
649 CloseHandle(pData->hWaveThreadEvent);
650 pData->hWaveThreadEvent = 0;
652 waveInClose(pData->hWaveHandle.In);
653 pData->hWaveHandle.In = 0;
655 free(pData);
656 pDevice->ExtraData = NULL;
659 static void WinMMStartCapture(ALCdevice *pDevice)
661 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
662 waveInStart(pData->hWaveHandle.In);
665 static void WinMMStopCapture(ALCdevice *pDevice)
667 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
668 waveInStop(pData->hWaveHandle.In);
671 static ALCenum WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
673 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
674 ReadRingBuffer(pData->pRing, pBuffer, lSamples);
675 return ALC_NO_ERROR;
678 static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
680 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
681 return RingBufferSize(pData->pRing);
685 static const BackendFuncs WinMMFuncs = {
686 WinMMOpenPlayback,
687 WinMMClosePlayback,
688 WinMMResetPlayback,
689 WinMMStopPlayback,
690 WinMMOpenCapture,
691 WinMMCloseCapture,
692 WinMMStartCapture,
693 WinMMStopCapture,
694 WinMMCaptureSamples,
695 WinMMAvailableSamples
698 ALCboolean alcWinMMInit(BackendFuncs *FuncList)
700 *FuncList = WinMMFuncs;
701 return ALC_TRUE;
704 void alcWinMMDeinit()
706 ALuint lLoop;
708 for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++)
709 free(PlaybackDeviceList[lLoop]);
710 free(PlaybackDeviceList);
711 PlaybackDeviceList = NULL;
713 NumPlaybackDevices = 0;
716 for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
717 free(CaptureDeviceList[lLoop]);
718 free(CaptureDeviceList);
719 CaptureDeviceList = NULL;
721 NumCaptureDevices = 0;
724 void alcWinMMProbe(enum DevProbe type)
726 ALuint i;
728 switch(type)
730 case DEVICE_PROBE:
731 ProbePlaybackDevices();
732 if(NumPlaybackDevices > 0)
733 AppendDeviceList(woDefault);
734 break;
736 case ALL_DEVICE_PROBE:
737 ProbePlaybackDevices();
738 if(NumPlaybackDevices > 0)
739 AppendAllDeviceList(woDefault);
740 for(i = 0;i < NumPlaybackDevices;i++)
742 if(PlaybackDeviceList[i])
743 AppendAllDeviceList(PlaybackDeviceList[i]);
745 break;
747 case CAPTURE_DEVICE_PROBE:
748 ProbeCaptureDevices();
749 for(i = 0;i < NumCaptureDevices;i++)
751 if(CaptureDeviceList[i])
752 AppendCaptureDeviceList(CaptureDeviceList[i]);
754 break;