Mercurial > audio-send
view Alc/backends/winmm.c @ 0:f9476ff7637e
initial forking of open-al to create multiple listeners
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Tue, 25 Oct 2011 13:02:31 -0700 |
parents | |
children |
line wrap: on
line source
1 /**2 * OpenAL cross platform audio library3 * Copyright (C) 1999-2007 by authors.4 * This library is free software; you can redistribute it and/or5 * modify it under the terms of the GNU Library General Public6 * License as published by the Free Software Foundation; either7 * version 2 of the License, or (at your option) any later version.8 *9 * This library is distributed in the hope that it will be useful,10 * but WITHOUT ANY WARRANTY; without even the implied warranty of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12 * Library General Public License for more details.13 *14 * You should have received a copy of the GNU Library General Public15 * License along with this library; if not, write to the16 * 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.html19 */21 #include "config.h"23 #define _WIN32_WINNT 0x050024 #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 Device38 volatile ALboolean bWaveShutdown;39 HANDLE hWaveThreadEvent;40 HANDLE hWaveThread;41 DWORD ulWaveThreadID;42 LONG lWaveBuffersCommitted;43 WAVEHDR WaveBuffer[4];45 union {46 HWAVEIN In;47 HWAVEOUT Out;48 } hWaveHandle;50 ALuint Frequency;52 RingBuffer *pRing;53 } WinMMData;56 static const ALCchar woDefault[] = "WaveOut Default";58 static ALCchar **PlaybackDeviceList;59 static ALuint NumPlaybackDevices;60 static ALCchar **CaptureDeviceList;61 static ALuint NumCaptureDevices;64 static void ProbePlaybackDevices(void)65 {66 ALuint i;68 for(i = 0;i < NumPlaybackDevices;i++)69 free(PlaybackDeviceList[i]);71 NumPlaybackDevices = waveOutGetNumDevs();72 PlaybackDeviceList = realloc(PlaybackDeviceList, sizeof(ALCchar*) * NumPlaybackDevices);73 for(i = 0;i < NumPlaybackDevices;i++)74 {75 WAVEOUTCAPS WaveCaps;77 PlaybackDeviceList[i] = NULL;78 if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)79 {80 char name[1024];81 ALuint count, j;83 count = 0;84 do {85 if(count == 0)86 snprintf(name, sizeof(name), "%s", WaveCaps.szPname);87 else88 snprintf(name, sizeof(name), "%s #%d", WaveCaps.szPname, count+1);89 count++;91 for(j = 0;j < i;j++)92 {93 if(strcmp(name, PlaybackDeviceList[j]) == 0)94 break;95 }96 } while(j != i);98 PlaybackDeviceList[i] = strdup(name);99 }100 }101 }103 static void ProbeCaptureDevices(void)104 {105 ALuint i;107 for(i = 0;i < NumCaptureDevices;i++)108 free(CaptureDeviceList[i]);110 NumCaptureDevices = waveInGetNumDevs();111 CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices);112 for(i = 0;i < NumCaptureDevices;i++)113 {114 WAVEINCAPS WaveInCaps;116 CaptureDeviceList[i] = NULL;117 if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)118 {119 char name[1024];120 ALuint count, j;122 count = 0;123 do {124 if(count == 0)125 snprintf(name, sizeof(name), "%s", WaveInCaps.szPname);126 else127 snprintf(name, sizeof(name), "%s #%d", WaveInCaps.szPname, count+1);128 count++;130 for(j = 0;j < i;j++)131 {132 if(strcmp(name, CaptureDeviceList[j]) == 0)133 break;134 }135 } while(j != i);137 CaptureDeviceList[i] = strdup(name);138 }139 }140 }143 /*144 WaveOutProc146 Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and147 returns to the application (for more data)148 */149 static void CALLBACK WaveOutProc(HWAVEOUT hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)150 {151 ALCdevice *pDevice = (ALCdevice*)dwInstance;152 WinMMData *pData = pDevice->ExtraData;154 (void)hDevice;155 (void)dwParam2;157 if(uMsg != WOM_DONE)158 return;160 // Decrement number of buffers in use161 InterlockedDecrement(&pData->lWaveBuffersCommitted);163 if(pData->bWaveShutdown == AL_FALSE)164 {165 // Notify Wave Processor Thread that a Wave Header has returned166 PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1);167 }168 else169 {170 if(pData->lWaveBuffersCommitted == 0)171 {172 // Post 'Quit' Message to WaveOut Processor Thread173 PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);174 }175 }176 }178 /*179 PlaybackThreadProc181 Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its182 audio data.183 */184 static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)185 {186 ALCdevice *pDevice = (ALCdevice*)lpParameter;187 WinMMData *pData = pDevice->ExtraData;188 LPWAVEHDR pWaveHdr;189 ALuint FrameSize;190 MSG msg;192 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);194 SetRTPriority();196 while(GetMessage(&msg, NULL, 0, 0))197 {198 if(msg.message != WOM_DONE || pData->bWaveShutdown)199 continue;201 pWaveHdr = ((LPWAVEHDR)msg.lParam);203 aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize);205 // Send buffer back to play more data206 waveOutWrite(pData->hWaveHandle.Out, pWaveHdr, sizeof(WAVEHDR));207 InterlockedIncrement(&pData->lWaveBuffersCommitted);208 }210 // Signal Wave Thread completed event211 if(pData->hWaveThreadEvent)212 SetEvent(pData->hWaveThreadEvent);214 ExitThread(0);216 return 0;217 }219 /*220 WaveInProc222 Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and223 returns to the application (with more data)224 */225 static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)226 {227 ALCdevice *pDevice = (ALCdevice*)dwInstance;228 WinMMData *pData = pDevice->ExtraData;230 (void)hDevice;231 (void)dwParam2;233 if(uMsg != WIM_DATA)234 return;236 // Decrement number of buffers in use237 InterlockedDecrement(&pData->lWaveBuffersCommitted);239 if(pData->bWaveShutdown == AL_FALSE)240 {241 // Notify Wave Processor Thread that a Wave Header has returned242 PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);243 }244 else245 {246 if(pData->lWaveBuffersCommitted == 0)247 {248 // Post 'Quit' Message to WaveIn Processor Thread249 PostThreadMessage(pData->ulWaveThreadID,WM_QUIT,0,0);250 }251 }252 }254 /*255 CaptureThreadProc257 Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new258 audio data.259 */260 static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)261 {262 ALCdevice *pDevice = (ALCdevice*)lpParameter;263 WinMMData *pData = pDevice->ExtraData;264 LPWAVEHDR pWaveHdr;265 ALuint FrameSize;266 MSG msg;268 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);270 while(GetMessage(&msg, NULL, 0, 0))271 {272 if(msg.message != WIM_DATA || pData->bWaveShutdown)273 continue;275 pWaveHdr = ((LPWAVEHDR)msg.lParam);277 WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData,278 pWaveHdr->dwBytesRecorded/FrameSize);280 // Send buffer back to capture more data281 waveInAddBuffer(pData->hWaveHandle.In,pWaveHdr,sizeof(WAVEHDR));282 InterlockedIncrement(&pData->lWaveBuffersCommitted);283 }285 // Signal Wave Thread completed event286 if(pData->hWaveThreadEvent)287 SetEvent(pData->hWaveThreadEvent);289 ExitThread(0);291 return 0;292 }295 static ALCboolean WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)296 {297 WAVEFORMATEX wfexFormat;298 WinMMData *pData = NULL;299 UINT lDeviceID = 0;300 MMRESULT res;301 ALuint i = 0;303 // Find the Device ID matching the deviceName if valid304 if(!deviceName || strcmp(deviceName, woDefault) == 0)305 lDeviceID = WAVE_MAPPER;306 else307 {308 if(!PlaybackDeviceList)309 ProbePlaybackDevices();311 for(i = 0;i < NumPlaybackDevices;i++)312 {313 if(PlaybackDeviceList[i] &&314 strcmp(deviceName, PlaybackDeviceList[i]) == 0)315 {316 lDeviceID = i;317 break;318 }319 }320 if(i == NumPlaybackDevices)321 return ALC_FALSE;322 }324 pData = calloc(1, sizeof(*pData));325 if(!pData)326 {327 alcSetError(pDevice, ALC_OUT_OF_MEMORY);328 return ALC_FALSE;329 }330 pDevice->ExtraData = pData;332 if(pDevice->FmtChans != DevFmtMono)333 {334 if((pDevice->Flags&DEVICE_CHANNELS_REQUEST) &&335 pDevice->FmtChans != DevFmtStereo)336 {337 ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(pDevice->FmtChans));338 pDevice->Flags &= ~DEVICE_CHANNELS_REQUEST;339 }340 pDevice->FmtChans = DevFmtStereo;341 }342 switch(pDevice->FmtType)343 {344 case DevFmtByte:345 pDevice->FmtType = DevFmtUByte;346 break;347 case DevFmtUShort:348 case DevFmtFloat:349 pDevice->FmtType = DevFmtShort;350 break;351 case DevFmtUByte:352 case DevFmtShort:353 break;354 }356 memset(&wfexFormat, 0, sizeof(WAVEFORMATEX));357 wfexFormat.wFormatTag = WAVE_FORMAT_PCM;358 wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);359 wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;360 wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample *361 wfexFormat.nChannels / 8;362 wfexFormat.nSamplesPerSec = pDevice->Frequency;363 wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec *364 wfexFormat.nBlockAlign;365 wfexFormat.cbSize = 0;367 if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)368 {369 ERR("waveOutOpen failed: %u\n", res);370 goto failure;371 }373 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);374 if(pData->hWaveThreadEvent == NULL)375 {376 ERR("CreateEvent failed: %lu\n", GetLastError());377 goto failure;378 }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);390 if(pData->hWaveHandle.Out)391 waveOutClose(pData->hWaveHandle.Out);393 free(pData);394 pDevice->ExtraData = NULL;395 return ALC_FALSE;396 }398 static void WinMMClosePlayback(ALCdevice *device)399 {400 WinMMData *pData = (WinMMData*)device->ExtraData;402 // Close the Wave device403 CloseHandle(pData->hWaveThreadEvent);404 pData->hWaveThreadEvent = 0;406 waveOutClose(pData->hWaveHandle.Out);407 pData->hWaveHandle.Out = 0;409 free(pData);410 device->ExtraData = NULL;411 }413 static ALCboolean WinMMResetPlayback(ALCdevice *device)414 {415 WinMMData *pData = (WinMMData*)device->ExtraData;416 ALbyte *BufferData;417 ALint lBufferSize;418 ALuint i;420 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);421 if(pData->hWaveThread == NULL)422 return ALC_FALSE;424 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *425 pData->Frequency / device->Frequency);426 if(device->Frequency != pData->Frequency)427 {428 if((device->Flags&DEVICE_FREQUENCY_REQUEST))429 ERR("WinMM does not support changing sample rates (wanted %dhz, got %dhz)\n", device->Frequency, pData->Frequency);430 device->Flags &= ~DEVICE_FREQUENCY_REQUEST;431 device->Frequency = pData->Frequency;432 }434 SetDefaultWFXChannelOrder(device);436 pData->lWaveBuffersCommitted = 0;438 // Create 4 Buffers439 lBufferSize = device->UpdateSize*device->NumUpdates / 4;440 lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);442 BufferData = calloc(4, lBufferSize);443 for(i = 0;i < 4;i++)444 {445 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));446 pData->WaveBuffer[i].dwBufferLength = lBufferSize;447 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :448 (pData->WaveBuffer[i-1].lpData +449 pData->WaveBuffer[i-1].dwBufferLength));450 waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));451 waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));452 InterlockedIncrement(&pData->lWaveBuffersCommitted);453 }455 return ALC_TRUE;456 }458 static void WinMMStopPlayback(ALCdevice *device)459 {460 WinMMData *pData = (WinMMData*)device->ExtraData;461 void *buffer = NULL;462 int i;464 if(pData->hWaveThread == NULL)465 return;467 // Set flag to stop processing headers468 pData->bWaveShutdown = AL_TRUE;470 // Wait for signal that Wave Thread has been destroyed471 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);473 CloseHandle(pData->hWaveThread);474 pData->hWaveThread = 0;476 pData->bWaveShutdown = AL_FALSE;478 // Release the wave buffers479 for(i = 0;i < 4;i++)480 {481 waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));482 if(i == 0) buffer = pData->WaveBuffer[i].lpData;483 pData->WaveBuffer[i].lpData = NULL;484 }485 free(buffer);486 }489 static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)490 {491 WAVEFORMATEX wfexCaptureFormat;492 DWORD ulCapturedDataSize;493 WinMMData *pData = NULL;494 UINT lDeviceID = 0;495 ALbyte *BufferData;496 ALint lBufferSize;497 MMRESULT res;498 ALuint i;500 if(!CaptureDeviceList)501 ProbeCaptureDevices();503 // Find the Device ID matching the deviceName if valid504 if(deviceName)505 {506 for(i = 0;i < NumCaptureDevices;i++)507 {508 if(CaptureDeviceList[i] &&509 strcmp(deviceName, CaptureDeviceList[i]) == 0)510 {511 lDeviceID = i;512 break;513 }514 }515 }516 else517 {518 for(i = 0;i < NumCaptureDevices;i++)519 {520 if(CaptureDeviceList[i])521 {522 lDeviceID = i;523 break;524 }525 }526 }527 if(i == NumCaptureDevices)528 return ALC_FALSE;530 pData = calloc(1, sizeof(*pData));531 if(!pData)532 {533 alcSetError(pDevice, ALC_OUT_OF_MEMORY);534 return ALC_FALSE;535 }536 pDevice->ExtraData = pData;538 if((pDevice->FmtChans != DevFmtMono && pDevice->FmtChans != DevFmtStereo) ||539 (pDevice->FmtType != DevFmtUByte && pDevice->FmtType != DevFmtShort))540 {541 alcSetError(pDevice, ALC_INVALID_ENUM);542 goto failure;543 }545 memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));546 wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM;547 wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);548 wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;549 wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *550 wfexCaptureFormat.nChannels / 8;551 wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;552 wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *553 wfexCaptureFormat.nBlockAlign;554 wfexCaptureFormat.cbSize = 0;556 if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)557 {558 ERR("waveInOpen failed: %u\n", res);559 goto failure;560 }562 pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);563 if(pData->hWaveThreadEvent == NULL)564 {565 ERR("CreateEvent failed: %lu\n", GetLastError());566 goto failure;567 }569 pData->Frequency = pDevice->Frequency;571 // Allocate circular memory buffer for the captured audio572 ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;574 // Make sure circular buffer is at least 100ms in size575 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 each585 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++)593 {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);604 }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++)618 {619 if(pData->WaveBuffer[i].lpData)620 {621 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));622 if(i == 0)623 free(pData->WaveBuffer[i].lpData);624 }625 }627 if(pData->pRing)628 DestroyRingBuffer(pData->pRing);630 if(pData->hWaveThreadEvent)631 CloseHandle(pData->hWaveThreadEvent);633 if(pData->hWaveHandle.In)634 waveInClose(pData->hWaveHandle.In);636 free(pData);637 pDevice->ExtraData = NULL;638 return ALC_FALSE;639 }641 static void WinMMCloseCapture(ALCdevice *pDevice)642 {643 WinMMData *pData = (WinMMData*)pDevice->ExtraData;644 void *buffer = NULL;645 int i;647 // Call waveOutReset to shutdown wave device648 pData->bWaveShutdown = AL_TRUE;649 waveInReset(pData->hWaveHandle.In);651 // Wait for signal that Wave Thread has been destroyed652 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);654 CloseHandle(pData->hWaveThread);655 pData->hWaveThread = 0;657 // Release the wave buffers658 for(i = 0;i < 4;i++)659 {660 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));661 if(i == 0) buffer = pData->WaveBuffer[i].lpData;662 pData->WaveBuffer[i].lpData = NULL;663 }664 free(buffer);666 DestroyRingBuffer(pData->pRing);667 pData->pRing = NULL;669 // Close the Wave device670 CloseHandle(pData->hWaveThreadEvent);671 pData->hWaveThreadEvent = 0;673 waveInClose(pData->hWaveHandle.In);674 pData->hWaveHandle.In = 0;676 free(pData);677 pDevice->ExtraData = NULL;678 }680 static void WinMMStartCapture(ALCdevice *pDevice)681 {682 WinMMData *pData = (WinMMData*)pDevice->ExtraData;683 waveInStart(pData->hWaveHandle.In);684 }686 static void WinMMStopCapture(ALCdevice *pDevice)687 {688 WinMMData *pData = (WinMMData*)pDevice->ExtraData;689 waveInStop(pData->hWaveHandle.In);690 }692 static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)693 {694 WinMMData *pData = (WinMMData*)pDevice->ExtraData;695 return RingBufferSize(pData->pRing);696 }698 static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)699 {700 WinMMData *pData = (WinMMData*)pDevice->ExtraData;702 if(WinMMAvailableSamples(pDevice) >= lSamples)703 ReadRingBuffer(pData->pRing, pBuffer, lSamples);704 else705 alcSetError(pDevice, ALC_INVALID_VALUE);706 }709 static const BackendFuncs WinMMFuncs = {710 WinMMOpenPlayback,711 WinMMClosePlayback,712 WinMMResetPlayback,713 WinMMStopPlayback,714 WinMMOpenCapture,715 WinMMCloseCapture,716 WinMMStartCapture,717 WinMMStopCapture,718 WinMMCaptureSamples,719 WinMMAvailableSamples720 };722 ALCboolean alcWinMMInit(BackendFuncs *FuncList)723 {724 *FuncList = WinMMFuncs;725 return ALC_TRUE;726 }728 void alcWinMMDeinit()729 {730 ALuint lLoop;732 for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++)733 free(PlaybackDeviceList[lLoop]);734 free(PlaybackDeviceList);735 PlaybackDeviceList = NULL;737 NumPlaybackDevices = 0;740 for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)741 free(CaptureDeviceList[lLoop]);742 free(CaptureDeviceList);743 CaptureDeviceList = NULL;745 NumCaptureDevices = 0;746 }748 void alcWinMMProbe(enum DevProbe type)749 {750 ALuint i;752 switch(type)753 {754 case DEVICE_PROBE:755 ProbePlaybackDevices();756 if(NumPlaybackDevices > 0)757 AppendDeviceList(woDefault);758 break;760 case ALL_DEVICE_PROBE:761 ProbePlaybackDevices();762 if(NumPlaybackDevices > 0)763 AppendAllDeviceList(woDefault);764 for(i = 0;i < NumPlaybackDevices;i++)765 {766 if(PlaybackDeviceList[i])767 AppendAllDeviceList(PlaybackDeviceList[i]);768 }769 break;771 case CAPTURE_DEVICE_PROBE:772 ProbeCaptureDevices();773 for(i = 0;i < NumCaptureDevices;i++)774 {775 if(CaptureDeviceList[i])776 AppendCaptureDeviceList(CaptureDeviceList[i]);777 }778 break;779 }780 }