PulseAudio: pass the latency test

See #2
This commit is contained in:
Andrew Kelley 2015-09-02 14:46:36 -07:00
parent e5cd076e2e
commit adb3cd88ee
2 changed files with 49 additions and 6 deletions

View file

@ -646,6 +646,12 @@ static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os
} }
} }
static void timing_update_callback(pa_stream *stream, int success, void *userdata) {
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_threaded_mainloop_signal(sipa->main_loop, 0);
}
static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
SoundIoOutStream *outstream = &os->pub; SoundIoOutStream *outstream = &os->pub;
@ -693,7 +699,7 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
ospa->buffer_attr.tlength = buffer_length; ospa->buffer_attr.tlength = buffer_length;
} }
pa_stream_flags_t flags = PA_STREAM_START_CORKED; pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_START_CORKED|PA_STREAM_AUTO_TIMING_UPDATE);
if (outstream->software_latency > 0.0) if (outstream->software_latency > 0.0)
flags = (pa_stream_flags_t) (flags | PA_STREAM_ADJUST_LATENCY); flags = (pa_stream_flags_t) (flags | PA_STREAM_ADJUST_LATENCY);
@ -708,6 +714,12 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
while (!ospa->stream_ready.load()) while (!ospa->stream_ready.load())
pa_threaded_mainloop_wait(sipa->main_loop); pa_threaded_mainloop_wait(sipa->main_loop);
pa_operation *update_timing_info_op = pa_stream_update_timing_info(ospa->stream, timing_update_callback, si);
if ((err = perform_operation(si, update_timing_info_op))) {
pa_threaded_mainloop_unlock(sipa->main_loop);
return err;
}
size_t writable_size = pa_stream_writable_size(ospa->stream); size_t writable_size = pa_stream_writable_size(ospa->stream);
outstream->software_latency = writable_size / bytes_per_second; outstream->software_latency = writable_size / bytes_per_second;
@ -810,7 +822,16 @@ static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, b
} }
static int outstream_get_latency_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, double *out_latency) { static int outstream_get_latency_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, double *out_latency) {
soundio_panic("TODO"); SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
int err;
pa_usec_t r_usec;
int negative;
if ((err = pa_stream_get_latency(ospa->stream, &r_usec, &negative))) {
return SoundIoErrorStreaming;
}
*out_latency = r_usec / 1000000.0;
return 0;
} }
static void recording_stream_state_callback(pa_stream *stream, void *userdata) { static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
@ -908,6 +929,13 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
ispa->buffer_attr.fragsize = buffer_length; ispa->buffer_attr.fragsize = buffer_length;
} }
int err;
pa_operation *update_timing_info_op = pa_stream_update_timing_info(ispa->stream, timing_update_callback, si);
if ((err = perform_operation(si, update_timing_info_op))) {
pa_threaded_mainloop_unlock(sipa->main_loop);
return err;
}
pa_threaded_mainloop_unlock(sipa->main_loop); pa_threaded_mainloop_unlock(sipa->main_loop);
return 0; return 0;
@ -919,7 +947,9 @@ static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
pa_stream_flags_t flags = (instream->software_latency > 0.0) ? PA_STREAM_ADJUST_LATENCY : PA_STREAM_NOFLAGS; pa_stream_flags_t flags = PA_STREAM_AUTO_TIMING_UPDATE;
if (instream->software_latency > 0.0)
flags = (pa_stream_flags_t) (flags|PA_STREAM_ADJUST_LATENCY);
int err = pa_stream_connect_record(ispa->stream, int err = pa_stream_connect_record(ispa->stream,
instream->device->id, instream->device->id,
@ -1016,7 +1046,16 @@ static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, boo
} }
static int instream_get_latency_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, double *out_latency) { static int instream_get_latency_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, double *out_latency) {
soundio_panic("TODO"); SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
int err;
pa_usec_t r_usec;
int negative;
if ((err = pa_stream_get_latency(ispa->stream, &r_usec, &negative))) {
return SoundIoErrorStreaming;
}
*out_latency = r_usec / 1000000.0;
return 0;
} }
int soundio_pulseaudio_init(SoundIoPrivate *si) { int soundio_pulseaudio_init(SoundIoPrivate *si) {

View file

@ -216,6 +216,7 @@ int main(int argc, char **argv) {
soundio_panic("unable to start device: %s", soundio_strerror(err)); soundio_panic("unable to start device: %s", soundio_strerror(err));
bool beep_on = true; bool beep_on = true;
int count = 0;
for (;;) { for (;;) {
int fill_count = soundio_ring_buffer_fill_count(&pulse_rb); int fill_count = soundio_ring_buffer_fill_count(&pulse_rb);
if (fill_count >= (int)sizeof(double)) { if (fill_count >= (int)sizeof(double)) {
@ -225,11 +226,14 @@ int main(int argc, char **argv) {
// Burn the CPU while we wait for our precisely timed event. // Burn the CPU while we wait for our precisely timed event.
} }
if (beep_on) { if (beep_on) {
fprintf(stderr, "BEEP!\r"); fprintf(stderr, "BEEP %d start\n", count);
} else { } else {
fprintf(stderr, " \r"); fprintf(stderr, "BEEP %d end\n", count++);
} }
fflush(stderr); fflush(stderr);
double off_by = soundio_os_get_time() - audible_time;
if (off_by > 0.0001)
fprintf(stderr, "off by %f\n", off_by);
beep_on = !beep_on; beep_on = !beep_on;
soundio_ring_buffer_advance_read_ptr(&pulse_rb, sizeof(double)); soundio_ring_buffer_advance_read_ptr(&pulse_rb, sizeof(double));
} }