Update the ALCdevice in winmm's reset method instead of open
[openal-soft.git] / Alc / backends / winmm.c
blob9641bcf8cd55ab945889b5d7c3965538cb8f659a
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 WAVEFORMATEX wfexFormat;
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 WinMMData *pData = NULL;
282 UINT lDeviceID = 0;
283 MMRESULT res;
284 ALuint i = 0;
286 if(!PlaybackDeviceList)
287 ProbePlaybackDevices();
289 // Find the Device ID matching the deviceName if valid
290 for(i = 0;i < NumPlaybackDevices;i++)
292 if(PlaybackDeviceList[i] &&
293 (!deviceName || strcmp(deviceName, PlaybackDeviceList[i]) == 0))
295 lDeviceID = i;
296 break;
299 if(i == NumPlaybackDevices)
300 return ALC_INVALID_VALUE;
302 pData = calloc(1, sizeof(*pData));
303 if(!pData)
304 return ALC_OUT_OF_MEMORY;
305 pDevice->ExtraData = pData;
307 retry_open:
308 memset(&pData->wfexFormat, 0, sizeof(WAVEFORMATEX));
309 if(pDevice->FmtType == DevFmtFloat)
311 pData->wfexFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
312 pData->wfexFormat.wBitsPerSample = 32;
314 else
316 pData->wfexFormat.wFormatTag = WAVE_FORMAT_PCM;
317 if(pDevice->FmtType == DevFmtUByte || pDevice->FmtType == DevFmtByte)
318 pData->wfexFormat.wBitsPerSample = 8;
319 else
320 pData->wfexFormat.wBitsPerSample = 16;
322 pData->wfexFormat.nChannels = ((pDevice->FmtChans == DevFmtMono) ? 1 : 2);
323 pData->wfexFormat.nBlockAlign = pData->wfexFormat.wBitsPerSample *
324 pData->wfexFormat.nChannels / 8;
325 pData->wfexFormat.nSamplesPerSec = pDevice->Frequency;
326 pData->wfexFormat.nAvgBytesPerSec = pData->wfexFormat.nSamplesPerSec *
327 pData->wfexFormat.nBlockAlign;
328 pData->wfexFormat.cbSize = 0;
330 if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &pData->wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
332 if(pDevice->FmtType == DevFmtFloat)
334 pDevice->FmtType = DevFmtShort;
335 goto retry_open;
337 ERR("waveOutOpen failed: %u\n", res);
338 goto failure;
341 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
342 if(pData->hWaveThreadEvent == NULL)
344 ERR("CreateEvent failed: %lu\n", GetLastError());
345 goto failure;
348 pDevice->szDeviceName = strdup(PlaybackDeviceList[lDeviceID]);
349 return ALC_NO_ERROR;
351 failure:
352 if(pData->hWaveThreadEvent)
353 CloseHandle(pData->hWaveThreadEvent);
355 if(pData->hWaveHandle.Out)
356 waveOutClose(pData->hWaveHandle.Out);
358 free(pData);
359 pDevice->ExtraData = NULL;
360 return ALC_INVALID_VALUE;
363 static void WinMMClosePlayback(ALCdevice *device)
365 WinMMData *pData = (WinMMData*)device->ExtraData;
367 // Close the Wave device
368 CloseHandle(pData->hWaveThreadEvent);
369 pData->hWaveThreadEvent = 0;
371 waveOutClose(pData->hWaveHandle.Out);
372 pData->hWaveHandle.Out = 0;
374 free(pData);
375 device->ExtraData = NULL;
378 static ALCboolean WinMMResetPlayback(ALCdevice *device)
380 WinMMData *data = (WinMMData*)device->ExtraData;
382 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
383 data->wfexFormat.nSamplesPerSec /
384 device->Frequency);
385 device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4;
386 device->NumUpdates = 4;
387 device->Frequency = data->wfexFormat.nSamplesPerSec;
389 if(data->wfexFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
391 if(data->wfexFormat.wBitsPerSample == 32)
392 device->FmtType = DevFmtFloat;
393 else
395 ERR("Unhandled IEEE float sample depth: %d\n", data->wfexFormat.wBitsPerSample);
396 return ALC_FALSE;
399 else if(data->wfexFormat.wFormatTag == WAVE_FORMAT_PCM)
401 if(data->wfexFormat.wBitsPerSample == 16)
402 device->FmtType = DevFmtShort;
403 else if(data->wfexFormat.wBitsPerSample == 8)
404 device->FmtType = DevFmtUByte;
405 else
407 ERR("Unhandled PCM sample depth: %d\n", data->wfexFormat.wBitsPerSample);
408 return ALC_FALSE;
411 else
413 ERR("Unhandled format tag: 0x%04x\n", data->wfexFormat.wFormatTag);
414 return ALC_FALSE;
417 if(data->wfexFormat.nChannels == 2)
418 device->FmtChans = DevFmtStereo;
419 else if(data->wfexFormat.nChannels == 1)
420 device->FmtChans = DevFmtMono;
421 else
423 ERR("Unhandled channel count: %d\n", data->wfexFormat.nChannels);
424 return ALC_FALSE;
426 SetDefaultWFXChannelOrder(device);
428 return ALC_TRUE;
431 static ALCboolean WinMMStartPlayback(ALCdevice *device)
433 WinMMData *pData = (WinMMData*)device->ExtraData;
434 ALbyte *BufferData;
435 ALint lBufferSize;
436 ALuint i;
438 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);
439 if(pData->hWaveThread == NULL)
440 return ALC_FALSE;
442 pData->lWaveBuffersCommitted = 0;
444 // Create 4 Buffers
445 lBufferSize = device->UpdateSize*device->NumUpdates / 4;
446 lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
448 BufferData = calloc(4, lBufferSize);
449 for(i = 0;i < 4;i++)
451 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
452 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
453 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
454 (pData->WaveBuffer[i-1].lpData +
455 pData->WaveBuffer[i-1].dwBufferLength));
456 waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
457 waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
458 InterlockedIncrement(&pData->lWaveBuffersCommitted);
461 return ALC_TRUE;
464 static void WinMMStopPlayback(ALCdevice *device)
466 WinMMData *pData = (WinMMData*)device->ExtraData;
467 void *buffer = NULL;
468 int i;
470 if(pData->hWaveThread == NULL)
471 return;
473 // Set flag to stop processing headers
474 pData->bWaveShutdown = AL_TRUE;
476 // Wait for signal that Wave Thread has been destroyed
477 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
479 CloseHandle(pData->hWaveThread);
480 pData->hWaveThread = 0;
482 pData->bWaveShutdown = AL_FALSE;
484 // Release the wave buffers
485 for(i = 0;i < 4;i++)
487 waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
488 if(i == 0) buffer = pData->WaveBuffer[i].lpData;
489 pData->WaveBuffer[i].lpData = NULL;
491 free(buffer);
495 static ALCenum WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
497 ALbyte *BufferData = NULL;
498 DWORD ulCapturedDataSize;
499 WinMMData *pData = NULL;
500 UINT lDeviceID = 0;
501 ALint lBufferSize;
502 MMRESULT res;
503 ALuint i;
505 if(!CaptureDeviceList)
506 ProbeCaptureDevices();
508 // Find the Device ID matching the deviceName if valid
509 for(i = 0;i < NumCaptureDevices;i++)
511 if(CaptureDeviceList[i] &&
512 (!deviceName || strcmp(deviceName, CaptureDeviceList[i]) == 0))
514 lDeviceID = i;
515 break;
518 if(i == NumCaptureDevices)
519 return ALC_INVALID_VALUE;
521 switch(pDevice->FmtChans)
523 case DevFmtMono:
524 case DevFmtStereo:
525 break;
527 case DevFmtQuad:
528 case DevFmtX51:
529 case DevFmtX51Side:
530 case DevFmtX61:
531 case DevFmtX71:
532 return ALC_INVALID_ENUM;
535 switch(pDevice->FmtType)
537 case DevFmtUByte:
538 case DevFmtShort:
539 case DevFmtInt:
540 case DevFmtFloat:
541 break;
543 case DevFmtByte:
544 case DevFmtUShort:
545 case DevFmtUInt:
546 return ALC_INVALID_ENUM;
549 pData = calloc(1, sizeof(*pData));
550 if(!pData)
551 return ALC_OUT_OF_MEMORY;
552 pDevice->ExtraData = pData;
554 memset(&pData->wfexFormat, 0, sizeof(WAVEFORMATEX));
555 pData->wfexFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
556 WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
557 pData->wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
558 pData->wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
559 pData->wfexFormat.nBlockAlign = pData->wfexFormat.wBitsPerSample *
560 pData->wfexFormat.nChannels / 8;
561 pData->wfexFormat.nSamplesPerSec = pDevice->Frequency;
562 pData->wfexFormat.nAvgBytesPerSec = pData->wfexFormat.nSamplesPerSec *
563 pData->wfexFormat.nBlockAlign;
564 pData->wfexFormat.cbSize = 0;
566 if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &pData->wfexFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
568 ERR("waveInOpen failed: %u\n", res);
569 goto failure;
572 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
573 if(pData->hWaveThreadEvent == NULL)
575 ERR("CreateEvent failed: %lu\n", GetLastError());
576 goto failure;
579 // Allocate circular memory buffer for the captured audio
580 ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;
582 // Make sure circular buffer is at least 100ms in size
583 if(ulCapturedDataSize < (pData->wfexFormat.nSamplesPerSec / 10))
584 ulCapturedDataSize = pData->wfexFormat.nSamplesPerSec / 10;
586 pData->pRing = CreateRingBuffer(pData->wfexFormat.nBlockAlign, ulCapturedDataSize);
587 if(!pData->pRing)
588 goto failure;
590 pData->lWaveBuffersCommitted = 0;
592 // Create 4 Buffers of 50ms each
593 lBufferSize = pData->wfexFormat.nAvgBytesPerSec / 20;
594 lBufferSize -= (lBufferSize % pData->wfexFormat.nBlockAlign);
596 BufferData = calloc(4, lBufferSize);
597 if(!BufferData)
598 goto failure;
600 for(i = 0;i < 4;i++)
602 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
603 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
604 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
605 (pData->WaveBuffer[i-1].lpData +
606 pData->WaveBuffer[i-1].dwBufferLength));
607 pData->WaveBuffer[i].dwFlags = 0;
608 pData->WaveBuffer[i].dwLoops = 0;
609 waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
610 waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
611 InterlockedIncrement(&pData->lWaveBuffersCommitted);
614 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID);
615 if (pData->hWaveThread == NULL)
616 goto failure;
618 pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
619 return ALC_NO_ERROR;
621 failure:
622 if(pData->hWaveThread)
623 CloseHandle(pData->hWaveThread);
625 if(BufferData)
627 for(i = 0;i < 4;i++)
628 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
629 free(BufferData);
632 if(pData->pRing)
633 DestroyRingBuffer(pData->pRing);
635 if(pData->hWaveThreadEvent)
636 CloseHandle(pData->hWaveThreadEvent);
638 if(pData->hWaveHandle.In)
639 waveInClose(pData->hWaveHandle.In);
641 free(pData);
642 pDevice->ExtraData = NULL;
643 return ALC_INVALID_VALUE;
646 static void WinMMCloseCapture(ALCdevice *pDevice)
648 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
649 void *buffer = NULL;
650 int i;
652 /* Tell the processing thread to quit and wait for it to do so. */
653 pData->bWaveShutdown = AL_TRUE;
654 PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
656 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
658 /* Make sure capture is stopped and all pending buffers are flushed. */
659 waveInReset(pData->hWaveHandle.In);
661 CloseHandle(pData->hWaveThread);
662 pData->hWaveThread = 0;
664 // Release the wave buffers
665 for(i = 0;i < 4;i++)
667 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
668 if(i == 0) buffer = pData->WaveBuffer[i].lpData;
669 pData->WaveBuffer[i].lpData = NULL;
671 free(buffer);
673 DestroyRingBuffer(pData->pRing);
674 pData->pRing = NULL;
676 // Close the Wave device
677 CloseHandle(pData->hWaveThreadEvent);
678 pData->hWaveThreadEvent = 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 ALCenum WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
701 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
702 ReadRingBuffer(pData->pRing, pBuffer, lSamples);
703 return ALC_NO_ERROR;
706 static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
708 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
709 return RingBufferSize(pData->pRing);
713 static const BackendFuncs WinMMFuncs = {
714 WinMMOpenPlayback,
715 WinMMClosePlayback,
716 WinMMResetPlayback,
717 WinMMStartPlayback,
718 WinMMStopPlayback,
719 WinMMOpenCapture,
720 WinMMCloseCapture,
721 WinMMStartCapture,
722 WinMMStopCapture,
723 WinMMCaptureSamples,
724 WinMMAvailableSamples
727 ALCboolean alcWinMMInit(BackendFuncs *FuncList)
729 *FuncList = WinMMFuncs;
730 return ALC_TRUE;
733 void alcWinMMDeinit()
735 ALuint lLoop;
737 for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++)
738 free(PlaybackDeviceList[lLoop]);
739 free(PlaybackDeviceList);
740 PlaybackDeviceList = NULL;
742 NumPlaybackDevices = 0;
745 for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
746 free(CaptureDeviceList[lLoop]);
747 free(CaptureDeviceList);
748 CaptureDeviceList = NULL;
750 NumCaptureDevices = 0;
753 void alcWinMMProbe(enum DevProbe type)
755 ALuint i;
757 switch(type)
759 case ALL_DEVICE_PROBE:
760 ProbePlaybackDevices();
761 for(i = 0;i < NumPlaybackDevices;i++)
763 if(PlaybackDeviceList[i])
764 AppendAllDeviceList(PlaybackDeviceList[i]);
766 break;
768 case CAPTURE_DEVICE_PROBE:
769 ProbeCaptureDevices();
770 for(i = 0;i < NumCaptureDevices;i++)
772 if(CaptureDeviceList[i])
773 AppendCaptureDeviceList(CaptureDeviceList[i]);
775 break;