diff options
author | Chris Robinson <[email protected]> | 2010-03-18 01:58:25 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2010-03-18 01:58:25 -0700 |
commit | 97b25755e7cca783d201c51c8f910588d6ed6beb (patch) | |
tree | a8267eab13cbf89310d98def32b6556d4dc866ce /Alc | |
parent | bdfafb454b4b1da00b6156b94dd711a72ea77e5b (diff) |
Support capture with PortAudio
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/portaudio.c | 150 |
1 files changed, 143 insertions, 7 deletions
diff --git a/Alc/portaudio.c b/Alc/portaudio.c index 1a6142ed..de58202e 100644 --- a/Alc/portaudio.c +++ b/Alc/portaudio.c @@ -47,6 +47,7 @@ MAKE_FUNC(Pa_GetStreamInfo); static const ALCchar pa_device[] = "PortAudio Software"; +static const ALCchar pa_capture[] = "PortAudio Capture"; static volatile ALuint load_count; @@ -127,6 +128,8 @@ void pa_unload(void) typedef struct { PaStream *stream; ALuint update_size; + + RingBuffer *ring; } pa_data; @@ -144,6 +147,21 @@ static int pa_callback(const void *inputBuffer, void *outputBuffer, return 0; } +static int pa_capture_cb(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData) +{ + ALCdevice *device = (ALCdevice*)userData; + pa_data *data = (pa_data*)device->ExtraData; + + (void)outputBuffer; + (void)timeInfo; + (void)statusFlags; + + WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer); + return 0; +} + static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName) { @@ -260,11 +278,127 @@ static void pa_stop_playback(ALCdevice *device) static ALCboolean pa_open_capture(ALCdevice *device, const ALCchar *deviceName) { + PaStreamParameters inParams; + ALuint frame_size; + pa_data *data; + PaError err; + + if(!deviceName) + deviceName = pa_capture; + else if(strcmp(deviceName, pa_capture) != 0) + return ALC_FALSE; + + if(!pa_load()) + return ALC_FALSE; + + data = (pa_data*)calloc(1, sizeof(pa_data)); + if(data == NULL) + { + alcSetError(device, ALC_OUT_OF_MEMORY); + return ALC_FALSE; + } + + frame_size = aluChannelsFromFormat(device->Format) * + aluBytesFromFormat(device->Format); + data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates); + if(data->ring == NULL) + { + alcSetError(device, ALC_OUT_OF_MEMORY); + goto error; + } + + inParams.device = GetConfigValueInt("port", "capture", -1); + if(inParams.device < 0) + inParams.device = pPa_GetDefaultOutputDevice(); + inParams.suggestedLatency = 0.0f; + inParams.hostApiSpecificStreamInfo = NULL; + + switch(aluBytesFromFormat(device->Format)) + { + case 1: + inParams.sampleFormat = paUInt8; + break; + case 2: + inParams.sampleFormat = paInt16; + break; + case 4: + inParams.sampleFormat = paFloat32; + break; + default: + AL_PRINT("Unknown format: 0x%x\n", device->Format); + goto error; + } + inParams.channelCount = aluChannelsFromFormat(device->Format); + + err = pPa_OpenStream(&data->stream, &inParams, NULL, device->Frequency, + paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device); + if(err != paNoError) + { + AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err)); + goto error; + } + + device->szDeviceName = strdup(deviceName); + + device->ExtraData = data; + return ALC_TRUE; + +error: + DestroyRingBuffer(data->ring); + free(data); + pa_unload(); return ALC_FALSE; - (void)device; - (void)deviceName; } +static void pa_close_capture(ALCdevice *device) +{ + pa_data *data = (pa_data*)device->ExtraData; + PaError err; + + err = pPa_CloseStream(data->stream); + if(err != paNoError) + AL_PRINT("Error closing stream: %s\n", pPa_GetErrorText(err)); + + free(data); + device->ExtraData = NULL; + + pa_unload(); +} + +static void pa_start_capture(ALCdevice *device) +{ + pa_data *data = device->ExtraData; + PaError err; + + err = pPa_StartStream(data->stream); + if(err != paNoError) + AL_PRINT("Error starting stream: %s\n", pPa_GetErrorText(err)); +} + +static void pa_stop_capture(ALCdevice *device) +{ + pa_data *data = (pa_data*)device->ExtraData; + PaError err; + + err = pPa_StopStream(data->stream); + if(err != paNoError) + AL_PRINT("Error stopping stream: %s\n", pPa_GetErrorText(err)); +} + +static void pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) +{ + pa_data *data = device->ExtraData; + if(samples <= (ALCuint)RingBufferSize(data->ring)) + ReadRingBuffer(data->ring, buffer, samples); + else + alcSetError(device, ALC_INVALID_VALUE); +} + +static ALCuint pa_available_samples(ALCdevice *device) +{ + pa_data *data = device->ExtraData; + return RingBufferSize(data->ring); +} static const BackendFuncs pa_funcs = { @@ -273,11 +407,11 @@ static const BackendFuncs pa_funcs = { pa_reset_playback, pa_stop_playback, pa_open_capture, - NULL, - NULL, - NULL, - NULL, - NULL + pa_close_capture, + pa_start_capture, + pa_stop_capture, + pa_capture_samples, + pa_available_samples }; void alc_pa_init(BackendFuncs *func_list) @@ -297,6 +431,8 @@ void alc_pa_probe(int type) AppendDeviceList(pa_device); else if(type == ALL_DEVICE_PROBE) AppendAllDeviceList(pa_device); + else if(type == CAPTURE_DEVICE_PROBE) + AppendCaptureDeviceList(pa_capture); pa_unload(); } |