]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Change measurement of frames and timing to mimimise effects of paging, cache loading...
authorMike Brady <mikebrady@eircom.net>
Sun, 29 Jul 2018 08:47:53 +0000 (09:47 +0100)
committerMike Brady <mikebrady@eircom.net>
Sun, 29 Jul 2018 08:47:53 +0000 (09:47 +0100)
audio_alsa.c

index cefd66657b20187c6ff58c8ad7670881c55a90ba..b122a63f4b8fb77e172e2064e3f9b7c27453d322 100644 (file)
@@ -113,8 +113,15 @@ int alsa_characteristics_already_listed = 0;
 static snd_pcm_uframes_t period_size_requested, buffer_size_requested;
 static int set_period_size_request, set_buffer_size_request;
 
-static uint64_t time_of_first_frame;
+static uint64_t measurement_start_time;
+static uint64_t frames_played_at_measurement_start_time;
+
+static uint64_t measurement_time;
+static uint64_t frames_played_at_measurement_time;
+
 static uint64_t frames_sent_for_playing;
+static uint64_t frame_index;
+static int measurement_data_is_valid;
 
 static void help(void) {
   printf("    -d output-device    set the output device [default*|...]\n"
@@ -817,8 +824,8 @@ static void start(int i_sample_rate, int i_sample_format) {
   else
     sample_format = i_sample_format;
   
-  time_of_first_frame = 0;
-  frames_sent_for_playing = 0;
+  frame_index = 0;
+  measurement_data_is_valid = 0;
 }
 
 int delay(long *the_delay) {
@@ -839,7 +846,9 @@ int delay(long *the_delay) {
         snd_pcm_recover(alsa_handle, reply, 1);
       }
     } else {
-      time_of_first_frame = 0;
+      frame_index = 0; //we'll be starting over...
+      measurement_data_is_valid = 0;
+
       if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) {
         *the_delay = 0;
         reply = 0; // no error
@@ -866,13 +875,14 @@ int delay(long *the_delay) {
 }
 
 int get_rate_information(uint64_t *elapsed_time, uint64_t *frames_played) {
-  long frames_left = 0;
-  int result = delay(&frames_left);
-  if (result >= 0) {
-    *elapsed_time = get_absolute_time_in_fp()-time_of_first_frame;
-    *frames_played = frames_sent_for_playing - frames_left;
+  if (measurement_data_is_valid) {
+    *elapsed_time = measurement_time - measurement_start_time;
+    *frames_played = frames_played_at_measurement_time - frames_played_at_measurement_start_time;
+  } else {
+    *elapsed_time = 0;
+    *frames_played = 0;  
   }
-  return result;
+  return 0;
 }
 
 static void play(void *buf, int samples) {
@@ -892,13 +902,14 @@ static void play(void *buf, int samples) {
   if (ret == 0) {
     debug_mutex_lock(&alsa_mutex, 10000, 1);
     //    snd_pcm_sframes_t current_delay = 0;
-    int err;
+    int err, err2;
     if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_XRUN) {
       if ((err = snd_pcm_prepare(alsa_handle))) {
         snd_pcm_recover(alsa_handle, err, 1);
         debug(1, "Error preparing after underrun: \"%s\".", snd_strerror(err));
       }
-      time_of_first_frame = 0;
+      frame_index = 0; // we'll be starting over
+      measurement_data_is_valid = 0;
     }
     if ((snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) ||
         (snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING)) {
@@ -908,16 +919,41 @@ static void play(void *buf, int samples) {
         debug(1, "empty buffer being passed to pcm_writei -- skipping it");
       if ((samples != 0) && (buf != NULL)) {
         err = alsa_pcm_write(alsa_handle, buf, samples);
-        if (time_of_first_frame == 0) {
-          time_of_first_frame = get_absolute_time_in_fp();
-          frames_sent_for_playing = 0;
-        }       
         if (err < 0) {
+          frame_index = 0;
+          measurement_data_is_valid = 0;
           debug(1, "Error %d writing %d samples in play(): \"%s\".", err, samples,
                 snd_strerror(err));
           snd_pcm_recover(alsa_handle, err, 1);
         }
-        frames_sent_for_playing += samples;
+        if (frame_index==0) {
+          frames_sent_for_playing = samples;
+        } else {
+          frames_sent_for_playing += samples;
+        }
+        const uint64_t start_measurement_from_this_frame = (2*44100)/352; // two seconds of frames…
+        frame_index++;
+        if ((frame_index == start_measurement_from_this_frame) || (frame_index % 32 == 0)) {
+          long fl = 0;
+          err2 = snd_pcm_delay(alsa_handle,&fl);
+          if (err2 != 0) {
+            frame_index = 0;
+            measurement_data_is_valid = 0;
+            debug(1, "Error %d in delay(): \"%s\". Delay reported is %d frames.", err2,
+                  snd_strerror(err2), fl);
+            snd_pcm_recover(alsa_handle, err2, 1);
+          }
+          uint64_t tf = get_absolute_time_in_fp();
+          frames_played_at_measurement_time = frames_sent_for_playing - fl;
+          if (frame_index == start_measurement_from_this_frame) {
+            frames_played_at_measurement_start_time = frames_played_at_measurement_time;
+            measurement_start_time = tf;
+          } else {
+            frames_played_at_measurement_time = frames_played_at_measurement_time;
+            measurement_time = tf;
+            measurement_data_is_valid = 1;
+          }
+        }
       }
     } else {
       debug(1, "Error -- ALSA device in incorrect state (%d) for play.",
@@ -926,7 +962,8 @@ static void play(void *buf, int samples) {
         snd_pcm_recover(alsa_handle, err, 1);
         debug(1, "Error preparing after play error: \"%s\".", snd_strerror(err));
       }
-      time_of_first_frame = 0;
+      frame_index = 0;
+      measurement_data_is_valid = 0;
     }
     debug_mutex_unlock(&alsa_mutex, 3);
   }
@@ -949,7 +986,8 @@ static void flush(void) {
     // flush also closes the device
     if ((derr = snd_pcm_close(alsa_handle)))
       debug(1, "Error %d (\"%s\") closing the output device.", derr, snd_strerror(derr));
-    time_of_first_frame = 0;
+    frame_index = 0;
+    measurement_data_is_valid = 0;
     alsa_handle = NULL;
   }
   debug_mutex_unlock(&alsa_mutex, 3);