From: Mike Brady Date: Fri, 2 Sep 2016 15:53:52 +0000 (+0100) Subject: Enable 64-bit monotonic rtptime calculations X-Git-Tag: 3.0.d18~63 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ef851a927bd948cd61dfae2ea3ca7c5101274098;p=thirdparty%2Fshairport-sync.git Enable 64-bit monotonic rtptime calculations --- diff --git a/common.h b/common.h index e2ab47b9..c273fd19 100644 --- a/common.h +++ b/common.h @@ -107,11 +107,11 @@ typedef struct { char *mdns_name; mdns_backend *mdns; int buffer_start_fill; - int32_t latency; - int32_t userSuppliedLatency; // overrides all other latencies -- use with caution - int32_t iTunesLatency; // supplied with --iTunesLatency option - int32_t AirPlayLatency; // supplied with --AirPlayLatency option - int32_t ForkedDaapdLatency; // supplied with --ForkedDaapdLatency option + int64_t latency; + int64_t userSuppliedLatency; // overrides all other latencies -- use with caution + int64_t iTunesLatency; // supplied with --iTunesLatency option + int64_t AirPlayLatency; // supplied with --AirPlayLatency option + int64_t ForkedDaapdLatency; // supplied with --ForkedDaapdLatency option int daemonise; int statistics_requested,use_negotiated_latencies; enum playback_mode_type playback_mode; @@ -176,7 +176,7 @@ config_t config_file_stuff; int32_t buffer_occupancy; // allow it to be negative because seq_diff may be negative int64_t session_corrections; -uint32_t play_segment_reference_frame; +int64_t play_segment_reference_frame; uint64_t play_segment_reference_frame_remote_time; void command_start(void); diff --git a/player.c b/player.c index 8f35c6d8..19892c82 100644 --- a/player.c +++ b/player.c @@ -122,7 +122,7 @@ static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER; typedef struct audio_buffer_entry { // decoded audio packets int ready; - uint32_t timestamp; + int64_t timestamp; seq_t sequence_number; signed short *data; int length; // the length of the decoded data @@ -133,9 +133,9 @@ static abuf_t audio_buffer[BUFFER_FRAMES]; // mutex-protected variables static seq_t ab_read, ab_write; static int ab_buffering = 1, ab_synced = 0; -static uint32_t first_packet_timestamp = 0; +static int64_t first_packet_timestamp = 0; static int flush_requested = 0; -static uint32_t flush_rtp_timestamp; +static int64_t flush_rtp_timestamp; static uint64_t time_of_last_audio_packet; static int shutdown_requested; @@ -153,12 +153,13 @@ static uint64_t missing_packets, late_packets, too_late_packets, resend_requests // make timestamps and seqnos definitely monotonic -// add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 and 2^33 frames and continue up to 2^64 frames -// which is about 4*10^8 * 1,000 seconds at 384,000 frames per second -- about 4 trillion seconds or over 100,000 years. +// add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 and 2^33 frames and continue up to 2^63-1 frames +// if should never get into the negative range +// which is about 2*10^8 * 1,000 seconds at 384,000 frames per second -- about 2 trillion seconds or over 50,000 years. // also, it won't reach zero until then, if ever, so we can safely say that a null monotonic timestamp can mean something special -uint64_t monotonic_timestamp(uint32_t timestamp) { - uint64_t previous_value; - uint64_t return_value; +int64_t monotonic_timestamp(uint32_t timestamp) { + int64_t previous_value; + int64_t return_value; if (timestamp_epoch==0) { if (timestamp>maximum_timestamp_interval) timestamp_epoch=1; @@ -194,6 +195,8 @@ uint64_t monotonic_timestamp(uint32_t timestamp) { if ((return_value-previous_value)>maximum_timestamp_interval) debug(1,"interval between successive rtptimes greater than allowed!"); } + if (return_value<0) + debug(1,"monotonic rtptime is negative!"); return return_value; } @@ -466,7 +469,7 @@ static void free_buffer(void) { free(audio_buffer[i].data); } -void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len) { +void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len) { // ignore a request to flush that has been made before the first packet... if (packet_count==0) { @@ -485,14 +488,13 @@ void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len) // debug(1,"Flush_rtp_timestamp is %u",flush_rtp_timestamp); if ((flush_rtp_timestamp != 0) && - ((timestamp == flush_rtp_timestamp) || seq32_order(timestamp, flush_rtp_timestamp))) { - debug(3, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %u, flushing to " - "timestamp: %u.", + (timestamp <= flush_rtp_timestamp)) { + debug(3, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %lld, flushing to " + "timestamp: %lld.", seqno, timestamp, flush_rtp_timestamp); } else { if ((flush_rtp_timestamp != 0x0) && - (!seq32_order(timestamp, - flush_rtp_timestamp))) // if we have gone past the flush boundary time + (timestamp>flush_rtp_timestamp)) // if we have gone past the flush boundary time flush_rtp_timestamp = 0x0; abuf_t *abuf = 0; @@ -699,17 +701,14 @@ static abuf_t *buffer_get_frame(void) { } if ((flush_rtp_timestamp != 0) && - ((curframe->timestamp == flush_rtp_timestamp) || - seq32_order(curframe->timestamp, flush_rtp_timestamp))) { - debug(1, "Dropping flushed packet seqno %u, timestamp %u", curframe->sequence_number, + (curframe->timestamp <= flush_rtp_timestamp)) { + debug(1, "Dropping flushed packet seqno %u, timestamp %lld", curframe->sequence_number, curframe->timestamp); curframe->ready = 0; flush_limit++; ab_read = SUCCESSOR(ab_read); } - if ((flush_rtp_timestamp != 0) && - (!seq32_order(curframe->timestamp, - flush_rtp_timestamp))) // if we have gone past the flush boundary time + if (curframe->timestamp>flush_rtp_timestamp) flush_rtp_timestamp = 0; } } while ((flush_rtp_timestamp != 0) && (flush_limit <= 8820) && (curframe->ready == 0)); @@ -725,7 +724,7 @@ static abuf_t *buffer_get_frame(void) { notified_buffer_empty=0; // at least one buffer now -- diagnostic only. if (ab_buffering) { // if we are getting packets but not yet forwarding them to the player int have_sent_prefiller_silence; // set true when we have sent some silent frames to the DAC - uint32_t reference_timestamp; + int64_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); if (first_packet_timestamp == 0) { // if this is the very first packet @@ -760,14 +759,14 @@ static abuf_t *buffer_get_frame(void) { // if would be in sync. To do this, we would give it a latency offset of -100 ms, i.e. // -4410 frames. - int64_t delta = ((int64_t)first_packet_timestamp - (int64_t)reference_timestamp)+config.latency+config.audio_backend_latency_offset; // uint32_t to int64_t is okay and int32t to int64t promotion is okay. + int64_t delta = (first_packet_timestamp - reference_timestamp)+config.latency+config.audio_backend_latency_offset; if (delta>=0) { - uint64_t delta_fp_sec = (delta << 32) / 44100; // int64_t which is positive + int64_t delta_fp_sec = (delta << 32) / 44100; // int64_t which is positive first_packet_time_to_play=reference_timestamp_time+delta_fp_sec; } else { int64_t abs_delta = -delta; - uint64_t delta_fp_sec = (abs_delta << 32) / 44100; // int64_t which is positive + int64_t delta_fp_sec = (abs_delta << 32) / 44100; // int64_t which is positive first_packet_time_to_play=reference_timestamp_time-delta_fp_sec; } @@ -782,14 +781,14 @@ static abuf_t *buffer_get_frame(void) { if (first_packet_time_to_play != 0) { // recalculate first_packet_time_to_play -- the latency might change - int64_t delta = ((int64_t)first_packet_timestamp - (int64_t)reference_timestamp)+config.latency+config.audio_backend_latency_offset; // uint32_t to int64_t is okay and int32t to int64t promotion is okay. + int64_t delta = (first_packet_timestamp - reference_timestamp)+config.latency+config.audio_backend_latency_offset; if (delta>=0) { - uint64_t delta_fp_sec = (delta << 32) / 44100; // int64_t which is positive + int64_t delta_fp_sec = (delta << 32) / 44100; // int64_t which is positive first_packet_time_to_play=reference_timestamp_time+delta_fp_sec; } else { int64_t abs_delta = -delta; - uint64_t delta_fp_sec = (abs_delta << 32) / 44100; // int64_t which is positive + int64_t delta_fp_sec = (abs_delta << 32) / 44100; // int64_t which is positive first_packet_time_to_play=reference_timestamp_time-delta_fp_sec; } @@ -896,12 +895,12 @@ static abuf_t *buffer_get_frame(void) { int do_wait = 0; // don't wait unless we can really prove we must if ((ab_synced) && (curframe) && (curframe->ready) && (curframe->timestamp)) { do_wait = 1; // if the current frame exists and is ready, then wait unless it's time to let it go... - uint32_t reference_timestamp; + int64_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); // all types okay if (reference_timestamp) { // if we have a reference time - uint32_t packet_timestamp = curframe->timestamp; // types okay - int64_t delta = (int64_t)packet_timestamp - (int64_t)reference_timestamp; // uint32_t to int64_t is okay. + int64_t packet_timestamp = curframe->timestamp; // types okay + int64_t delta = packet_timestamp - reference_timestamp; int64_t offset = config.latency + config.audio_backend_latency_offset - config.audio_backend_buffer_desired_length; // all arguments are int32_t, so expression promotion okay int64_t net_offset = delta + offset; // okay @@ -954,7 +953,6 @@ static abuf_t *buffer_get_frame(void) { #endif #ifdef COMPILE_FOR_OSX uint64_t sec = time_to_wait_for_wakeup_fp >> 32; - ; uint64_t nsec = ((time_to_wait_for_wakeup_fp & 0xffffffff) * 1000000000) >> 32; struct timespec time_to_wait; time_to_wait.tv_sec = sec; @@ -1288,7 +1286,7 @@ static void *player_thread_func(void *arg) { at_least_one_frame_seen = 1; - uint32_t reference_timestamp; + int64_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); // types okay @@ -1840,7 +1838,7 @@ void player_volume(double airplay_volume) { #endif } -void player_flush(uint32_t timestamp) { +void player_flush(int64_t timestamp) { debug(3,"Flush requested up to %u. It seems as if 0 is special.",timestamp); pthread_mutex_lock(&flush_mutex); flush_requested = 1; diff --git a/player.h b/player.h index d6a16e5a..bd14acd2 100644 --- a/player.h +++ b/player.h @@ -18,12 +18,12 @@ int player_play(stream_cfg *cfg, pthread_t *thread); void player_stop(pthread_t *thread); void player_volume(double f); -void player_flush(uint32_t timestamp); +void player_flush(int64_t timestamp); -void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len); +void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len); -uint64_t monotonic_timestamp(uint32_t timestamp); // add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 2^33 frames and continue up to 2^64 frames -// which is about 4*10^8 * 1,000 seconds at 384,000 frames per second -- about 4 trillion seconds. +int64_t monotonic_timestamp(uint32_t timestamp); // add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 2^33 frames and continue up to 2^64 frames +// which is about 2*10^8 * 1,000 seconds at 384,000 frames per second -- about 2 trillion seconds. // assumes, without checking, that successive timestamps in a series always span an interval of less than one minute. uint64_t monotonic_seqno(uint16_t seq_no); // add an epoch to the seq_no. Uses the accompanying timstamp to detemine the correct epoch diff --git a/rtp.c b/rtp.c index 0f8dae93..cbef773d 100644 --- a/rtp.c +++ b/rtp.c @@ -71,7 +71,7 @@ static int control_socket; // our local [server] control socket static int timing_socket; // local timing socket //static pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread; -static uint32_t reference_timestamp; +static int64_t reference_timestamp; static uint64_t reference_timestamp_time; static uint64_t remote_reference_timestamp_time; @@ -159,7 +159,7 @@ void *rtp_audio_receiver(void *arg) { // debug(3, "RTP: Packets out of sequence: expected: %d, got %d.", last_seqno, seqno); last_seqno = seqno; // reset warning... } - uint32_t timestamp = ntohl(*(unsigned long *)(pktp + 4)); + int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4))); // if (packet[1]&0x10) // debug(1,"Audio packet Extension bit set."); @@ -198,7 +198,7 @@ void *rtp_control_receiver(void *arg) { uint8_t packet[2048], *pktp; struct timespec tn; uint64_t remote_time_of_sync, local_time_now, remote_time_now; - uint32_t sync_rtp_timestamp, rtp_timestamp_less_latency; + int64_t sync_rtp_timestamp, rtp_timestamp_less_latency; ssize_t nread; while (itr->please_stop==0) { nread = recv(control_socket, packet, sizeof(packet), 0); @@ -229,11 +229,11 @@ void *rtp_control_receiver(void *arg) { // debug(1,"Remote Sync Time: %0llx.",remote_time_of_sync); - rtp_timestamp_less_latency = ntohl(*((uint32_t *)&packet[4])); - sync_rtp_timestamp = ntohl(*((uint32_t *)&packet[16])); + rtp_timestamp_less_latency = monotonic_timestamp(ntohl(*((uint32_t *)&packet[4]))); + sync_rtp_timestamp = monotonic_timestamp(ntohl(*((uint32_t *)&packet[16]))); if (config.use_negotiated_latencies) { - uint32_t la = sync_rtp_timestamp-rtp_timestamp_less_latency+11025; + int64_t la = sync_rtp_timestamp-rtp_timestamp_less_latency+11025; if (la!=config.latency) { config.latency = la; // debug(1,"Using negotiated latency of %u frames.",config.latency); @@ -269,7 +269,7 @@ void *rtp_control_receiver(void *arg) { plen -= 4; seq_t seqno = ntohs(*(unsigned short *)(pktp + 2)); - uint32_t timestamp = ntohl(*(unsigned long *)(pktp + 4)); + int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4))); pktp += 12; plen -= 12; @@ -494,7 +494,7 @@ void *rtp_timing_receiver(void *arg) { int64_t source_drift_usec; if (play_segment_reference_frame!=0) { - uint32_t reference_timestamp; + int64_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); uint64_t frame_difference = 0; @@ -708,7 +708,7 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t request_sent = 0; } -void get_reference_timestamp_stuff(uint32_t *timestamp, uint64_t *timestamp_time, uint64_t *remote_timestamp_time) { +void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time, uint64_t *remote_timestamp_time) { // types okay pthread_mutex_lock(&reference_time_mutex); *timestamp = reference_timestamp; diff --git a/rtp.h b/rtp.h index 446142d0..195f6738 100644 --- a/rtp.h +++ b/rtp.h @@ -19,7 +19,7 @@ void rtp_shutdown(void); void rtp_request_resend(seq_t first, uint32_t count); void rtp_request_client_pause(void); // ask the client to pause -void get_reference_timestamp_stuff(uint32_t *timestamp, uint64_t *timestamp_time, uint64_t *remote_timestamp_time); +void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time, uint64_t *remote_timestamp_time); void clear_reference_timestamp(void); uint64_t static local_to_remote_time_jitters;