Convert the PortAudio backend to the new backend API
This commit is contained in:
parent
6689c61ff4
commit
6fc8cd3b29
@ -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 },
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user