// debug(1,"clock: %" PRIx64 ", rtptime: %" PRIu32 ".", clock_id, rtptime);
if (conn->anchor_clock != clock_id) {
debug(1, "Connection %d: Set Anchor Clock: %" PRIx64 ".", conn->connection_number, clock_id);
- conn->anchor_clock_is_new = 1;
}
// debug(1,"set anchor info clock: %" PRIx64", rtptime: %u, networktime: %" PRIx64 ".", clock_id,
// rtptime, networktime);
if (conn->anchor_remote_info_is_valid !=
0) { // i.e. if we have anchor clock ID and anchor time / rtptime
- // figure out how long the clock has been master
- int64_t duration_of_mastership = time_now - start_of_mastership;
- // if we have an alternative, i.e. if last anchor stuff is valid
- // then we can wait for a long time to let the new master settle
- // if we do not, we can wait for some different (shorter) time before
- // using the master clock timing
if (actual_clock_id == conn->anchor_clock) {
- // if the master clock and the anchor clock are the same
- // wait at least this time before using the new master clock
- // note that mastership may be backdated
- if (duration_of_mastership < 1500000000) {
- debug(3, "master not old enough yet: %f ms", 0.000001 * duration_of_mastership);
- response = clock_not_ready;
- } else if ((duration_of_mastership > 5000000000) ||
- (conn->last_anchor_info_is_valid == 0)) {
- // use the master clock if it's at least this old or if we have no alternative
- // and it at least is the minimum age.
- conn->last_anchor_rtptime = conn->anchor_rtptime;
- conn->last_anchor_local_time = conn->anchor_time - actual_offset;
- conn->last_anchor_time_of_update = time_now;
- if (conn->last_anchor_info_is_valid == 0)
- conn->last_anchor_validity_start_time = start_of_mastership;
- conn->last_anchor_info_is_valid = 1;
- if (conn->anchor_clock_is_new != 0)
- debug(1,
- "Connection %d: Clock %" PRIx64
- " is now the new anchor clock and master clock. History: %f milliseconds.",
- conn->connection_number, conn->anchor_clock, 0.000001 * duration_of_mastership);
- conn->anchor_clock_is_new = 0;
- }
+ conn->last_anchor_rtptime = conn->anchor_rtptime;
+ conn->last_anchor_local_time = conn->anchor_time - actual_offset;
+ conn->last_anchor_time_of_update = time_now;
+ if (conn->last_anchor_info_is_valid == 0)
+ conn->last_anchor_validity_start_time = start_of_mastership;
+ conn->last_anchor_info_is_valid = 1;
} else {
+ debug(3, "Current master clock %" PRIx64 " and anchor_clock %" PRIx64 " are different",
+ actual_clock_id, conn->anchor_clock);
// the anchor clock and the actual clock are different
- // this could happen because
- // the master clock has changed or
- // because the anchor clock has changed
-
- // so, if the anchor has not changed, it must be that the master clock has changed
- if (conn->anchor_clock_is_new != 0)
- debug(3,
- "Connection %d: Anchor clock has changed to %" PRIx64 ", master clock is: %" PRIx64
- ". History: %f milliseconds.",
- conn->connection_number, conn->anchor_clock, actual_clock_id,
- 0.000001 * duration_of_mastership);
-
- if ((conn->last_anchor_info_is_valid != 0) && (conn->anchor_clock_is_new == 0)) {
+ // this could happen because the master clock has changed or
+ // because the anchor clock has changed (this can happen with a Realtime Stream)
+
+ if (conn->last_anchor_info_is_valid != 0) {
int64_t time_since_last_update =
get_absolute_time_in_ns() - conn->last_anchor_time_of_update;
if (time_since_last_update > 5000000000) {
+ int64_t duration_of_mastership = time_now - start_of_mastership;
debug(1,
"Connection %d: Master clock has changed to %" PRIx64
". History: %f milliseconds.",
conn->connection_number, actual_clock_id, 0.000001 * duration_of_mastership);
- // here we adjust the time of the anchor rtptime
- // we know its local time, so we use the new clocks's offset to
- // calculate what time that must be on the new clock
+ // Here we adjust the time of the anchor rtptime.
+ // We know its local time, so we use the new clocks's offset to
+ // calculate what time that must be on the new clock.
// Now, the thing is that while the anchor clock and master clock for a
// buffered session starts off the same,
// the master clock can change without the anchor clock changing.
- // SPS allows the new master clock time to settle down and then
+ // SPS gives the new master clock time to settle down and then
// calculates the appropriate offset to it by
// calculating back from the local anchor information and the new clock's
// advertised offset. Of course, small errors will occur.
- // More importantly, the new master clock(s) and the original one will
+ // Equally importantly, the new master clock(s) and the original one will
// drift at different rates. So, after all this, if the original master
- // clock becomes the master again, then there could be quite a difference
+ // clock becomes the master again, there could be quite a difference
// in the time information that was calculated through all the clock
// changes and the actual master clock's time information.
// What do we do? We can hardly ignore this new and reliable information
// So, if the master clock has again become equal to the actual anchor clock
// then we can reinstate it all.
- // first, let us calculate the cumulative offset after swapping all the clocks...
+
+ // First, let us calculate the cumulative offset after swapping all the clocks...
conn->anchor_time = conn->last_anchor_local_time + actual_offset;
- // we can check how much of a deviation there was going from clock to clock and back
- // around to the master clock
+ // Here we can check how much of a deviation there was going from clock to clock and
+ // back around to the master clock
if (actual_clock_id == conn->actual_anchor_clock) {
int64_t cumulative_deviation = conn->anchor_time - conn->actual_anchor_time;
debug(1,
- "Master clock has become equal to the anchor clock. The estimated clock time "
- "was %f ms ahead(+) or behind (-) the real clock time.",
+ "The original master clock has become the master clock again."
+ "The estimated clock time "
+ "was %f ms ahead(+) or behind (-) the original master clock time.",
0.000001 * cumulative_deviation);
conn->anchor_clock = conn->actual_anchor_clock;
conn->anchor_time = conn->actual_anchor_time;
conn->anchor_rtptime = conn->actual_anchor_rtptime;
} else {
- // conn->anchor_time = conn->last_anchor_local_time + actual_offset; // already done
conn->anchor_clock = actual_clock_id;
}
- conn->anchor_clock_is_new = 0;
}
} else {
response = clock_not_valid; // no current clock information and no previous clock info
if ((clock_status_t)response != conn->clock_status) {
switch (response) {
case clock_ok:
- debug(1, "Connection %d: NQPTP new master clock %" PRIx64 ".", conn->connection_number,
+ debug(1, "Connection %d: NQPTP master clock %" PRIx64 ".", conn->connection_number,
actual_clock_id);
break;
case clock_not_ready:
debug(2, "Connection %d: No NQPTP master clock.", conn->connection_number);
break;
case clock_no_anchor_info:
- debug(1, "Connection %d: No clock anchor information.", conn->connection_number);
+ debug(1, "Connection %d: Awaiting clock anchor information.", conn->connection_number);
break;
case clock_version_mismatch:
debug(1, "Connection %d: NQPTP clock interface mismatch.", conn->connection_number);
// debug(1,"frame_1: %" PRIu32 ", added latency: %" PRId32 ".", frame_1, added_latency);
set_ptp_anchor_info(conn, clock_id, frame_1 - 11035 - added_latency,
remote_packet_time_ns);
+ if (conn->anchor_clock != clock_id) {
+ debug(1, "Connection %d: Change Anchor Clock: %" PRIx64 ".", conn->connection_number,
+ clock_id);
+ }
} break;
case 0xd6:
if (count == 2)
debug(2, "buffered_read: waiting for %u bytes (okay at start of a track).", count);
else
- debug(1, "buffered_read: waiting for %u bytes.", count);
+ debug(2, "buffered_read: waiting for %u bytes.", count);
}
while ((descriptor->buffer_occupancy == 0) && (descriptor->error_code == 0)) {
if (pthread_cond_wait(&descriptor->not_empty_cv, &descriptor->mutex))
int streaming_has_started = 0;
int play_enabled = 0;
uint32_t flush_from_timestamp;
- double requested_lead_time = 0.1; // normal lead time minimum -- maybe it should be about 0.1
+ double requested_lead_time = 0.0; // normal lead time minimum -- maybe it should be about 0.1
// wait until our timing information is valid
if (player_buffer_occupancy > ((requested_lead_time + 0.4) * conn->input_rate /
352)) { // must be greater than the lead time.
// if there is enough stuff in the player's buffer, sleep for a while and try again
- usleep(1000); // wait for a while
+ debug(3, "sleep while full");
+ usleep(10000); // wait for a while
} else {
if ((pcm_buffer_occupancy - pcm_buffer_read_point) >= (352 * conn->input_bytes_per_frame)) {
new_buffer_needed = 0;
// it seems that some garbage blocks can be left after the flush, so
// only accept them if they have sensible lead times
- if ((lead_time < (int64_t)5000000000L) && (lead_time >= 0)) {
+ if ((lead_time < (int64_t)30000000000L) && (lead_time >= 0)) {
// if it's the very first block (thus no priming needed)
if ((blocks_read == 1) || (blocks_read_since_flush > 3)) {
if ((lead_time >= (int64_t)(requested_lead_time * 1000000000L)) ||
debug(1, "frame to local time error");
}
} else {
- usleep(1000); // wait before asking if play is enabled again
+ debug(3, "sleep until demand");
+ usleep(10000); // wait before asking if play is enabled again
}
} else {
new_buffer_needed = 1;
// debug(1,"requested_lead_time_ns is actually %f milliseconds.", requested_lead_time_ns *
// 1E-6);
int outdated = 0;
+ int too_soon_after_connection = 0;
if (have_time_information == 0) {
+ int64_t play_time_since_connection = local_should_be_time - conn->connection_start_time;
+ int64_t time_since_connection = get_absolute_time_in_ns() - conn->connection_start_time;
+
+ too_soon_after_connection =
+ ((play_time_since_connection < 2000000000) && (time_since_connection < 2000000000));
+ if (too_soon_after_connection)
+ debug(3, "time_since_connection is %f milliseconds. too_soon_after_connection is %d.",
+ time_since_connection * 1E-6, too_soon_after_connection);
local_lead_time = local_should_be_time - get_absolute_time_in_ns();
// debug(1,"local_lead_time is actually %f milliseconds.", local_lead_time * 1E-6);
outdated = (local_lead_time < requested_lead_time_ns);
// debug(1,"Frame is outdated %d if lead_time %" PRId64 " is less than requested lead time
// %" PRId64 " ns.", outdated, local_lead_time, requested_lead_time_ns);
} else {
- debug(1, "Timing information not valid");
+ debug(3, "Timing information not valid");
// outdated = 1;
}
// flushing the pcm buffer wasn't enough, as the request would have been turned off by now
// so we better indicate that the pcm buffer is empty and its contents invalid
- // also, if the incomgin frame is outdated, set pcm_buffer_occupancy to 0;
- if ((flush_requested) || (outdated)) {
+ // also, if the incoming frame is outdated, set pcm_buffer_occupancy to 0;
+ if ((flush_requested) || (outdated) || (too_soon_after_connection)) {
pcm_buffer_occupancy = 0;
}
//}
}
- if (((flush_requested != 0) && (seq_no == flushUntilSeq)) ||
- ((flush_requested == 0) && (new_buffer_needed))) {
+ if ((((flush_requested != 0) && (seq_no == flushUntilSeq)) ||
+ ((flush_requested == 0) && (new_buffer_needed))) &&
+ (too_soon_after_connection == 0)) {
unsigned char nonce[12];
memset(nonce, 0, sizeof(nonce));
// revert the state of cancellability
}
+ } else {
+ debug(3, "Dropping block %u with timestamp %u.", seq_no, timestamp);
}
} else {
// nread is 0 -- the port has been closed