]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add ability to send frame/time updates at intervals as metadata.
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Sat, 26 Nov 2022 15:56:25 +0000 (15:56 +0000)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Sat, 26 Nov 2022 15:56:25 +0000 (15:56 +0000)
common.h
player.c
shairport.c

index 9f323e1b5a2c36c4965c3e5875a960363ff6a5b8..639c1c0f8ceef836607e03d3a0c0edd0f363a3df 100644 (file)
--- a/common.h
+++ b/common.h
@@ -141,6 +141,7 @@ typedef struct {
   int metadata_sockport;
   size_t metadata_sockmsglength;
   int get_coverart;
+  double metadata_progress_interval; // 0 means no progress reports
 #endif
 #ifdef CONFIG_MQTT
   int mqtt_enabled;
index ab85cb7bc0e5cf84643b7d597277563849197721..ebab2c01c03d1fb1e521e7d19b42092a95a4b643 100644 (file)
--- a/player.c
+++ b/player.c
@@ -1837,7 +1837,9 @@ void player_thread_cleanup_handler(void *arg) {
 
 void *player_thread_func(void *arg) {
   rtsp_conn_info *conn = (rtsp_conn_info *)arg;
-
+#ifdef CONFIG_METADATA
+  uint64_t time_of_last_metadata_progress_update;
+#endif
   uint64_t previous_frames_played = 0; // initialised to avoid a "possibly uninitialised" warning
   uint64_t previous_raw_measurement_time =
       0; // initialised to avoid a "possibly uninitialised" warning
@@ -2197,7 +2199,7 @@ void *player_thread_func(void *arg) {
 
   debug(2, "Play begin");
   while (1) {
-
+    int this_is_the_first_frame = 0; //will be set if it is
     // check a few parameters to ensure they are non-zero
     if (config.output_rate == 0)
       debug(1, "config.output_rate is zero!");
@@ -2690,6 +2692,7 @@ void *player_thread_func(void *arg) {
 
             if (at_least_one_frame_seen_this_session == 0) {
               at_least_one_frame_seen_this_session = 1;
+              this_is_the_first_frame = 1;
 
               // debug(2,"first frame real sync error (positive --> late): %" PRId64 " frames.",
               // sync_error);
@@ -2740,11 +2743,10 @@ void *player_thread_func(void *arg) {
                 sync_error = 0; // say the error was fixed!
               }
               // since this is the first frame of audio, inform the user if requested...
-
 #ifdef CONFIG_AIRPLAY_2
               if (conn->airplay_stream_type == realtime_stream) {
                 if (conn->airplay_type == ap_1) {
-#ifdef CONFIG_METADATA_HUB
+#ifdef CONFIG_METADATA
                   send_ssnc_metadata('styp', "Classic", strlen("Classic"), 1);
 #endif
                   if (config.statistics_requested)
@@ -2752,7 +2754,7 @@ void *player_thread_func(void *arg) {
                            " -- AirPlay 1 Compatible.",
                            conn->connection_number, inframe->given_timestamp);
                 } else {
-#ifdef CONFIG_METADATA_HUB
+#ifdef CONFIG_METADATA
                   send_ssnc_metadata('styp', "Realtime", strlen("Realtime"), 1);
 #endif
                   if (config.statistics_requested)
@@ -2761,7 +2763,7 @@ void *player_thread_func(void *arg) {
                            conn->connection_number, inframe->given_timestamp);
                 }
               } else {
-#ifdef CONFIG_METADATA_HUB
+#ifdef CONFIG_METADATA
                 send_ssnc_metadata('styp', "Buffered", strlen("Buffered"), 1);
 #endif
                 if (config.statistics_requested)
@@ -2770,7 +2772,7 @@ void *player_thread_func(void *arg) {
                          conn->connection_number, inframe->given_timestamp);
               }
 #else
-#ifdef CONFIG_METADATA_HUB
+#ifdef CONFIG_METADATA
               send_ssnc_metadata('styp', "Classic", strlen("Classic"), 1);
 #endif
               if (config.statistics_requested)
@@ -3042,6 +3044,29 @@ void *player_thread_func(void *arg) {
                   }
                   uint64_t should_be_time;
                   frame_to_local_time(inframe->given_timestamp, &should_be_time, conn);
+                  
+#ifdef CONFIG_METADATA
+                  if (config.metadata_progress_interval != 0.0) {
+                    char hb[128];
+                    if (this_is_the_first_frame != 0) {
+                      memset(hb, 0, 128);
+                      snprintf(hb, 127, "%" PRIu32 "/%" PRId64 "", inframe->given_timestamp, should_be_time);
+                      send_ssnc_metadata('phbt', hb, strlen(hb), 1);
+                      time_of_last_metadata_progress_update = local_time_now;
+                    } else {
+                      uint64_t mx = 1000000000;
+                      uint64_t iv = config.metadata_progress_interval * mx;
+                      iv = iv + time_of_last_metadata_progress_update;
+                      int64_t delta = iv - local_time_now;
+                      if (delta <= 0) {
+                        memset(hb, 0, 128);
+                        snprintf(hb, 127, "%" PRIu32 "/%" PRId64 "", inframe->given_timestamp, should_be_time);
+                        send_ssnc_metadata('phbt', hb, strlen(hb), 1);
+                        time_of_last_metadata_progress_update = local_time_now;
+                      }
+                    }                
+                  }
+#endif
                   config.output->play(conn->outbuf, play_samples, play_samples_are_timed,
                                       inframe->given_timestamp, should_be_time);
                 }
@@ -3075,6 +3100,7 @@ void *player_thread_func(void *arg) {
             // if this is the first frame, see if it's close to when it's supposed to be
             // release, which will be its time plus latency and any offset_time
             if (at_least_one_frame_seen_this_session == 0) {
+              this_is_the_first_frame = 1;
               at_least_one_frame_seen_this_session = 1;
             }
 
@@ -3090,6 +3116,28 @@ void *player_thread_func(void *arg) {
               }
               uint64_t should_be_time;
               frame_to_local_time(inframe->given_timestamp, &should_be_time, conn);
+#ifdef CONFIG_METADATA
+              if (config.metadata_progress_interval != 0.0) {
+                char hb[128];
+                if (this_is_the_first_frame != 0) {
+                  memset(hb, 0, 128);
+                  snprintf(hb, 127, "%" PRIu32 "/%" PRId64 "", inframe->given_timestamp, should_be_time);
+                  send_ssnc_metadata('phbt', hb, strlen(hb), 1);
+                  time_of_last_metadata_progress_update = local_time_now;
+                } else {
+                  uint64_t mx = 1000000000;
+                  uint64_t iv = config.metadata_progress_interval * mx;
+                  iv = iv + time_of_last_metadata_progress_update;
+                  int64_t delta = iv - local_time_now;
+                  if (delta <= 0) {
+                    memset(hb, 0, 128);
+                    snprintf(hb, 127, "%" PRIu32 "/%" PRId64 "", inframe->given_timestamp, should_be_time);
+                    send_ssnc_metadata('phbt', hb, strlen(hb), 1);
+                    time_of_last_metadata_progress_update = local_time_now;
+                  }
+                }                
+              }
+#endif
               config.output->play(conn->outbuf, play_samples, play_samples_are_timed,
                                   inframe->given_timestamp, should_be_time);
             }
index 3503deb72e52674f45c70983af0ba46c486fe86f..a5e521fffd364a5f7b74ad5304a4e593e40a344e 100644 (file)
@@ -998,6 +998,11 @@ int parse_options(int argc, char **argv) {
       if (config_lookup_string(config.cfg, "metadata.pipe_name", &str)) {
         config.metadata_pipename = (char *)str;
       }
+      
+      if (config_lookup_float(config.cfg, "metadata.progress_interval", &dvalue)) {
+        config.metadata_progress_interval = dvalue;
+      }
+
 
       if (config_lookup_string(config.cfg, "metadata.socket_address", &str)) {
         config.metadata_sockaddr = (char *)str;