Add a basic WaveOut device
[openal-soft.git] / Alc / winmm.c
blob8688b7b09b842b2c9c0a70a13546f6cfcbf9507b
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 #define _WIN32_WINNT 0x0500
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
28 #include <windows.h>
29 #include <mmsystem.h>
31 #include "alMain.h"
32 #include "AL/al.h"
33 #include "AL/alc.h"
36 typedef struct {
37 // MMSYSTEM Device
38 volatile ALboolean bWaveShutdown;
39 HANDLE hWaveHdrEvent;
40 HANDLE hWaveThreadEvent;
41 HANDLE hWaveThread;
42 DWORD ulWaveThreadID;
43 LONG lWaveBuffersCommitted;
44 WAVEHDR WaveBuffer[4];
46 union {
47 HWAVEIN In;
48 HWAVEOUT Out;
49 } hWaveHandle;
51 ALsizei Frequency;
53 RingBuffer *pRing;
54 } WinMMData;
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)
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 via WaveOut", WaveCaps.szPname);
88 else
89 snprintf(name, sizeof(name), "%s #%d via WaveOut", 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 via WaveIn", WaveInCaps.szPname);
127 else
128 snprintf(name, sizeof(name), "%s #%d via WaveIn", 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 // 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);
169 else
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);
184 PlaybackThreadProc
186 Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its
187 audio data.
189 static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)
191 ALCdevice *pDevice = (ALCdevice*)lpParameter;
192 WinMMData *pData = pDevice->ExtraData;
193 LPWAVEHDR pWaveHdr;
194 ALuint FrameSize;
195 MSG msg;
197 FrameSize = aluFrameSizeFromFormat(pDevice->Format);
199 while(GetMessage(&msg, NULL, 0, 0))
201 if(msg.message != WOM_DONE || pData->bWaveShutdown)
202 continue;
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);
217 ExitThread(0);
219 return 0;
223 WaveInProc
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;
233 (void)hDevice;
234 (void)dwParam2;
236 if(uMsg != WIM_DATA)
237 return;
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);
247 else
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);
262 CaptureThreadProc
264 Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new
265 audio data.
267 static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
269 ALCdevice *pDevice = (ALCdevice*)lpParameter;
270 WinMMData *pData = pDevice->ExtraData;
271 LPWAVEHDR pWaveHdr;
272 ALuint FrameSize;
273 MSG msg;
275 FrameSize = aluFrameSizeFromFormat(pDevice->Format);
277 while(GetMessage(&msg, NULL, 0, 0))
279 if(msg.message != WIM_DATA || pData->bWaveShutdown)
280 continue;
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);
296 ExitThread(0);
298 return 0;
302 static ALCboolean WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)
304 WAVEFORMATEX wfexFormat;
305 WinMMData *pData = NULL;
306 UINT_PTR lDeviceID = 0;
307 MMRESULT res;
308 ALuint i = 0;
310 // Find the Device ID matching the deviceName if valid
311 if(!deviceName || strcmp(deviceName, woDefault) == 0)
312 lDeviceID = WAVE_MAPPER;
313 else
315 if(!PlaybackDeviceList)
316 ProbePlaybackDevices();
318 for(i = 0;i < NumPlaybackDevices;i++)
320 if(PlaybackDeviceList[i] &&
321 strcmp(deviceName, PlaybackDeviceList[i]) == 0)
323 lDeviceID = i;
324 break;
327 if(i == NumPlaybackDevices)
328 return ALC_FALSE;
331 pData = calloc(1, sizeof(*pData));
332 if(!pData)
334 alcSetError(pDevice, ALC_OUT_OF_MEMORY);
335 return ALC_FALSE;
337 pDevice->ExtraData = pData;
339 if(aluChannelsFromFormat(pDevice->Format) >= 2)
341 if(aluBytesFromFormat(pDevice->Format) >= 2)
342 pDevice->Format = AL_FORMAT_STEREO16;
343 else
344 pDevice->Format = AL_FORMAT_STEREO8;
346 else
348 if(aluBytesFromFormat(pDevice->Format) >= 2)
349 pDevice->Format = AL_FORMAT_MONO16;
350 else
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);
368 goto failure;
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());
376 goto failure;
379 pData->Frequency = pDevice->Frequency;
381 pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault :
382 PlaybackDeviceList[lDeviceID]);
383 return ALC_TRUE;
385 failure:
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);
394 free(pData);
395 pDevice->ExtraData = NULL;
396 return ALC_FALSE;
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;
413 free(pData);
414 device->ExtraData = NULL;
417 static ALCboolean WinMMResetPlayback(ALCdevice *device)
419 WinMMData *pData = (WinMMData*)device->ExtraData;
420 ALbyte *BufferData;
421 ALint lBufferSize;
422 ALuint i;
424 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);
425 if(pData->hWaveThread == NULL)
426 return ALC_FALSE;
428 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
429 pData->Frequency / device->Frequency);
430 device->Frequency = pData->Frequency;
432 pData->lWaveBuffersCommitted = 0;
434 // Create 4 Buffers
435 lBufferSize = device->UpdateSize*device->NumUpdates / 4;
436 lBufferSize *= aluFrameSizeFromFormat(device->Format);
438 BufferData = calloc(4, lBufferSize);
439 for(i = 0;i < 4;i++)
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);
451 return ALC_TRUE;
454 static void WinMMStopPlayback(ALCdevice *device)
456 WinMMData *pData = (WinMMData*)device->ExtraData;
457 int i;
459 if(pData->hWaveThread == NULL)
460 return;
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
477 for(i = 0;i < 4;i++)
479 waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
480 if(i == 0)
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;
492 ALint lDeviceID = 0;
493 ALbyte *BufferData;
494 ALint lBufferSize;
495 MMRESULT res;
496 ALuint i;
498 if(!CaptureDeviceList)
499 ProbeCaptureDevices();
501 // Find the Device ID matching the deviceName if valid
502 if(deviceName)
504 for(i = 0;i < NumCaptureDevices;i++)
506 if(CaptureDeviceList[i] &&
507 strcmp(deviceName, CaptureDeviceList[i]) == 0)
509 lDeviceID = i;
510 break;
514 else
516 for(i = 0;i < NumCaptureDevices;i++)
518 if(CaptureDeviceList[i])
520 lDeviceID = i;
521 break;
525 if(i == NumCaptureDevices)
526 return ALC_FALSE;
528 pData = calloc(1, sizeof(*pData));
529 if(!pData)
531 alcSetError(pDevice, ALC_OUT_OF_MEMORY);
532 return ALC_FALSE;
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);
550 goto failure;
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());
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_TRUE;
605 failure:
606 if(pData->hWaveThread)
607 CloseHandle(pData->hWaveThread);
609 for(i = 0;i < 4;i++)
611 if(pData->WaveBuffer[i].lpData)
613 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
614 if(i == 0)
615 free(pData->WaveBuffer[i].lpData);
619 if(pData->pRing)
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);
630 free(pData);
631 pDevice->ExtraData = NULL;
632 return ALC_FALSE;
635 static void WinMMCloseCapture(ALCdevice *pDevice)
637 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
638 int i;
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
654 for(i = 0;i < 4;i++)
656 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
657 if(i == 0)
658 free(pData->WaveBuffer[i].lpData);
659 pData->WaveBuffer[i].lpData = NULL;
662 DestroyRingBuffer(pData->pRing);
663 pData->pRing = NULL;
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;
675 free(pData);
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);
703 else
704 alcSetError(pDevice, ALC_INVALID_VALUE);
708 static BackendFuncs WinMMFuncs = {
709 WinMMOpenPlayback,
710 WinMMClosePlayback,
711 WinMMResetPlayback,
712 WinMMStopPlayback,
713 WinMMOpenCapture,
714 WinMMCloseCapture,
715 WinMMStartCapture,
716 WinMMStopCapture,
717 WinMMCaptureSamples,
718 WinMMAvailableSamples
721 void alcWinMMInit(BackendFuncs *FuncList)
723 *FuncList = WinMMFuncs;
726 void alcWinMMDeinit()
728 ALuint lLoop;
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)
748 ALuint i;
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]);