Add code to check divisions and mods for a potrntial divide by zero problem. MAy cause SPS to terminate but leave a log message.

This commit is contained in:
Mike Brady
2021-11-21 21:47:32 +00:00
parent 881a5ca25e
commit 14bfba2724
10 changed files with 208 additions and 131 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ typedef struct {
// returns a negative error code if there's a problem
int (*delay)(long *the_delay); // snd_pcm_sframes_t is a signed long
int (*stats)(uint64_t *measurement_time, uint64_t *delay,
uint64_t *frames_sent_to_dac); // use this to get the true rate of the DAC
uint64_t *frames_sent_to_dac); // use this to get the true rate of the DAC
// may be NULL, in which case soft volume is applied
void (*volume)(double vol);
+6 -6
View File
@@ -89,9 +89,9 @@ audio_output audio_alsa = {
.flush = &flush,
.delay = &delay,
.play = &play,
.stats = &stats, // will also include frames of silence sent to stop
// standby mode
// .rate_info = NULL,
.stats = &stats, // will also include frames of silence sent to stop
// standby mode
// .rate_info = NULL,
.mute = NULL, // a function will be provided if it can, and is allowed to,
// do hardware mute
.volume = NULL, // a function will be provided if it can do hardware volume
@@ -781,8 +781,8 @@ int actual_open_alsa_device(int do_auto_setup) {
if ((snd_pcm_hw_params_get_rate_numden(alsa_params, &uval, &uval2) == 0) && (uval2 != 0))
// watch for a divide by zero too!
debug(log_level, " precise (rational) rate = %.3f frames per second (i.e. %u/%u).", uval,
uval2, ((double)uval) / uval2);
else
uval2, ((double)uval) / uval2);
else
debug(log_level, " precise (rational) rate information unavailable.");
snd_pcm_hw_params_get_period_time(alsa_params, &uval, &dir);
@@ -1570,7 +1570,7 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
((uint64_t)frames_played_since_last_interrupt_sized !=
frames_played_since_last_interrupt))
debug(1,
"overflow resizing frames_played_since_last_interrupt % " PRIx64
"overflow resizing frames_played_since_last_interrupt %" PRIx64
" to frames_played_since_last_interrupt %lx.",
frames_played_since_last_interrupt, frames_played_since_last_interrupt_sized);
delay_temp = delay_temp - frames_played_since_last_interrupt_sized;
+7
View File
@@ -204,12 +204,19 @@ static int init(int argc, char **argv) {
framesize = par.bps * par.pchan;
config.output_rate = par.rate;
if (par.rate == 0) {
die("sndio: par.rate set to zero.");
}
config.audio_backend_buffer_desired_length = 1.0 * par.bufsz / par.rate;
config.audio_backend_latency_offset = 0;
sio_onmove(hdl, onmove_cb, NULL);
pthread_mutex_unlock(&sndio_mutex);
if (framesize == 0) {
die("sndio: framesize set to zero.");
}
return 0;
}
+2
View File
@@ -22,6 +22,8 @@ static void write_callback(struct SoundIoOutStream *outstream, int frame_count_m
char *read_ptr = soundio_ring_buffer_read_ptr(ring_buffer);
int fill_bytes = soundio_ring_buffer_fill_count(ring_buffer);
if (outstream->bytes_per_frame == 0)
die("soundio: outstream->bytes_per_frame is zero.");
int fill_count = fill_bytes / outstream->bytes_per_frame;
debug(3,
+18 -8
View File
@@ -1187,6 +1187,8 @@ double vol2attn(double vol, long max_db, long min_db) {
int i;
for (i = 0; i < order; i++) {
if (vol <= lines[i][0]) {
if ((-30 - lines[i][0]) == 0.0)
die("(-30 - lines[%d][0]) == 0.0!", i);
double tvol = lines[i][1] * (vol - lines[i][0]) / (-30 - lines[i][0]);
// debug(1,"On line %d, end point of %f, input vol %f yields output vol
// %f.",i,lines[i][1],vol,tvol);
@@ -1246,8 +1248,10 @@ uint64_t get_absolute_time_in_fp() {
// Do the maths. We hope that the multiplication doesn't
// overflow; the price you pay for working in fixed point.
// this gives us nanoseconds
uint64_t time_now_ns = time_now_mach * sTimebaseInfo.numer / sTimebaseInfo.denom;
if (sTimebaseInfo.denom == 0)
die("could not initialise Mac timebase info in get_absolute_time_in_fp().")
// this gives us nanoseconds
uint64_t time_now_ns = time_now_mach * sTimebaseInfo.numer / sTimebaseInfo.denom;
// take the units and shift them to the upper half of the fp, and take the nanoseconds, shift them
// to the upper half and then divide the result to 1000000000
@@ -1291,11 +1295,14 @@ uint64_t get_monotonic_time_in_ns() {
(void)mach_timebase_info(&sTimebaseInfo);
}
// Do the maths. We hope that the multiplication doesn't
// overflow; the price you pay for working in fixed point.
if (sTimebaseInfo.denom == 0)
die("could not initialise Mac timebase info in get_monotonic_time_in_ns().")
// this gives us nanoseconds
time_now_ns = time_now_mach * sTimebaseInfo.numer / sTimebaseInfo.denom;
// Do the maths. We hope that the multiplication doesn't
// overflow; the price you pay for working in fixed point.
// this gives us nanoseconds
time_now_ns = time_now_mach * sTimebaseInfo.numer / sTimebaseInfo.denom;
#endif
return time_now_ns;
@@ -1336,8 +1343,11 @@ uint64_t get_absolute_time_in_ns() {
// Do the maths. We hope that the multiplication doesn't
// overflow; the price you pay for working in fixed point.
// this gives us nanoseconds
time_now_ns = time_now_mach * sTimebaseInfo.numer / sTimebaseInfo.denom;
if (sTimebaseInfo.denom == 0)
die("could not initialise Mac timebase info in get_absolute_time_in_ns().")
// this gives us nanoseconds
time_now_ns = time_now_mach * sTimebaseInfo.numer / sTimebaseInfo.denom;
#endif
return time_now_ns;
+8 -6
View File
@@ -1351,12 +1351,14 @@ int dacp_set_volume(int32_t vo) {
machine_number,
highest_other_volume); // set the overall volume to the highest one
}
int32_t desired_relative_volume =
(vo * 100 + (highest_other_volume / 2)) / highest_other_volume;
debug(2, "Set our speaker volume relative to the highest volume.");
http_response = dacp_set_speaker_volume(
machine_number,
desired_relative_volume); // set the overall volume to the highest one
if (highest_other_volume != 0) {
int32_t desired_relative_volume =
(vo * 100 + (highest_other_volume / 2)) / highest_other_volume;
debug(2, "Set our speaker volume relative to the highest volume.");
http_response = dacp_set_speaker_volume(
machine_number,
desired_relative_volume); // set the overall volume to the highest one
}
}
}
}
+138 -106
View File
@@ -235,7 +235,10 @@ int audio_packet_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_c
reply = -1; // output packet is the wrong size
}
*destlen = outsize / conn->input_bytes_per_frame;
if (conn->input_bytes_per_frame != 0)
*destlen = outsize / conn->input_bytes_per_frame;
else
die("Unexpectedly, conn->input_bytes_per_frame is zero.");
if ((outsize % conn->input_bytes_per_frame) != 0)
debug(1,
"Number of audio frames (%d) does not correspond exactly to the number of bytes (%d) "
@@ -1354,6 +1357,8 @@ static inline int32_t mean_32(int32_t a, int32_t b) {
// stuff: 1 means add 1; 0 means do nothing; -1 means remove 1
static int stuff_buffer_basic_32(int32_t *inptr, int length, sps_format_t l_output_format,
char *outptr, int stuff, int dither, rtsp_conn_info *conn) {
if (length < 3)
die("buffer length expected to be 3 or more, but is %d!", length);
int tstuff = stuff;
char *l_outptr = outptr;
if ((stuff > 1) || (stuff < -1) || (length < 100)) {
@@ -1465,7 +1470,10 @@ int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int length,
longest_soxr_execution_time = soxr_execution_time;
stat_n += 1;
double stat_delta = soxr_execution_time - stat_mean;
stat_mean += stat_delta / stat_n;
if (stat_n != 0)
stat_mean += stat_delta / stat_n;
else
warn("calculation error for stat_n");
stat_M2 += stat_delta * (soxr_execution_time - stat_mean);
int i;
@@ -2071,6 +2079,17 @@ void *player_thread_func(void *arg) {
debug(2, "Play begin");
while (1) {
// check a few parameters to ensure they are non-zero
if (config.output_rate == 0)
debug(1, "config.output_rate is zero!");
if (conn->output_sample_ratio == 0)
debug(1, "conn->output_sample_ratio is zero!");
if (conn->input_rate == 0)
debug(1, "conn->input_rate is zero!");
if (conn->input_bytes_per_frame == 0)
debug(1, "conn->input_bytes_per_frame is zero!");
pthread_testcancel(); // allow a pthread_cancel request to take effect.
abuf_t *inframe = buffer_get_frame(conn); // this has cancellation point(s), but it's not
// guaranteed that they'll always be executed
@@ -2290,50 +2309,56 @@ void *player_thread_func(void *arg) {
if (conn->buffer_occupancy > maximum_buffer_occupancy)
maximum_buffer_occupancy = conn->buffer_occupancy;
// now, before outputting anything to the output device, check the stats
if (play_number % print_interval == 0) {
// here, calculate the input and output frame rates, where possible, even if statistics
// have not been requested
// this is to calculate them in case they are needed by the D-Bus interface or elsewhere.
if (play_number % print_interval == 0) {
if (conn->input_frame_rate_starting_point_is_valid) {
uint64_t elapsed_reception_time, frames_received;
elapsed_reception_time =
conn->frames_inward_measurement_time - conn->frames_inward_measurement_start_time;
frames_received = conn->frames_inward_frames_received_at_measurement_time -
conn->frames_inward_frames_received_at_measurement_start_time;
conn->input_frame_rate =
(1.0E9 * frames_received) /
elapsed_reception_time; // an IEEE double calculation with two 64-bit integers
} else {
conn->input_frame_rate = 0.0;
}
// here, calculate the input and output frame rates, where possible, even if statistics
// have not been requested
// this is to calculate them in case they are needed by the D-Bus interface or
// elsewhere.
int stats_status = -1;
if ((config.output->delay) && (config.no_sync == 0) && (config.output->stats)) {
uint64_t frames_sent_for_play;
uint64_t measurement_time;
uint64_t actual_delay;
stats_status = config.output->stats(&measurement_time, &actual_delay, &frames_sent_for_play);
// debug(1,"actual_delay: %" PRIu64 ", frames_sent_for_play: %" PRIu64 ", frames_played: %" PRIu64 ".", actual_delay, frames_sent_for_play, frames_sent_for_play - actual_delay);
uint64_t frames_played = frames_sent_for_play - actual_delay;
// If the status is zero, it means that there were no output problems since the
// last time the stats call was made. Thus, the frame rate should be valid.
if ((stats_status == 0) && (previous_frames_played_valid)) {
uint64_t frames_played_in_this_interval = frames_played - previous_frames_played;
uint64_t interval = measurement_time - previous_frames_played_time;
// debug(1,"frames_played_in_this_interval: %" PRIu64 ", interval: %" PRIu64 ".", frames_played_in_this_interval, interval);
conn->frame_rate = (1e9 * frames_played_in_this_interval) / interval;
conn->frame_rate_valid = 1;
if (conn->input_frame_rate_starting_point_is_valid) {
uint64_t elapsed_reception_time, frames_received;
elapsed_reception_time =
conn->frames_inward_measurement_time - conn->frames_inward_measurement_start_time;
frames_received = conn->frames_inward_frames_received_at_measurement_time -
conn->frames_inward_frames_received_at_measurement_start_time;
conn->input_frame_rate =
(1.0E9 * frames_received) /
elapsed_reception_time; // an IEEE double calculation with two 64-bit integers
} else {
conn->input_frame_rate = 0.0;
}
// uncomment the if statement if your want to get as long a period for
// calculating the frame rate as possible without an output break or error
// if ((status != 0) || (previous_frames_played_valid == 0)) {
int stats_status = -1;
if ((config.output->delay) && (config.no_sync == 0) && (config.output->stats)) {
uint64_t frames_sent_for_play;
uint64_t measurement_time;
uint64_t actual_delay;
stats_status =
config.output->stats(&measurement_time, &actual_delay, &frames_sent_for_play);
// debug(1,"actual_delay: %" PRIu64 ", frames_sent_for_play: %" PRIu64 ",
// frames_played: %" PRIu64 ".", actual_delay, frames_sent_for_play,
// frames_sent_for_play - actual_delay);
uint64_t frames_played = frames_sent_for_play - actual_delay;
// If the status is zero, it means that there were no output problems since the
// last time the stats call was made. Thus, the frame rate should be valid.
if ((stats_status == 0) && (previous_frames_played_valid)) {
uint64_t frames_played_in_this_interval = frames_played - previous_frames_played;
uint64_t interval = measurement_time - previous_frames_played_time;
// debug(1,"frames_played_in_this_interval: %" PRIu64 ", interval: %" PRIu64 ".",
// frames_played_in_this_interval, interval);
if (interval != 0) {
conn->frame_rate = (1e9 * frames_played_in_this_interval) / interval;
conn->frame_rate_valid = 1;
}
}
// uncomment the if statement if your want to get as long a period for
// calculating the frame rate as possible without an output break or error
// if ((status != 0) || (previous_frames_played_valid == 0)) {
// if we have just detected an outputting error, or if we have no
// starting information
if (stats_status != 0)
@@ -2341,73 +2366,80 @@ void *player_thread_func(void *arg) {
previous_frames_played = frames_played;
previous_frames_played_time = measurement_time;
previous_frames_played_valid = 1;
// }
}
// we can now calculate running averages for sync error (frames), corrections (ppm),
// insertions plus deletions (ppm), drift (ppm)
double moving_average_sync_error = (1.0 * tsum_of_sync_errors) / number_of_statistics;
double moving_average_correction = (1.0 * tsum_of_corrections) / number_of_statistics;
double moving_average_insertions_plus_deletions =
(1.0 * tsum_of_insertions_and_deletions) / number_of_statistics;
// double moving_average_drift = (1.0 * tsum_of_drifts) / number_of_statistics;
// if ((play_number/print_interval)%20==0)
// figure out which statistics profile to use, depending on the kind of stream
if (config.statistics_requested) {
if (at_least_one_frame_seen) {
do {
line_of_stats[0] = '\0';
statistics_column = 0;
was_a_previous_column = 0;
statistics_item("sync error ms", "%*.2f", 13,
1000 * moving_average_sync_error / config.output_rate);
statistics_item("net sync ppm", "%*.1f", 12,
moving_average_correction * 1000000 /
(352 * conn->output_sample_ratio));
statistics_item("all sync ppm", "%*.1f", 12,
moving_average_insertions_plus_deletions * 1000000 /
(352 * conn->output_sample_ratio));
statistics_item(" packets", "%*d", 11, play_number);
statistics_item("missing", "%*" PRIu64 "", 7, conn->missing_packets);
statistics_item(" late", "%*" PRIu64 "", 6, conn->late_packets);
statistics_item("too late", "%*" PRIu64 "", 8, conn->too_late_packets);
statistics_item("resend reqs", "%*" PRIu64 "", 11, conn->resend_requests);
statistics_item("min DAC queue", "%*" PRIu64 "", 13, minimum_dac_queue_size);
statistics_item("min buffers", "%*" PRIu32 "", 11, minimum_buffer_occupancy);
statistics_item("max buffers", "%*" PRIu32 "", 11, maximum_buffer_occupancy);
statistics_item("nominal fps", "%*.2f", 11, conn->remote_frame_rate);
statistics_item(" actual fps", "%*.2f", 11, conn->input_frame_rate);
if (conn->frame_rate_valid)
statistics_item(" output fps", "%*.2f", 11, conn->frame_rate);
else
statistics_item(" output fps", " N/A");
statistics_item("source drift ppm", "%*.2f", 16,
(conn->local_to_remote_time_gradient - 1.0) * 1000000);
statistics_item("drift samples", "%*d", 13,
conn->local_to_remote_time_gradient_sample_count);
statistics_item(
"estimated (unused) correction ppm", "%*.2f",
strlen("estimated (unused) correction ppm"),
(conn->frame_rate_valid != 0)
? ((conn->frame_rate - conn->remote_frame_rate * conn->output_sample_ratio *
conn->local_to_remote_time_gradient) *
1000000) /
conn->frame_rate
: 0.0);
statistics_row++;
inform(line_of_stats);
} while (statistics_row < 2);
} else {
inform("No frames received in the last sampling interval.");
// }
}
// we can now calculate running averages for sync error (frames), corrections (ppm),
// insertions plus deletions (ppm), drift (ppm)
double moving_average_sync_error = 0.0;
double moving_average_correction = 0.0;
double moving_average_insertions_plus_deletions = 0.0;
if (number_of_statistics == 0) {
debug(1, "number_of_statistics is zero!");
} else {
moving_average_sync_error = (1.0 * tsum_of_sync_errors) / number_of_statistics;
moving_average_correction = (1.0 * tsum_of_corrections) / number_of_statistics;
moving_average_insertions_plus_deletions =
(1.0 * tsum_of_insertions_and_deletions) / number_of_statistics;
// double moving_average_drift = (1.0 * tsum_of_drifts) / number_of_statistics;
}
// if ((play_number/print_interval)%20==0)
// figure out which statistics profile to use, depending on the kind of stream
if (config.statistics_requested) {
if (at_least_one_frame_seen) {
do {
line_of_stats[0] = '\0';
statistics_column = 0;
was_a_previous_column = 0;
statistics_item("sync error ms", "%*.2f", 13,
1000 * moving_average_sync_error / config.output_rate);
statistics_item("net sync ppm", "%*.1f", 12,
moving_average_correction * 1000000 /
(352 * conn->output_sample_ratio));
statistics_item("all sync ppm", "%*.1f", 12,
moving_average_insertions_plus_deletions * 1000000 /
(352 * conn->output_sample_ratio));
statistics_item(" packets", "%*d", 11, play_number);
statistics_item("missing", "%*" PRIu64 "", 7, conn->missing_packets);
statistics_item(" late", "%*" PRIu64 "", 6, conn->late_packets);
statistics_item("too late", "%*" PRIu64 "", 8, conn->too_late_packets);
statistics_item("resend reqs", "%*" PRIu64 "", 11, conn->resend_requests);
statistics_item("min DAC queue", "%*" PRIu64 "", 13, minimum_dac_queue_size);
statistics_item("min buffers", "%*" PRIu32 "", 11, minimum_buffer_occupancy);
statistics_item("max buffers", "%*" PRIu32 "", 11, maximum_buffer_occupancy);
statistics_item("nominal fps", "%*.2f", 11, conn->remote_frame_rate);
statistics_item(" actual fps", "%*.2f", 11, conn->input_frame_rate);
if (conn->frame_rate_valid)
statistics_item(" output fps", "%*.2f", 11, conn->frame_rate);
else
statistics_item(" output fps", " N/A");
statistics_item("source drift ppm", "%*.2f", 16,
(conn->local_to_remote_time_gradient - 1.0) * 1000000);
statistics_item("drift samples", "%*d", 13,
conn->local_to_remote_time_gradient_sample_count);
statistics_item("estimated (unused) correction ppm", "%*.2f",
strlen("estimated (unused) correction ppm"),
(conn->frame_rate_valid != 0)
? ((conn->frame_rate -
conn->remote_frame_rate * conn->output_sample_ratio *
conn->local_to_remote_time_gradient) *
1000000) /
conn->frame_rate
: 0.0);
statistics_row++;
inform(line_of_stats);
} while (statistics_row < 2);
} else {
inform("No frames received in the last sampling interval.");
}
}
minimum_dac_queue_size = UINT64_MAX; // hack reset
maximum_buffer_occupancy = INT32_MIN; // can't be less than this
minimum_buffer_occupancy = INT32_MAX; // can't be more than this
at_least_one_frame_seen = 0;
}
minimum_dac_queue_size = UINT64_MAX; // hack reset
maximum_buffer_occupancy = INT32_MIN; // can't be less than this
minimum_buffer_occupancy = INT32_MAX; // can't be more than this
at_least_one_frame_seen = 0;
}
// here, we want to check (a) if we are meant to do synchronisation,
// (b) if we have a delay procedure, (c) if we can get the delay.
@@ -2737,7 +2769,7 @@ void *player_thread_func(void *arg) {
#ifdef CONFIG_SOXR
if ((current_delay < conn->dac_buffer_queue_minimum_length) ||
(config.packet_stuffing == ST_basic) ||
(config.soxr_delay_index == 0) || // not computed yet
(config.soxr_delay_index == 0) || // not computed
((config.packet_stuffing == ST_auto) &&
(config.soxr_delay_index >
config.soxr_delay_threshold)) // if the CPU is deemed too slow
+1
View File
@@ -30,6 +30,7 @@
#include "audio.h"
#define time_ping_history_power_of_two 7
// this must now be zero, otherwise bad things will happen
#define time_ping_history \
(1 << time_ping_history_power_of_two) // 2^7 is 128. At 1 per three seconds, approximately six
// minutes of records
+15 -1
View File
@@ -154,7 +154,7 @@ void *rtp_audio_receiver(void *arg) {
float stat_delta = time_interval_us - stat_mean;
stat_mean += stat_delta / stat_n;
stat_M2 += stat_delta * (time_interval_us - stat_mean);
if (stat_n % 2500 == 0) {
if ((stat_n != 1) && (stat_n % 2500 == 0)) {
debug(2,
"Packet reception interval stats: mean, standard deviation and max for the last "
"2,500 packets in microseconds: %10.1f, %10.1f, %10.1f.",
@@ -650,6 +650,8 @@ void *rtp_timing_receiver(void *arg) {
double log_of_multiplier = log10(diffusion_expansion_factor) / time_ping_history;
double multiplier = pow(10, log_of_multiplier);
uint64_t dispersion_factor = (uint64_t)(multiplier * 100);
if (dispersion_factor == 0)
die("dispersion factor is zero!");
// debug(1,"dispersion factor is %" PRIu64 ".", dispersion_factor);
// uint64_t first_local_to_remote_time_difference_time;
@@ -1029,6 +1031,8 @@ const int use_nominal_rate = 0; // specify whether to use the nominal input rate
int sanitised_source_rate_information(uint32_t *frames, uint64_t *time, rtsp_conn_info *conn) {
int result = 1;
if (conn->input_rate == 0)
die("conn->input_rate is zero!");
uint32_t fs = conn->input_rate;
*frames = fs; // default value to return
*time = 1000000000; // default value to return
@@ -1051,7 +1055,11 @@ int sanitised_source_rate_information(uint32_t *frames, uint64_t *time, rtsp_con
result = 1;
} else {
*frames = local_frames;
if (local_frames == 0)
die("local_frames is zero!");
*time = local_time;
if (local_time == 0)
die("local_time is zero!");
result = 0;
}
}
@@ -1469,6 +1477,8 @@ int frame_to_ptp_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info *
int32_t frame_difference = timestamp - anchor_rtptime;
int64_t time_difference = frame_difference;
time_difference = time_difference * 1000000000;
if (conn->input_rate == 0)
die("conn->input_rate is zero!");
time_difference = time_difference / conn->input_rate;
uint64_t ltime = anchor_local_time + time_difference;
*time = ltime;
@@ -2246,6 +2256,10 @@ void *rtp_buffered_audio_processor(void *arg) {
double requested_lead_time = 0.3; // normal lead time minimum
reset_buffer(conn); // in case there is any garbage in the player
// int not_first_time_out = 0;
// quick check of parameters
if (conn->input_bytes_per_frame == 0)
die("conn->input_bytes_per_frame is zero!");
do {
int flush_is_delayed = 0;
int flush_newly_requested = 0;
+12 -3
View File
@@ -202,15 +202,24 @@ void *soxr_time_check(__attribute__((unused)) void *arg) {
double soxr_execution_time_ns = (get_absolute_time_in_ns() - soxr_start_time) * 1.0;
// free(outbuffer);
// free(inbuffer);
config.soxr_delay_index = (int)(0.9 + soxr_execution_time_ns / (number_of_iterations * 1000000));
if (number_of_iterations != 0) {
config.soxr_delay_index =
(int)(0.9 + soxr_execution_time_ns / (number_of_iterations * 1000000));
} else {
debug(1, "No soxr-timing iterations performed, so \"basic\" iteration will be used.");
config.soxr_delay_index = 0; // used as a flag
}
debug(2, "soxr_delay_index: %d.", config.soxr_delay_index);
if ((config.packet_stuffing == ST_soxr) &&
(config.soxr_delay_index > config.soxr_delay_threshold))
inform("Note: this device may be too slow for \"soxr\" interpolation. Consider choosing the "
"\"basic\" or \"auto\" interpolation setting.");
if (config.packet_stuffing == ST_auto)
debug(1, "\"%s\" interpolation has been chosen.",
config.soxr_delay_index <= config.soxr_delay_threshold ? "soxr" : "basic");
debug(
1, "\"%s\" interpolation has been chosen.",
((config.soxr_delay_index != 0) && (config.soxr_delay_index <= config.soxr_delay_threshold))
? "soxr"
: "basic");
pthread_exit(NULL);
}