]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add the idea of a preflight message to tell the backend that frames will be coming...
authorMike Brady <mikebrady@eircom.net>
Mon, 7 Jan 2019 17:34:50 +0000 (17:34 +0000)
committerMike Brady <mikebrady@eircom.net>
Mon, 7 Jan 2019 17:34:50 +0000 (17:34 +0000)
audio.h
audio_alsa.c
audio_ao.c
audio_dummy.c
audio_jack.c
audio_pa.c
audio_pipe.c
audio_sndio.c
audio_soundio.c
audio_stdout.c
common.h

diff --git a/audio.h b/audio.h
index a4f0f178e3357edb56bb8e74fb42ebdc35fe2fbe..b8ecf958c3e3dc7426b4c443bd4a96f28e8ca06a 100644 (file)
--- a/audio.h
+++ b/audio.h
@@ -22,6 +22,7 @@ typedef struct {
   void (*start)(int sample_rate, int sample_format);
 
   // block of samples
+  int (*preflight)(void *buf, int samples); // say you are about to send these samples (before interpolation)
   int (*play)(void *buf, int samples);
   void (*stop)(void);
 
index b1c7ae7c253373bff5c52715c55418ec0a3155b7..b7a5de8d5f3f9cd9a8513d3787d1a88e1712b9a9 100644 (file)
@@ -42,6 +42,7 @@ static int init(int argc, char **argv);
 static void deinit(void);
 static void start(int i_sample_rate, int i_sample_format);
 static int play(void *buf, int samples);
+int preflight(void *buf, int samples);
 static void stop(void);
 static void flush(void);
 int delay(long *the_delay);
@@ -632,6 +633,8 @@ static int init(int argc, char **argv) {
   config.audio_backend_buffer_interpolation_threshold_in_seconds =
       0.100; // below this, basic interpolation will be used to save time.
   config.alsa_maximum_stall_time = 0.200; // 200 milliseconds -- if it takes longer, it's a problem
+  config.audio_backend_silence_threshold = 0.050; //start sending silent frames if the delay goes below this time
+  config.audio_backend_silence_scan_interval = 0.005; //check silence threshold this often
 
   stall_monitor_error_threshold =
       (uint64_t)1000000 * config.alsa_maximum_stall_time; // stall time max to microseconds;
@@ -1081,7 +1084,7 @@ int delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay) {
   return ret;
 }
 
-int untimed_delay(long *the_delay) {
+int delay(long *the_delay) {
   // returns 0 if the device is in a valid state -- SND_PCM_STATE_RUNNING or SND_PCM_STATE_PREPARED
   // or SND_PCM_STATE_DRAINING
   // and returns the actual delay if running or 0 if prepared in *the_delay
@@ -1126,7 +1129,7 @@ int get_rate_information(uint64_t *elapsed_time, uint64_t *frames_played) {
   return response;
 }
 
-int untimed_play(void *buf, int samples) {
+int play(void *buf, int samples) {
 
   // debug(3,"audio_alsa play called.");
   int oldState;
@@ -1258,6 +1261,16 @@ static void flush(void) {
   pthread_setcancelstate(oldState, NULL);
 }
 
+int preflight(__attribute__((unused)) void *buf, __attribute__((unused)) int samples) {
+  uint64_t time_now =
+      get_absolute_time_in_fp(); // this is to regulate access by the silence filler thread
+  uint64_t standoff_time = 100; // milliseconds
+  standoff_time = (standoff_time << 32)/1000;
+  most_recent_write_time = time_now + standoff_time;
+  return 0;
+}
+
+/*
 static int play(void *buf, int samples) {
   uint64_t time_now =
       get_absolute_time_in_fp(); // this is to regulate access by the silence filler thread
@@ -1273,6 +1286,7 @@ int delay(long *the_delay) {
   most_recent_write_time = time_now;
   return untimed_delay(the_delay);
 }
+*/
 
 static void stop(void) {
   // debug(2,"audio_alsa stop called.");
@@ -1451,12 +1465,14 @@ void *alsa_buffer_monitor_thread_code(void *arg) {
 
   debug(1, "alsa: dither will %sbe added to inter-session silence.", use_dither ? "" : "not ");
 
-  int sleep_time_ms = 30;
+  int sleep_time_ms = (int)(config.audio_backend_silence_scan_interval * 1000);
+  long buffer_size_threshold = (long)(config.audio_backend_silence_threshold * desired_sample_rate);
+  
   uint64_t sleep_time_in_fp = sleep_time_ms;
   sleep_time_in_fp = sleep_time_in_fp << 32;
   sleep_time_in_fp = sleep_time_in_fp / 1000;
   // debug(1,"alsa: sleep_time: %d ms or 0x%" PRIx64 " in fp form.",sleep_time_ms,sleep_time_in_fp);
-  int frames_of_silence = (desired_sample_rate * sleep_time_ms * 2) / 1000;
+  int frames_of_silence = (desired_sample_rate * sleep_time_ms * 4) / 1000;
   size_t size_of_silence_buffer = frames_of_silence * frame_size;
   // debug(1,"Silence buffer length: %u bytes.",size_of_silence_buffer);
   void *silence = malloc(size_of_silence_buffer);
@@ -1470,10 +1486,11 @@ void *alsa_buffer_monitor_thread_code(void *arg) {
       if (config.keep_dac_busy != 0) {
         uint64_t present_time = get_absolute_time_in_fp();
 
-        if ((most_recent_write_time == 0) ||
-            ((present_time > most_recent_write_time) &&
-             ((present_time - most_recent_write_time) > (sleep_time_in_fp)))) {
-          reply = untimed_delay(&buffer_size);
+        if ((most_recent_write_time == 0) || (present_time > most_recent_write_time)) {
+
+//            ((present_time > most_recent_write_time) &&
+//             ((present_time - most_recent_write_time) > (sleep_time_in_fp)))) {
+          reply = delay(&buffer_size);
           if (reply != 0) {
             buffer_size = 0;
             char errorstring[1024];
@@ -1481,7 +1498,7 @@ void *alsa_buffer_monitor_thread_code(void *arg) {
             debug(1, "alsa: alsa_buffer_monitor_thread_code delay error %d: \"%s\".", reply,
                   (char *)errorstring);
           }
-          if (buffer_size < frames_of_silence) {
+          if (buffer_size < buffer_size_threshold) {
             if ((hardware_mixer == 0) && (config.ignore_volume_control == 0) &&
                 (config.airplay_volume != 0.0))
               use_dither = 1;
@@ -1492,7 +1509,7 @@ void *alsa_buffer_monitor_thread_code(void *arg) {
                 dither_random_number_store);
             // debug(1,"Play %d frames of silence with most_recent_write_time of %" PRIx64 ".",
             // frames_of_silence,most_recent_write_time);
-            untimed_play(silence, frames_of_silence);
+            play(silence, frames_of_silence);
           }
         } else {
           // debug(2,"Skipping sending silence");
index 42147bab96a59735e8ee833211bd151b000e2786..30f80d8d509b2697bb9ff0949de9d957e1e41f89 100644 (file)
@@ -134,6 +134,7 @@ audio_output audio_ao = {.name = "ao",
                          .is_running = NULL,
                          .flush = NULL,
                          .delay = NULL,
+                         .preflight = NULL,
                          .play = &play,
                          .volume = NULL,
                          .parameters = NULL,
index d8dea87f2a0e16a6cdd2562052954095df23d812..69518cd03bc10821d7d413092a2324b9564e6244 100644 (file)
@@ -65,6 +65,7 @@ audio_output audio_dummy = {.name = "dummy",
                             .is_running = NULL,
                             .flush = NULL,
                             .delay = NULL,
+                            .preflight = NULL,
                             .play = &play,
                             .volume = NULL,
                             .parameters = NULL,
index 11ae60724465789fb0c0d9c25fe1e95235675d1c..90f08ac49e3211e8213804bb5922f897546f5010 100644 (file)
@@ -67,6 +67,7 @@ audio_output audio_jack = {.name = "jack",
                            .is_running = &jack_is_running,
                            .flush = &jack_flush,
                            .delay = &jack_delay,
+                           .preflight = NULL,
                            .play = &play,
                            .volume = NULL,
                            .parameters = NULL,
index cd321bd9f4d681023374f60f5b3110ff12d012bc..4ee20c7508d4ebdb7fc92db251743ce69ca4e2e7 100644 (file)
@@ -312,6 +312,7 @@ audio_output audio_pa = {.name = "pa",
                          .flush = &flush,
                          .delay = &pa_delay,
                          .play = &play,
+                         .preflight = NULL,
                          .volume = NULL,
                          .parameters = NULL,
                          .mute = NULL};
index 89a09a0c656fb7c0c5c806b7d4a55d9dd7a9abd5..0d4a42fd91ba81fe32f22041fac8f0e54404888e 100644 (file)
@@ -139,6 +139,7 @@ audio_output audio_pipe = {.name = "pipe",
                            .flush = NULL,
                            .delay = NULL,
                            .play = &play,
+                           .preflight = NULL,
                            .volume = NULL,
                            .parameters = NULL,
                            .mute = NULL};
index f22ed5af1430867d0a87826f40157adf3e526922..e106b15d9aa03d54654004621457ce7e3a32c497 100644 (file)
@@ -49,6 +49,7 @@ audio_output audio_sndio = {.name = "sndio",
                             .flush = &flush,
                             .delay = &delay,
                             .play = &play,
+                            .preflight = NULL,
                             .volume = NULL,
                             .parameters = NULL,
                             .mute = NULL};
index 7d3b48ad3ee35f6bf2b71cee29967ebad18790db..0449895b8af1db06460b29f57f37df57412a0587 100644 (file)
@@ -221,6 +221,7 @@ audio_output audio_soundio = {.name = "soundio",
                               .flush = &flush,
                               .delay = NULL,
                               .play = &play,
+                              .preflight = NULL,
                               .volume = NULL,
                               .parameters = &parameters,
                               .mute = NULL};
index 0438b1afad88c067cb6886a75ac4d78db752d9bd..37d6f78121765131eaff8dc3a1d3562f5e739a28 100644 (file)
@@ -86,6 +86,7 @@ audio_output audio_stdout = {.name = "stdout",
                              .flush = NULL,
                              .delay = NULL,
                              .play = &play,
+                             .preflight = NULL,
                              .volume = NULL,
                              .parameters = NULL,
                              .mute = NULL};
index 35996fef8c922005c29f7f35e5884bb42743eb45..6f07f6d30f4e50f718dcf80140029b1653565fa7 100644 (file)
--- a/common.h
+++ b/common.h
@@ -171,6 +171,9 @@ typedef struct {
   double audio_backend_buffer_interpolation_threshold_in_seconds; // below this, soxr interpolation
                                                                   // will not occur -- it'll be
                                                                   // basic interpolation instead.
+  double audio_backend_silence_threshold;  // below this, silence will be added to the output buffer
+  double audio_backend_silence_scan_interval; // check the threshold this often
+                                         
   double audio_backend_latency_offset; // this will be the offset in seconds to compensate for any
                                        // fixed latency there might be in the audio path
   double audio_backend_silent_lead_in_time; // the length of the silence that should precede a play.