Always use "OpenAL Soft" for the short device enumeration list
[openal-soft.git] / Alc / backends / winmm.c
blob994c073c41d6a1165cdf932765964749fb791f44
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 DevFmtInt:
331 case DevFmtUInt:
332 case DevFmtUShort:
333 pDevice->FmtType = DevFmtShort;
334 break;
335 case DevFmtUByte:
336 case DevFmtShort:
337 case DevFmtFloat:
338 break;
341 retry_open:
342 memset(&wfexFormat, 0, sizeof(WAVEFORMATEX));
343 wfexFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
344 WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
345 wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
346 wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
347 wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample *
348 wfexFormat.nChannels / 8;
349 wfexFormat.nSamplesPerSec = pDevice->Frequency;
350 wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec *
351 wfexFormat.nBlockAlign;
352 wfexFormat.cbSize = 0;
354 if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
356 if(pDevice->FmtType == DevFmtFloat)
358 pDevice->FmtType = DevFmtShort;
359 goto retry_open;
361 ERR("waveOutOpen failed: %u\n", res);
362 goto failure;
365 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
366 if(pData->hWaveThreadEvent == NULL)
368 ERR("CreateEvent failed: %lu\n", GetLastError());
369 goto failure;
372 pData->Frequency = pDevice->Frequency;
374 pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault :
375 PlaybackDeviceList[lDeviceID]);
376 return ALC_NO_ERROR;
378 failure:
379 if(pData->hWaveThreadEvent)
380 CloseHandle(pData->hWaveThreadEvent);
382 if(pData->hWaveHandle.Out)
383 waveOutClose(pData->hWaveHandle.Out);
385 free(pData);
386 pDevice->ExtraData = NULL;
387 return ALC_INVALID_VALUE;
390 static void WinMMClosePlayback(ALCdevice *device)
392 WinMMData *pData = (WinMMData*)device->ExtraData;
394 // Close the Wave device
395 CloseHandle(pData->hWaveThreadEvent);
396 pData->hWaveThreadEvent = 0;
398 waveOutClose(pData->hWaveHandle.Out);
399 pData->hWaveHandle.Out = 0;
401 free(pData);
402 device->ExtraData = NULL;
405 static ALCboolean WinMMResetPlayback(ALCdevice *device)
407 WinMMData *pData = (WinMMData*)device->ExtraData;
408 ALbyte *BufferData;
409 ALint lBufferSize;
410 ALuint i;
412 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);
413 if(pData->hWaveThread == NULL)
414 return ALC_FALSE;
416 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
417 pData->Frequency / device->Frequency);
418 device->Frequency = pData->Frequency;
420 SetDefaultWFXChannelOrder(device);
422 pData->lWaveBuffersCommitted = 0;
424 // Create 4 Buffers
425 lBufferSize = device->UpdateSize*device->NumUpdates / 4;
426 lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
428 BufferData = calloc(4, lBufferSize);
429 for(i = 0;i < 4;i++)
431 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
432 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
433 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
434 (pData->WaveBuffer[i-1].lpData +
435 pData->WaveBuffer[i-1].dwBufferLength));
436 waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
437 waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
438 InterlockedIncrement(&pData->lWaveBuffersCommitted);
441 return ALC_TRUE;
444 static void WinMMStopPlayback(ALCdevice *device)
446 WinMMData *pData = (WinMMData*)device->ExtraData;
447 void *buffer = NULL;
448 int i;
450 if(pData->hWaveThread == NULL)
451 return;
453 // Set flag to stop processing headers
454 pData->bWaveShutdown = AL_TRUE;
456 // Wait for signal that Wave Thread has been destroyed
457 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
459 CloseHandle(pData->hWaveThread);
460 pData->hWaveThread = 0;
462 pData->bWaveShutdown = AL_FALSE;
464 // Release the wave buffers
465 for(i = 0;i < 4;i++)
467 waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
468 if(i == 0) buffer = pData->WaveBuffer[i].lpData;
469 pData->WaveBuffer[i].lpData = NULL;
471 free(buffer);
475 static ALCenum WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
477 WAVEFORMATEX wfexCaptureFormat;
478 ALbyte *BufferData = NULL;
479 DWORD ulCapturedDataSize;
480 WinMMData *pData = NULL;
481 UINT lDeviceID = 0;
482 ALint lBufferSize;
483 MMRESULT res;
484 ALuint i;
486 if(!CaptureDeviceList)
487 ProbeCaptureDevices();
489 // Find the Device ID matching the deviceName if valid
490 if(deviceName)
492 for(i = 0;i < NumCaptureDevices;i++)
494 if(CaptureDeviceList[i] &&
495 strcmp(deviceName, CaptureDeviceList[i]) == 0)
497 lDeviceID = i;
498 break;
502 else
504 for(i = 0;i < NumCaptureDevices;i++)
506 if(CaptureDeviceList[i])
508 lDeviceID = i;
509 break;
513 if(i == NumCaptureDevices)
514 return ALC_INVALID_VALUE;
516 switch(pDevice->FmtChans)
518 case DevFmtMono:
519 case DevFmtStereo:
520 break;
522 case DevFmtQuad:
523 case DevFmtX51:
524 case DevFmtX51Side:
525 case DevFmtX61:
526 case DevFmtX71:
527 return ALC_INVALID_ENUM;
530 switch(pDevice->FmtType)
532 case DevFmtUByte:
533 case DevFmtShort:
534 case DevFmtInt:
535 case DevFmtFloat:
536 break;
538 case DevFmtByte:
539 case DevFmtUShort:
540 case DevFmtUInt:
541 return ALC_INVALID_ENUM;
544 pData = calloc(1, sizeof(*pData));
545 if(!pData)
546 return ALC_OUT_OF_MEMORY;
547 pDevice->ExtraData = pData;
549 memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));
550 wfexCaptureFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
551 WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
552 wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
553 wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
554 wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
555 wfexCaptureFormat.nChannels / 8;
556 wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;
557 wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
558 wfexCaptureFormat.nBlockAlign;
559 wfexCaptureFormat.cbSize = 0;
561 if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
563 ERR("waveInOpen failed: %u\n", res);
564 goto failure;
567 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
568 if(pData->hWaveThreadEvent == NULL)
570 ERR("CreateEvent failed: %lu\n", GetLastError());
571 goto failure;
574 pData->Frequency = pDevice->Frequency;
576 // Allocate circular memory buffer for the captured audio
577 ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;
579 // Make sure circular buffer is at least 100ms in size
580 if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10))
581 ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10;
583 pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize);
584 if(!pData->pRing)
585 goto failure;
587 pData->lWaveBuffersCommitted = 0;
589 // Create 4 Buffers of 50ms each
590 lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20;
591 lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign);
593 BufferData = calloc(4, lBufferSize);
594 if(!BufferData)
595 goto failure;
597 for(i = 0;i < 4;i++)
599 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
600 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
601 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
602 (pData->WaveBuffer[i-1].lpData +
603 pData->WaveBuffer[i-1].dwBufferLength));
604 pData->WaveBuffer[i].dwFlags = 0;
605 pData->WaveBuffer[i].dwLoops = 0;
606 waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
607 waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
608 InterlockedIncrement(&pData->lWaveBuffersCommitted);
611 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID);
612 if (pData->hWaveThread == NULL)
613 goto failure;
615 pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
616 return ALC_NO_ERROR;
618 failure:
619 if(pData->hWaveThread)
620 CloseHandle(pData->hWaveThread);
622 if(BufferData)
624 for(i = 0;i < 4;i++)
625 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
626 free(BufferData);
629 if(pData->pRing)
630 DestroyRingBuffer(pData->pRing);
632 if(pData->hWaveThreadEvent)
633 CloseHandle(pData->hWaveThreadEvent);
635 if(pData->hWaveHandle.In)
636 waveInClose(pData->hWaveHandle.In);
638 free(pData);
639 pDevice->ExtraData = NULL;
640 return ALC_INVALID_VALUE;
643 static void WinMMCloseCapture(ALCdevice *pDevice)
645 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
646 void *buffer = NULL;
647 int i;
649 /* Tell the processing thread to quit and wait for it to do so. */
650 pData->bWaveShutdown = AL_TRUE;
651 PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
653 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
655 /* Make sure capture is stopped and all pending buffers are flushed. */
656 waveInReset(pData->hWaveHandle.In);
658 CloseHandle(pData->hWaveThread);
659 pData->hWaveThread = 0;
661 // Release the wave buffers
662 for(i = 0;i < 4;i++)
664 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
665 if(i == 0) buffer = pData->WaveBuffer[i].lpData;
666 pData->WaveBuffer[i].lpData = NULL;
668 free(buffer);
670 DestroyRingBuffer(pData->pRing);
671 pData->pRing = NULL;
673 // Close the Wave device
674 CloseHandle(pData->hWaveThreadEvent);
675 pData->hWaveThreadEvent = 0;
677 waveInClose(pData->hWaveHandle.In);
678 pData->hWaveHandle.In = 0;
680 free(pData);
681 pDevice->ExtraData = NULL;
684 static void WinMMStartCapture(ALCdevice *pDevice)
686 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
687 waveInStart(pData->hWaveHandle.In);
690 static void WinMMStopCapture(ALCdevice *pDevice)
692 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
693 waveInStop(pData->hWaveHandle.In);
696 static ALCenum WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
698 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
699 ReadRingBuffer(pData->pRing, pBuffer, lSamples);
700 return ALC_NO_ERROR;
703 static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
705 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
706 return RingBufferSize(pData->pRing);
710 static const BackendFuncs WinMMFuncs = {
711 WinMMOpenPlayback,
712 WinMMClosePlayback,
713 WinMMResetPlayback,
714 WinMMStopPlayback,
715 WinMMOpenCapture,
716 WinMMCloseCapture,
717 WinMMStartCapture,
718 WinMMStopCapture,
719 WinMMCaptureSamples,
720 WinMMAvailableSamples
723 ALCboolean alcWinMMInit(BackendFuncs *FuncList)
725 *FuncList = WinMMFuncs;
726 return ALC_TRUE;
729 void alcWinMMDeinit()
731 ALuint lLoop;
733 for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++)
734 free(PlaybackDeviceList[lLoop]);
735 free(PlaybackDeviceList);
736 PlaybackDeviceList = NULL;
738 NumPlaybackDevices = 0;
741 for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
742 free(CaptureDeviceList[lLoop]);
743 free(CaptureDeviceList);
744 CaptureDeviceList = NULL;
746 NumCaptureDevices = 0;
749 void alcWinMMProbe(enum DevProbe type)
751 ALuint i;
753 switch(type)
755 case ALL_DEVICE_PROBE:
756 ProbePlaybackDevices();
757 if(NumPlaybackDevices > 0)
758 AppendAllDeviceList(woDefault);
759 for(i = 0;i < NumPlaybackDevices;i++)
761 if(PlaybackDeviceList[i])
762 AppendAllDeviceList(PlaybackDeviceList[i]);
764 break;
766 case CAPTURE_DEVICE_PROBE:
767 ProbeCaptureDevices();
768 for(i = 0;i < NumCaptureDevices;i++)
770 if(CaptureDeviceList[i])
771 AppendCaptureDeviceList(CaptureDeviceList[i]);
773 break;