Constify some variables
[openal-soft.git] / Alc / winmm.c
blobee21e71e101bf71504aac92b553d2c56ef8df990
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 = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
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 = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
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(pDevice->FmtChans != DevFmtMono)
340 pDevice->FmtChans = DevFmtStereo;
341 switch(pDevice->FmtType)
343 case DevFmtByte:
344 pDevice->FmtType = DevFmtUByte;
345 break;
346 case DevFmtUShort:
347 case DevFmtFloat:
348 pDevice->FmtType = DevFmtShort;
349 break;
350 case DevFmtUByte:
351 case DevFmtShort:
352 break;
355 memset(&wfexFormat, 0, sizeof(WAVEFORMATEX));
356 wfexFormat.wFormatTag = WAVE_FORMAT_PCM;
357 wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
358 wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
359 wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample *
360 wfexFormat.nChannels / 8;
361 wfexFormat.nSamplesPerSec = pDevice->Frequency;
362 wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec *
363 wfexFormat.nBlockAlign;
364 wfexFormat.cbSize = 0;
366 if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
368 AL_PRINT("waveInOpen failed: %u\n", res);
369 goto failure;
372 pData->hWaveHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveOutAllHeadersReturned");
373 pData->hWaveThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveOutThreadDestroyed");
374 if(pData->hWaveHdrEvent == NULL || pData->hWaveThreadEvent == NULL)
376 AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
377 goto failure;
380 pData->Frequency = pDevice->Frequency;
382 pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault :
383 PlaybackDeviceList[lDeviceID]);
384 return ALC_TRUE;
386 failure:
387 if(pData->hWaveThreadEvent)
388 CloseHandle(pData->hWaveThreadEvent);
389 if(pData->hWaveHdrEvent)
390 CloseHandle(pData->hWaveHdrEvent);
392 if(pData->hWaveHandle.Out)
393 waveOutClose(pData->hWaveHandle.Out);
395 free(pData);
396 pDevice->ExtraData = NULL;
397 return ALC_FALSE;
400 static void WinMMClosePlayback(ALCdevice *device)
402 WinMMData *pData = (WinMMData*)device->ExtraData;
404 // Close the Wave device
405 CloseHandle(pData->hWaveThreadEvent);
406 pData->hWaveThreadEvent = 0;
408 CloseHandle(pData->hWaveHdrEvent);
409 pData->hWaveHdrEvent = 0;
411 waveInClose(pData->hWaveHandle.In);
412 pData->hWaveHandle.In = 0;
414 free(pData);
415 device->ExtraData = NULL;
418 static ALCboolean WinMMResetPlayback(ALCdevice *device)
420 WinMMData *pData = (WinMMData*)device->ExtraData;
421 ALbyte *BufferData;
422 ALint lBufferSize;
423 ALuint i;
425 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);
426 if(pData->hWaveThread == NULL)
427 return ALC_FALSE;
429 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
430 pData->Frequency / device->Frequency);
431 device->Frequency = pData->Frequency;
433 pData->lWaveBuffersCommitted = 0;
435 // Create 4 Buffers
436 lBufferSize = device->UpdateSize*device->NumUpdates / 4;
437 lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
439 BufferData = calloc(4, lBufferSize);
440 for(i = 0;i < 4;i++)
442 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
443 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
444 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
445 (pData->WaveBuffer[i-1].lpData +
446 pData->WaveBuffer[i-1].dwBufferLength));
447 waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
448 waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
449 InterlockedIncrement(&pData->lWaveBuffersCommitted);
452 return ALC_TRUE;
455 static void WinMMStopPlayback(ALCdevice *device)
457 WinMMData *pData = (WinMMData*)device->ExtraData;
458 int i;
460 if(pData->hWaveThread == NULL)
461 return;
463 // Set flag to stop processing headers
464 pData->bWaveShutdown = AL_TRUE;
466 // Wait for signal that all Wave Buffers have returned
467 WaitForSingleObjectEx(pData->hWaveHdrEvent, 5000, FALSE);
469 // Wait for signal that Wave Thread has been destroyed
470 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
472 CloseHandle(pData->hWaveThread);
473 pData->hWaveThread = 0;
475 pData->bWaveShutdown = AL_FALSE;
477 // Release the wave buffers
478 for(i = 0;i < 4;i++)
480 waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
481 if(i == 0)
482 free(pData->WaveBuffer[i].lpData);
483 pData->WaveBuffer[i].lpData = NULL;
488 static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
490 WAVEFORMATEX wfexCaptureFormat;
491 DWORD ulCapturedDataSize;
492 WinMMData *pData = NULL;
493 ALint lDeviceID = 0;
494 ALbyte *BufferData;
495 ALint lBufferSize;
496 MMRESULT res;
497 ALuint i;
499 if(!CaptureDeviceList)
500 ProbeCaptureDevices();
502 // Find the Device ID matching the deviceName if valid
503 if(deviceName)
505 for(i = 0;i < NumCaptureDevices;i++)
507 if(CaptureDeviceList[i] &&
508 strcmp(deviceName, CaptureDeviceList[i]) == 0)
510 lDeviceID = i;
511 break;
515 else
517 for(i = 0;i < NumCaptureDevices;i++)
519 if(CaptureDeviceList[i])
521 lDeviceID = i;
522 break;
526 if(i == NumCaptureDevices)
527 return ALC_FALSE;
529 pData = calloc(1, sizeof(*pData));
530 if(!pData)
532 alcSetError(pDevice, ALC_OUT_OF_MEMORY);
533 return ALC_FALSE;
535 pDevice->ExtraData = pData;
537 if((pDevice->FmtChans != DevFmtMono && pDevice->FmtChans != DevFmtStereo) ||
538 (pDevice->FmtType != DevFmtUByte && pDevice->FmtType != DevFmtShort))
540 alcSetError(pDevice, ALC_INVALID_ENUM);
541 goto failure;
544 memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));
545 wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM;
546 wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
547 wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
548 wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
549 wfexCaptureFormat.nChannels / 8;
550 wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;
551 wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
552 wfexCaptureFormat.nBlockAlign;
553 wfexCaptureFormat.cbSize = 0;
555 if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
557 AL_PRINT("waveInOpen failed: %u\n", res);
558 goto failure;
561 pData->hWaveHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInAllHeadersReturned");
562 pData->hWaveThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInThreadDestroyed");
563 if(pData->hWaveHdrEvent == NULL || pData->hWaveThreadEvent == NULL)
565 AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
566 goto failure;
569 pData->Frequency = pDevice->Frequency;
571 // Allocate circular memory buffer for the captured audio
572 ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;
574 // Make sure circular buffer is at least 100ms in size
575 if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10))
576 ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10;
578 pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize);
579 if(!pData->pRing)
580 goto failure;
582 pData->lWaveBuffersCommitted = 0;
584 // Create 4 Buffers of 50ms each
585 lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20;
586 lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign);
588 BufferData = calloc(4, lBufferSize);
589 if(!BufferData)
590 goto failure;
592 for(i = 0;i < 4;i++)
594 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
595 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
596 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
597 (pData->WaveBuffer[i-1].lpData +
598 pData->WaveBuffer[i-1].dwBufferLength));
599 pData->WaveBuffer[i].dwFlags = 0;
600 pData->WaveBuffer[i].dwLoops = 0;
601 waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
602 waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
603 InterlockedIncrement(&pData->lWaveBuffersCommitted);
606 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID);
607 if (pData->hWaveThread == NULL)
608 goto failure;
610 pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
611 return ALC_TRUE;
613 failure:
614 if(pData->hWaveThread)
615 CloseHandle(pData->hWaveThread);
617 for(i = 0;i < 4;i++)
619 if(pData->WaveBuffer[i].lpData)
621 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
622 if(i == 0)
623 free(pData->WaveBuffer[i].lpData);
627 if(pData->pRing)
628 DestroyRingBuffer(pData->pRing);
630 if(pData->hWaveThreadEvent)
631 CloseHandle(pData->hWaveThreadEvent);
632 if(pData->hWaveHdrEvent)
633 CloseHandle(pData->hWaveHdrEvent);
635 if(pData->hWaveHandle.In)
636 waveInClose(pData->hWaveHandle.In);
638 free(pData);
639 pDevice->ExtraData = NULL;
640 return ALC_FALSE;
643 static void WinMMCloseCapture(ALCdevice *pDevice)
645 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
646 int i;
648 // Call waveOutReset to shutdown wave device
649 pData->bWaveShutdown = AL_TRUE;
650 waveInReset(pData->hWaveHandle.In);
652 // Wait for signal that all Wave Buffers have returned
653 WaitForSingleObjectEx(pData->hWaveHdrEvent, 5000, FALSE);
655 // Wait for signal that Wave Thread has been destroyed
656 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
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)
666 free(pData->WaveBuffer[i].lpData);
667 pData->WaveBuffer[i].lpData = NULL;
670 DestroyRingBuffer(pData->pRing);
671 pData->pRing = NULL;
673 // Close the Wave device
674 CloseHandle(pData->hWaveThreadEvent);
675 pData->hWaveThreadEvent = 0;
677 CloseHandle(pData->hWaveHdrEvent);
678 pData->hWaveHdrEvent = 0;
680 waveInClose(pData->hWaveHandle.In);
681 pData->hWaveHandle.In = 0;
683 free(pData);
684 pDevice->ExtraData = NULL;
687 static void WinMMStartCapture(ALCdevice *pDevice)
689 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
690 waveInStart(pData->hWaveHandle.In);
693 static void WinMMStopCapture(ALCdevice *pDevice)
695 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
696 waveInStop(pData->hWaveHandle.In);
699 static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
701 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
702 return RingBufferSize(pData->pRing);
705 static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
707 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
709 if(WinMMAvailableSamples(pDevice) >= lSamples)
710 ReadRingBuffer(pData->pRing, pBuffer, lSamples);
711 else
712 alcSetError(pDevice, ALC_INVALID_VALUE);
716 static BackendFuncs WinMMFuncs = {
717 WinMMOpenPlayback,
718 WinMMClosePlayback,
719 WinMMResetPlayback,
720 WinMMStopPlayback,
721 WinMMOpenCapture,
722 WinMMCloseCapture,
723 WinMMStartCapture,
724 WinMMStopCapture,
725 WinMMCaptureSamples,
726 WinMMAvailableSamples
729 void alcWinMMInit(BackendFuncs *FuncList)
731 *FuncList = WinMMFuncs;
734 void alcWinMMDeinit()
736 ALuint lLoop;
738 for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++)
739 free(PlaybackDeviceList[lLoop]);
740 free(PlaybackDeviceList);
741 PlaybackDeviceList = NULL;
743 NumPlaybackDevices = 0;
746 for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
747 free(CaptureDeviceList[lLoop]);
748 free(CaptureDeviceList);
749 CaptureDeviceList = NULL;
751 NumCaptureDevices = 0;
754 void alcWinMMProbe(int type)
756 ALuint i;
758 if(type == DEVICE_PROBE)
760 ProbePlaybackDevices();
761 if(NumPlaybackDevices > 0)
762 AppendDeviceList(woDefault);
764 else if(type == ALL_DEVICE_PROBE)
766 ProbePlaybackDevices();
767 if(NumPlaybackDevices > 0)
768 AppendAllDeviceList(woDefault);
769 for(i = 0;i < NumPlaybackDevices;i++)
771 if(PlaybackDeviceList[i])
772 AppendAllDeviceList(PlaybackDeviceList[i]);
775 else if(type == CAPTURE_DEVICE_PROBE)
777 ProbeCaptureDevices();
778 for(i = 0;i < NumCaptureDevices;i++)
780 if(CaptureDeviceList[i])
781 AppendCaptureDeviceList(CaptureDeviceList[i]);