]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Enable 64-bit monotonic rtptime calculations
authorMike Brady <mikebrady@eircom.net>
Fri, 2 Sep 2016 15:53:52 +0000 (16:53 +0100)
committerMike Brady <mikebrady@eircom.net>
Fri, 2 Sep 2016 15:53:52 +0000 (16:53 +0100)
common.h
player.c
player.h
rtp.c
rtp.h

index e2ab47b9166e080633fc66eb282b241707267576..c273fd19d09c4d2ead4c2e44f88c0bb3325ee7c9 100644 (file)
--- 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);
index 8f35c6d8aca5dd2b7da65015bb419c484d1fe6fe..19892c8243153e4000d0d088e6732dd851c01c67 100644 (file)
--- 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;
index d6a16e5add7120232eb595f5984e3de1f7622b0a..bd14acd2ea007a246b872861af086635bef6caa9 100644 (file)
--- 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 0f8dae931e1cad51d322f9d0f300130bdb33d21b..cbef773d1c2e300324336477b7362c9118694d77 100644 (file)
--- 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 446142d096ac47607e9d3bbbeb3c5d3914568505..195f6738a05aea774beea8f258fce0ca7ad19790 100644 (file)
--- 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;