From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Sun, 21 Nov 2021 21:47:32 +0000 (+0000) Subject: Add code to check divisions and mods for a potrntial divide by zero problem. MAy... X-Git-Tag: 4.1-rc1~24^2~372 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=14bfba27242545c7c3aa426528da730ab05a7e05;p=thirdparty%2Fshairport-sync.git Add code to check divisions and mods for a potrntial divide by zero problem. MAy cause SPS to terminate but leave a log message. --- diff --git a/audio.h b/audio.h index ad574adb..25742d7b 100644 --- a/audio.h +++ b/audio.h @@ -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); diff --git a/audio_alsa.c b/audio_alsa.c index 3fcbde66..caaad899 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -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; diff --git a/audio_sndio.c b/audio_sndio.c index e32c1f4d..f710e200 100644 --- a/audio_sndio.c +++ b/audio_sndio.c @@ -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; } diff --git a/audio_soundio.c b/audio_soundio.c index 28108a9f..ccf44bf7 100644 --- a/audio_soundio.c +++ b/audio_soundio.c @@ -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, diff --git a/common.c b/common.c index b1525a31..a947be41 100644 --- a/common.c +++ b/common.c @@ -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; diff --git a/dacp.c b/dacp.c index 35dbabd0..ef2297e2 100644 --- a/dacp.c +++ b/dacp.c @@ -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 + } } } } diff --git a/player.c b/player.c index 41010643..7a66a1b3 100644 --- a/player.c +++ b/player.c @@ -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 (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; - } - 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 (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 (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); + // 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 { - inform("No frames received in the last sampling interval."); + 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 diff --git a/player.h b/player.h index 526572ef..b08a379e 100644 --- a/player.h +++ b/player.h @@ -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 diff --git a/rtp.c b/rtp.c index 41b07371..a79e0bbd 100644 --- a/rtp.c +++ b/rtp.c @@ -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; diff --git a/shairport.c b/shairport.c index 4afcd86f..9b7648e3 100644 --- a/shairport.c +++ b/shairport.c @@ -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); }