Convert the PortAudio backend to the new backend API

This commit is contained in:
Chris Robinson 2015-10-22 10:46:36 -07:00
parent 6689c61ff4
commit 6fc8cd3b29
4 changed files with 259 additions and 156 deletions

View File

@ -93,7 +93,7 @@ static struct BackendInfo BackendList[] = {
{ "winmm", ALCwinmmBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, { "winmm", ALCwinmmBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif #endif
#ifdef HAVE_PORTAUDIO #ifdef HAVE_PORTAUDIO
{ "port", NULL, alc_pa_init, alc_pa_deinit, alc_pa_probe, EmptyFuncs }, { "port", ALCportBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif #endif
#ifdef HAVE_OPENSL #ifdef HAVE_OPENSL
{ "opensl", NULL, alc_opensl_init, alc_opensl_deinit, alc_opensl_probe, EmptyFuncs }, { "opensl", NULL, alc_opensl_init, alc_opensl_deinit, alc_opensl_probe, EmptyFuncs },

View File

@ -128,6 +128,7 @@ ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void); ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void);
ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void);
ALCbackendFactory *ALCportBackendFactory_getFactory(void);
ALCbackendFactory *ALCnullBackendFactory_getFactory(void); ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
ALCbackendFactory *ALCloopbackFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void);

View File

