From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Wed, 26 May 2021 15:48:25 +0000 (+0100) Subject: a slightly more rational clock handling regime, I hope. Wait for 400 ms when a clock... X-Git-Tag: 4.1-dev~114 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=26ce13d51180f1f613561e330f5861b3ed08a657;p=thirdparty%2Fshairport-sync.git a slightly more rational clock handling regime, I hope. Wait for 400 ms when a clock becomes master. Wait five seconds when you get a new master clock. --- diff --git a/player.h b/player.h index cc4dda2c..2a606a0e 100644 --- a/player.h +++ b/player.h @@ -209,7 +209,7 @@ typedef struct { int fix_volume; double initial_airplay_volume; int initial_airplay_volume_set; - + uint32_t timestamp_epoch, last_timestamp, maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 // or 1. @@ -270,6 +270,7 @@ typedef struct { // this is what connects an rtp timestamp to the remote time int anchor_remote_info_is_valid; + int anchor_clock_is_new; uint64_t anchor_clock; uint64_t anchor_time; // this is the time according to the clock uint32_t anchor_rtptime; @@ -287,7 +288,8 @@ typedef struct { pthread_t rtp_buffered_audio_thread; int last_anchor_info_is_valid; - uint64_t last_anchor_clock_offset; + uint32_t last_anchor_rtptime; + uint64_t last_anchor_local_time; uint64_t last_anchor_time_of_update; uint64_t last_anchor_clock; diff --git a/ptp-utilities.c b/ptp-utilities.c index 6b6ffd1a..61041bd8 100644 --- a/ptp-utilities.c +++ b/ptp-utilities.c @@ -74,10 +74,19 @@ int ptp_get_clock_info(uint64_t *actual_clock_id, uint64_t *raw_offset) { if (nqptp_data.version == NQPTP_SHM_STRUCTURES_VERSION) { // assuming a clock id can not be zero if (nqptp_data.master_clock_id != 0) { - if (actual_clock_id != NULL) - *actual_clock_id = nqptp_data.master_clock_id; - if (raw_offset != NULL) - *raw_offset = nqptp_data.local_to_master_time_offset; + // find out how long it's been since it became master + uint64_t time_now = get_absolute_time_in_ns(); + int64_t time_of_mastership = time_now - nqptp_data.master_clock_start_time; + // if (0) { + if (time_of_mastership < 700000000) { + // should get between 3 and 4 pings in this time -- less likely to get a bad start + response = clock_no_master; // not ready yet + } else { + if (actual_clock_id != NULL) + *actual_clock_id = nqptp_data.master_clock_id; + if (raw_offset != NULL) + *raw_offset = nqptp_data.local_to_master_time_offset; + } } else { response = clock_no_master; } diff --git a/rtp.c b/rtp.c index 90362752..4d5ba055 100644 --- a/rtp.c +++ b/rtp.c @@ -290,8 +290,8 @@ void *rtp_control_receiver(void *arg) { obfp += 2; }; *obfp = 0; - - + + // get raw timestamp information // I think that a good way to understand these timestamps is that // (1) the rtlt below is the timestamp of the frame that should be playing at the @@ -302,19 +302,19 @@ void *rtp_control_receiver(void *arg) { // Thus, (3) the latency can be calculated by subtracting the second from the // first. // There must be more to it -- there something missing. - + // In addition, it seems that if the value of the short represented by the second // pair of bytes in the packet is 7 // then an extra time lag is expected to be added, presumably by // the AirPort Express. - + // Best guess is that this delay is 11,025 frames. - + uint32_t rtlt = nctohl(&packet[4]); // raw timestamp less latency uint32_t rt = nctohl(&packet[16]); // raw timestamp - + uint32_t fl = nctohs(&packet[2]); // - + debug(1,"Sync Packet of %d bytes received: \"%s\", flags: %d, timestamps %u and %u, giving a latency of %d frames.",plen,obf,fl,rt,rtlt,rt-rtlt); //debug(1,"Monotonic timestamps are: %" PRId64 " and %" PRId64 " @@ -1209,8 +1209,10 @@ void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) { void set_ptp_anchor_info(rtsp_conn_info *conn, uint64_t clock_id, uint32_t rtptime, uint64_t networktime) { - if (conn->anchor_clock != clock_id) + 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; + } conn->anchor_remote_info_is_valid = 1; conn->anchor_rtptime = rtptime; conn->anchor_time = networktime; @@ -1225,7 +1227,6 @@ void reset_ptp_anchor_info(rtsp_conn_info *conn) { int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, uint64_t *anchorLocalTime) { - uint64_t actual_clock_id, actual_offset; int response = ptp_get_clock_info(&actual_clock_id, &actual_offset); @@ -1233,36 +1234,38 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, if (conn->anchor_remote_info_is_valid != 0) { // i.e. if we have anchor clock ID and anchor time / rtptime if (actual_clock_id == conn->anchor_clock) { - conn->last_anchor_clock_offset = actual_offset; + // if the master clock and the anchor clock are the same + conn->last_anchor_clock = conn->anchor_clock; + conn->last_anchor_rtptime = conn->anchor_rtptime; + conn->last_anchor_local_time = conn->anchor_time - actual_offset; conn->last_anchor_time_of_update = get_absolute_time_in_ns(); conn->last_anchor_info_is_valid = 1; - if (anchorRTP != NULL) - *anchorRTP = conn->anchor_rtptime; - if (anchorLocalTime != NULL) - *anchorLocalTime = conn->anchor_time - conn->last_anchor_clock_offset; + if (conn->anchor_clock_is_new != 0) + debug(1,"new anchor recognised"); + conn->anchor_clock_is_new = 0; } else { - if (conn->last_anchor_info_is_valid != 0) { + // 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(1,"anchor has changed"); + + if ((conn->last_anchor_info_is_valid != 0) && (conn->anchor_clock_is_new == 0)) { int64_t time_since_last_update = get_absolute_time_in_ns() - conn->last_anchor_time_of_update; if (time_since_last_update > 5000000000) { debug(1, "change master clock to %" PRIx64 ".", actual_clock_id); - uint64_t new_anchor_time = conn->anchor_time; - new_anchor_time = new_anchor_time - conn->last_anchor_clock_offset; // to local - new_anchor_time = new_anchor_time + actual_offset; // to the next clock - conn->anchor_time = new_anchor_time; + // 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 + conn->anchor_time = conn->last_anchor_local_time + actual_offset; conn->anchor_clock = actual_clock_id; - if (anchorRTP != NULL) - *anchorRTP = conn->anchor_rtptime; - if (anchorLocalTime != NULL) - *anchorLocalTime = conn->anchor_time - actual_offset; - } else { - if (anchorRTP != NULL) - *anchorRTP = conn->anchor_rtptime; - if (anchorLocalTime != NULL) - *anchorLocalTime = conn->anchor_time - conn->last_anchor_clock_offset; } } else { - response = clock_not_valid; // no current clock information and no previous clock info + response = clock_not_valid; // no current clock information and no previous clock info } } } else { @@ -1313,11 +1316,12 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, conn->clock_status = response; } - if ((response != clock_ok) && (conn->last_anchor_info_is_valid != 0)) { + if (conn->last_anchor_info_is_valid != 0) { if (anchorRTP != NULL) - *anchorRTP = conn->anchor_rtptime; + *anchorRTP = conn->last_anchor_rtptime; if (anchorLocalTime != NULL) - *anchorLocalTime = conn->anchor_time - conn->last_anchor_clock_offset; + *anchorLocalTime = conn->last_anchor_local_time; + response = clock_ok; } return response; @@ -2137,8 +2141,12 @@ void *rtp_buffered_audio_processor(void *arg) { if ((lead_time >= (int64_t)(reqested_lead_time * 1000000000)) || (streaming_has_started == 1)) { if (streaming_has_started == 0) - debug(2, "Connection %d: buffered audio lead time is %f seconds.", conn->connection_number, + debug(1, "Connection %d: buffered audio starting lead time is %f seconds.", conn->connection_number, 0.000000001 * lead_time); + //else + // debug(1, "Connection %d: buffered audio lead time is %f seconds.", conn->connection_number, + // 0.000000001 * lead_time); + streaming_has_started = 1; player_put_packet(0, 0, pcm_buffer_read_point_rtptime, pcm_buffer + pcm_buffer_read_point, 352, conn); diff --git a/rtsp.c b/rtsp.c index ace0e98f..7ae9fc7b 100644 --- a/rtsp.c +++ b/rtsp.c @@ -1298,7 +1298,7 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r void handle_flushbuffered(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { debug(3, "Connection %d: FLUSHBUFFERED %s :: Content-Length %d", conn->connection_number, req->path, req->contentlength); - debug_log_rtsp_message(2, "FLUSHBUFFERED request", req); + debug_log_rtsp_message(1, "FLUSHBUFFERED request", req); uint64_t flushUntilSeq = 0; uint64_t flushUntilTS = 0;