aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/backends/pulseaudio.c
diff options
context:
space:
mode:
Diffstat (limited to 'Alc/backends/pulseaudio.c')
-rw-r--r--Alc/backends/pulseaudio.c99
1 files changed, 66 insertions, 33 deletions
diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c
index b93a90d8..4d6cedc2 100644
--- a/Alc/backends/pulseaudio.c
+++ b/Alc/backends/pulseaudio.c
@@ -193,10 +193,13 @@ MAKE_FUNC(pa_stream_begin_write);
typedef struct {
char *device_name;
- ALCuint samples;
ALCuint frame_size;
- RingBuffer *ring;
+ const void *cap_store;
+ size_t cap_len;
+ size_t cap_remain;
+
+ ALCuint last_readable;
pa_buffer_attr attr;
pa_sample_spec spec;
@@ -804,7 +807,6 @@ static void pulse_close(ALCdevice *device) //{{{
pa_threaded_mainloop_stop(data->loop);
pa_threaded_mainloop_free(data->loop);
- DestroyRingBuffer(data->ring);
free(data->device_name);
device->ExtraData = NULL;
@@ -1078,6 +1080,7 @@ static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name)
pa_stream_flags_t flags = 0;
pa_stream_state_t state;
pa_channel_map chanmap;
+ ALuint samples;
if(!allCaptureDevNameMap)
probe_devices(AL_TRUE);
@@ -1108,21 +1111,15 @@ static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name)
data = device->ExtraData;
pa_threaded_mainloop_lock(data->loop);
- data->samples = device->UpdateSize * device->NumUpdates;
+ samples = device->UpdateSize * device->NumUpdates;
+ samples = maxu(samples, 100 * device->Frequency / 1000);
data->frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
- data->samples = maxu(data->samples, 100 * device->Frequency / 1000);
-
- if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples)))
- {
- pa_threaded_mainloop_unlock(data->loop);
- goto fail;
- }
data->attr.minreq = -1;
data->attr.prebuf = -1;
- data->attr.maxlength = data->samples * data->frame_size;
+ data->attr.maxlength = samples * data->frame_size;
data->attr.tlength = -1;
- data->attr.fragsize = minu(data->samples, 50*device->Frequency/1000) *
+ data->attr.fragsize = minu(samples, 50*device->Frequency/1000) *
data->frame_size;
data->spec.rate = device->Frequency;
@@ -1249,39 +1246,75 @@ static void pulse_stop_capture(ALCdevice *device) //{{{
static ALCenum pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) //{{{
{
pulse_data *data = device->ExtraData;
- ReadRingBuffer(data->ring, buffer, samples);
- return ALC_NO_ERROR;
-} //}}}
-
-static ALCuint pulse_available_samples(ALCdevice *device) //{{{
-{
- pulse_data *data = device->ExtraData;
- size_t samples;
+ ALCuint todo = samples * data->frame_size;
pa_threaded_mainloop_lock(data->loop);
/* Capture is done in fragment-sized chunks, so we loop until we get all
* that's available */
- samples = (device->Connected ? pa_stream_readable_size(data->stream) : 0);
- while(samples > 0)
+ data->last_readable -= todo;
+ while(todo > 0)
{
- const void *buf;
- size_t length;
+ size_t rem = todo;
- if(pa_stream_peek(data->stream, &buf, &length) < 0)
+ if(data->cap_len == 0)
{
- ERR("pa_stream_peek() failed: %s\n",
- pa_strerror(pa_context_errno(data->context)));
- break;
+ pa_stream_state_t state;
+
+ state = pa_stream_get_state(data->stream);
+ if(!PA_STREAM_IS_GOOD(state))
+ {
+ aluHandleDisconnect(device);
+ break;
+ }
+ if(pa_stream_peek(data->stream, &data->cap_store, &data->cap_len) < 0)
+ {
+ ERR("pa_stream_peek() failed: %s\n",
+ pa_strerror(pa_context_errno(data->context)));
+ aluHandleDisconnect(device);
+ break;
+ }
+ data->cap_remain = data->cap_len;
}
+ if(rem > data->cap_remain)
+ rem = data->cap_remain;
+
+ memcpy(buffer, data->cap_store, rem);
+
+ buffer = (ALbyte*)buffer + rem;
+ todo -= rem;
+
+ data->cap_store = (ALbyte*)data->cap_store + rem;
+ data->cap_remain -= rem;
+ if(data->cap_remain == 0)
+ {
+ pa_stream_drop(data->stream);
+ data->cap_len = 0;
+ }
+ }
+ if(todo > 0)
+ memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo);
+ pa_threaded_mainloop_unlock(data->loop);
- WriteRingBuffer(data->ring, buf, length/data->frame_size);
- samples -= length;
+ return ALC_NO_ERROR;
+} //}}}
- pa_stream_drop(data->stream);
+static ALCuint pulse_available_samples(ALCdevice *device) //{{{
+{
+ pulse_data *data = device->ExtraData;
+ size_t readable = data->cap_remain;
+
+ pa_threaded_mainloop_lock(data->loop);
+ if(device->Connected)
+ {
+ ssize_t got = pa_stream_readable_size(data->stream);
+ if(got > 0 && (size_t)got > data->cap_len)
+ readable += got - data->cap_len;
}
pa_threaded_mainloop_unlock(data->loop);
- return RingBufferSize(data->ring);
+ if(data->last_readable < readable)
+ data->last_readable = readable;
+ return data->last_readable / data->frame_size;
} //}}}