@ -28,6 +28,8 @@
#include "alu.h" #include "alu.h"
#include "compat.h" #include "compat.h"
#include "backends/base.h"
#include <portaudio.h> #include <portaudio.h>
@ -122,149 +124,171 @@ static ALCboolean pa_load(void)
} }
typedef struct { typedef struct ALCportPlayback {
DERIVE_FROM_TYPE(ALCbackend);
PaStream *stream; PaStream *stream;
PaStreamParameters params; PaStreamParameters params;
ALuint update_size; ALuint update_size;
} ALCportPlayback;
RingBuffer *ring; static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer,
} pa_data; unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
const PaStreamCallbackFlags statusFlags, void *userData);
static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device);
static void ALCportPlayback_Destruct(ALCportPlayback *self);
static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name);
static void ALCportPlayback_close(ALCportPlayback *self);
static ALCboolean ALCportPlayback_reset(ALCportPlayback *self);
static ALCboolean ALCportPlayback_start(ALCportPlayback *self);
static void ALCportPlayback_stop(ALCportPlayback *self);
static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback)
DEFINE_ALCBACKEND_VTABLE(ALCportPlayback);
static int pa_callback(const void *UNUSED(inputBuffer), void *outputBuffer, static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device)
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{ {
ALCdevice *device = (ALCdevice*)userData; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCportPlayback, ALCbackend, self);
aluMixData(device, outputBuffer, framesPerBuffer); self->stream = NULL;
return 0;
} }
static int pa_capture_cb(const void *inputBuffer, void *UNUSED(outputBuffer), static void ALCportPlayback_Destruct(ALCportPlayback *self)
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{ {
ALCdevice *device = (ALCdevice*)userData; if(self->stream)
pa_data *data = (pa_data*)device->ExtraData; Pa_CloseStream(self->stream);
self->stream = NULL;
WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
ALCportPlayback *self = userData;
aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer);
return 0; return 0;
} }
static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName) static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name)
{ {
pa_data *data; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
PaError err; PaError err;
if(!deviceName) if(!name)
deviceName = pa_device; name = pa_device;
else if(strcmp(deviceName, pa_device) != 0) else if(strcmp(name, pa_device) != 0)
return ALC_INVALID_VALUE; return ALC_INVALID_VALUE;
data = (pa_data*)calloc(1, sizeof(pa_data)); self->update_size = device->UpdateSize;
data->update_size = device->UpdateSize;
data->params.device = -1; self->params.device = -1;
if(!ConfigValueInt(NULL, "port", "device", &data->params.device) || if(!ConfigValueInt(NULL, "port", "device", &self->params.device) ||
data->params.device < 0) self->params.device < 0)
data->params.device = Pa_GetDefaultOutputDevice(); self->params.device = Pa_GetDefaultOutputDevice();
data->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) / self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
(float)device->Frequency; (float)device->Frequency;
data->params.hostApiSpecificStreamInfo = NULL; self->params.hostApiSpecificStreamInfo = NULL;
data->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
switch(device->FmtType) switch(device->FmtType)
{ {
case DevFmtByte: case DevFmtByte:
data->params.sampleFormat = paInt8; self->params.sampleFormat = paInt8;
break; break;
case DevFmtUByte: case DevFmtUByte:
data->params.sampleFormat = paUInt8; self->params.sampleFormat = paUInt8;
break; break;
case DevFmtUShort: case DevFmtUShort:
/* fall-through */ /* fall-through */
case DevFmtShort: case DevFmtShort:
data->params.sampleFormat = paInt16; self->params.sampleFormat = paInt16;
break; break;
case DevFmtUInt: case DevFmtUInt:
/* fall-through */ /* fall-through */
case DevFmtInt: case DevFmtInt:
data->params.sampleFormat = paInt32; self->params.sampleFormat = paInt32;
break; break;
case DevFmtFloat: case DevFmtFloat:
data->params.sampleFormat = paFloat32; self->params.sampleFormat = paFloat32;
break; break;
} }
retry_open: retry_open:
err = Pa_OpenStream(&data->stream, NULL, &data->params, device->Frequency, err = Pa_OpenStream(&self->stream, NULL, &self->params,
device->UpdateSize, paNoFlag, pa_callback, device); device->Frequency, device->UpdateSize, paNoFlag,
ALCportPlayback_WriteCallback, self
);
if(err != paNoError) if(err != paNoError)
{ {
if(data->params.sampleFormat == paFloat32) if(self->params.sampleFormat == paFloat32)
{ {
data->params.sampleFormat = paInt16; self->params.sampleFormat = paInt16;
goto retry_open; goto retry_open;
} }
ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
free(data);
return ALC_INVALID_VALUE; return ALC_INVALID_VALUE;
} }
device->ExtraData = data; al_string_copy_cstr(&device->DeviceName, name);
al_string_copy_cstr(&device->DeviceName, deviceName);
return ALC_NO_ERROR; return ALC_NO_ERROR;
} }
static void pa_close_playback(ALCdevice *device) static void ALCportPlayback_close(ALCportPlayback *self)
{ {
pa_data *data = (pa_data*)device->ExtraData; PaError err = Pa_CloseStream(self->stream);
PaError err;
err = Pa_CloseStream(data->stream);
if(err != paNoError) if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
self->stream = NULL;
free(data);
device->ExtraData = NULL;
} }
static ALCboolean pa_reset_playback(ALCdevice *device) static ALCboolean ALCportPlayback_reset(ALCportPlayback *self)
{ {
pa_data *data = (pa_data*)device->ExtraData; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const PaStreamInfo *streamInfo; const PaStreamInfo *streamInfo;
streamInfo = Pa_GetStreamInfo(data->stream); streamInfo = Pa_GetStreamInfo(self->stream);
device->Frequency = streamInfo->sampleRate; device->Frequency = streamInfo->sampleRate;
device->UpdateSize = data->update_size; device->UpdateSize = self->update_size;
if(data->params.sampleFormat == paInt8) if(self->params.sampleFormat == paInt8)
device->FmtType = DevFmtByte; device->FmtType = DevFmtByte;
else if(data->params.sampleFormat == paUInt8) else if(self->params.sampleFormat == paUInt8)
device->FmtType = DevFmtUByte; device->FmtType = DevFmtUByte;
else if(data->params.sampleFormat == paInt16) else if(self->params.sampleFormat == paInt16)
device->FmtType = DevFmtShort; device->FmtType = DevFmtShort;
else if(data->params.sampleFormat == paInt32) else if(self->params.sampleFormat == paInt32)
device->FmtType = DevFmtInt; device->FmtType = DevFmtInt;
else if(data->params.sampleFormat == paFloat32) else if(self->params.sampleFormat == paFloat32)
device->FmtType = DevFmtFloat; device->FmtType = DevFmtFloat;
else else
{ {
ERR("Unexpected sample format: 0x%lx\n", data->params.sampleFormat); ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat);
return ALC_FALSE; return ALC_FALSE;
} }
if(data->params.channelCount == 2) if(self->params.channelCount == 2)
device->FmtChans = DevFmtStereo; device->FmtChans = DevFmtStereo;
else if(data->params.channelCount == 1) else if(self->params.channelCount == 1)
device->FmtChans = DevFmtMono; device->FmtChans = DevFmtMono;
else else
{ {
ERR("Unexpected channel count: %u\n", data->params.channelCount); ERR("Unexpected channel count: %u\n", self->params.channelCount);
return ALC_FALSE; return ALC_FALSE;
} }
SetDefaultChannelOrder(device); SetDefaultChannelOrder(device);
@ -272,12 +296,11 @@ static ALCboolean pa_reset_playback(ALCdevice *device)
return ALC_TRUE; return ALC_TRUE;
} }
static ALCboolean pa_start_playback(ALCdevice *device) static ALCboolean ALCportPlayback_start(ALCportPlayback *self)
{ {
pa_data *data = (pa_data*)device->ExtraData;
PaError err; PaError err;
err = Pa_StartStream(data->stream); err = Pa_StartStream(self->stream);
if(err != paNoError) if(err != paNoError)
{ {
ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err));
@ -287,160 +310,209 @@ static ALCboolean pa_start_playback(ALCdevice *device)
return ALC_TRUE; return ALC_TRUE;
} }
static void pa_stop_playback(ALCdevice *device) static void ALCportPlayback_stop(ALCportPlayback *self)
{ {
pa_data *data = (pa_data*)device->ExtraData; PaError err = Pa_StopStream(self->stream);
PaError err;
err = Pa_StopStream(data->stream);
if(err != paNoError) if(err != paNoError)
ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
} }
static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName) typedef struct ALCportCapture {
DERIVE_FROM_TYPE(ALCbackend);
PaStream *stream;
PaStreamParameters params;
ll_ringbuffer_t *ring;
} ALCportCapture;
static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
const PaStreamCallbackFlags statusFlags, void *userData);
static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device);
static void ALCportCapture_Destruct(ALCportCapture *self);
static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name);
static void ALCportCapture_close(ALCportCapture *self);
static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset)
static ALCboolean ALCportCapture_start(ALCportCapture *self);
static void ALCportCapture_stop(ALCportCapture *self);
static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCportCapture_availableSamples(ALCportCapture *self);
static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCportCapture)
DEFINE_ALCBACKEND_VTABLE(ALCportCapture);
static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device)
{ {
ALuint frame_size; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
pa_data *data; SET_VTABLE2(ALCportCapture, ALCbackend, self);
self->stream = NULL;
}
static void ALCportCapture_Destruct(ALCportCapture *self)
{
if(self->stream)
Pa_CloseStream(self->stream);
self->stream = NULL;
if(self->ring)
ll_ringbuffer_free(self->ring);
self->ring = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer),
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
ALCportCapture *self = userData;
size_t writable = ll_ringbuffer_write_space(self->ring);
if(framesPerBuffer > writable)
framesPerBuffer = writable;
ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer);
return 0;
}
static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALuint samples, frame_size;
PaError err; PaError err;
if(!deviceName) if(!name)
deviceName = pa_device; name = pa_device;
else if(strcmp(deviceName, pa_device) != 0) else if(strcmp(name, pa_device) != 0)
return ALC_INVALID_VALUE; return ALC_INVALID_VALUE;
data = (pa_data*)calloc(1, sizeof(pa_data)); samples = device->UpdateSize * device->NumUpdates;
if(data == NULL) samples = maxu(samples, 100 * device->Frequency / 1000);
return ALC_OUT_OF_MEMORY;
frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates);
if(data->ring == NULL)
goto error;
data->params.device = -1; self->ring = ll_ringbuffer_create(samples, frame_size);
if(!ConfigValueInt(NULL, "port", "capture", &data->params.device) || if(self->ring == NULL) return ALC_INVALID_VALUE;
data->params.device < 0)
data->params.device = Pa_GetDefaultInputDevice(); self->params.device = -1;
data->params.suggestedLatency = 0.0f; if(!ConfigValueInt(NULL, "port", "capture", &self->params.device) ||
data->params.hostApiSpecificStreamInfo = NULL; self->params.device < 0)
self->params.device = Pa_GetDefaultInputDevice();
self->params.suggestedLatency = 0.0f;
self->params.hostApiSpecificStreamInfo = NULL;
switch(device->FmtType) switch(device->FmtType)
{ {
case DevFmtByte: case DevFmtByte:
data->params.sampleFormat = paInt8; self->params.sampleFormat = paInt8;
break; break;
case DevFmtUByte: case DevFmtUByte:
data->params.sampleFormat = paUInt8; self->params.sampleFormat = paUInt8;
break; break;
case DevFmtShort: case DevFmtShort:
data->params.sampleFormat = paInt16; self->params.sampleFormat = paInt16;
break; break;
case DevFmtInt: case DevFmtInt:
data->params.sampleFormat = paInt32; self->params.sampleFormat = paInt32;
break; break;
case DevFmtFloat: case DevFmtFloat:
data->params.sampleFormat = paFloat32; self->params.sampleFormat = paFloat32;
break; break;
case DevFmtUInt: case DevFmtUInt:
case DevFmtUShort: case DevFmtUShort:
ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
goto error; return ALC_INVALID_VALUE;
} }
data->params.channelCount = ChannelsFromDevFmt(device->FmtChans); self->params.channelCount = ChannelsFromDevFmt(device->FmtChans);
err = Pa_OpenStream(&data->stream, &data->params, NULL, device->Frequency, err = Pa_OpenStream(&self->stream, &self->params, NULL,
paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device); device->Frequency, paFramesPerBufferUnspecified, paNoFlag,
ALCportCapture_ReadCallback, self
);
if(err != paNoError) if(err != paNoError)
{ {
ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
goto error; return ALC_INVALID_VALUE;
} }
al_string_copy_cstr(&device->DeviceName, deviceName); al_string_copy_cstr(&device->DeviceName, name);
device->ExtraData = data;
return ALC_NO_ERROR; return ALC_NO_ERROR;
error:
DestroyRingBuffer(data->ring);
free(data);
return ALC_INVALID_VALUE;
} }
static void pa_close_capture(ALCdevice *device) static void ALCportCapture_close(ALCportCapture *self)
{ {
pa_data *data = (pa_data*)device->ExtraData; PaError err = Pa_CloseStream(self->stream);
PaError err;
err = Pa_CloseStream(data->stream);
if(err != paNoError) if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
self->stream = NULL;
DestroyRingBuffer(data->ring); ll_ringbuffer_free(self->ring);
data->ring = NULL; self->ring = NULL;
free(data);
device->ExtraData = NULL;
} }
static void pa_start_capture(ALCdevice *device)
{
pa_data *data = device->ExtraData;
PaError err;
err = Pa_StartStream(data->stream); static ALCboolean ALCportCapture_start(ALCportCapture *self)
{
PaError err = Pa_StartStream(self->stream);
if(err != paNoError) if(err != paNoError)
{
ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); ERR("Error starting stream: %s\n", Pa_GetErrorText(err));
return ALC_FALSE;
}
return ALC_TRUE;
} }
static void pa_stop_capture(ALCdevice *device) static void ALCportCapture_stop(ALCportCapture *self)
{ {
pa_data *data = (pa_data*)device->ExtraData; PaError err = Pa_StopStream(self->stream);
PaError err;
err = Pa_StopStream(data->stream);
if(err != paNoError) if(err != paNoError)
ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
} }
static ALCenum pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
static ALCuint ALCportCapture_availableSamples(ALCportCapture *self)
{ {
pa_data *data = device->ExtraData; return ll_ringbuffer_read_space(self->ring);
ReadRingBuffer(data->ring, buffer, samples); }
static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples)
{
ll_ringbuffer_read(self->ring, buffer, samples);
return ALC_NO_ERROR; return ALC_NO_ERROR;
} }
static ALCuint pa_available_samples(ALCdevice *device)
{ typedef struct ALCportBackendFactory {
pa_data *data = device->ExtraData; DERIVE_FROM_TYPE(ALCbackendFactory);
return RingBufferSize(data->ring); } ALCportBackendFactory;
} #define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } }
static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self);
static void ALCportBackendFactory_deinit(ALCportBackendFactory *self);
static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type);
static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory);
static const BackendFuncs pa_funcs = { static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self))
pa_open_playback,
pa_close_playback,
pa_reset_playback,
pa_start_playback,
pa_stop_playback,
pa_open_capture,
pa_close_capture,
pa_start_capture,
pa_stop_capture,
pa_capture_samples,
pa_available_samples
};
ALCboolean alc_pa_init(BackendFuncs *func_list)
{ {
if(!pa_load()) if(!pa_load())
return ALC_FALSE; return ALC_FALSE;
*func_list = pa_funcs;
return ALC_TRUE; return ALC_TRUE;
} }
void alc_pa_deinit(void) static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self))
{ {
#ifdef HAVE_DYNLOAD #ifdef HAVE_DYNLOAD
if(pa_handle) if(pa_handle)
@ -454,7 +526,14 @@ void alc_pa_deinit(void)
#endif #endif
} }
void alc_pa_probe(enum DevProbe type) static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback || type == ALCbackend_Capture)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type)
{ {
switch(type) switch(type)
{ {
@ -466,3 +545,29 @@ void alc_pa_probe(enum DevProbe type)
break; break;
} }
} }
static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCportPlayback *backend;
NEW_OBJ(backend, ALCportPlayback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCportCapture *backend;
NEW_OBJ(backend, ALCportCapture)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
ALCbackendFactory *ALCportBackendFactory_getFactory(void)
{
static ALCportBackendFactory factory = ALCPORTBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}

View File

@ -303,9 +303,6 @@ typedef struct {
ALCboolean alc_sndio_init(BackendFuncs *func_list); ALCboolean alc_sndio_init(BackendFuncs *func_list);
void alc_sndio_deinit(void); void alc_sndio_deinit(void);
void alc_sndio_probe(enum DevProbe type); void alc_sndio_probe(enum DevProbe type);
ALCboolean alc_pa_init(BackendFuncs *func_list);
void alc_pa_deinit(void);
void alc_pa_probe(enum DevProbe type);
ALCboolean alc_ca_init(BackendFuncs *func_list); ALCboolean alc_ca_init(BackendFuncs *func_list);
void alc_ca_deinit(void); void alc_ca_deinit(void);
void alc_ca_probe(enum DevProbe type); void alc_ca_probe(enum DevProbe type);