]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add code to check divisions and mods for a potrntial divide by zero problem. MAy...
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Sun, 21 Nov 2021 21:47:32 +0000 (21:47 +0000)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Sun, 21 Nov 2021 21:47:32 +0000 (21:47 +0000)
audio.h
audio_alsa.c
audio_sndio.c
audio_soundio.c
common.c
dacp.c
player.c
player.h
rtp.c
shairport.c

diff --git a/audio.h b/audio.h
index ad574adb0e722bce5fb36cc3ee078c6534ca27a0..25742d7b05803f15cac7a222550d260ab89d97e7 100644 (file)
--- 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);
index 3fcbde6615c4a9ab5234bf252d8e3a8c6ba8e272..caaad89977fe2eb535432f6cf0cb5c42142c8e18 100644 (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;
index e32c1f4d32884bada7ff4d94db666aaeaf6e6708..f710e200ef3d9051432ea0c4fe14f7b9c78ef7fa 100644 (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;
 }
 
index 28108a9fbc544987320835fd6c22b1dde5a4adec..ccf44bf7a0fa767a5eca709226f5e2e600190825 100644 (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,
index b1525a318a01b3aa7b2ded652cbff91811bc9b44..a947be416baad62ee442d016726ca56d70eb338c 100644 (file)
--- 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 35dbabd0ccc04069ebae3c9cc2e6e300bcd26ba5..ef2297e28d25f8547bc81155d27f708f7c215a21 100644 (file)
--- 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
+              }
             }
           }
         }
index 410106433f35dd10bfa3da4e3c8c35b4e18f025d..7a66a1b367a9642054f6bc2c912cadd7ea69ba87 100644 (file)
--- 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
index 526572ef3041c66c30b276f810396287a22ce5fd..b08a379efc8631606c7e8922b0d8e92f7c0f85dd 100644 (file)
--- 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 41b07371ccfe0970f6b16d817842e28bc32591af..a79e0bbd922366f0fb57bc87fc238769a5abc8ac 100644 (file)
--- 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;
index 4afcd86f7b8ea9d2c2c762ddce5a543c44ea717e..9b7648e3b8dc3561102a0032e2d2ea020feae356 100644 (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);
 }