]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Try using the monotonic clock for checking output rate...
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Mon, 8 Nov 2021 10:14:42 +0000 (10:14 +0000)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Mon, 8 Nov 2021 10:14:42 +0000 (10:14 +0000)
common.c
common.h
player.c
player.h

index 866222c22c22aa170e737d146c78f5b5633dbade..b1525a318a01b3aa7b2ded652cbff91811bc9b44 100644 (file)
--- a/common.c
+++ b/common.c
@@ -55,9 +55,9 @@
 #endif
 
 #ifdef COMPILE_FOR_FREEBSD
-#include <netinet/in.h>
-#include <net/if_types.h>
 #include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
 #endif
 
 #ifdef COMPILE_FOR_OSX
@@ -1258,6 +1258,49 @@ uint64_t get_absolute_time_in_fp() {
   return time_now_fp;
 }
 
+uint64_t get_monotonic_time_in_ns() {
+  uint64_t time_now_ns;
+
+#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD
+  struct timespec tn;
+  // can't use CLOCK_MONOTONIC_RAW as it's not implemented in OpenWrt
+  // CLOCK_REALTIME because PTP uses it.
+  clock_gettime(CLOCK_MONOTONIC, &tn);
+  uint64_t tnnsec = tn.tv_sec;
+  tnnsec = tnnsec * 1000000000;
+  uint64_t tnjnsec = tn.tv_nsec;
+  time_now_ns = tnnsec + tnjnsec;
+#endif
+
+#ifdef COMPILE_FOR_OSX
+  uint64_t time_now_mach;
+  uint64_t elapsedNano;
+  static mach_timebase_info_data_t sTimebaseInfo = {0, 0};
+
+  // this actually give you a monotonic clock
+  // see https://news.ycombinator.com/item?id=6303755
+  time_now_mach = mach_absolute_time();
+
+  // If this is the first time we've run, get the timebase.
+  // We can use denom == 0 to indicate that sTimebaseInfo is
+  // uninitialised because it makes no sense to have a zero
+  // denominator in a fraction.
+
+  if (sTimebaseInfo.denom == 0) {
+    debug(1, "Mac initialise timebase info.");
+    (void)mach_timebase_info(&sTimebaseInfo);
+  }
+
+  // Do the maths. We hope that the multiplication doesn't
+  // overflow; the price you pay for working in fixed point.
+
+  // this gives us nanoseconds
+  time_now_ns = time_now_mach * sTimebaseInfo.numer / sTimebaseInfo.denom;
+#endif
+
+  return time_now_ns;
+}
+
 uint64_t get_absolute_time_in_ns() {
   uint64_t time_now_ns;
 
@@ -1277,6 +1320,7 @@ uint64_t get_absolute_time_in_ns() {
   uint64_t elapsedNano;
   static mach_timebase_info_data_t sTimebaseInfo = {0, 0};
 
+  // this actually give you a monotonic clock
   time_now_mach = mach_absolute_time();
 
   // If this is the first time we've run, get the timebase.
@@ -1963,7 +2007,7 @@ int get_device_id(uint8_t *id, int int_length) {
     t = id;
     int found = 0;
     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- #ifdef AF_PACKET
+#ifdef AF_PACKET
       if ((ifa->ifa_addr) && (ifa->ifa_addr->sa_family == AF_PACKET)) {
         struct sockaddr_ll *s = (struct sockaddr_ll *)ifa->ifa_addr;
         if ((strcmp(ifa->ifa_name, "lo") != 0) && (found == 0)) {
@@ -1973,25 +2017,23 @@ int get_device_id(uint8_t *id, int int_length) {
           found = 1;
         }
       }
- #else
- #ifdef AF_LINK
-       struct sockaddr_dl * sdl = (struct sockaddr_dl *) ifa->ifa_addr;
-       if ((sdl) && (sdl->sdl_family == AF_LINK)) {
+#else
+#ifdef AF_LINK
+      struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+      if ((sdl) && (sdl->sdl_family == AF_LINK)) {
         if (sdl->sdl_type == IFT_ETHER) {
           char *s = LLADDR(sdl);
           for (i = 0; i < sdl->sdl_alen; i++) {
-            debug(1,"char %d: \"%c\".", i, *s);
-            *t++ = (uint8_t)*s++;   
-          }   
+            debug(1, "char %d: \"%c\".", i, *s);
+            *t++ = (uint8_t)*s++;
+          }
           found = 1;
         }
       }
- #endif
- #endif
-
+#endif
+#endif
     }
     freeifaddrs(ifaddr);
   }
   return response;
 }
-
index 9c3496f6a1c79e262069249503e1f8f7a22deb87..199b3d416704d96bf7dbdb311977d56d1e407b92 100644 (file)
--- a/common.h
+++ b/common.h
@@ -381,6 +381,7 @@ double vol2attn(double vol, long max_db, long min_db);
 // return a time in nanoseconds
 // uint64_t get_absolute_time_in_fp(void); // obselete
 uint64_t get_absolute_time_in_ns(void);
+uint64_t get_monotonic_time_in_ns(void); // to try and get precise FPS values
 
 // time at startup for debugging timing
 extern uint64_t ns_time_at_startup, ns_time_at_last_debug_message;
index 74c6eac2bfa6a8cc5715e35b5ff048625ff2621c..e19e6cab7dd5ed0b4ec27f14b7cd05f1929b979b 100644 (file)
--- a/player.c
+++ b/player.c
@@ -1714,12 +1714,11 @@ void player_thread_cleanup_handler(void *arg) {
 
 void *player_thread_func(void *arg) {
   rtsp_conn_info *conn = (rtsp_conn_info *)arg;
-  
+
   uint64_t previous_frames_played;
   uint64_t previous_frames_played_time;
   int previous_frames_played_valid = 0;
 
-  
   // pthread_cleanup_push(player_thread_initial_cleanup_handler, arg);
   conn->packet_count = 0;
   conn->packet_count_since_flush = 0;
@@ -2787,6 +2786,7 @@ void *player_thread_func(void *arg) {
           uint64_t frames_sent_for_play;
           int status = -1;
           if ((config.output->delay) && (config.no_sync == 0) && (config.output->rate_info)) {
+            uint64_t monotonic_time_now = get_monotonic_time_in_ns();
             uint64_t elapsed_play_time; // dummy
             status = config.output->rate_info(&elapsed_play_time, &frames_sent_for_play);
             uint64_t frames_played = frames_sent_for_play - play_samples - current_delay;
@@ -2794,22 +2794,22 @@ void *player_thread_func(void *arg) {
             // last time the rate_info call was made. Thus, the frame rate should be valid.
             if ((status == 0) && (previous_frames_played_valid)) {
               uint64_t frames_played_in_this_interval = frames_played - previous_frames_played;
-              uint64_t interval = local_time_now - previous_frames_played_time;
+              uint64_t interval = monotonic_time_now - previous_frames_played_time;
               conn->frame_rate = (1e9 * frames_played_in_this_interval) / interval;
               conn->frame_rate_valid = 1;
             }
-            
+
             // uncomment the if statement if your want to get as long a period for
             // calculating the frame rate
             // if ((status != 0) || (previous_frames_played_valid == 0)) {
-              // if we have just detected an outputting error, or if we have no
-              // starting information
-              previous_frames_played = frames_played;
-              previous_frames_played_time = local_time_now;
-              previous_frames_played_valid = 1;
-            // }
+            // if we have just detected an outputting error, or if we have no
+            // starting information
+            previous_frames_played = frames_played;
+            previous_frames_played_time = monotonic_time_now;
+            previous_frames_played_valid = 1;
+            //}
           }
-          
+
           // we can now calculate running averages for sync error (frames), corrections (ppm),
           // insertions plus deletions (ppm), drift (ppm)
           double moving_average_sync_error = (1.0 * tsum_of_sync_errors) / number_of_statistics;
@@ -2931,7 +2931,7 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
         else
           sw_min_db = (sw_max_db - desired_sw_range);
       } else {
-          hw_min_db = hw_max_db - desired_range_db;
+        hw_min_db = hw_max_db - desired_range_db;
       }
     }
   } else {
index d5719031a49b63e35bb147a414a6a5a4dec4ba3b..41cdc5bd42e34067574a090dd138f0f7bb91e019 100644 (file)
--- a/player.h
+++ b/player.h
@@ -109,7 +109,6 @@ typedef enum {
   remote_control_stream
 } airplay_stream_c; // "c" for category
 
-
 #ifdef CONFIG_AIRPLAY_2
 typedef enum { ts_ntp, ts_ptp } timing_t;
 typedef enum { ap_1, ap_2 } airplay_t;
@@ -296,7 +295,8 @@ typedef struct {
   clock_status_t clock_status;
 
   airplay_stream_c
-      airplay_stream_category; // is it a remote control stream or a normal "full service" stream? (will be unspecified if not build for AirPlay 2)
+      airplay_stream_category; // is it a remote control stream or a normal "full service" stream?
+                               // (will be unspecified if not build for AirPlay 2)
 
 #ifdef CONFIG_AIRPLAY_2
   char *airplay_gid; // UUID in the Bonjour advertisement -- if NULL, the group UUID is the same as