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 +}