// anything with ORDINATE in it must be proctected by the ab_mutex
static inline int32_t ORDINATE(seq_t x) {
- int32_t p = x & 0xffff;
- int32_t q = ab_read & 0x0ffff;
+ int32_t p = x; // int32_t from seq_t, i.e. uint16_t, so okay
+ int32_t q = ab_read; // int32_t from seq_t, i.e. uint16_t, so okay
int32_t t = (p + 0x10000 - q) & 0xffff;
// we definitely will get a positive number in t at this point, but it might be a
// positive alias of a negative number, i.e. x might actually be "before" ab_read
int64_t tsum_of_sync_errors, tsum_of_corrections, tsum_of_insertions_and_deletions,
tsum_of_drifts;
int64_t previous_sync_error, previous_correction;
- int64_t minimum_dac_queue_size = 1000000;
- int32_t minimum_buffer_occupancy = BUFFER_FRAMES;
- int32_t maximum_buffer_occupancy = 0;
+ int64_t minimum_dac_queue_size = INT64_MAX;
+ int32_t minimum_buffer_occupancy = INT32_MAX;
+ int32_t maximum_buffer_occupancy = INT32_MIN;
buffer_occupancy = 0;
uint32_t reference_timestamp;
uint64_t reference_timestamp_time,remote_reference_timestamp_time;
- get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time);
+ get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time); // types okay
int64_t rt, nt;
- rt = reference_timestamp;
- nt = inframe->timestamp;
+ rt = reference_timestamp; // uint32_t to int64_t
+ nt = inframe->timestamp; // uint32_t to int64_t
- uint64_t local_time_now = get_absolute_time_in_fp();
+ uint64_t local_time_now = get_absolute_time_in_fp(); // types okay
// struct timespec tn;
// clock_gettime(CLOCK_MONOTONIC,&tn);
// uint64_t
// local_time_now=((uint64_t)tn.tv_sec<<32)+((uint64_t)tn.tv_nsec<<32)/1000000000;
- int64_t td_in_frames;
- int64_t td = local_time_now - reference_timestamp_time;
+ int64_t td = 0;
+ int64_t td_in_frames = 0;
+ if (local_time_now >= reference_timestamp_time) {
// debug(1,"td is %lld.",td);
- if (td >= 0) {
+ td = local_time_now - reference_timestamp_time; // this is the positive value. Conversion is positive uint64_t to int64_t, thus okay
td_in_frames = (td * 44100) >> 32;
} else {
- td_in_frames = -((-td * 44100) >> 32);
+ td = reference_timestamp_time - local_time_now; // this is the absolute value, which should be negated. Conversion is positive uint64_t to int64_t, thus okay.
+ td_in_frames = -((td * 44100) >> 32); //use the absolute td value for the present. Types okay
+ td = -td; // should be okay, as the range of values should be very small w.r.t 64 bits
}
// This is the timing error for the next audio frame in the DAC, if applicable
// check sequencing
if (last_seqno_read == -1)
- last_seqno_read = inframe->sequence_number;
+ last_seqno_read = inframe->sequence_number; //int32_t from seq_t, i.e. uint16_t, so okay.
else {
- last_seqno_read = (SUCCESSOR(last_seqno_read) & 0xffff);
- if (inframe->sequence_number != last_seqno_read) {
+ last_seqno_read = SUCCESSOR(last_seqno_read); // int32_t from seq_t, i.e. uint16_t, so okay.
+ if (inframe->sequence_number != last_seqno_read) { //seq_t, ei.e. uint16_t and int32_t, so okay
debug(
1,
"Player: packets out of sequence: expected: %d, got: %d, sync error: %d frames.",
}
}
- buffer_occupancy = seq_diff(ab_read, ab_write);
+ buffer_occupancy = seq_diff(ab_read, ab_write); // int32_t from int32
if (buffer_occupancy < minimum_buffer_occupancy)
minimum_buffer_occupancy = buffer_occupancy;
if (buffer_occupancy > maximum_buffer_occupancy)
maximum_buffer_occupancy = buffer_occupancy;
- if (config.output->delay) {
- current_delay = config.output->delay();
- if (current_delay == -1) {
+ // here, we want to check (a) if we are meant to do synchronisation, (b) if we have a delay procedure, (b) if we can get the delay.
+ // If any of these are false, we don't do any synchronisation stuff
+
+ current_delay = -1; // use this as a failure flag
+
+ if (config.output->delay) {
+ current_delay = config.output->delay(); // int64_t from int32_t, so okay;
+ if (current_delay >= 0) {
+ if (current_delay < minimum_dac_queue_size) {
+ minimum_dac_queue_size = current_delay; // update for display later
+ }
+ } else {
debug(1, "Delay error when checking running latency.");
- current_delay = 0;
}
- if (current_delay < minimum_dac_queue_size)
- minimum_dac_queue_size = current_delay;
+ }
+
+ if (current_delay >= 0) {
// this is the actual delay, including the latency we actually want, which will
// fluctuate a good bit about a potentially rising or falling trend.
- int64_t delay = td_in_frames + rt - (nt - current_delay);
+ int64_t delay = td_in_frames + rt - (nt - current_delay); // all int64_t
+
// This is the timing error for the next audio frame in the DAC.
- sync_error = delay - config.latency;
+ sync_error = delay - config.latency; // int64_t from int64_t - int32_t, so okay
+
+ // if (llabs(sync_error)>352*512)
+ // debug(1,"Very large sync error: %lld",sync_error);
// before we finally commit to this frame, check its sequencing and timing
// require a certain error before bothering to fix it...
- if (sync_error > config.tolerance) {
+ if (sync_error > config.tolerance) { // int64_t > int, okay
amount_to_stuff = -1;
}
if (sync_error < -config.tolerance) {
if (amount_to_stuff) {
if ((local_time_now) && (first_packet_time_to_play) && (local_time_now >= first_packet_time_to_play)) {
- int64_t tp = (local_time_now - first_packet_time_to_play)>>32; // seconds
+ int64_t tp = (local_time_now - first_packet_time_to_play)>>32; // seconds int64_t from uint64_t which is always positive, so ok
if (tp<5)
amount_to_stuff = 0; // wait at least five seconds
}
}
}
+
+ if (config.no_sync!=0)
+ amount_to_stuff = 0 ; // no stuffing if it's been disabled
if ((amount_to_stuff == 0) && (fix_volume == 0x10000)) {
// if no stuffing needed and no volume adjustment, then
// check for loss of sync
// timestamp of zero means an inserted silent frame in place of a missing frame
- if ((inframe->timestamp != 0) && (!please_stop) && (config.resyncthreshold != 0) &&
- (abs(sync_error) > config.resyncthreshold)) {
+
+ // not too sure if abs() is implemented for int64_t, so we'll do it manually
+ int64_t abs_sync_error = sync_error;
+ if (abs_sync_error<0)
+ abs_sync_error = -abs_sync_error;
+
+ if ((config.no_sync==0) && (inframe->timestamp != 0) && (!please_stop) && (config.resyncthreshold != 0) &&
+ (abs_sync_error > config.resyncthreshold)) {
sync_error_out_of_bounds++;
// debug(1,"Sync error out of bounds: Error: %lld; previous error: %lld; DAC: %lld;
// timestamp: %llx, time now
sync_error_out_of_bounds = 0;
}
} else {
- // if there is no delay procedure, there can be no synchronising
+ // if there is no delay procedure, or it's not working or not allowed, there can be no synchronising
+
if (fix_volume == 0x10000)
config.output->play(inbuf, frame_size);
else {
- play_samples = stuff_buffer_basic(inbuf, outbuf, 0);
+ play_samples = stuff_buffer_basic(inbuf, outbuf, 0); // no stuffing, but volume adjustment
config.output->play(outbuf, frame_size);
}
}
// new stats calculation. We want a running average of sync error, drift, adjustment,
// number of additions+subtractions
+
+ // this is a misleading hack -- the statistics should include some data on the number of valid samples and the number of times sync wasn't checked due to non availability of a delay figure.
+ // for the present, stats are only updated when sync has been checked
+ if (sync_error!=-1) {
+ if (number_of_statistics == trend_interval) {
+ // here we remove the oldest statistical data and take it from the summaries as well
+ tsum_of_sync_errors -= statistics[oldest_statistic].sync_error;
+ tsum_of_drifts -= statistics[oldest_statistic].drift;
+ if (statistics[oldest_statistic].correction > 0)
+ tsum_of_insertions_and_deletions -= statistics[oldest_statistic].correction;
+ else
+ tsum_of_insertions_and_deletions += statistics[oldest_statistic].correction;
+ tsum_of_corrections -= statistics[oldest_statistic].correction;
+ oldest_statistic = (oldest_statistic + 1) % trend_interval;
+ number_of_statistics--;
+ }
- if (number_of_statistics == trend_interval) {
- // here we remove the oldest statistical data and take it from the summaries as well
- tsum_of_sync_errors -= statistics[oldest_statistic].sync_error;
- tsum_of_drifts -= statistics[oldest_statistic].drift;
- if (statistics[oldest_statistic].correction > 0)
- tsum_of_insertions_and_deletions -= statistics[oldest_statistic].correction;
- else
- tsum_of_insertions_and_deletions += statistics[oldest_statistic].correction;
- tsum_of_corrections -= statistics[oldest_statistic].correction;
- oldest_statistic = (oldest_statistic + 1) % trend_interval;
- number_of_statistics--;
- }
-
- statistics[newest_statistic].sync_error = sync_error;
- statistics[newest_statistic].correction = amount_to_stuff;
+ statistics[newest_statistic].sync_error = sync_error;
+ statistics[newest_statistic].correction = amount_to_stuff;
- if (number_of_statistics == 0)
- statistics[newest_statistic].drift = 0;
- else
- statistics[newest_statistic].drift =
- sync_error - previous_sync_error - previous_correction;
+ if (number_of_statistics == 0)
+ statistics[newest_statistic].drift = 0;
+ else
+ statistics[newest_statistic].drift =
+ sync_error - previous_sync_error - previous_correction;
- previous_sync_error = sync_error;
- previous_correction = amount_to_stuff;
+ previous_sync_error = sync_error;
+ previous_correction = amount_to_stuff;
- tsum_of_sync_errors += sync_error;
- tsum_of_drifts += statistics[newest_statistic].drift;
- if (amount_to_stuff > 0) {
- tsum_of_insertions_and_deletions += amount_to_stuff;
- } else {
- tsum_of_insertions_and_deletions -= amount_to_stuff;
- }
- tsum_of_corrections += amount_to_stuff;
- session_corrections += amount_to_stuff;
+ tsum_of_sync_errors += sync_error;
+ tsum_of_drifts += statistics[newest_statistic].drift;
+ if (amount_to_stuff > 0) {
+ tsum_of_insertions_and_deletions += amount_to_stuff;
+ } else {
+ tsum_of_insertions_and_deletions -= amount_to_stuff;
+ }
+ tsum_of_corrections += amount_to_stuff;
+ session_corrections += amount_to_stuff;
- newest_statistic = (newest_statistic + 1) % trend_interval;
- number_of_statistics++;
+ newest_statistic = (newest_statistic + 1) % trend_interval;
+ number_of_statistics++;
+ }
}
if (play_number % print_interval == 0) {
// we can now calculate running averages for sync error (frames), corrections (ppm),
// if ((play_number/print_interval)%20==0)
if (config.statistics_requested) {
if (at_least_one_frame_seen) {
- if (config.output->delay)
- inform("Sync error: %.1f (frames); net correction: %.1f (ppm); corrections: %.1f "
- "(ppm); missing packets %llu; late packets %llu; too late packets %llu; "
- "resend requests %llu; min DAC queue size %lli, min and max buffer occupancy "
- "%d and %d.",
- moving_average_sync_error, moving_average_correction * 1000000 / 352,
- moving_average_insertions_plus_deletions * 1000000 / 352, missing_packets,
- late_packets, too_late_packets, resend_requests, minimum_dac_queue_size,
- minimum_buffer_occupancy, maximum_buffer_occupancy);
- else
+ if ((config.output->delay)) {
+ if (config.no_sync==0) {
+ inform("Sync error: %.1f (frames); net correction: %.1f (ppm); corrections: %.1f "
+ "(ppm); missing packets %llu; late packets %llu; too late packets %llu; "
+ "resend requests %llu; min DAC queue size %lli, min and max buffer occupancy "
+ "%d and %d.",
+ moving_average_sync_error, moving_average_correction * 1000000 / 352,
+ moving_average_insertions_plus_deletions * 1000000 / 352, missing_packets,
+ late_packets, too_late_packets, resend_requests, minimum_dac_queue_size,
+ minimum_buffer_occupancy, maximum_buffer_occupancy);
+ } else {
+ inform("Synchronisation disabled. Sync error: %.1f (frames); missing packets %llu; late packets %llu; too late packets %llu; "
+ "resend requests %llu; min DAC queue size %lli, min and max buffer occupancy "
+ "%d and %d.",
+ moving_average_sync_error, missing_packets,
+ late_packets, too_late_packets, resend_requests, minimum_dac_queue_size,
+ minimum_buffer_occupancy, maximum_buffer_occupancy);
+ }
+ } else {
inform("Synchronisation disabled. Missing packets %llu; late packets %llu; too late packets %llu; "
"resend requests %llu; min and max buffer occupancy "
"%d and %d.",
missing_packets,
late_packets, too_late_packets, resend_requests,
- minimum_buffer_occupancy, maximum_buffer_occupancy);
+ minimum_buffer_occupancy, maximum_buffer_occupancy);
+ }
} else {
inform("No frames received in the last sampling interval.");
}
}
- minimum_dac_queue_size = 1000000; // hack reset
- maximum_buffer_occupancy = 0; // can't be less than this
- minimum_buffer_occupancy = BUFFER_FRAMES; // can't be more than this
+ minimum_dac_queue_size = INT64_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;
}
}