diff options
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/ALc.c | 2 | ||||
-rw-r--r-- | Alc/backends/base.h | 1 | ||||
-rw-r--r-- | Alc/backends/winmm.c | 665 |
3 files changed, 382 insertions, 286 deletions
@@ -89,7 +89,7 @@ static struct BackendInfo BackendList[] = { { "dsound", ALCdsoundBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_WINMM - { "winmm", NULL, alcWinMMInit, alcWinMMDeinit, alcWinMMProbe, EmptyFuncs }, + { "winmm", ALCwinmmBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_PORTAUDIO { "port", NULL, alc_pa_init, alc_pa_deinit, alc_pa_probe, EmptyFuncs }, diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 99556f3f..4ed3bfc9 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -125,6 +125,7 @@ ALCbackendFactory *ALCalsaBackendFactory_getFactory(void); ALCbackendFactory *ALCossBackendFactory_getFactory(void); ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); +ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); ALCbackendFactory *ALCnullBackendFactory_getFactory(void); ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void); diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index f6b2d344..1e557883 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -31,30 +31,13 @@ #include "alu.h" #include "threads.h" +#include "backends/base.h" + #ifndef WAVE_FORMAT_IEEE_FLOAT #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif -typedef struct { - // MMSYSTEM Device - volatile ALboolean killNow; - althrd_t thread; - - RefCount WaveBuffersCommitted; - WAVEHDR WaveBuffer[4]; - - union { - HWAVEIN In; - HWAVEOUT Out; - } WaveHandle; - - WAVEFORMATEX Format; - - RingBuffer *Ring; -} WinMMData; - - TYPEDEF_VECTOR(al_string, vector_al_string) static vector_al_string PlaybackDevices; static vector_al_string CaptureDevices; @@ -155,111 +138,117 @@ static void ProbeCaptureDevices(void) } -/* - WaveOutProc +typedef struct ALCwinmmPlayback { + DERIVE_FROM_TYPE(ALCbackend); - Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and - returns to the application (for more data) -*/ -static void CALLBACK WaveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) -{ - ALCdevice *Device = (ALCdevice*)instance; - WinMMData *data = Device->ExtraData; + RefCount WaveBuffersCommitted; + WAVEHDR WaveBuffer[4]; - if(msg != WOM_DONE) - return; + HWAVEOUT OutHdl; - DecrementRef(&data->WaveBuffersCommitted); - PostThreadMessage(data->thread, msg, 0, param1); -} + WAVEFORMATEX Format; -FORCE_ALIGN static int PlaybackThreadProc(void *arg) -{ - ALCdevice *Device = (ALCdevice*)arg; - WinMMData *data = Device->ExtraData; - WAVEHDR *WaveHdr; - MSG msg; + volatile ALboolean killNow; + althrd_t thread; +} ALCwinmmPlayback; - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); +static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); +static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self); - while(GetMessage(&msg, NULL, 0, 0)) - { - if(msg.message != WOM_DONE) - continue; +static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); +static int ALCwinmmPlayback_mixerProc(void *arg); - if(data->killNow) - { - if(ReadRef(&data->WaveBuffersCommitted) == 0) - break; - continue; - } +static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name); +static void ALCwinmmPlayback_close(ALCwinmmPlayback *self); +static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self); +static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self); +static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self); +static DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback) - WaveHdr = ((WAVEHDR*)msg.lParam); - aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength / - data->Format.nBlockAlign); +DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback); - // Send buffer back to play more data - waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR)); - IncrementRef(&data->WaveBuffersCommitted); - } - return 0; +static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self); + + InitRef(&self->WaveBuffersCommitted, 0); + self->OutHdl = NULL; + + self->killNow = AL_TRUE; +} + +static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) +{ + if(self->OutHdl) + waveOutClose(self->OutHdl); + self->OutHdl = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } -/* - WaveInProc - Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and - returns to the application (with more data) -*/ -static void CALLBACK WaveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) +/* ALCwinmmPlayback_waveOutProc + * + * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer + * is completed and returns to the application (for more data) + */ +static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) { - ALCdevice *Device = (ALCdevice*)instance; - WinMMData *data = Device->ExtraData; + ALCwinmmPlayback *self = (ALCwinmmPlayback*)instance; - if(msg != WIM_DATA) + if(msg != WOM_DONE) return; - DecrementRef(&data->WaveBuffersCommitted); - PostThreadMessage(data->thread, msg, 0, param1); + DecrementRef(&self->WaveBuffersCommitted); + PostThreadMessage(self->thread, msg, 0, param1); } -static int CaptureThreadProc(void *arg) +FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) { - ALCdevice *Device = (ALCdevice*)arg; - WinMMData *data = Device->ExtraData; + ALCwinmmPlayback *self = arg; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; WAVEHDR *WaveHdr; MSG msg; - althrd_setname(althrd_current(), "alsoft-record"); + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); while(GetMessage(&msg, NULL, 0, 0)) { - if(msg.message != WIM_DATA) + if(msg.message != WOM_DONE) continue; - /* Don't wait for other buffers to finish before quitting. We're - * closing so we don't need them. */ - if(data->killNow) - break; + + if(self->killNow) + { + if(ReadRef(&self->WaveBuffersCommitted) == 0) + break; + continue; + } WaveHdr = ((WAVEHDR*)msg.lParam); - WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData, - WaveHdr->dwBytesRecorded/data->Format.nBlockAlign); + aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength / + self->Format.nBlockAlign); - // Send buffer back to capture more data - waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR)); - IncrementRef(&data->WaveBuffersCommitted); + // Send buffer back to play more data + waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); } return 0; } -static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName) +static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) { - WinMMData *data = NULL; - const al_string *iter, *end; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const al_string *iter; UINT DeviceID; MMRESULT res; @@ -267,129 +256,109 @@ static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName) ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid - iter = VECTOR_ITER_BEGIN(PlaybackDevices); - end = VECTOR_ITER_END(PlaybackDevices); - for(;iter != end;iter++) - { - if(!al_string_empty(*iter) && - (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0)) - { - DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices)); - break; - } - } - if(iter == end) +#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && \ + (!deviceName || al_string_cmp_cstr(*(iter), deviceName) == 0)) + VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME); + if(iter == VECTOR_ITER_END(PlaybackDevices)) return ALC_INVALID_VALUE; +#undef MATCH_DEVNAME - data = calloc(1, sizeof(*data)); - if(!data) - return ALC_OUT_OF_MEMORY; - Device->ExtraData = data; + DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices)); retry_open: - memset(&data->Format, 0, sizeof(WAVEFORMATEX)); - if(Device->FmtType == DevFmtFloat) + memset(&self->Format, 0, sizeof(WAVEFORMATEX)); + if(device->FmtType == DevFmtFloat) { - data->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - data->Format.wBitsPerSample = 32; + self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + self->Format.wBitsPerSample = 32; } else { - data->Format.wFormatTag = WAVE_FORMAT_PCM; - if(Device->FmtType == DevFmtUByte || Device->FmtType == DevFmtByte) - data->Format.wBitsPerSample = 8; + self->Format.wFormatTag = WAVE_FORMAT_PCM; + if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte) + self->Format.wBitsPerSample = 8; else - data->Format.wBitsPerSample = 16; + self->Format.wBitsPerSample = 16; } - data->Format.nChannels = ((Device->FmtChans == DevFmtMono) ? 1 : 2); - data->Format.nBlockAlign = data->Format.wBitsPerSample * - data->Format.nChannels / 8; - data->Format.nSamplesPerSec = Device->Frequency; - data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec * - data->Format.nBlockAlign; - data->Format.cbSize = 0; - - if((res=waveOutOpen(&data->WaveHandle.Out, DeviceID, &data->Format, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); + self->Format.nBlockAlign = self->Format.wBitsPerSample * + self->Format.nChannels / 8; + self->Format.nSamplesPerSec = device->Frequency; + self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * + self->Format.nBlockAlign; + self->Format.cbSize = 0; + + if((res=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { - if(Device->FmtType == DevFmtFloat) + if(device->FmtType == DevFmtFloat) { - Device->FmtType = DevFmtShort; + device->FmtType = DevFmtShort; goto retry_open; } ERR("waveOutOpen failed: %u\n", res); goto failure; } - al_string_copy(&Device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); + al_string_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); return ALC_NO_ERROR; failure: - if(data->WaveHandle.Out) - waveOutClose(data->WaveHandle.Out); + if(self->OutHdl) + waveOutClose(self->OutHdl); + self->OutHdl = NULL; - free(data); - Device->ExtraData = NULL; return ALC_INVALID_VALUE; } -static void WinMMClosePlayback(ALCdevice *device) -{ - WinMMData *data = (WinMMData*)device->ExtraData; - - // Close the Wave device - waveOutClose(data->WaveHandle.Out); - data->WaveHandle.Out = 0; - - free(data); - device->ExtraData = NULL; -} +static void ALCwinmmPlayback_close(ALCwinmmPlayback* UNUSED(self)) +{ } -static ALCboolean WinMMResetPlayback(ALCdevice *device) +static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) { - WinMMData *data = (WinMMData*)device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * - data->Format.nSamplesPerSec / + self->Format.nSamplesPerSec / device->Frequency); device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4; device->NumUpdates = 4; - device->Frequency = data->Format.nSamplesPerSec; + device->Frequency = self->Format.nSamplesPerSec; - if(data->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + if(self->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { - if(data->Format.wBitsPerSample == 32) + if(self->Format.wBitsPerSample == 32) device->FmtType = DevFmtFloat; else { - ERR("Unhandled IEEE float sample depth: %d\n", data->Format.wBitsPerSample); + ERR("Unhandled IEEE float sample depth: %d\n", self->Format.wBitsPerSample); return ALC_FALSE; } } - else if(data->Format.wFormatTag == WAVE_FORMAT_PCM) + else if(self->Format.wFormatTag == WAVE_FORMAT_PCM) { - if(data->Format.wBitsPerSample == 16) + if(self->Format.wBitsPerSample == 16) device->FmtType = DevFmtShort; - else if(data->Format.wBitsPerSample == 8) + else if(self->Format.wBitsPerSample == 8) device->FmtType = DevFmtUByte; else { - ERR("Unhandled PCM sample depth: %d\n", data->Format.wBitsPerSample); + ERR("Unhandled PCM sample depth: %d\n", self->Format.wBitsPerSample); return ALC_FALSE; } } else { - ERR("Unhandled format tag: 0x%04x\n", data->Format.wFormatTag); + ERR("Unhandled format tag: 0x%04x\n", self->Format.wFormatTag); return ALC_FALSE; } - if(data->Format.nChannels == 2) + if(self->Format.nChannels == 2) device->FmtChans = DevFmtStereo; - else if(data->Format.nChannels == 1) + else if(self->Format.nChannels == 1) device->FmtChans = DevFmtMono; else { - ERR("Unhandled channel count: %d\n", data->Format.nChannels); + ERR("Unhandled channel count: %d\n", self->Format.nChannels); return ALC_FALSE; } SetDefaultWFXChannelOrder(device); @@ -397,18 +366,18 @@ static ALCboolean WinMMResetPlayback(ALCdevice *device) return ALC_TRUE; } -static ALCboolean WinMMStartPlayback(ALCdevice *device) +static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) { - WinMMData *data = (WinMMData*)device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALbyte *BufferData; ALint BufferSize; ALuint i; - data->killNow = AL_FALSE; - if(althrd_create(&data->thread, PlaybackThreadProc, device) != althrd_success) + self->killNow = AL_FALSE; + if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success) return ALC_FALSE; - InitRef(&data->WaveBuffersCommitted, 0); + InitRef(&self->WaveBuffersCommitted, 0); // Create 4 Buffers BufferSize = device->UpdateSize*device->NumUpdates / 4; @@ -417,49 +386,153 @@ static ALCboolean WinMMStartPlayback(ALCdevice *device) BufferData = calloc(4, BufferSize); for(i = 0;i < 4;i++) { - memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR)); - data->WaveBuffer[i].dwBufferLength = BufferSize; - data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : - (data->WaveBuffer[i-1].lpData + - data->WaveBuffer[i-1].dwBufferLength)); - waveOutPrepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); - waveOutWrite(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); - IncrementRef(&data->WaveBuffersCommitted); + memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); + self->WaveBuffer[i].dwBufferLength = BufferSize; + self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : + (self->WaveBuffer[i-1].lpData + + self->WaveBuffer[i-1].dwBufferLength)); + waveOutPrepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + waveOutWrite(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); } return ALC_TRUE; } -static void WinMMStopPlayback(ALCdevice *device) +static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) { - WinMMData *data = (WinMMData*)device->ExtraData; void *buffer = NULL; int i; - if(data->killNow) + if(self->killNow) return; // Set flag to stop processing headers - data->killNow = AL_TRUE; - althrd_join(data->thread, &i); + self->killNow = AL_TRUE; + althrd_join(self->thread, &i); // Release the wave buffers for(i = 0;i < 4;i++) { - waveOutUnprepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); - if(i == 0) buffer = data->WaveBuffer[i].lpData; - data->WaveBuffer[i].lpData = NULL; + waveOutUnprepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + if(i == 0) buffer = self->WaveBuffer[i].lpData; + self->WaveBuffer[i].lpData = NULL; } free(buffer); } -static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) + +typedef struct ALCwinmmCapture { + DERIVE_FROM_TYPE(ALCbackend); + + RefCount WaveBuffersCommitted; + WAVEHDR WaveBuffer[4]; + + HWAVEIN InHdl; + + RingBuffer *Ring; + + WAVEFORMATEX Format; + + volatile ALboolean killNow; + althrd_t thread; +} ALCwinmmCapture; + +static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); +static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self); + +static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); +static int ALCwinmmCapture_captureProc(void *arg); + +static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name); +static void ALCwinmmCapture_close(ALCwinmmCapture *self); +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); +static void ALCwinmmCapture_stop(ALCwinmmCapture *self); +static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self); +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture) + +DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture); + + +static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCwinmmCapture, ALCbackend, self); + + InitRef(&self->WaveBuffersCommitted, 0); + self->InHdl = NULL; + + self->killNow = AL_TRUE; +} + +static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) { - const al_string *iter, *end; + if(self->InHdl) + waveInClose(self->InHdl); + self->InHdl = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +/* ALCwinmmCapture_waveInProc + * + * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer + * is completed and returns to the application (with more data). + */ +static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) +{ + ALCwinmmCapture *self = (ALCwinmmCapture*)instance; + + if(msg != WIM_DATA) + return; + + DecrementRef(&self->WaveBuffersCommitted); + PostThreadMessage(self->thread, msg, 0, param1); +} + +static int ALCwinmmCapture_captureProc(void *arg) +{ + ALCwinmmCapture *self = arg; + WAVEHDR *WaveHdr; + MSG msg; + + althrd_setname(althrd_current(), "alsoft-record"); + + while(GetMessage(&msg, NULL, 0, 0)) + { + if(msg.message != WIM_DATA) + continue; + /* Don't wait for other buffers to finish before quitting. We're + * closing so we don't need them. */ + if(self->killNow) + break; + + WaveHdr = ((WAVEHDR*)msg.lParam); + WriteRingBuffer(self->Ring, (ALubyte*)WaveHdr->lpData, + WaveHdr->dwBytesRecorded/self->Format.nBlockAlign); + + // Send buffer back to capture more data + waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); + } + + return 0; +} + + +static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const al_string *iter; ALbyte *BufferData = NULL; DWORD CapturedDataSize; - WinMMData *data = NULL; ALint BufferSize; UINT DeviceID; MMRESULT res; @@ -469,21 +542,15 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid - iter = VECTOR_ITER_BEGIN(CaptureDevices); - end = VECTOR_ITER_END(CaptureDevices); - for(;iter != end;iter++) - { - if(!al_string_empty(*iter) && - (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0)) - { - DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices)); - break; - } - } - if(iter == end) +#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && (!name || al_string_cmp_cstr(*iter, name) == 0)) + VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME); + if(iter == VECTOR_ITER_END(CaptureDevices)) return ALC_INVALID_VALUE; +#undef MATCH_DEVNAME + + DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices)); - switch(Device->FmtChans) + switch(device->FmtChans) { case DevFmtMono: case DevFmtStereo: @@ -497,7 +564,7 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) return ALC_INVALID_ENUM; } - switch(Device->FmtType) + switch(device->FmtType) { case DevFmtUByte: case DevFmtShort: @@ -511,147 +578,134 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) return ALC_INVALID_ENUM; } - data = calloc(1, sizeof(*data)); - if(!data) - return ALC_OUT_OF_MEMORY; - Device->ExtraData = data; - - memset(&data->Format, 0, sizeof(WAVEFORMATEX)); - data->Format.wFormatTag = ((Device->FmtType == DevFmtFloat) ? + memset(&self->Format, 0, sizeof(WAVEFORMATEX)); + self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); - data->Format.nChannels = ChannelsFromDevFmt(Device->FmtChans); - data->Format.wBitsPerSample = BytesFromDevFmt(Device->FmtType) * 8; - data->Format.nBlockAlign = data->Format.wBitsPerSample * - data->Format.nChannels / 8; - data->Format.nSamplesPerSec = Device->Frequency; - data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec * - data->Format.nBlockAlign; - data->Format.cbSize = 0; - - if((res=waveInOpen(&data->WaveHandle.In, DeviceID, &data->Format, (DWORD_PTR)&WaveInProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans); + self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + self->Format.nBlockAlign = self->Format.wBitsPerSample * + self->Format.nChannels / 8; + self->Format.nSamplesPerSec = device->Frequency; + self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * + self->Format.nBlockAlign; + self->Format.cbSize = 0; + + if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); goto failure; } // Allocate circular memory buffer for the captured audio - CapturedDataSize = Device->UpdateSize*Device->NumUpdates; + CapturedDataSize = device->UpdateSize*device->NumUpdates; // Make sure circular buffer is at least 100ms in size - if(CapturedDataSize < (data->Format.nSamplesPerSec / 10)) - CapturedDataSize = data->Format.nSamplesPerSec / 10; + if(CapturedDataSize < (self->Format.nSamplesPerSec / 10)) + CapturedDataSize = self->Format.nSamplesPerSec / 10; - data->Ring = CreateRingBuffer(data->Format.nBlockAlign, CapturedDataSize); - if(!data->Ring) - goto failure; + self->Ring = CreateRingBuffer(self->Format.nBlockAlign, CapturedDataSize); + if(!self->Ring) goto failure; - InitRef(&data->WaveBuffersCommitted, 0); + InitRef(&self->WaveBuffersCommitted, 0); // Create 4 Buffers of 50ms each - BufferSize = data->Format.nAvgBytesPerSec / 20; - BufferSize -= (BufferSize % data->Format.nBlockAlign); + BufferSize = self->Format.nAvgBytesPerSec / 20; + BufferSize -= (BufferSize % self->Format.nBlockAlign); BufferData = calloc(4, BufferSize); - if(!BufferData) - goto failure; + if(!BufferData) goto failure; for(i = 0;i < 4;i++) { - memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR)); - data->WaveBuffer[i].dwBufferLength = BufferSize; - data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : - (data->WaveBuffer[i-1].lpData + - data->WaveBuffer[i-1].dwBufferLength)); - data->WaveBuffer[i].dwFlags = 0; - data->WaveBuffer[i].dwLoops = 0; - waveInPrepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); - waveInAddBuffer(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); - IncrementRef(&data->WaveBuffersCommitted); + memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); + self->WaveBuffer[i].dwBufferLength = BufferSize; + self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : + (self->WaveBuffer[i-1].lpData + + self->WaveBuffer[i-1].dwBufferLength)); + self->WaveBuffer[i].dwFlags = 0; + self->WaveBuffer[i].dwLoops = 0; + waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); } - if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success) + self->killNow = AL_FALSE; + if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success) goto failure; - al_string_copy(&Device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); + al_string_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); return ALC_NO_ERROR; failure: if(BufferData) { for(i = 0;i < 4;i++) - waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); + waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); free(BufferData); } - if(data->Ring) - DestroyRingBuffer(data->Ring); + if(self->Ring) + DestroyRingBuffer(self->Ring); + self->Ring = NULL; - if(data->WaveHandle.In) - waveInClose(data->WaveHandle.In); + if(self->InHdl) + waveInClose(self->InHdl); + self->InHdl = NULL; - free(data); - Device->ExtraData = NULL; return ALC_INVALID_VALUE; } -static void WinMMCloseCapture(ALCdevice *Device) +static void ALCwinmmCapture_close(ALCwinmmCapture *self) { - WinMMData *data = (WinMMData*)Device->ExtraData; void *buffer = NULL; int i; /* Tell the processing thread to quit and wait for it to do so. */ - data->killNow = AL_TRUE; - PostThreadMessage(data->thread, WM_QUIT, 0, 0); + self->killNow = AL_TRUE; + PostThreadMessage(self->thread, WM_QUIT, 0, 0); - althrd_join(data->thread, &i); + althrd_join(self->thread, &i); /* Make sure capture is stopped and all pending buffers are flushed. */ - waveInReset(data->WaveHandle.In); + waveInReset(self->InHdl); // Release the wave buffers for(i = 0;i < 4;i++) { - waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); - if(i == 0) buffer = data->WaveBuffer[i].lpData; - data->WaveBuffer[i].lpData = NULL; + waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + if(i == 0) buffer = self->WaveBuffer[i].lpData; + self->WaveBuffer[i].lpData = NULL; } free(buffer); - DestroyRingBuffer(data->Ring); - data->Ring = NULL; + DestroyRingBuffer(self->Ring); + self->Ring = NULL; // Close the Wave device - waveInClose(data->WaveHandle.In); - data->WaveHandle.In = 0; - - free(data); - Device->ExtraData = NULL; + waveInClose(self->InHdl); + self->InHdl = NULL; } -static void WinMMStartCapture(ALCdevice *Device) +static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) { - WinMMData *data = (WinMMData*)Device->ExtraData; - waveInStart(data->WaveHandle.In); + waveInStart(self->InHdl); + return ALC_TRUE; } -static void WinMMStopCapture(ALCdevice *Device) +static void ALCwinmmCapture_stop(ALCwinmmCapture *self) { - WinMMData *data = (WinMMData*)Device->ExtraData; - waveInStop(data->WaveHandle.In); + waveInStop(self->InHdl); } -static ALCenum WinMMCaptureSamples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples) +static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) { - WinMMData *data = (WinMMData*)Device->ExtraData; - ReadRingBuffer(data->Ring, Buffer, Samples); + ReadRingBuffer(self->Ring, buffer, samples); return ALC_NO_ERROR; } -static ALCuint WinMMAvailableSamples(ALCdevice *Device) +static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) { - WinMMData *data = (WinMMData*)Device->ExtraData; - return RingBufferSize(data->Ring); + return RingBufferSize(self->Ring); } @@ -666,31 +720,29 @@ static inline void AppendCaptureDeviceList2(const al_string *name) AppendCaptureDeviceList(al_string_get_cstr(*name)); } -static const BackendFuncs WinMMFuncs = { - WinMMOpenPlayback, - WinMMClosePlayback, - WinMMResetPlayback, - WinMMStartPlayback, - WinMMStopPlayback, - WinMMOpenCapture, - WinMMCloseCapture, - WinMMStartCapture, - WinMMStopCapture, - WinMMCaptureSamples, - WinMMAvailableSamples, - ALCdevice_GetLatencyDefault -}; - -ALCboolean alcWinMMInit(BackendFuncs *FuncList) +typedef struct ALCwinmmBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCwinmmBackendFactory; +#define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } } + +static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self); +static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self); +static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type); +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type); +static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type); + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory); + + +static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory* UNUSED(self)) { VECTOR_INIT(PlaybackDevices); VECTOR_INIT(CaptureDevices); - *FuncList = WinMMFuncs; return ALC_TRUE; } -void alcWinMMDeinit() +static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory* UNUSED(self)) { clear_devlist(&PlaybackDevices); VECTOR_DEINIT(PlaybackDevices); @@ -699,7 +751,14 @@ void alcWinMMDeinit() VECTOR_DEINIT(CaptureDevices); } -void alcWinMMProbe(enum DevProbe type) +static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type) { switch(type) { @@ -714,3 +773,39 @@ void alcWinMMProbe(enum DevProbe type) break; } } + +static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCwinmmPlayback *backend; + + backend = ALCwinmmPlayback_New(sizeof(*backend)); + if(!backend) return NULL; + memset(backend, 0, sizeof(*backend)); + + ALCwinmmPlayback_Construct(backend, device); + + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCwinmmCapture *backend; + + backend = ALCwinmmCapture_New(sizeof(*backend)); + if(!backend) return NULL; + memset(backend, 0, sizeof(*backend)); + + ALCwinmmCapture_Construct(backend, device); + + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void) +{ + static ALCwinmmBackendFactory factory = ALCWINMMBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} |