From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Tue, 1 Jun 2021 13:51:17 +0000 (+0100) Subject: Remember the original anchor information so that if the master clock become equal... X-Git-Tag: 4.1-dev~98 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c5dafbd28b78ed30b041a4b9889339bc05f42b8d;p=thirdparty%2Fshairport-sync.git Remember the original anchor information so that if the master clock become equal to it in the future, it can be restored to those exact numbers and eliminate any intervening approximations. Add some diagnostics. --- diff --git a/audio_alsa.c b/audio_alsa.c index c5794348..2d07c8f4 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -501,8 +501,8 @@ int actual_open_alsa_device(int do_auto_setup) { } ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf); if (ret < 0) { - die("audio_alsa: Alsa sample format %d not available for device \"%s\": %s", sf, - alsa_out_dev, snd_strerror(ret)); + die("audio_alsa: Alsa sample format %d not available for device \"%s\": %s", sf, alsa_out_dev, + snd_strerror(ret)); return ret; } } else { // auto format diff --git a/player.c b/player.c index a0e10d94..a9822d68 100644 --- a/player.c +++ b/player.c @@ -384,11 +384,12 @@ static void terminate_decoders(rtsp_conn_info *conn) { } static void init_buffer(rtsp_conn_info *conn) { - debug(1,"input_bytes_per_frame: %d.", conn->input_bytes_per_frame); - debug(1,"input_bit_depth: %d.", conn->input_bit_depth); + // debug(1,"input_bytes_per_frame: %d.", conn->input_bytes_per_frame); + // debug(1,"input_bit_depth: %d.", conn->input_bit_depth); int i; for (i = 0; i < BUFFER_FRAMES; i++) -// conn->audio_buffer[i].data = malloc(conn->input_bytes_per_frame * conn->max_frames_per_packet); + // conn->audio_buffer[i].data = malloc(conn->input_bytes_per_frame * + // conn->max_frames_per_packet); conn->audio_buffer[i].data = malloc(8 * conn->max_frames_per_packet); // todo } @@ -2121,7 +2122,7 @@ void *player_thread_func(void *arg) { int i, j; int32_t ls, rs; int32_t ll = 0, rl = 0; - int32_t *inps = (int32_t*) inbuf; + int32_t *inps = (int32_t *)inbuf; int32_t *outpl = (int32_t *)conn->tbuf; for (i = 0; i < inbuflength; i++) { ls = *inps++; diff --git a/player.h b/player.h index a21deec6..c35e5726 100644 --- a/player.h +++ b/player.h @@ -273,10 +273,18 @@ typedef struct { int anchor_remote_info_is_valid; int anchor_clock_is_new; + + // these can be modified if the master clock changes over time uint64_t anchor_clock; uint64_t anchor_time; // this is the time according to the clock uint32_t anchor_rtptime; + // these are used to identify when the master clock becomes equal to the + // actual anchor clock information, so it can be used to avoid accumulating errors + uint64_t actual_anchor_clock; + uint64_t actual_anchor_time; + uint32_t actual_anchor_rtptime; + clock_status_t clock_status; #ifdef CONFIG_AIRPLAY_2 diff --git a/rtp.c b/rtp.c index dc3ba0aa..9fb8481c 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 " @@ -1220,22 +1220,45 @@ void set_ptp_anchor_info(rtsp_conn_info *conn, uint64_t clock_id, uint32_t rtpti // valid for some minimum time (and thus may not be reliable), we need to invalidate // last_anchor_info + if ((conn->airplay_stream_type == buffered_stream) && + ((clock_id != conn->anchor_clock) || (conn->anchor_rtptime != rtptime) || + (conn->anchor_time != networktime))) { + uint64_t master_clock_id = 0; + ptp_get_clock_info(&master_clock_id, NULL, NULL); + debug(1, + "Connection %d: Note: anchor parameters have changed. Old clock: %" PRIx64 + ", rtptime: %u, networktime: %" PRIu64 ". New clock: %" PRIx64 + ", rtptime: %u, networktime: %" PRIu64 ". Current master clock: %" PRIx64 ".", + conn->connection_number, conn->anchor_clock, conn->anchor_rtptime, conn->anchor_time, + clock_id, rtptime, networktime, master_clock_id); + } + if ((clock_id == conn->anchor_clock) && ((conn->anchor_rtptime != rtptime) || (conn->anchor_time != networktime))) { uint64_t time_now = get_absolute_time_in_ns(); int64_t last_anchor_validity_duration = time_now - conn->last_anchor_validity_start_time; if (last_anchor_validity_duration < 5000000000) { - debug(1, - "Connection %d: Note: anchor parameters have changed before clock %" PRIx64 - " has stabilised.", - conn->connection_number, clock_id); + if (conn->airplay_stream_type == buffered_stream) + debug(1, + "Connection %d: Note: anchor parameters have changed before clock %" PRIx64 + " has stabilised.", + conn->connection_number, clock_id); conn->last_anchor_info_is_valid = 0; } } + conn->anchor_remote_info_is_valid = 1; + + // these can be modified if the master clock changes over time conn->anchor_rtptime = rtptime; conn->anchor_time = networktime; conn->anchor_clock = clock_id; + + // these are used to identify when the master clock becomes equal to the + // actual anchor clock information, so it can be used to avoid accumulating errors + conn->actual_anchor_rtptime = rtptime; + conn->actual_anchor_time = networktime; + conn->actual_anchor_clock = clock_id; } void reset_ptp_anchor_info(rtsp_conn_info *conn) { @@ -1303,8 +1326,18 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, // 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; + + // but if the master clock has become equal to the actual anchor clock + // then we can reinstate it all + if (actual_clock_id == conn->actual_anchor_clock) { + debug(1, "Master clock has become equal to the anchor clock"); + 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; + conn->anchor_clock = actual_clock_id; + } } } else { response = clock_not_valid; // no current clock information and no previous clock info @@ -2087,37 +2120,38 @@ void *rtp_buffered_audio_processor(void *arg) { enum AVSampleFormat av_format; switch (config.output_format) { - case SPS_FORMAT_S32: - case SPS_FORMAT_S32_LE: - case SPS_FORMAT_S32_BE: - case SPS_FORMAT_S24: - case SPS_FORMAT_S24_LE: - case SPS_FORMAT_S24_BE: - case SPS_FORMAT_S24_3LE: - case SPS_FORMAT_S24_3BE: - av_format = AV_SAMPLE_FMT_S32; - conn->input_bytes_per_frame = 8; // the output from the decoder will be input to the player - conn->input_bit_depth = 32; - debug(1,"32-bit output format chosen"); - break; - case SPS_FORMAT_S16: - case SPS_FORMAT_S16_LE: - case SPS_FORMAT_S16_BE: - av_format = AV_SAMPLE_FMT_S16; - conn->input_bytes_per_frame = 4; - conn->input_bit_depth = 16; - break; - case SPS_FORMAT_U8: - av_format = AV_SAMPLE_FMT_U8; - conn->input_bytes_per_frame = 2; - conn->input_bit_depth = 8; - break; - default: - debug(1,"Unsupported DAC output format %u. AV_SAMPLE_FMT_S16 decoding chosen. Good luck!", config.output_format); - av_format = AV_SAMPLE_FMT_S16; - conn->input_bytes_per_frame = 4; // the output from the decoder will be input to the player - conn->input_bit_depth = 16; - break; + case SPS_FORMAT_S32: + case SPS_FORMAT_S32_LE: + case SPS_FORMAT_S32_BE: + case SPS_FORMAT_S24: + case SPS_FORMAT_S24_LE: + case SPS_FORMAT_S24_BE: + case SPS_FORMAT_S24_3LE: + case SPS_FORMAT_S24_3BE: + av_format = AV_SAMPLE_FMT_S32; + conn->input_bytes_per_frame = 8; // the output from the decoder will be input to the player + conn->input_bit_depth = 32; + debug(1, "32-bit output format chosen"); + break; + case SPS_FORMAT_S16: + case SPS_FORMAT_S16_LE: + case SPS_FORMAT_S16_BE: + av_format = AV_SAMPLE_FMT_S16; + conn->input_bytes_per_frame = 4; + conn->input_bit_depth = 16; + break; + case SPS_FORMAT_U8: + av_format = AV_SAMPLE_FMT_U8; + conn->input_bytes_per_frame = 2; + conn->input_bit_depth = 8; + break; + default: + debug(1, "Unsupported DAC output format %u. AV_SAMPLE_FMT_S16 decoding chosen. Good luck!", + config.output_format); + av_format = AV_SAMPLE_FMT_S16; + conn->input_bytes_per_frame = 4; // the output from the decoder will be input to the player + conn->input_bit_depth = 16; + break; }; av_opt_set_sample_fmt(swr, "out_sample_fmt", av_format, 0); @@ -2134,8 +2168,7 @@ void *rtp_buffered_audio_processor(void *arg) { ssize_t nread; int finished = 0; - int pcm_buffer_size = - (1024 + 352) * conn->input_bytes_per_frame; + int pcm_buffer_size = (1024 + 352) * conn->input_bytes_per_frame; uint8_t pcm_buffer[pcm_buffer_size]; int pcm_buffer_occupancy = 0; @@ -2307,8 +2340,9 @@ void *rtp_buffered_audio_processor(void *arg) { new_buffer_needed = 1; if (pcm_buffer_read_point != 0) { // debug(1,"pcm_buffer_read_point (frames): %u, pcm_buffer_occupancy (frames): %u", - // pcm_buffer_read_point/conn->input_bytes_per_frame, pcm_buffer_occupancy/conn->input_bytes_per_frame); - // if there is anything to move down to the front of the buffer, do it now; + // pcm_buffer_read_point/conn->input_bytes_per_frame, + // pcm_buffer_occupancy/conn->input_bytes_per_frame); if there is anything to move down + // to the front of the buffer, do it now; if ((pcm_buffer_occupancy - pcm_buffer_read_point) > 0) { // move the remaining frames down to the start of the buffer // debug(1,"move the remaining frames down to the start of the pcm_buffer"); @@ -2501,8 +2535,8 @@ void *rtp_buffered_audio_processor(void *arg) { debug(2, "samples remaining before flush: %d, number of samples %d. " "flushFromTS: %u, pcm_buffer_read_point_rtptime: %u.", - samples_remaining, dst_bufsize / conn->input_bytes_per_frame, flush_from_timestamp, - pcm_buffer_read_point_rtptime); + samples_remaining, dst_bufsize / conn->input_bytes_per_frame, + flush_from_timestamp, pcm_buffer_read_point_rtptime); dst_bufsize = samples_remaining * conn->input_bytes_per_frame; } } @@ -2510,7 +2544,8 @@ void *rtp_buffered_audio_processor(void *arg) { debug(1, "pcm_buffer_read_point (frames): %u, pcm_buffer_occupancy " "(frames): %u", - pcm_buffer_read_point / conn->input_bytes_per_frame, pcm_buffer_occupancy / conn->input_bytes_per_frame); + pcm_buffer_read_point / conn->input_bytes_per_frame, + pcm_buffer_occupancy / conn->input_bytes_per_frame); pcm_buffer_size = dst_bufsize + pcm_buffer_occupancy; debug(1, "fatal error! pcm buffer too small at %d bytes.", pcm_buffer_size); diff --git a/rtsp.c b/rtsp.c index c50b7679..a808c96f 100644 --- a/rtsp.c +++ b/rtsp.c @@ -2077,7 +2077,8 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) conn->input_bit_depth = 16; conn->input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8); - player_prepare_to_play(conn); // get capabilities of DAC before creating the buffered audio thread + player_prepare_to_play( + conn); // get capabilities of DAC before creating the buffered audio thread pthread_create(&conn->rtp_buffered_audio_thread, NULL, &rtp_buffered_audio_processor, (void *)conn);