Mercurial > audio-send
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/Alc/backends/winmm.c Tue Oct 25 13:02:31 2011 -0700 1.3 @@ -0,0 +1,780 @@ 1.4 +/** 1.5 + * OpenAL cross platform audio library 1.6 + * Copyright (C) 1999-2007 by authors. 1.7 + * This library is free software; you can redistribute it and/or 1.8 + * modify it under the terms of the GNU Library General Public 1.9 + * License as published by the Free Software Foundation; either 1.10 + * version 2 of the License, or (at your option) any later version. 1.11 + * 1.12 + * This library is distributed in the hope that it will be useful, 1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.15 + * Library General Public License for more details. 1.16 + * 1.17 + * You should have received a copy of the GNU Library General Public 1.18 + * License along with this library; if not, write to the 1.19 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 1.20 + * Boston, MA 02111-1307, USA. 1.21 + * Or go to http://www.gnu.org/copyleft/lgpl.html 1.22 + */ 1.23 + 1.24 +#include "config.h" 1.25 + 1.26 +#define _WIN32_WINNT 0x0500 1.27 +#include <stdlib.h> 1.28 +#include <stdio.h> 1.29 +#include <memory.h> 1.30 + 1.31 +#include <windows.h> 1.32 +#include <mmsystem.h> 1.33 + 1.34 +#include "alMain.h" 1.35 +#include "AL/al.h" 1.36 +#include "AL/alc.h" 1.37 + 1.38 + 1.39 +typedef struct { 1.40 + // MMSYSTEM Device 1.41 + volatile ALboolean bWaveShutdown; 1.42 + HANDLE hWaveThreadEvent; 1.43 + HANDLE hWaveThread; 1.44 + DWORD ulWaveThreadID; 1.45 + LONG lWaveBuffersCommitted; 1.46 + WAVEHDR WaveBuffer[4]; 1.47 + 1.48 + union { 1.49 + HWAVEIN In; 1.50 + HWAVEOUT Out; 1.51 + } hWaveHandle; 1.52 + 1.53 + ALuint Frequency; 1.54 + 1.55 + RingBuffer *pRing; 1.56 +} WinMMData; 1.57 + 1.58 + 1.59 +static const ALCchar woDefault[] = "WaveOut Default"; 1.60 + 1.61 +static ALCchar **PlaybackDeviceList; 1.62 +static ALuint NumPlaybackDevices; 1.63 +static ALCchar **CaptureDeviceList; 1.64 +static ALuint NumCaptureDevices; 1.65 + 1.66 + 1.67 +static void ProbePlaybackDevices(void) 1.68 +{ 1.69 + ALuint i; 1.70 + 1.71 + for(i = 0;i < NumPlaybackDevices;i++) 1.72 + free(PlaybackDeviceList[i]); 1.73 + 1.74 + NumPlaybackDevices = waveOutGetNumDevs(); 1.75 + PlaybackDeviceList = realloc(PlaybackDeviceList, sizeof(ALCchar*) * NumPlaybackDevices); 1.76 + for(i = 0;i < NumPlaybackDevices;i++) 1.77 + { 1.78 + WAVEOUTCAPS WaveCaps; 1.79 + 1.80 + PlaybackDeviceList[i] = NULL; 1.81 + if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) 1.82 + { 1.83 + char name[1024]; 1.84 + ALuint count, j; 1.85 + 1.86 + count = 0; 1.87 + do { 1.88 + if(count == 0) 1.89 + snprintf(name, sizeof(name), "%s", WaveCaps.szPname); 1.90 + else 1.91 + snprintf(name, sizeof(name), "%s #%d", WaveCaps.szPname, count+1); 1.92 + count++; 1.93 + 1.94 + for(j = 0;j < i;j++) 1.95 + { 1.96 + if(strcmp(name, PlaybackDeviceList[j]) == 0) 1.97 + break; 1.98 + } 1.99 + } while(j != i); 1.100 + 1.101 + PlaybackDeviceList[i] = strdup(name); 1.102 + } 1.103 + } 1.104 +} 1.105 + 1.106 +static void ProbeCaptureDevices(void) 1.107 +{ 1.108 + ALuint i; 1.109 + 1.110 + for(i = 0;i < NumCaptureDevices;i++) 1.111 + free(CaptureDeviceList[i]); 1.112 + 1.113 + NumCaptureDevices = waveInGetNumDevs(); 1.114 + CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices); 1.115 + for(i = 0;i < NumCaptureDevices;i++) 1.116 + { 1.117 + WAVEINCAPS WaveInCaps; 1.118 + 1.119 + CaptureDeviceList[i] = NULL; 1.120 + if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) 1.121 + { 1.122 + char name[1024]; 1.123 + ALuint count, j; 1.124 + 1.125 + count = 0; 1.126 + do { 1.127 + if(count == 0) 1.128 + snprintf(name, sizeof(name), "%s", WaveInCaps.szPname); 1.129 + else 1.130 + snprintf(name, sizeof(name), "%s #%d", WaveInCaps.szPname, count+1); 1.131 + count++; 1.132 + 1.133 + for(j = 0;j < i;j++) 1.134 + { 1.135 + if(strcmp(name, CaptureDeviceList[j]) == 0) 1.136 + break; 1.137 + } 1.138 + } while(j != i); 1.139 + 1.140 + CaptureDeviceList[i] = strdup(name); 1.141 + } 1.142 + } 1.143 +} 1.144 + 1.145 + 1.146 +/* 1.147 + WaveOutProc 1.148 + 1.149 + Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and 1.150 + returns to the application (for more data) 1.151 +*/ 1.152 +static void CALLBACK WaveOutProc(HWAVEOUT hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2) 1.153 +{ 1.154 + ALCdevice *pDevice = (ALCdevice*)dwInstance; 1.155 + WinMMData *pData = pDevice->ExtraData; 1.156 + 1.157 + (void)hDevice; 1.158 + (void)dwParam2; 1.159 + 1.160 + if(uMsg != WOM_DONE) 1.161 + return; 1.162 + 1.163 + // Decrement number of buffers in use 1.164 + InterlockedDecrement(&pData->lWaveBuffersCommitted); 1.165 + 1.166 + if(pData->bWaveShutdown == AL_FALSE) 1.167 + { 1.168 + // Notify Wave Processor Thread that a Wave Header has returned 1.169 + PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1); 1.170 + } 1.171 + else 1.172 + { 1.173 + if(pData->lWaveBuffersCommitted == 0) 1.174 + { 1.175 + // Post 'Quit' Message to WaveOut Processor Thread 1.176 + PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0); 1.177 + } 1.178 + } 1.179 +} 1.180 + 1.181 +/* 1.182 + PlaybackThreadProc 1.183 + 1.184 + Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its 1.185 + audio data. 1.186 +*/ 1.187 +static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter) 1.188 +{ 1.189 + ALCdevice *pDevice = (ALCdevice*)lpParameter; 1.190 + WinMMData *pData = pDevice->ExtraData; 1.191 + LPWAVEHDR pWaveHdr; 1.192 + ALuint FrameSize; 1.193 + MSG msg; 1.194 + 1.195 + FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); 1.196 + 1.197 + SetRTPriority(); 1.198 + 1.199 + while(GetMessage(&msg, NULL, 0, 0)) 1.200 + { 1.201 + if(msg.message != WOM_DONE || pData->bWaveShutdown) 1.202 + continue; 1.203 + 1.204 + pWaveHdr = ((LPWAVEHDR)msg.lParam); 1.205 + 1.206 + aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize); 1.207 + 1.208 + // Send buffer back to play more data 1.209 + waveOutWrite(pData->hWaveHandle.Out, pWaveHdr, sizeof(WAVEHDR)); 1.210 + InterlockedIncrement(&pData->lWaveBuffersCommitted); 1.211 + } 1.212 + 1.213 + // Signal Wave Thread completed event 1.214 + if(pData->hWaveThreadEvent) 1.215 + SetEvent(pData->hWaveThreadEvent); 1.216 + 1.217 + ExitThread(0); 1.218 + 1.219 + return 0; 1.220 +} 1.221 + 1.222 +/* 1.223 + WaveInProc 1.224 + 1.225 + Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and 1.226 + returns to the application (with more data) 1.227 +*/ 1.228 +static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2) 1.229 +{ 1.230 + ALCdevice *pDevice = (ALCdevice*)dwInstance; 1.231 + WinMMData *pData = pDevice->ExtraData; 1.232 + 1.233 + (void)hDevice; 1.234 + (void)dwParam2; 1.235 + 1.236 + if(uMsg != WIM_DATA) 1.237 + return; 1.238 + 1.239 + // Decrement number of buffers in use 1.240 + InterlockedDecrement(&pData->lWaveBuffersCommitted); 1.241 + 1.242 + if(pData->bWaveShutdown == AL_FALSE) 1.243 + { 1.244 + // Notify Wave Processor Thread that a Wave Header has returned 1.245 + PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1); 1.246 + } 1.247 + else 1.248 + { 1.249 + if(pData->lWaveBuffersCommitted == 0) 1.250 + { 1.251 + // Post 'Quit' Message to WaveIn Processor Thread 1.252 + PostThreadMessage(pData->ulWaveThreadID,WM_QUIT,0,0); 1.253 + } 1.254 + } 1.255 +} 1.256 + 1.257 +/* 1.258 + CaptureThreadProc 1.259 + 1.260 + Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new 1.261 + audio data. 1.262 +*/ 1.263 +static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter) 1.264 +{ 1.265 + ALCdevice *pDevice = (ALCdevice*)lpParameter; 1.266 + WinMMData *pData = pDevice->ExtraData; 1.267 + LPWAVEHDR pWaveHdr; 1.268 + ALuint FrameSize; 1.269 + MSG msg; 1.270 + 1.271 + FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); 1.272 + 1.273 + while(GetMessage(&msg, NULL, 0, 0)) 1.274 + { 1.275 + if(msg.message != WIM_DATA || pData->bWaveShutdown) 1.276 + continue; 1.277 + 1.278 + pWaveHdr = ((LPWAVEHDR)msg.lParam); 1.279 + 1.280 + WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData, 1.281 + pWaveHdr->dwBytesRecorded/FrameSize); 1.282 + 1.283 + // Send buffer back to capture more data 1.284 + waveInAddBuffer(pData->hWaveHandle.In,pWaveHdr,sizeof(WAVEHDR)); 1.285 + InterlockedIncrement(&pData->lWaveBuffersCommitted); 1.286 + } 1.287 + 1.288 + // Signal Wave Thread completed event 1.289 + if(pData->hWaveThreadEvent) 1.290 + SetEvent(pData->hWaveThreadEvent); 1.291 + 1.292 + ExitThread(0); 1.293 + 1.294 + return 0; 1.295 +} 1.296 + 1.297 + 1.298 +static ALCboolean WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName) 1.299 +{ 1.300 + WAVEFORMATEX wfexFormat; 1.301 + WinMMData *pData = NULL; 1.302 + UINT lDeviceID = 0; 1.303 + MMRESULT res; 1.304 + ALuint i = 0; 1.305 + 1.306 + // Find the Device ID matching the deviceName if valid 1.307 + if(!deviceName || strcmp(deviceName, woDefault) == 0) 1.308 + lDeviceID = WAVE_MAPPER; 1.309 + else 1.310 + { 1.311 + if(!PlaybackDeviceList) 1.312 + ProbePlaybackDevices(); 1.313 + 1.314 + for(i = 0;i < NumPlaybackDevices;i++) 1.315 + { 1.316 + if(PlaybackDeviceList[i] && 1.317 + strcmp(deviceName, PlaybackDeviceList[i]) == 0) 1.318 + { 1.319 + lDeviceID = i; 1.320 + break; 1.321 + } 1.322 + } 1.323 + if(i == NumPlaybackDevices) 1.324 + return ALC_FALSE; 1.325 + } 1.326 + 1.327 + pData = calloc(1, sizeof(*pData)); 1.328 + if(!pData) 1.329 + { 1.330 + alcSetError(pDevice, ALC_OUT_OF_MEMORY); 1.331 + return ALC_FALSE; 1.332 + } 1.333 + pDevice->ExtraData = pData; 1.334 + 1.335 + if(pDevice->FmtChans != DevFmtMono) 1.336 + { 1.337 + if((pDevice->Flags&DEVICE_CHANNELS_REQUEST) && 1.338 + pDevice->FmtChans != DevFmtStereo) 1.339 + { 1.340 + ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(pDevice->FmtChans)); 1.341 + pDevice->Flags &= ~DEVICE_CHANNELS_REQUEST; 1.342 + } 1.343 + pDevice->FmtChans = DevFmtStereo; 1.344 + } 1.345 + switch(pDevice->FmtType) 1.346 + { 1.347 + case DevFmtByte: 1.348 + pDevice->FmtType = DevFmtUByte; 1.349 + break; 1.350 + case DevFmtUShort: 1.351 + case DevFmtFloat: 1.352 + pDevice->FmtType = DevFmtShort; 1.353 + break; 1.354 + case DevFmtUByte: 1.355 + case DevFmtShort: 1.356 + break; 1.357 + } 1.358 + 1.359 + memset(&wfexFormat, 0, sizeof(WAVEFORMATEX)); 1.360 + wfexFormat.wFormatTag = WAVE_FORMAT_PCM; 1.361 + wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans); 1.362 + wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8; 1.363 + wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample * 1.364 + wfexFormat.nChannels / 8; 1.365 + wfexFormat.nSamplesPerSec = pDevice->Frequency; 1.366 + wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec * 1.367 + wfexFormat.nBlockAlign; 1.368 + wfexFormat.cbSize = 0; 1.369 + 1.370 + if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) 1.371 + { 1.372 + ERR("waveOutOpen failed: %u\n", res); 1.373 + goto failure; 1.374 + } 1.375 + 1.376 + pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 1.377 + if(pData->hWaveThreadEvent == NULL) 1.378 + { 1.379 + ERR("CreateEvent failed: %lu\n", GetLastError()); 1.380 + goto failure; 1.381 + } 1.382 + 1.383 + pData->Frequency = pDevice->Frequency; 1.384 + 1.385 + pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault : 1.386 + PlaybackDeviceList[lDeviceID]); 1.387 + return ALC_TRUE; 1.388 + 1.389 +failure: 1.390 + if(pData->hWaveThreadEvent) 1.391 + CloseHandle(pData->hWaveThreadEvent); 1.392 + 1.393 + if(pData->hWaveHandle.Out) 1.394 + waveOutClose(pData->hWaveHandle.Out); 1.395 + 1.396 + free(pData); 1.397 + pDevice->ExtraData = NULL; 1.398 + return ALC_FALSE; 1.399 +} 1.400 + 1.401 +static void WinMMClosePlayback(ALCdevice *device) 1.402 +{ 1.403 + WinMMData *pData = (WinMMData*)device->ExtraData; 1.404 + 1.405 + // Close the Wave device 1.406 + CloseHandle(pData->hWaveThreadEvent); 1.407 + pData->hWaveThreadEvent = 0; 1.408 + 1.409 + waveOutClose(pData->hWaveHandle.Out); 1.410 + pData->hWaveHandle.Out = 0; 1.411 + 1.412 + free(pData); 1.413 + device->ExtraData = NULL; 1.414 +} 1.415 + 1.416 +static ALCboolean WinMMResetPlayback(ALCdevice *device) 1.417 +{ 1.418 + WinMMData *pData = (WinMMData*)device->ExtraData; 1.419 + ALbyte *BufferData; 1.420 + ALint lBufferSize; 1.421 + ALuint i; 1.422 + 1.423 + pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID); 1.424 + if(pData->hWaveThread == NULL) 1.425 + return ALC_FALSE; 1.426 + 1.427 + device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * 1.428 + pData->Frequency / device->Frequency); 1.429 + if(device->Frequency != pData->Frequency) 1.430 + { 1.431 + if((device->Flags&DEVICE_FREQUENCY_REQUEST)) 1.432 + ERR("WinMM does not support changing sample rates (wanted %dhz, got %dhz)\n", device->Frequency, pData->Frequency); 1.433 + device->Flags &= ~DEVICE_FREQUENCY_REQUEST; 1.434 + device->Frequency = pData->Frequency; 1.435 + } 1.436 + 1.437 + SetDefaultWFXChannelOrder(device); 1.438 + 1.439 + pData->lWaveBuffersCommitted = 0; 1.440 + 1.441 + // Create 4 Buffers 1.442 + lBufferSize = device->UpdateSize*device->NumUpdates / 4; 1.443 + lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType); 1.444 + 1.445 + BufferData = calloc(4, lBufferSize); 1.446 + for(i = 0;i < 4;i++) 1.447 + { 1.448 + memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR)); 1.449 + pData->WaveBuffer[i].dwBufferLength = lBufferSize; 1.450 + pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData : 1.451 + (pData->WaveBuffer[i-1].lpData + 1.452 + pData->WaveBuffer[i-1].dwBufferLength)); 1.453 + waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR)); 1.454 + waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR)); 1.455 + InterlockedIncrement(&pData->lWaveBuffersCommitted); 1.456 + } 1.457 + 1.458 + return ALC_TRUE; 1.459 +} 1.460 + 1.461 +static void WinMMStopPlayback(ALCdevice *device) 1.462 +{ 1.463 + WinMMData *pData = (WinMMData*)device->ExtraData; 1.464 + void *buffer = NULL; 1.465 + int i; 1.466 + 1.467 + if(pData->hWaveThread == NULL) 1.468 + return; 1.469 + 1.470 + // Set flag to stop processing headers 1.471 + pData->bWaveShutdown = AL_TRUE; 1.472 + 1.473 + // Wait for signal that Wave Thread has been destroyed 1.474 + WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE); 1.475 + 1.476 + CloseHandle(pData->hWaveThread); 1.477 + pData->hWaveThread = 0; 1.478 + 1.479 + pData->bWaveShutdown = AL_FALSE; 1.480 + 1.481 + // Release the wave buffers 1.482 + for(i = 0;i < 4;i++) 1.483 + { 1.484 + waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR)); 1.485 + if(i == 0) buffer = pData->WaveBuffer[i].lpData; 1.486 + pData->WaveBuffer[i].lpData = NULL; 1.487 + } 1.488 + free(buffer); 1.489 +} 1.490 + 1.491 + 1.492 +static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName) 1.493 +{ 1.494 + WAVEFORMATEX wfexCaptureFormat; 1.495 + DWORD ulCapturedDataSize; 1.496 + WinMMData *pData = NULL; 1.497 + UINT lDeviceID = 0; 1.498 + ALbyte *BufferData; 1.499 + ALint lBufferSize; 1.500 + MMRESULT res; 1.501 + ALuint i; 1.502 + 1.503 + if(!CaptureDeviceList) 1.504 + ProbeCaptureDevices(); 1.505 + 1.506 + // Find the Device ID matching the deviceName if valid 1.507 + if(deviceName) 1.508 + { 1.509 + for(i = 0;i < NumCaptureDevices;i++) 1.510 + { 1.511 + if(CaptureDeviceList[i] && 1.512 + strcmp(deviceName, CaptureDeviceList[i]) == 0) 1.513 + { 1.514 + lDeviceID = i; 1.515 + break; 1.516 + } 1.517 + } 1.518 + } 1.519 + else 1.520 + { 1.521 + for(i = 0;i < NumCaptureDevices;i++) 1.522 + { 1.523 + if(CaptureDeviceList[i]) 1.524 + { 1.525 + lDeviceID = i; 1.526 + break; 1.527 + } 1.528 + } 1.529 + } 1.530 + if(i == NumCaptureDevices) 1.531 + return ALC_FALSE; 1.532 + 1.533 + pData = calloc(1, sizeof(*pData)); 1.534 + if(!pData) 1.535 + { 1.536 + alcSetError(pDevice, ALC_OUT_OF_MEMORY); 1.537 + return ALC_FALSE; 1.538 + } 1.539 + pDevice->ExtraData = pData; 1.540 + 1.541 + if((pDevice->FmtChans != DevFmtMono && pDevice->FmtChans != DevFmtStereo) || 1.542 + (pDevice->FmtType != DevFmtUByte && pDevice->FmtType != DevFmtShort)) 1.543 + { 1.544 + alcSetError(pDevice, ALC_INVALID_ENUM); 1.545 + goto failure; 1.546 + } 1.547 + 1.548 + memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX)); 1.549 + wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM; 1.550 + wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans); 1.551 + wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8; 1.552 + wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample * 1.553 + wfexCaptureFormat.nChannels / 8; 1.554 + wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency; 1.555 + wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec * 1.556 + wfexCaptureFormat.nBlockAlign; 1.557 + wfexCaptureFormat.cbSize = 0; 1.558 + 1.559 + if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) 1.560 + { 1.561 + ERR("waveInOpen failed: %u\n", res); 1.562 + goto failure; 1.563 + } 1.564 + 1.565 + pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 1.566 + if(pData->hWaveThreadEvent == NULL) 1.567 + { 1.568 + ERR("CreateEvent failed: %lu\n", GetLastError()); 1.569 + goto failure; 1.570 + } 1.571 + 1.572 + pData->Frequency = pDevice->Frequency; 1.573 + 1.574 + // Allocate circular memory buffer for the captured audio 1.575 + ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates; 1.576 + 1.577 + // Make sure circular buffer is at least 100ms in size 1.578 + if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10)) 1.579 + ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10; 1.580 + 1.581 + pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize); 1.582 + if(!pData->pRing) 1.583 + goto failure; 1.584 + 1.585 + pData->lWaveBuffersCommitted = 0; 1.586 + 1.587 + // Create 4 Buffers of 50ms each 1.588 + lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20; 1.589 + lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign); 1.590 + 1.591 + BufferData = calloc(4, lBufferSize); 1.592 + if(!BufferData) 1.593 + goto failure; 1.594 + 1.595 + for(i = 0;i < 4;i++) 1.596 + { 1.597 + memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR)); 1.598 + pData->WaveBuffer[i].dwBufferLength = lBufferSize; 1.599 + pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData : 1.600 + (pData->WaveBuffer[i-1].lpData + 1.601 + pData->WaveBuffer[i-1].dwBufferLength)); 1.602 + pData->WaveBuffer[i].dwFlags = 0; 1.603 + pData->WaveBuffer[i].dwLoops = 0; 1.604 + waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); 1.605 + waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); 1.606 + InterlockedIncrement(&pData->lWaveBuffersCommitted); 1.607 + } 1.608 + 1.609 + pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID); 1.610 + if (pData->hWaveThread == NULL) 1.611 + goto failure; 1.612 + 1.613 + pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]); 1.614 + return ALC_TRUE; 1.615 + 1.616 +failure: 1.617 + if(pData->hWaveThread) 1.618 + CloseHandle(pData->hWaveThread); 1.619 + 1.620 + for(i = 0;i < 4;i++) 1.621 + { 1.622 + if(pData->WaveBuffer[i].lpData) 1.623 + { 1.624 + waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); 1.625 + if(i == 0) 1.626 + free(pData->WaveBuffer[i].lpData); 1.627 + } 1.628 + } 1.629 + 1.630 + if(pData->pRing) 1.631 + DestroyRingBuffer(pData->pRing); 1.632 + 1.633 + if(pData->hWaveThreadEvent) 1.634 + CloseHandle(pData->hWaveThreadEvent); 1.635 + 1.636 + if(pData->hWaveHandle.In) 1.637 + waveInClose(pData->hWaveHandle.In); 1.638 + 1.639 + free(pData); 1.640 + pDevice->ExtraData = NULL; 1.641 + return ALC_FALSE; 1.642 +} 1.643 + 1.644 +static void WinMMCloseCapture(ALCdevice *pDevice) 1.645 +{ 1.646 + WinMMData *pData = (WinMMData*)pDevice->ExtraData; 1.647 + void *buffer = NULL; 1.648 + int i; 1.649 + 1.650 + // Call waveOutReset to shutdown wave device 1.651 + pData->bWaveShutdown = AL_TRUE; 1.652 + waveInReset(pData->hWaveHandle.In); 1.653 + 1.654 + // Wait for signal that Wave Thread has been destroyed 1.655 + WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE); 1.656 + 1.657 + CloseHandle(pData->hWaveThread); 1.658 + pData->hWaveThread = 0; 1.659 + 1.660 + // Release the wave buffers 1.661 + for(i = 0;i < 4;i++) 1.662 + { 1.663 + waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); 1.664 + if(i == 0) buffer = pData->WaveBuffer[i].lpData; 1.665 + pData->WaveBuffer[i].lpData = NULL; 1.666 + } 1.667 + free(buffer); 1.668 + 1.669 + DestroyRingBuffer(pData->pRing); 1.670 + pData->pRing = NULL; 1.671 + 1.672 + // Close the Wave device 1.673 + CloseHandle(pData->hWaveThreadEvent); 1.674 + pData->hWaveThreadEvent = 0; 1.675 + 1.676 + waveInClose(pData->hWaveHandle.In); 1.677 + pData->hWaveHandle.In = 0; 1.678 + 1.679 + free(pData); 1.680 + pDevice->ExtraData = NULL; 1.681 +} 1.682 + 1.683 +static void WinMMStartCapture(ALCdevice *pDevice) 1.684 +{ 1.685 + WinMMData *pData = (WinMMData*)pDevice->ExtraData; 1.686 + waveInStart(pData->hWaveHandle.In); 1.687 +} 1.688 + 1.689 +static void WinMMStopCapture(ALCdevice *pDevice) 1.690 +{ 1.691 + WinMMData *pData = (WinMMData*)pDevice->ExtraData; 1.692 + waveInStop(pData->hWaveHandle.In); 1.693 +} 1.694 + 1.695 +static ALCuint WinMMAvailableSamples(ALCdevice *pDevice) 1.696 +{ 1.697 + WinMMData *pData = (WinMMData*)pDevice->ExtraData; 1.698 + return RingBufferSize(pData->pRing); 1.699 +} 1.700 + 1.701 +static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) 1.702 +{ 1.703 + WinMMData *pData = (WinMMData*)pDevice->ExtraData; 1.704 + 1.705 + if(WinMMAvailableSamples(pDevice) >= lSamples) 1.706 + ReadRingBuffer(pData->pRing, pBuffer, lSamples); 1.707 + else 1.708 + alcSetError(pDevice, ALC_INVALID_VALUE); 1.709 +} 1.710 + 1.711 + 1.712 +static const BackendFuncs WinMMFuncs = { 1.713 + WinMMOpenPlayback, 1.714 + WinMMClosePlayback, 1.715 + WinMMResetPlayback, 1.716 + WinMMStopPlayback, 1.717 + WinMMOpenCapture, 1.718 + WinMMCloseCapture, 1.719 + WinMMStartCapture, 1.720 + WinMMStopCapture, 1.721 + WinMMCaptureSamples, 1.722 + WinMMAvailableSamples 1.723 +}; 1.724 + 1.725 +ALCboolean alcWinMMInit(BackendFuncs *FuncList) 1.726 +{ 1.727 + *FuncList = WinMMFuncs; 1.728 + return ALC_TRUE; 1.729 +} 1.730 + 1.731 +void alcWinMMDeinit() 1.732 +{ 1.733 + ALuint lLoop; 1.734 + 1.735 + for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++) 1.736 + free(PlaybackDeviceList[lLoop]); 1.737 + free(PlaybackDeviceList); 1.738 + PlaybackDeviceList = NULL; 1.739 + 1.740 + NumPlaybackDevices = 0; 1.741 + 1.742 + 1.743 + for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++) 1.744 + free(CaptureDeviceList[lLoop]); 1.745 + free(CaptureDeviceList); 1.746 + CaptureDeviceList = NULL; 1.747 + 1.748 + NumCaptureDevices = 0; 1.749 +} 1.750 + 1.751 +void alcWinMMProbe(enum DevProbe type) 1.752 +{ 1.753 + ALuint i; 1.754 + 1.755 + switch(type) 1.756 + { 1.757 + case DEVICE_PROBE: 1.758 + ProbePlaybackDevices(); 1.759 + if(NumPlaybackDevices > 0) 1.760 + AppendDeviceList(woDefault); 1.761 + break; 1.762 + 1.763 + case ALL_DEVICE_PROBE: 1.764 + ProbePlaybackDevices(); 1.765 + if(NumPlaybackDevices > 0) 1.766 + AppendAllDeviceList(woDefault); 1.767 + for(i = 0;i < NumPlaybackDevices;i++) 1.768 + { 1.769 + if(PlaybackDeviceList[i]) 1.770 + AppendAllDeviceList(PlaybackDeviceList[i]); 1.771 + } 1.772 + break; 1.773 + 1.774 + case CAPTURE_DEVICE_PROBE: 1.775 + ProbeCaptureDevices(); 1.776 + for(i = 0;i < NumCaptureDevices;i++) 1.777 + { 1.778 + if(CaptureDeviceList[i]) 1.779 + AppendCaptureDeviceList(CaptureDeviceList[i]); 1.780 + } 1.781 + break; 1.782 + } 1.783 +}