aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/backends/qsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'Alc/backends/qsa.c')
-rw-r--r--Alc/backends/qsa.c415
1 files changed, 283 insertions, 132 deletions
diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c
index 291e49fc..81645096 100644
--- a/Alc/backends/qsa.c
+++ b/Alc/backends/qsa.c
@@ -33,6 +33,8 @@
#include "alu.h"
#include "threads.h"
+#include "backends/base.h"
+
typedef struct {
snd_pcm_t* pcmHandle;
@@ -44,7 +46,7 @@ typedef struct {
ALvoid* buffer;
ALsizei size;
- volatile int killNow;
+ ATOMIC(ALenum) killNow;
althrd_t thread;
} qsa_data;
@@ -117,8 +119,10 @@ static void deviceList(int type, vector_DevMap *devmap)
if(max_cards < 0)
return;
- VECTOR_RESERVE(*devmap, max_cards+1);
- VECTOR_RESIZE(*devmap, 0);
+#define FREE_NAME(iter) free((iter)->name)
+ VECTOR_FOR_EACH(DevMap, *devmap, FREE_NAME);
+#undef FREE_NAME
+ VECTOR_RESIZE(*devmap, 0, max_cards+1);
entry.name = strdup(qsaDevice);
entry.card = 0;
@@ -158,17 +162,39 @@ static void deviceList(int type, vector_DevMap *devmap)
}
-FORCE_ALIGN static int qsa_proc_playback(void* ptr)
+/* Wrappers to use an old-style backend with the new interface. */
+typedef struct PlaybackWrapper {
+ DERIVE_FROM_TYPE(ALCbackend);
+ qsa_data *ExtraData;
+} PlaybackWrapper;
+
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device);
+static void PlaybackWrapper_Destruct(PlaybackWrapper *self);
+static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name);
+static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self);
+static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self);
+static void PlaybackWrapper_stop(PlaybackWrapper *self);
+static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
+DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper);
+
+
+FORCE_ALIGN static int qsa_proc_playback(void *ptr)
{
- ALCdevice* device=(ALCdevice*)ptr;
- qsa_data* data=(qsa_data*)device->ExtraData;
- char* write_ptr;
- int avail;
+ PlaybackWrapper *self = ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ qsa_data *data = self->ExtraData;
snd_pcm_channel_status_t status;
struct sched_param param;
- fd_set wfds;
- int selectret;
struct timeval timeout;
+ char* write_ptr;
+ fd_set wfds;
+ ALint len;
+ int sret;
SetRTPriority();
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
@@ -178,72 +204,69 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr)
param.sched_priority=param.sched_curpriority+1;
SchedSet(0, 0, SCHED_NOCHANGE, &param);
- ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ const ALint frame_size = FrameSizeFromDevFmt(
+ device->FmtChans, device->FmtType, device->AmbiOrder
+ );
- while (!data->killNow)
+ V0(device->Backend,lock)();
+ while(!ATOMIC_LOAD(&data->killNow, almemory_order_acquire))
{
- ALint len=data->size;
- write_ptr=data->buffer;
-
- avail=len/frame_size;
- aluMixData(device, write_ptr, avail);
+ FD_ZERO(&wfds);
+ FD_SET(data->audio_fd, &wfds);
+ timeout.tv_sec=2;
+ timeout.tv_usec=0;
- while (len>0 && !data->killNow)
+ /* Select also works like time slice to OS */
+ V0(device->Backend,unlock)();
+ sret = select(data->audio_fd+1, NULL, &wfds, NULL, &timeout);
+ V0(device->Backend,lock)();
+ if(sret == -1)
{
- FD_ZERO(&wfds);
- FD_SET(data->audio_fd, &wfds);
- timeout.tv_sec=2;
- timeout.tv_usec=0;
-
- /* Select also works like time slice to OS */
- selectret=select(data->audio_fd+1, NULL, &wfds, NULL, &timeout);
- switch (selectret)
- {
- case -1:
- aluHandleDisconnect(device);
- return 1;
- case 0:
- break;
- default:
- if (FD_ISSET(data->audio_fd, &wfds))
- {
- break;
- }
- break;
- }
-
- int wrote=snd_pcm_plugin_write(data->pcmHandle, write_ptr, len);
+ ERR("select error: %s\n", strerror(errno));
+ aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno));
+ break;
+ }
+ if(sret == 0)
+ {
+ ERR("select timeout\n");
+ continue;
+ }
- if (wrote<=0)
+ len = data->size;
+ write_ptr = data->buffer;
+ aluMixData(device, write_ptr, len/frame_size);
+ while(len>0 && !ATOMIC_LOAD(&data->killNow, almemory_order_acquire))
+ {
+ int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len);
+ if(wrote <= 0)
{
- if ((errno==EAGAIN) || (errno==EWOULDBLOCK))
- {
+ if(errno==EAGAIN || errno==EWOULDBLOCK)
continue;
- }
- memset(&status, 0, sizeof (status));
- status.channel=SND_PCM_CHANNEL_PLAYBACK;
+ memset(&status, 0, sizeof(status));
+ status.channel = SND_PCM_CHANNEL_PLAYBACK;
snd_pcm_plugin_status(data->pcmHandle, &status);
/* we need to reinitialize the sound channel if we've underrun the buffer */
- if ((status.status==SND_PCM_STATUS_UNDERRUN) ||
- (status.status==SND_PCM_STATUS_READY))
+ if(status.status == SND_PCM_STATUS_UNDERRUN ||
+ status.status == SND_PCM_STATUS_READY)
{
- if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0)
+ if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0)
{
- aluHandleDisconnect(device);
+ aluHandleDisconnect(device, "Playback recovery failed");
break;
}
}
}
else
{
- write_ptr+=wrote;
- len-=wrote;
+ write_ptr += wrote;
+ len -= wrote;
}
}
}
+ V0(device->Backend,unlock)();
return 0;
}
@@ -252,8 +275,9 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr)
/* Playback */
/************/
-static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
+static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName)
{
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
qsa_data *data;
int card, dev;
int status;
@@ -261,6 +285,7 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
data = (qsa_data*)calloc(1, sizeof(qsa_data));
if(data == NULL)
return ALC_OUT_OF_MEMORY;
+ ATOMIC_INIT(&data->killNow, AL_TRUE);
if(!deviceName)
deviceName = qsaDevice;
@@ -277,7 +302,7 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME);
#undef MATCH_DEVNAME
- if(iter == VECTOR_ITER_END(DeviceNameMap))
+ if(iter == VECTOR_END(DeviceNameMap))
{
free(data);
return ALC_INVALID_DEVICE;
@@ -300,15 +325,15 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
return ALC_INVALID_DEVICE;
}
- al_string_copy_cstr(&device->DeviceName, deviceName);
- device->ExtraData = data;
+ alstr_copy_cstr(&device->DeviceName, deviceName);
+ self->ExtraData = data;
return ALC_NO_ERROR;
}
-static void qsa_close_playback(ALCdevice* device)
+static void qsa_close_playback(PlaybackWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
if (data->buffer!=NULL)
{
@@ -319,12 +344,13 @@ static void qsa_close_playback(ALCdevice* device)
snd_pcm_close(data->pcmHandle);
free(data);
- device->ExtraData=NULL;
+ self->ExtraData = NULL;
}
-static ALCboolean qsa_reset_playback(ALCdevice* device)
+static ALCboolean qsa_reset_playback(PlaybackWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ qsa_data *data = self->ExtraData;
int32_t format=-1;
switch(device->FmtType)
@@ -365,14 +391,14 @@ static ALCboolean qsa_reset_playback(ALCdevice* device)
data->cparams.start_mode=SND_PCM_START_FULL;
data->cparams.stop_mode=SND_PCM_STOP_STOP;
- data->cparams.buf.block.frag_size=device->UpdateSize*
- ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType);
+ data->cparams.buf.block.frag_size=device->UpdateSize *
+ FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
data->cparams.buf.block.frags_max=device->NumUpdates;
data->cparams.buf.block.frags_min=device->NumUpdates;
data->cparams.format.interleave=1;
data->cparams.format.rate=device->Frequency;
- data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
+ data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
data->cparams.format.format=format;
if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
@@ -556,7 +582,7 @@ static ALCboolean qsa_reset_playback(ALCdevice* device)
SetDefaultChannelOrder(device);
device->UpdateSize=data->csetup.buf.block.frag_size/
- (ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType));
+ FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
device->NumUpdates=data->csetup.buf.block.frags;
data->size=data->csetup.buf.block.frag_size;
@@ -569,35 +595,93 @@ static ALCboolean qsa_reset_playback(ALCdevice* device)
return ALC_TRUE;
}
-static ALCboolean qsa_start_playback(ALCdevice* device)
+static ALCboolean qsa_start_playback(PlaybackWrapper *self)
{
- qsa_data *data = (qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
- data->killNow = 0;
- if(althrd_create(&data->thread, qsa_proc_playback, device) != althrd_success)
+ ATOMIC_STORE(&data->killNow, AL_FALSE, almemory_order_release);
+ if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
-static void qsa_stop_playback(ALCdevice* device)
+static void qsa_stop_playback(PlaybackWrapper *self)
{
- qsa_data *data = (qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
int res;
- if(data->killNow)
+ if(ATOMIC_EXCHANGE(&data->killNow, AL_TRUE, almemory_order_acq_rel))
return;
-
- data->killNow = 1;
althrd_join(data->thread, &res);
}
+
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(PlaybackWrapper, ALCbackend, self);
+
+ self->ExtraData = NULL;
+}
+
+static void PlaybackWrapper_Destruct(PlaybackWrapper *self)
+{
+ if(self->ExtraData)
+ qsa_close_playback(self);
+
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name)
+{
+ return qsa_open_playback(self, name);
+}
+
+static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self)
+{
+ return qsa_reset_playback(self);
+}
+
+static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self)
+{
+ return qsa_start_playback(self);
+}
+
+static void PlaybackWrapper_stop(PlaybackWrapper *self)
+{
+ qsa_stop_playback(self);
+}
+
+
+
/***********/
/* Capture */
/***********/
-static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
+typedef struct CaptureWrapper {
+ DERIVE_FROM_TYPE(ALCbackend);
+ qsa_data *ExtraData;
+} CaptureWrapper;
+
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device);
+static void CaptureWrapper_Destruct(CaptureWrapper *self);
+static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset)
+static ALCboolean CaptureWrapper_start(CaptureWrapper *self);
+static void CaptureWrapper_stop(CaptureWrapper *self);
+static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples);
+static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper)
+DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
+
+
+static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName)
{
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
qsa_data *data;
int card, dev;
int format=-1;
@@ -624,7 +708,7 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME);
#undef MATCH_DEVNAME
- if(iter == VECTOR_ITER_END(CaptureNameMap))
+ if(iter == VECTOR_END(CaptureNameMap))
{
free(data);
return ALC_INVALID_DEVICE;
@@ -647,8 +731,8 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
return ALC_INVALID_DEVICE;
}
- al_string_copy_cstr(&device->DeviceName, deviceName);
- device->ExtraData = data;
+ alstr_copy_cstr(&device->DeviceName, deviceName);
+ self->ExtraData = data;
switch (device->FmtType)
{
@@ -688,20 +772,19 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
data->cparams.stop_mode=SND_PCM_STOP_STOP;
data->cparams.buf.block.frag_size=device->UpdateSize*
- ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType);
+ FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
data->cparams.buf.block.frags_max=device->NumUpdates;
data->cparams.buf.block.frags_min=device->NumUpdates;
data->cparams.format.interleave=1;
data->cparams.format.rate=device->Frequency;
- data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
+ data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
data->cparams.format.format=format;
if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0)
{
snd_pcm_close(data->pcmHandle);
free(data);
- device->ExtraData=NULL;
return ALC_INVALID_VALUE;
}
@@ -709,20 +792,20 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
return ALC_NO_ERROR;
}
-static void qsa_close_capture(ALCdevice* device)
+static void qsa_close_capture(CaptureWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
if (data->pcmHandle!=NULL)
snd_pcm_close(data->pcmHandle);
free(data);
- device->ExtraData=NULL;
+ self->ExtraData = NULL;
}
-static void qsa_start_capture(ALCdevice* device)
+static void qsa_start_capture(CaptureWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
int rstatus;
if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
@@ -742,18 +825,18 @@ static void qsa_start_capture(ALCdevice* device)
snd_pcm_capture_go(data->pcmHandle);
}
-static void qsa_stop_capture(ALCdevice* device)
+static void qsa_stop_capture(CaptureWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
-
+ qsa_data *data = self->ExtraData;
snd_pcm_capture_flush(data->pcmHandle);
}
-static ALCuint qsa_available_samples(ALCdevice* device)
+static ALCuint qsa_available_samples(CaptureWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ qsa_data *data = self->ExtraData;
snd_pcm_channel_status_t status;
- ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
ALint free_size;
int rstatus;
@@ -766,7 +849,7 @@ static ALCuint qsa_available_samples(ALCdevice* device)
if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
{
ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
- aluHandleDisconnect(device);
+ aluHandleDisconnect(device, "Failed capture recovery: %s", snd_strerror(rstatus));
return 0;
}
@@ -780,16 +863,17 @@ static ALCuint qsa_available_samples(ALCdevice* device)
return free_size/frame_size;
}
-static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ qsa_data *data = self->ExtraData;
char* read_ptr;
snd_pcm_channel_status_t status;
fd_set rfds;
int selectret;
struct timeval timeout;
int bytes_read;
- ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
ALint len=samples*frame_size;
int rstatus;
@@ -808,7 +892,7 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
switch (selectret)
{
case -1:
- aluHandleDisconnect(device);
+ aluHandleDisconnect(device, "Failed to check capture samples");
return ALC_INVALID_DEVICE;
case 0:
break;
@@ -839,7 +923,8 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
{
ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
- aluHandleDisconnect(device);
+ aluHandleDisconnect(device, "Failed capture recovery: %s",
+ snd_strerror(rstatus));
return ALC_INVALID_DEVICE;
}
snd_pcm_capture_go(data->pcmHandle);
@@ -855,27 +940,68 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
return ALC_NO_ERROR;
}
-static const BackendFuncs qsa_funcs= {
- qsa_open_playback,
- qsa_close_playback,
- qsa_reset_playback,
- qsa_start_playback,
- qsa_stop_playback,
- qsa_open_capture,
- qsa_close_capture,
- qsa_start_capture,
- qsa_stop_capture,
- qsa_capture_samples,
- qsa_available_samples
-};
-ALCboolean alc_qsa_init(BackendFuncs* func_list)
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(CaptureWrapper, ALCbackend, self);
+
+ self->ExtraData = NULL;
+}
+
+static void CaptureWrapper_Destruct(CaptureWrapper *self)
+{
+ if(self->ExtraData)
+ qsa_close_capture(self);
+
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name)
+{
+ return qsa_open_capture(self, name);
+}
+
+static ALCboolean CaptureWrapper_start(CaptureWrapper *self)
{
- *func_list = qsa_funcs;
+ qsa_start_capture(self);
return ALC_TRUE;
}
-void alc_qsa_deinit(void)
+static void CaptureWrapper_stop(CaptureWrapper *self)
+{
+ qsa_stop_capture(self);
+}
+
+static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples)
+{
+ return qsa_capture_samples(self, buffer, samples);
+}
+
+static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
+{
+ return qsa_available_samples(self);
+}
+
+
+typedef struct ALCqsaBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCqsaBackendFactory;
+#define ALCQSABACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCqsaBackendFactory, ALCbackendFactory) } }
+
+static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self));
+static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self));
+static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type);
+static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames);
+static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory);
+
+static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self))
+{
+ return ALC_TRUE;
+}
+
+static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self))
{
#define FREE_NAME(iter) free((iter)->name)
VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
@@ -886,32 +1012,57 @@ void alc_qsa_deinit(void)
#undef FREE_NAME
}
-void alc_qsa_probe(enum DevProbe type)
+static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
{
switch (type)
{
+#define APPEND_OUTNAME(e) do { \
+ const char *n_ = (e)->name; \
+ if(n_ && n_[0]) \
+ alstr_append_range(outnames, n_, n_+strlen(n_)+1); \
+} while(0)
case ALL_DEVICE_PROBE:
-#define FREE_NAME(iter) free((iter)->name)
- VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
-#undef FREE_NAME
- VECTOR_RESIZE(DeviceNameMap, 0);
-
deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
-#define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name)
- VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_DEVICE);
-#undef APPEND_DEVICE
+ VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_OUTNAME);
break;
case CAPTURE_DEVICE_PROBE:
-#define FREE_NAME(iter) free((iter)->name)
- VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME);
-#undef FREE_NAME
- VECTOR_RESIZE(CaptureNameMap, 0);
-
deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
-#define APPEND_DEVICE(iter) AppendCaptureDeviceList((iter)->name)
- VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_DEVICE);
-#undef APPEND_DEVICE
+ VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_OUTNAME);
break;
+#undef APPEND_OUTNAME
+ }
+}
+
+static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ PlaybackWrapper *backend;
+ NEW_OBJ(backend, PlaybackWrapper)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
}
+ if(type == ALCbackend_Capture)
+ {
+ CaptureWrapper *backend;
+ NEW_OBJ(backend, CaptureWrapper)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
+
+ALCbackendFactory *ALCqsaBackendFactory_getFactory(void)
+{
+ static ALCqsaBackendFactory factory = ALCQSABACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
}