JACK: pass the latency test

See #2
This commit is contained in:
Andrew Kelley 2015-09-02 15:23:25 -07:00
parent adb3cd88ee
commit e444b8823b
4 changed files with 34 additions and 9 deletions

View file

@ -1004,9 +1004,12 @@ SOUNDIO_EXPORT int soundio_outstream_clear_buffer(struct SoundIoOutStream *outst
/// device does not support pausing/unpausing.
SOUNDIO_EXPORT int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause);
/// Obtain the total number of seconds that the next frame you write to the
/// outstream will take to become audible. This includes both software and
/// hardware latency.
/// Obtain the total number of seconds that the next frame written after the
/// last frame written with ::soundio_outstream_end_write will take to become
/// audible. This includes both software and hardware latency. In other words,
/// if you call this function directly after calling ::soundio_outstream_end_write,
/// this gives you the number of seconds that the next frame written will take
/// to become audible.
///
/// This function must be called only from within SoundIoOutStream::write_callback.
SOUNDIO_EXPORT int soundio_outstream_get_latency(struct SoundIoOutStream *outstream,

View file

@ -214,6 +214,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
djp->full_name = soundio_str_dupe(port->full_name, port->full_name_len);
djp->full_name_len = port->full_name_len;
djp->channel_id = port->channel_id;
djp->latency_range = port->latency_range;
if (!djp->full_name) {
jack_free(port_names);
@ -469,6 +470,8 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
jack_on_shutdown(osj->client, outstream_shutdown_callback, os);
jack_nframes_t max_port_latency = 0;
// register ports and map channels
int connected_count = 0;
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
@ -490,11 +493,13 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
osjp->dest_port_name = djp->full_name;
osjp->dest_port_name_len = djp->full_name_len;
connected_count += 1;
max_port_latency = max(max_port_latency, djp->latency_range.max);
}
}
// If nothing got connected, channel layouts aren't working. Just send the
// data in the order of the ports.
if (connected_count == 0) {
max_port_latency = 0;
outstream->layout_error = SoundIoErrorIncompatibleDevice;
int ch_count = min(outstream->layout.channel_count, dj->port_count);
@ -503,9 +508,12 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
SoundIoDeviceJackPort *djp = &dj->ports[ch];
osjp->dest_port_name = djp->full_name;
osjp->dest_port_name_len = djp->full_name_len;
max_port_latency = max(max_port_latency, djp->latency_range.max);
}
}
osj->hardware_latency = max_port_latency / (double)outstream->sample_rate;
return 0;
}
@ -575,7 +583,9 @@ static int outstream_clear_buffer_jack(struct SoundIoPrivate *si, struct SoundIo
static int outstream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
double *out_latency)
{
soundio_panic("TODO");
SoundIoOutStreamJack *osj = &os->backend_data.jack;
*out_latency = osj->hardware_latency;
return 0;
}
@ -684,6 +694,8 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
}
jack_on_shutdown(isj->client, instream_shutdown_callback, is);
jack_nframes_t max_port_latency = 0;
// register ports and map channels
int connected_count = 0;
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
@ -705,11 +717,13 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
isjp->source_port_name = djp->full_name;
isjp->source_port_name_len = djp->full_name_len;
connected_count += 1;
max_port_latency = max(max_port_latency, djp->latency_range.max);
}
}
// If nothing got connected, channel layouts aren't working. Just send the
// data in the order of the ports.
if (connected_count == 0) {
max_port_latency = 0;
instream->layout_error = SoundIoErrorIncompatibleDevice;
int ch_count = min(instream->layout.channel_count, dj->port_count);
@ -718,9 +732,12 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
SoundIoDeviceJackPort *djp = &dj->ports[ch];
isjp->source_port_name = djp->full_name;
isjp->source_port_name_len = djp->full_name_len;
max_port_latency = max(max_port_latency, djp->latency_range.max);
}
}
isj->hardware_latency = max_port_latency / (double)instream->sample_rate;
return 0;
}
@ -780,7 +797,9 @@ static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStr
static int instream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
double *out_latency)
{
soundio_panic("TODO");
SoundIoInStreamJack *isj = &is->backend_data.jack;
*out_latency = isj->hardware_latency;
return 0;
}
static void notify_devices_change(SoundIoPrivate *si) {

View file

@ -20,6 +20,7 @@ struct SoundIoDeviceJackPort {
char *full_name;
int full_name_len;
SoundIoChannelId channel_id;
jack_latency_range_t latency_range;
};
struct SoundIoDeviceJack {
@ -49,6 +50,7 @@ struct SoundIoOutStreamJack {
int period_size;
int frames_left;
bool is_paused;
double hardware_latency;
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
@ -63,6 +65,7 @@ struct SoundIoInStreamJack {
jack_client_t *client;
int period_size;
int frames_left;
double hardware_latency;
SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
char *buf_ptrs[SOUNDIO_MAX_CHANNELS];

View file

@ -53,14 +53,14 @@ static double seconds_offset = 0.0;
static SoundIoRingBuffer pulse_rb;
static void write_time(SoundIoOutStream *outstream) {
static void write_time(SoundIoOutStream *outstream, double extra) {
double latency;
int err;
if ((err = soundio_outstream_get_latency(outstream, &latency))) {
soundio_panic("getting latency: %s", soundio_strerror(err));
}
double now = soundio_os_get_time();
double audible_time = now + latency;
double audible_time = now + latency + extra;
double *write_ptr = (double *)soundio_ring_buffer_write_ptr(&pulse_rb);
*write_ptr = audible_time;
soundio_ring_buffer_advance_write_ptr(&pulse_rb, sizeof(double));
@ -92,7 +92,7 @@ static void write_callback(struct SoundIoOutStream *outstream, int frame_count_m
if (frames_until_pulse <= 0) {
if (pulse_frames_left == -1) {
pulse_frames_left = 0.25 * float_sample_rate;
write_time(outstream); // announce beep start
write_time(outstream, seconds_per_frame * frame); // announce beep start
}
if (pulse_frames_left > 0) {
pulse_frames_left -= 1;
@ -101,7 +101,7 @@ static void write_callback(struct SoundIoOutStream *outstream, int frame_count_m
frames_until_pulse = (0.5 + (rand() / (double)RAND_MAX) * 2.0) * float_sample_rate;
pulse_frames_left = -1;
sample = 0.0;
write_time(outstream); // announce beep end
write_time(outstream, seconds_per_frame * frame); // announce beep end
}
} else {
frames_until_pulse -= 1;