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:
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user