Use a separate backend callback to start playback of the device
[openal-soft.git] / Alc / backends / winmm.c
blob57d2797418b2269912b01e40a51c46736c0f3df9
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 ALCchar **PlaybackDeviceList;
60 static ALuint NumPlaybackDevices;
61 static ALCchar **CaptureDeviceList;
62 static ALuint NumCaptureDevices;
65 static void ProbePlaybackDevices(void)
67 ALuint i;
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++)
76 WAVEOUTCAPS WaveCaps;
78 PlaybackDeviceList[i] = NULL;
79 if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
81 char name[1024];
82 ALuint count, j;
84 count = 0;
85 do {
86 if(count == 0)
87 snprintf(name, sizeof(name), "%s", WaveCaps.szPname);
88 else
89 snprintf(name, sizeof(name), "%s #%d", WaveCaps.szPname, count+1);
90 count++;
92 for(j = 0;j < i;j++)
94 if(strcmp(name, PlaybackDeviceList[j]) == 0)
95 break;
97 } while(j != i);
99 PlaybackDeviceList[i] = strdup(name);
104 static void ProbeCaptureDevices(void)
106 ALuint i;
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)
120 char name[1024];
121 ALuint count, j;
123 count = 0;
124 do {
125 if(count == 0)
126 snprintf(name, sizeof(name), "%s", WaveInCaps.szPname);
127 else
128 snprintf(name, sizeof(name), "%s #%d", WaveInCaps.szPname, count+1);
129 count++;
131 for(j = 0;j < i;j++)
133 if(strcmp(name, CaptureDeviceList[j]) == 0)
134 break;
136 } while(j != i);
138 CaptureDeviceList[i] = strdup(name);
145 WaveOutProc
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;
155 (void)hDevice;
156 (void)dwParam2;
158 if(uMsg != WOM_DONE)
159 return;
161 InterlockedDecrement(&pData->lWaveBuffersCommitted);
162 PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1);
166 PlaybackThreadProc
168 Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its
169 audio data.
171 static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)
173 ALCdevice *pDevice = (ALCdevice*)lpParameter;
174 WinMMData *pData = pDevice->ExtraData;
175 LPWAVEHDR pWaveHdr;
176 ALuint FrameSize;
177 MSG msg;
179 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
181 SetRTPriority();
183 while(GetMessage(&msg, NULL, 0, 0))
185 if(msg.message != WOM_DONE)
186 continue;
188 if(pData->bWaveShutdown)
190 if(pData->lWaveBuffersCommitted == 0)
191 break;
192 continue;
195 pWaveHdr = ((LPWAVEHDR)msg.lParam);
197 aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize);
199 // Send buffer back to play more data
200 waveOutWrite(pData->hWaveHandle.Out, pWaveHdr, sizeof(WAVEHDR));
201 InterlockedIncrement(&pData->lWaveBuffersCommitted);
204 // Signal Wave Thread completed event
205 if(pData->hWaveThreadEvent)
206 SetEvent(pData->hWaveThreadEvent);
208 ExitThread(0);
210 return 0;
214 WaveInProc
216 Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
217 returns to the application (with more data)
219 static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
221 ALCdevice *pDevice = (ALCdevice*)dwInstance;
222 WinMMData *pData = pDevice->ExtraData;
224 (void)hDevice;
225 (void)dwParam2;
227 if(uMsg != WIM_DATA)
228 return;
230 InterlockedDecrement(&pData->lWaveBuffersCommitted);
231 PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);
235 CaptureThreadProc
237 Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new
238 audio data.
240 static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
242 ALCdevice *pDevice = (ALCdevice*)lpParameter;
243 WinMMData *pData = pDevice->ExtraData;
244 LPWAVEHDR pWaveHdr;
245 ALuint FrameSize;
246 MSG msg;
248 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
250 while(GetMessage(&msg, NULL, 0, 0))
252 if(msg.message != WIM_DATA)
253 continue;
254 /* Don't wait for other buffers to finish before quitting. We're
255 * closing so we don't need them. */
256 if(pData->bWaveShutdown)
257 break;
259 pWaveHdr = ((LPWAVEHDR)msg.lParam);
261 WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData,
262 pWaveHdr->dwBytesRecorded/FrameSize);
264 // Send buffer back to capture more data
265 waveInAddBuffer(pData->hWaveHandle.In,pWaveHdr,sizeof(WAVEHDR));
266 InterlockedIncrement(&pData->lWaveBuffersCommitted);
269 // Signal Wave Thread completed event
270 if(pData->hWaveThreadEvent)
271 SetEvent(pData->hWaveThreadEvent);
273 ExitThread(0);
275 return 0;
279 static ALCenum WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)
281 WAVEFORMATEX wfexFormat;
282 WinMMData *pData = NULL;
283 UINT lDeviceID = 0;
284 MMRESULT res;
285 ALuint i = 0;
287 if(!PlaybackDeviceList)
288 ProbePlaybackDevices();
290 // Find the Device ID matching the deviceName if valid
291 for(i = 0;i < NumPlaybackDevices;i++)
293 if(PlaybackDeviceList[i] &&
294 (!deviceName || strcmp(deviceName, PlaybackDeviceList[i]) == 0))
296 lDeviceID = i;
297 break;
300 if(i == NumPlaybackDevices)
301 return ALC_INVALID_VALUE;
303 pData = calloc(1, sizeof(*pData));
304 if(!pData)
305 return ALC_OUT_OF_MEMORY;
306 pDevice->ExtraData = pData;
308 if(pDevice->FmtChans != DevFmtMono)
310 if((pDevice->Flags&DEVICE_CHANNELS_REQUEST) &&
311 pDevice->FmtChans != DevFmtStereo)
313 ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(pDevice->FmtChans));
314 pDevice->Flags &= ~DEVICE_CHANNELS_REQUEST;
316 pDevice->FmtChans = DevFmtStereo;
318 switch(pDevice->FmtType)
320 case DevFmtByte:
321 pDevice->FmtType = DevFmtUByte;
322 break;
323 case DevFmtInt:
324 case DevFmtUInt:
325 case DevFmtUShort:
326 pDevice->FmtType = DevFmtShort;
327 break;
328 case DevFmtUByte:
329 case DevFmtShort:
330 case DevFmtFloat:
331 break;
334 retry_open:
335 memset(&wfexFormat, 0, sizeof(WAVEFORMATEX));
336 wfexFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
337 WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
338 wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
339 wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
340 wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample *
341 wfexFormat.nChannels / 8;
342 wfexFormat.nSamplesPerSec = pDevice->Frequency;
343 wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec *
344 wfexFormat.nBlockAlign;
345 wfexFormat.cbSize = 0;
347 if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
349 if(pDevice->FmtType == DevFmtFloat)
351 pDevice->FmtType = DevFmtShort;
352 goto retry_open;
354 ERR("waveOutOpen failed: %u\n", res);
355 goto failure;
358 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
359 if(pData->hWaveThreadEvent == NULL)
361 ERR("CreateEvent failed: %lu\n", GetLastError());
362 goto failure;
365 pData->Frequency = pDevice->Frequency;
367 pDevice->szDeviceName = strdup(PlaybackDeviceList[lDeviceID]);
368 return ALC_NO_ERROR;
370 failure:
371 if(pData->hWaveThreadEvent)
372 CloseHandle(pData->hWaveThreadEvent);
374 if(pData->hWaveHandle.Out)
375 waveOutClose(pData->hWaveHandle.Out);
377 free(pData);
378 pDevice->ExtraData = NULL;
379 return ALC_INVALID_VALUE;
382 static void WinMMClosePlayback(ALCdevice *device)
384 WinMMData *pData = (WinMMData*)device->ExtraData;
386 // Close the Wave device
387 CloseHandle(pData->hWaveThreadEvent);
388 pData->hWaveThreadEvent = 0;
390 waveOutClose(pData->hWaveHandle.Out);
391 pData->hWaveHandle.Out = 0;
393 free(pData);
394 device->ExtraData = NULL;
397 static ALCboolean WinMMResetPlayback(ALCdevice *device)
399 WinMMData *pData = (WinMMData*)device->ExtraData;
401 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
402 pData->Frequency / device->Frequency);
403 device->UpdateSize = device->UpdateSize*device->NumUpdates / 4;
404 device->NumUpdates = 4;
405 device->Frequency = pData->Frequency;
407 SetDefaultWFXChannelOrder(device);
409 return ALC_TRUE;
412 static ALCboolean WinMMStartPlayback(ALCdevice *device)
414 WinMMData *pData = (WinMMData*)device->ExtraData;
415 ALbyte *BufferData;
416 ALint lBufferSize;
417 ALuint i;
419 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);
420 if(pData->hWaveThread == NULL)
421 return ALC_FALSE;
423 pData->lWaveBuffersCommitted = 0;
425 // Create 4 Buffers
426 lBufferSize = device->UpdateSize*device->NumUpdates / 4;
427 lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
429 BufferData = calloc(4, lBufferSize);
430 for(i = 0;i < 4;i++)
432 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
433 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
434 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
435 (pData->WaveBuffer[i-1].lpData +
436 pData->WaveBuffer[i-1].dwBufferLength));
437 waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
438 waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
439 InterlockedIncrement(&pData->lWaveBuffersCommitted);
442 return ALC_TRUE;
445 static void WinMMStopPlayback(ALCdevice *device)
447 WinMMData *pData = (WinMMData*)device->ExtraData;
448 void *buffer = NULL;
449 int i;
451 if(pData->hWaveThread == NULL)
452 return;
454 // Set flag to stop processing headers
455 pData->bWaveShutdown = AL_TRUE;
457 // Wait for signal that Wave Thread has been destroyed
458 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
460 CloseHandle(pData->hWaveThread);
461 pData->hWaveThread = 0;
463 pData->bWaveShutdown = AL_FALSE;
465 // Release the wave buffers
466 for(i = 0;i < 4;i++)
468 waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
469 if(i == 0) buffer = pData->WaveBuffer[i].lpData;
470 pData->WaveBuffer[i].lpData = NULL;
472 free(buffer);
476 static ALCenum WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
478 WAVEFORMATEX wfexCaptureFormat;
479 ALbyte *BufferData = NULL;
480 DWORD ulCapturedDataSize;
481 WinMMData *pData = NULL;
482 UINT lDeviceID = 0;
483 ALint lBufferSize;
484 MMRESULT res;
485 ALuint i;
487 if(!CaptureDeviceList)
488 ProbeCaptureDevices();
490 // Find the Device ID matching the deviceName if valid
491 for(i = 0;i < NumCaptureDevices;i++)
493 if(CaptureDeviceList[i] &&
494 (!deviceName || strcmp(deviceName, CaptureDeviceList[i]) == 0))
496 lDeviceID = i;
497 break;
500 if(i == NumCaptureDevices)
501 return ALC_INVALID_VALUE;
503 switch(pDevice->FmtChans)
505 case DevFmtMono:
506 case DevFmtStereo:
507 break;
509 case DevFmtQuad:
510 case DevFmtX51:
511 case DevFmtX51Side:
512 case DevFmtX61:
513 case DevFmtX71:
514 return ALC_INVALID_ENUM;
517 switch(pDevice->FmtType)
519 case DevFmtUByte:
520 case DevFmtShort:
521 case DevFmtInt:
522 case DevFmtFloat:
523 break;
525 case DevFmtByte:
526 case DevFmtUShort:
527 case DevFmtUInt:
528 return ALC_INVALID_ENUM;
531 pData = calloc(1, sizeof(*pData));
532 if(!pData)
533 return ALC_OUT_OF_MEMORY;
534 pDevice->ExtraData = pData;
536 memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));
537 wfexCaptureFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
538 WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
539 wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
540 wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
541 wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
542 wfexCaptureFormat.nChannels / 8;
543 wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;
544 wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
545 wfexCaptureFormat.nBlockAlign;
546 wfexCaptureFormat.cbSize = 0;
548 if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
550 ERR("waveInOpen failed: %u\n", res);
551 goto failure;
554 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
555 if(pData->hWaveThreadEvent == NULL)
557 ERR("CreateEvent failed: %lu\n", GetLastError());
558 goto failure;
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);
571 if(!pData->pRing)
572 goto failure;
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);
581 if(!BufferData)
582 goto failure;
584 for(i = 0;i < 4;i++)
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)
600 goto failure;
602 pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
603 return ALC_NO_ERROR;
605 failure:
606 if(pData->hWaveThread)
607 CloseHandle(pData->hWaveThread);
609 if(BufferData)
611 for(i = 0;i < 4;i++)
612 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
613 free(BufferData);
616 if(pData->pRing)
617 DestroyRingBuffer(pData->pRing);
619 if(pData->hWaveThreadEvent)
620 CloseHandle(pData->hWaveThreadEvent);
622 if(pData->hWaveHandle.In)
623 waveInClose(pData->hWaveHandle.In);
625 free(pData);
626 pDevice->ExtraData = NULL;
627 return ALC_INVALID_VALUE;
630 static void WinMMCloseCapture(ALCdevice *pDevice)
632 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
633 void *buffer = NULL;
634 int i;
636 /* Tell the processing thread to quit and wait for it to do so. */
637 pData->bWaveShutdown = AL_TRUE;
638 PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
640 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
642 /* Make sure capture is stopped and all pending buffers are flushed. */
643 waveInReset(pData->hWaveHandle.In);
645 CloseHandle(pData->hWaveThread);
646 pData->hWaveThread = 0;
648 // Release the wave buffers
649 for(i = 0;i < 4;i++)
651 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
652 if(i == 0) buffer = pData->WaveBuffer[i].lpData;
653 pData->WaveBuffer[i].lpData = NULL;
655 free(buffer);
657 DestroyRingBuffer(pData->pRing);
658 pData->pRing = NULL;
660 // Close the Wave device
661 CloseHandle(pData->hWaveThreadEvent);
662 pData->hWaveThreadEvent = 0;
664 waveInClose(pData->hWaveHandle.In);
665 pData->hWaveHandle.In = 0;
667 free(pData);
668 pDevice->ExtraData = NULL;
671 static void WinMMStartCapture(ALCdevice *pDevice)
673 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
674 waveInStart(pData->hWaveHandle.In);
677 static void WinMMStopCapture(ALCdevice *pDevice)
679 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
680 waveInStop(pData->hWaveHandle.In);
683 static ALCenum WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
685 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
686 ReadRingBuffer(pData->pRing, pBuffer, lSamples);
687 return ALC_NO_ERROR;
690 static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
692 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
693 return RingBufferSize(pData->pRing);
697 static const BackendFuncs WinMMFuncs = {
698 WinMMOpenPlayback,
699 WinMMClosePlayback,
700 WinMMResetPlayback,
701 WinMMStartPlayback,
702 WinMMStopPlayback,
703 WinMMOpenCapture,
704 WinMMCloseCapture,
705 WinMMStartCapture,
706 WinMMStopCapture,
707 WinMMCaptureSamples,
708 WinMMAvailableSamples
711 ALCboolean alcWinMMInit(BackendFuncs *FuncList)
713 *FuncList = WinMMFuncs;
714 return ALC_TRUE;
717 void alcWinMMDeinit()
719 ALuint lLoop;
721 for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++)
722 free(PlaybackDeviceList[lLoop]);
723 free(PlaybackDeviceList);
724 PlaybackDeviceList = NULL;
726 NumPlaybackDevices = 0;
729 for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
730 free(CaptureDeviceList[lLoop]);
731 free(CaptureDeviceList);
732 CaptureDeviceList = NULL;
734 NumCaptureDevices = 0;
737 void alcWinMMProbe(enum DevProbe type)
739 ALuint i;
741 switch(type)
743 case ALL_DEVICE_PROBE:
744 ProbePlaybackDevices();
745 for(i = 0;i < NumPlaybackDevices;i++)
747 if(PlaybackDeviceList[i])
748 AppendAllDeviceList(PlaybackDeviceList[i]);
750 break;
752 case CAPTURE_DEVICE_PROBE:
753 ProbeCaptureDevices();
754 for(i = 0;i < NumCaptureDevices;i++)
756 if(CaptureDeviceList[i])
757 AppendCaptureDeviceList(CaptureDeviceList[i]);
759 break;