aboutsummaryrefslogtreecommitdiffstats
path: root/Alc
diff options
context:
space:
mode:
Diffstat (limited to 'Alc')
-rw-r--r--Alc/ALc.c2
-rw-r--r--Alc/backends/base.h1
-rw-r--r--Alc/backends/winmm.c665
3 files changed, 382 insertions, 286 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index ae31ad87..5697017d 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -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);
+}