mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2025-01-03 20:05:40 +00:00
parent
adb3cd88ee
commit
e444b8823b
|
@ -1004,9 +1004,12 @@ SOUNDIO_EXPORT int soundio_outstream_clear_buffer(struct SoundIoOutStream *outst
|
||||||
/// device does not support pausing/unpausing.
|
/// device does not support pausing/unpausing.
|
||||||
SOUNDIO_EXPORT int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause);
|
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
|
/// Obtain the total number of seconds that the next frame written after the
|
||||||
/// outstream will take to become audible. This includes both software and
|
/// last frame written with ::soundio_outstream_end_write will take to become
|
||||||
/// hardware latency.
|
/// 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.
|
/// This function must be called only from within SoundIoOutStream::write_callback.
|
||||||
SOUNDIO_EXPORT int soundio_outstream_get_latency(struct SoundIoOutStream *outstream,
|
SOUNDIO_EXPORT int soundio_outstream_get_latency(struct SoundIoOutStream *outstream,
|
||||||
|
|
23
src/jack.cpp
23
src/jack.cpp
|
@ -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 = soundio_str_dupe(port->full_name, port->full_name_len);
|
||||||
djp->full_name_len = port->full_name_len;
|
djp->full_name_len = port->full_name_len;
|
||||||
djp->channel_id = port->channel_id;
|
djp->channel_id = port->channel_id;
|
||||||
|
djp->latency_range = port->latency_range;
|
||||||
|
|
||||||
if (!djp->full_name) {
|
if (!djp->full_name) {
|
||||||
jack_free(port_names);
|
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_on_shutdown(osj->client, outstream_shutdown_callback, os);
|
||||||
|
|
||||||
|
|
||||||
|
jack_nframes_t max_port_latency = 0;
|
||||||
|
|
||||||
// register ports and map channels
|
// register ports and map channels
|
||||||
int connected_count = 0;
|
int connected_count = 0;
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
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 = djp->full_name;
|
||||||
osjp->dest_port_name_len = djp->full_name_len;
|
osjp->dest_port_name_len = djp->full_name_len;
|
||||||
connected_count += 1;
|
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
|
// If nothing got connected, channel layouts aren't working. Just send the
|
||||||
// data in the order of the ports.
|
// data in the order of the ports.
|
||||||
if (connected_count == 0) {
|
if (connected_count == 0) {
|
||||||
|
max_port_latency = 0;
|
||||||
outstream->layout_error = SoundIoErrorIncompatibleDevice;
|
outstream->layout_error = SoundIoErrorIncompatibleDevice;
|
||||||
|
|
||||||
int ch_count = min(outstream->layout.channel_count, dj->port_count);
|
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];
|
SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
||||||
osjp->dest_port_name = djp->full_name;
|
osjp->dest_port_name = djp->full_name;
|
||||||
osjp->dest_port_name_len = djp->full_name_len;
|
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;
|
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,
|
static int outstream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||||
double *out_latency)
|
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_on_shutdown(isj->client, instream_shutdown_callback, is);
|
||||||
|
|
||||||
|
jack_nframes_t max_port_latency = 0;
|
||||||
|
|
||||||
// register ports and map channels
|
// register ports and map channels
|
||||||
int connected_count = 0;
|
int connected_count = 0;
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
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 = djp->full_name;
|
||||||
isjp->source_port_name_len = djp->full_name_len;
|
isjp->source_port_name_len = djp->full_name_len;
|
||||||
connected_count += 1;
|
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
|
// If nothing got connected, channel layouts aren't working. Just send the
|
||||||
// data in the order of the ports.
|
// data in the order of the ports.
|
||||||
if (connected_count == 0) {
|
if (connected_count == 0) {
|
||||||
|
max_port_latency = 0;
|
||||||
instream->layout_error = SoundIoErrorIncompatibleDevice;
|
instream->layout_error = SoundIoErrorIncompatibleDevice;
|
||||||
|
|
||||||
int ch_count = min(instream->layout.channel_count, dj->port_count);
|
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];
|
SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
||||||
isjp->source_port_name = djp->full_name;
|
isjp->source_port_name = djp->full_name;
|
||||||
isjp->source_port_name_len = djp->full_name_len;
|
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;
|
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,
|
static int instream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||||
double *out_latency)
|
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) {
|
static void notify_devices_change(SoundIoPrivate *si) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ struct SoundIoDeviceJackPort {
|
||||||
char *full_name;
|
char *full_name;
|
||||||
int full_name_len;
|
int full_name_len;
|
||||||
SoundIoChannelId channel_id;
|
SoundIoChannelId channel_id;
|
||||||
|
jack_latency_range_t latency_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoDeviceJack {
|
struct SoundIoDeviceJack {
|
||||||
|
@ -49,6 +50,7 @@ struct SoundIoOutStreamJack {
|
||||||
int period_size;
|
int period_size;
|
||||||
int frames_left;
|
int frames_left;
|
||||||
bool is_paused;
|
bool is_paused;
|
||||||
|
double hardware_latency;
|
||||||
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
@ -63,6 +65,7 @@ struct SoundIoInStreamJack {
|
||||||
jack_client_t *client;
|
jack_client_t *client;
|
||||||
int period_size;
|
int period_size;
|
||||||
int frames_left;
|
int frames_left;
|
||||||
|
double hardware_latency;
|
||||||
SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
char *buf_ptrs[SOUNDIO_MAX_CHANNELS];
|
char *buf_ptrs[SOUNDIO_MAX_CHANNELS];
|
||||||
|
|
|
@ -53,14 +53,14 @@ static double seconds_offset = 0.0;
|
||||||
|
|
||||||
static SoundIoRingBuffer pulse_rb;
|
static SoundIoRingBuffer pulse_rb;
|
||||||
|
|
||||||
static void write_time(SoundIoOutStream *outstream) {
|
static void write_time(SoundIoOutStream *outstream, double extra) {
|
||||||
double latency;
|
double latency;
|
||||||
int err;
|
int err;
|
||||||
if ((err = soundio_outstream_get_latency(outstream, &latency))) {
|
if ((err = soundio_outstream_get_latency(outstream, &latency))) {
|
||||||
soundio_panic("getting latency: %s", soundio_strerror(err));
|
soundio_panic("getting latency: %s", soundio_strerror(err));
|
||||||
}
|
}
|
||||||
double now = soundio_os_get_time();
|
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);
|
double *write_ptr = (double *)soundio_ring_buffer_write_ptr(&pulse_rb);
|
||||||
*write_ptr = audible_time;
|
*write_ptr = audible_time;
|
||||||
soundio_ring_buffer_advance_write_ptr(&pulse_rb, sizeof(double));
|
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 (frames_until_pulse <= 0) {
|
||||||
if (pulse_frames_left == -1) {
|
if (pulse_frames_left == -1) {
|
||||||
pulse_frames_left = 0.25 * float_sample_rate;
|
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) {
|
if (pulse_frames_left > 0) {
|
||||||
pulse_frames_left -= 1;
|
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;
|
frames_until_pulse = (0.5 + (rand() / (double)RAND_MAX) * 2.0) * float_sample_rate;
|
||||||
pulse_frames_left = -1;
|
pulse_frames_left = -1;
|
||||||
sample = 0.0;
|
sample = 0.0;
|
||||||
write_time(outstream); // announce beep end
|
write_time(outstream, seconds_per_frame * frame); // announce beep end
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
frames_until_pulse -= 1;
|
frames_until_pulse -= 1;
|
||||||
|
|
Loading…
Reference in a new issue