]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Handle active_remote_id as a string rather than an unsigned 32-bit number --... 3.3.7rc3
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Wed, 30 Sep 2020 13:57:09 +0000 (14:57 +0100)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Wed, 30 Sep 2020 14:02:35 +0000 (15:02 +0100)
    Tidy up some error messages about which backend is selected.
    Tighten up memory allocatons in DACP.c.
    Add a default name for the pipe backend: /tmp/shairport-sync-audio
    Ensure the metadata pipe is created, if necessary, when the --with-metadata option is chosen without dbus or mpris
    Make the first output backend in the list of backends the default and make its name the default output_name. Clang-format everything
    Add the word 'jack' to the version string if Jack Audio support is compiled in.
    Fix a flaw in resyncing -- a flush is set up but not triggered.
    Open metadata and audio pipes with 666 permissions.
    Ensure metadata and cover art are enabled if metadata support is included at compilation.
    Reword some misleading error messages.
    Set convolution defaults even if no configuration file is found.

15 files changed:
audio.c
audio.h
audio_pipe.c
common.c
common.h
configure.ac
dacp.c
metadata_hub.c
metadata_hub.h
player.c
player.h
rtp.c
rtsp.c
scripts/shairport-sync.conf
shairport.c

diff --git a/audio.c b/audio.c
index 23b1760dce480be4ce21c8d80123656e50f7e5f3..0fe7b04f7b9ed59c7451e002f4ad2f67eabd0523 100644 (file)
--- a/audio.c
+++ b/audio.c
@@ -89,7 +89,7 @@ static audio_output *outputs[] = {
 #endif
     NULL};
 
-audio_output *audio_get_output(char *name) {
+audio_output *audio_get_output(const char *name) {
   audio_output **out;
 
   // default to the first
diff --git a/audio.h b/audio.h
index 856f184b4510f26eae7cbf6c3f511dd052a8ac5a..3413250ceaab4c30ebdcffd4b5dfe0ddf33510a6 100644 (file)
--- a/audio.h
+++ b/audio.h
@@ -54,7 +54,7 @@ typedef struct {
 
 } audio_output;
 
-audio_output *audio_get_output(char *name);
+audio_output *audio_get_output(const char *name);
 void audio_ls_outputs(void);
 void parse_general_audio_options(void);
 
index 45e0f06008b43ec282517822d851a91c5983ecd3..a7925fbc565c71f7f1a8803f557b1c1c3e94e613 100644 (file)
@@ -42,6 +42,7 @@
 static int fd = -1;
 
 char *pipename = NULL;
+char *default_pipe_name = "/tmp/shairport-sync-audio";
 
 static void start(__attribute__((unused)) int sample_rate,
                   __attribute__((unused)) int sample_format) {
@@ -51,33 +52,34 @@ static void start(__attribute__((unused)) int sample_rate,
   // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
   // open for reading."
 
-       fd = try_to_open_pipe_for_writing(pipename);
-       // we check that it's not a "real" error. From the "man 2 open" page:
-       // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
-       // open for reading." Which is okay.
-       if ((fd == -1) && (errno != ENXIO)) {
-               char errorstring[1024];
-               strerror_r(errno, (char *)errorstring, sizeof(errorstring));
-               debug(1, "audio_pipe start -- error %d (\"%s\") opening pipe: \"%s\".", errno,
-                                       (char *)errorstring, pipename);
-               warn("can not open audio pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
-                                       (char *)errorstring, pipename);
-       }
+  fd = try_to_open_pipe_for_writing(pipename);
+  // we check that it's not a "real" error. From the "man 2 open" page:
+  // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
+  // open for reading." Which is okay.
+  if ((fd == -1) && (errno != ENXIO)) {
+    char errorstring[1024];
+    strerror_r(errno, (char *)errorstring, sizeof(errorstring));
+    debug(1, "audio_pipe start -- error %d (\"%s\") opening pipe: \"%s\".", errno,
+          (char *)errorstring, pipename);
+    warn("can not open audio pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
+         (char *)errorstring, pipename);
+  }
 }
 
 static int play(void *buf, int samples) {
   // if the file is not open, try to open it.
   char errorstring[1024];
   if (fd == -1) {
-       fd = try_to_open_pipe_for_writing(pipename);
+    fd = try_to_open_pipe_for_writing(pipename);
   }
   // if it's got a reader, write to it.
   if (fd > 0) {
-    //int rc = non_blocking_write(fd, buf, samples * 4);
+    // int rc = non_blocking_write(fd, buf, samples * 4);
     int rc = write(fd, buf, samples * 4);
     if ((rc < 0) && (errno != EPIPE)) {
       strerror_r(errno, (char *)errorstring, 1024);
-      debug(1, "audio_pip play: error %d writing to the pipe named \"%s\": \"%s\".", errno, pipename, errorstring);
+      debug(1, "audio_pip play: error %d writing to the pipe named \"%s\": \"%s\".", errno,
+            pipename, errorstring);
     }
   }
   return 0;
@@ -85,7 +87,6 @@ static int play(void *buf, int samples) {
 
 static void stop(void) {
   // Don't close the pipe just because a play session has stopped.
-
 }
 
 static int init(int argc, char **argv) {
@@ -108,16 +109,19 @@ static int init(int argc, char **argv) {
     if (config_lookup_string(config.cfg, "pipe.name", &str)) {
       pipename = (char *)str;
     }
-
-    if ((pipename) && (strcasecmp(pipename, "STDOUT") == 0))
-      die("Can't use \"pipe\" backend for STDOUT. Use the \"stdout\" backend instead.");
   }
 
-  if ((pipename == NULL) && (argc != 1))
-    die("bad or missing argument(s) to pipe");
+  if (argc > 1)
+    die("too many command-line arguments to pipe");
 
   if (argc == 1)
-    pipename = strdup(argv[0]);
+    pipename = argv[0]; // command line argument has priority
+
+  if ((pipename) && (strcasecmp(pipename, "STDOUT") == 0))
+    die("Can't use \"pipe\" backend for STDOUT. Use the \"stdout\" backend instead.");
+
+  if (pipename == NULL)
+    pipename = default_pipe_name; // if none specified
 
   // here, create the pipe
   mode_t oldumask = umask(000);
index 39c4d62eeaf23358984482a14305840f684bff83..b48adad4952cf66d107de40da2b3d85219099a7b 100644 (file)
--- a/common.c
+++ b/common.c
@@ -29,6 +29,8 @@
 #include "common.h"
 #include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
 #include <memory.h>
 #include <poll.h>
 #include <popt.h>
@@ -40,8 +42,6 @@
 #include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
-#include <fcntl.h>
-#include <libgen.h>
 
 #ifdef COMPILE_FOR_OSX
 #include <CoreServices/CoreServices.h>
@@ -141,64 +141,69 @@ void do_sps_log_to_stdout(__attribute__((unused)) int prio, const char *t, ...)
   fprintf(stdout, "%s\n", s);
 }
 
-int create_log_file(const char* path) {
-       int fd = -1;
-       if (path != NULL) {
-               char *dirc = strdup(path);
-               if (dirc) {
-                       char *dname = dirname(dirc);
-                       // create the directory, if necessary
-                       int result = 0;
-                       if (dname) {
-                               char *pdir = realpath(dname, NULL); // will return a NULL if the directory doesn't exist
-                               if (pdir == NULL) {
-                                       mode_t oldumask = umask(000);
-                                       result = mkpath(dname, 0777);
-                                       umask(oldumask);
-                               } else {
-                                       free(pdir);
-                               }
-                               if ((result == 0) || (result == -EEXIST)) {
-                                       // now open the file
-                                       fd = open(path, O_WRONLY | O_NONBLOCK | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-                                       if ((fd == -1) && (errno == EEXIST))
-                                               fd = open(path, O_WRONLY | O_APPEND | O_NONBLOCK);
-
-                                       if (fd >= 0) {
-                                               // now we switch to blocking mode
-                                               int flags = fcntl(fd, F_GETFL);
-                                               if (flags == -1) {
-//                                                     strerror_r(errno, (char *)errorstring, sizeof(errorstring));
-//                                                     debug(1, "create_log_file -- error %d (\"%s\") getting flags of pipe: \"%s\".", errno,
-//                                                                             (char *)errorstring, pathname);
-                                               } else {
-                                                       flags = fcntl(fd, F_SETFL,flags & ~O_NONBLOCK);
-//                                                     if (flags == -1) {
-//                                                             strerror_r(errno, (char *)errorstring, sizeof(errorstring));
-//                                                             debug(1, "create_log_file -- error %d (\"%s\") unsetting NONBLOCK of pipe: \"%s\".", errno,
-//                                                                                     (char *)errorstring, pathname);
-                                               }
-                                       }
-                               }
-                       }
-                       free(dirc);
-               }
-       }
-       return fd;
+int create_log_file(const char *path) {
+  int fd = -1;
+  if (path != NULL) {
+    char *dirc = strdup(path);
+    if (dirc) {
+      char *dname = dirname(dirc);
+      // create the directory, if necessary
+      int result = 0;
+      if (dname) {
+        char *pdir = realpath(dname, NULL); // will return a NULL if the directory doesn't exist
+        if (pdir == NULL) {
+          mode_t oldumask = umask(000);
+          result = mkpath(dname, 0777);
+          umask(oldumask);
+        } else {
+          free(pdir);
+        }
+        if ((result == 0) || (result == -EEXIST)) {
+          // now open the file
+          fd = open(path, O_WRONLY | O_NONBLOCK | O_CREAT | O_EXCL,
+                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+          if ((fd == -1) && (errno == EEXIST))
+            fd = open(path, O_WRONLY | O_APPEND | O_NONBLOCK);
+
+          if (fd >= 0) {
+            // now we switch to blocking mode
+            int flags = fcntl(fd, F_GETFL);
+            if (flags == -1) {
+              //                                                       strerror_r(errno, (char
+              //*)errorstring, sizeof(errorstring));
+              // debug(1, "create_log_file -- error %d (\"%s\") getting flags of pipe: \"%s\".",
+              // errno,
+              // (char *)errorstring, pathname);
+            } else {
+              flags = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+              //                                                       if (flags == -1) {
+              //                                                               strerror_r(errno,
+              //(char *)errorstring, sizeof(errorstring));
+              // debug(1, "create_log_file -- error %d
+              //(\"%s\") unsetting NONBLOCK of pipe: \"%s\".", errno,
+              //(char *)errorstring, pathname);
+            }
+          }
+        }
+      }
+      free(dirc);
+    }
+  }
+  return fd;
 }
 
 void do_sps_log_to_fd(__attribute__((unused)) int prio, const char *t, ...) {
-               char s[1024];
-               va_list args;
-               va_start(args, t);
-               vsnprintf(s, sizeof(s), t, args);
-               va_end(args);
-               if (config.log_fd == -1)
-                       config.log_fd = create_log_file(config.log_file_path);
-       if (config.log_fd >= 0) {
-               dprintf(config.log_fd, "%s\n", s);
+  char s[1024];
+  va_list args;
+  va_start(args, t);
+  vsnprintf(s, sizeof(s), t, args);
+  va_end(args);
+  if (config.log_fd == -1)
+    config.log_fd = create_log_file(config.log_file_path);
+  if (config.log_fd >= 0) {
+    dprintf(config.log_fd, "%s\n", s);
   } else if (errno != ENXIO) { // maybe there is a pipe there but not hooked up
-       fprintf(stderr, "%s\n", s);
+    fprintf(stderr, "%s\n", s);
   }
 }
 
@@ -207,9 +212,9 @@ void log_to_stdout() { sps_log = do_sps_log_to_stdout; }
 void log_to_file() { sps_log = do_sps_log_to_fd; }
 void log_to_syslog() {
 #ifdef CONFIG_LIBDAEMON
-       sps_log = daemon_log;
+  sps_log = daemon_log;
 #else
-       sps_log = syslog;
+  sps_log = syslog;
 #endif
 }
 
@@ -309,8 +314,8 @@ void _die(const char *filename, const int linenumber, const char *format, ...) {
                                     1.0 * time_since_last_debug_message / 1000000000, filename,
                                     linenumber, " *fatal error: ");
   } else {
-       strncpy(b, "fatal error: ", sizeof(b));
-    s = b+strlen(b);
+    strncpy(b, "fatal error: ", sizeof(b));
+    s = b + strlen(b);
   }
   va_list args;
   va_start(args, format);
@@ -339,8 +344,8 @@ void _warn(const char *filename, const int linenumber, const char *format, ...)
                                     1.0 * time_since_last_debug_message / 1000000000, filename,
                                     linenumber, " *warning: ");
   } else {
-       strncpy(b, "warning: ", sizeof(b));
-    s = b+strlen(b);
+    strncpy(b, "warning: ", sizeof(b));
+    s = b + strlen(b);
   }
   va_list args;
   va_start(args, format);
@@ -1134,12 +1139,12 @@ uint64_t get_absolute_time_in_ns() {
   return time_now_ns;
 }
 
-int try_to_open_pipe_for_writing(const charpathname) {
-       // tries to open the pipe in non-blocking mode first.
-       // if it succeeds, it sets it to blocking.
-       // if not, it returns -1.
+int try_to_open_pipe_for_writing(const char *pathname) {
+  // tries to open the pipe in non-blocking mode first.
+  // if it succeeds, it sets it to blocking.
+  // if not, it returns -1.
 
-       int fdis = open(pathname, O_WRONLY | O_NONBLOCK); // open it in non blocking mode first
+  int fdis = open(pathname, O_WRONLY | O_NONBLOCK); // open it in non blocking mode first
 
   // we check that it's not a "real" error. From the "man 2 open" page:
   // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
@@ -1147,24 +1152,24 @@ int try_to_open_pipe_for_writing(const char* pathname) {
   // This is checked by the caller.
 
   if (fdis >= 0) {
-       // now we switch to blocking mode
-       int flags = fcntl(fdis, F_GETFL);
-       if (flags == -1) {
-               char errorstring[1024];
-                       strerror_r(errno, (char *)errorstring, sizeof(errorstring));
-                       debug(1, "try_to_open_pipe -- error %d (\"%s\") getting flags of pipe: \"%s\".", errno,
-                                               (char *)errorstring, pathname);
-       } else {
-               flags = fcntl(fdis, F_SETFL,flags & ~O_NONBLOCK);
-               if (flags == -1) {
-                       char errorstring[1024];
-                               strerror_r(errno, (char *)errorstring, sizeof(errorstring));
-                               debug(1, "try_to_open_pipe -- error %d (\"%s\") unsetting NONBLOCK of pipe: \"%s\".", errno,
-                                                       (char *)errorstring, pathname);
-               }
-       }
+    // now we switch to blocking mode
+    int flags = fcntl(fdis, F_GETFL);
+    if (flags == -1) {
+      char errorstring[1024];
+      strerror_r(errno, (char *)errorstring, sizeof(errorstring));
+      debug(1, "try_to_open_pipe -- error %d (\"%s\") getting flags of pipe: \"%s\".", errno,
+            (char *)errorstring, pathname);
+    } else {
+      flags = fcntl(fdis, F_SETFL, flags & ~O_NONBLOCK);
+      if (flags == -1) {
+        char errorstring[1024];
+        strerror_r(errno, (char *)errorstring, sizeof(errorstring));
+        debug(1, "try_to_open_pipe -- error %d (\"%s\") unsetting NONBLOCK of pipe: \"%s\".", errno,
+              (char *)errorstring, pathname);
+      }
+    }
   }
-       return fdis;
+  return fdis;
 }
 
 /* from
@@ -1460,6 +1465,9 @@ char *get_version_string() {
 #ifdef CONFIG_SNDIO
     strcat(version_string, "-sndio");
 #endif
+#ifdef CONFIG_JACK
+    strcat(version_string, "-jack");
+#endif
 #ifdef CONFIG_AO
     strcat(version_string, "-ao");
 #endif
@@ -1707,11 +1715,11 @@ int string_update_with_size(char **str, int *flag, char *s, size_t len) {
 }
 
 // from https://stackoverflow.com/questions/13663617/memdup-function-in-c, with thanks
-void* memdup(const void* mem, size_t size) {
-   void* out = malloc(size);
+void *memdup(const void *mem, size_t size) {
+  void *out = malloc(size);
 
-   if(out != NULL)
-       memcpy(out, mem, size);
+  if (out != NULL)
+    memcpy(out, mem, size);
 
-   return out;
+  return out;
 }
index 1f5d1c87b24575707d02f9944bd026f1bc87be99..68666ac9097780bb4c9e6a9bbdb3a72c6d016439 100644 (file)
--- a/common.h
+++ b/common.h
@@ -182,8 +182,8 @@ typedef struct {
   char *pidfile;
 #endif
 
-       int     log_fd; // file descriptor of the file or pipe to log stuff to.
-       char *log_file_path; // path to file or pipe to log to, if any
+  int log_fd;                      // file descriptor of the file or pipe to log stuff to.
+  char *log_file_path;             // path to file or pipe to log to, if any
   int logOutputLevel;              // log output level
   int debugger_show_elapsed_time;  // in the debug message, display the time since startup
   int debugger_show_relative_time; // in the debug message, display the time since the last one
@@ -285,10 +285,10 @@ typedef struct {
   int jack_soxr_resample_quality;
 #endif
 #endif
-       void *gradients; // a linked list of the clock gradients discovered for all DACP IDs
-       // can't use IP numbers as they might be given to different devices
-       // can't get hold of MAC addresses.
-       // can't define the nvll linked list struct here
+  void *gradients; // a linked list of the clock gradients discovered for all DACP IDs
+                   // can't use IP numbers as they might be given to different devices
+                   // can't get hold of MAC addresses.
+                   // can't define the nvll linked list struct here
 } shairport_cfg;
 
 // accessors to config for multi-thread access
@@ -303,9 +303,7 @@ void memory_barrier();
 void log_to_stderr(); // call this to direct logging to stderr;
 void log_to_stdout(); // call this to direct logging to stdout;
 void log_to_syslog(); // call this to direct logging to the system log;
-void log_to_file(); // call this to direct logging to a file or (pre-existing) pipe;
-
-
+void log_to_file();   // call this to direct logging to a file or (pre-existing) pipe;
 
 // true if Shairport Sync is supposed to be sending output to the output device, false otherwise
 
@@ -313,7 +311,8 @@ int get_requested_connection_state_to_output();
 
 void set_requested_connection_state_to_output(int v);
 
-int try_to_open_pipe_for_writing(const char* pathname); // open it without blocking if it's not hooked up
+int try_to_open_pipe_for_writing(
+    const char *pathname); // open it without blocking if it's not hooked up
 
 /* from
  * http://coding.debuntu.org/c-implementing-str_replace-replace-all-occurrences-substring#comment-722
@@ -446,6 +445,6 @@ void malloc_cleanup(void *arg);
 int string_update_with_size(char **str, int *flag, char *s, size_t len);
 
 // from https://stackoverflow.com/questions/13663617/memdup-function-in-c, with thanks
-void* memdup(const void* mem, size_t size);
+void *memdup(const void *mem, size_t size);
 
 #endif // _COMMON_H
index 7f25369996a5255f85a14683fb41a619438d68b8..78e337e7a7a3db5047aafecb145d37d1344c1630 100644 (file)
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.50])
-AC_INIT([shairport-sync], [3.3.7rc2], [4265913+mikebrady@users.noreply.github.com])
+AC_INIT([shairport-sync], [3.3.7rc3], [4265913+mikebrady@users.noreply.github.com])
 AM_INIT_AUTOMAKE
 AC_CONFIG_SRCDIR([shairport.c])
 AC_CONFIG_HEADERS([config.h])
@@ -156,7 +156,7 @@ AC_ARG_WITH(ssl, [ choose --with-ssl=openssl, --with-ssl=mbedtls or --with-ssl=p
     AC_MSG_ERROR(choose "openssl", "mbedtls" or "polarssl" encryption)
   fi
   if test "x${with_ssl}" = xopenssl ; then
-  AC_DEFINE([CONFIG_OPENSSL], 1, [Use the OpenSSL libraries for encryption and encoding and decoding])    
+  AC_DEFINE([CONFIG_OPENSSL], 1, [Use the OpenSSL libraries for encryption and encoding and decoding])
     if  test "x${with_pkg_config}" = xyes ; then
       PKG_CHECK_MODULES(
           [SSL], [libssl,libcrypto],
@@ -166,7 +166,7 @@ AC_ARG_WITH(ssl, [ choose --with-ssl=openssl, --with-ssl=mbedtls or --with-ssl=p
       AC_CHECK_LIB([ssl], [main], , AC_MSG_ERROR(libssl selected but the library cannot be found!))
     fi
   elif test "x${with_ssl}" = xmbedtls ; then
-    AC_DEFINE([CONFIG_MBEDTLS], 1, [Use the mbed TLS libraries for encryption and encoding and decoding])    
+    AC_DEFINE([CONFIG_MBEDTLS], 1, [Use the mbed TLS libraries for encryption and encoding and decoding])
     AC_CHECK_LIB([mbedtls],[mbedtls_ssl_init],,
                [AC_MSG_ERROR([mbed tls support requires the mbedtls library -- libmbedtls-dev suggested],1)])
     AC_CHECK_LIB([mbedcrypto], [mbedtls_entropy_func],,
@@ -174,7 +174,7 @@ AC_ARG_WITH(ssl, [ choose --with-ssl=openssl, --with-ssl=mbedtls or --with-ssl=p
     AC_CHECK_LIB([mbedx509], [mbedtls_pk_init],,
                 [AC_MSG_ERROR([mbed tls support requires the mbedx509 library -- libmbedx509-0 suggested],1)])
   elif test "x${with_ssl}" = xpolarssl ; then
-    AC_DEFINE([CONFIG_POLARSSL], 1, [Use the PolarSSL libraries for encryption and encoding and decoding])    
+    AC_DEFINE([CONFIG_POLARSSL], 1, [Use the PolarSSL libraries for encryption and encoding and decoding])
     AC_CHECK_LIB([polarssl],[ssl_init], , AC_MSG_ERROR(PolarSSL is selected but the library cannot be found and is deprecated. Consider selecting mbed TLS instead using --with-ssl=mbedtls.))
   else
     AC_MSG_ERROR(unknown option "${with_ssl}"." Please choose with "openssl", "mbedtls" or "polarssl")
diff --git a/dacp.c b/dacp.c
index a25bf9e48257ccc64bedc59df91681432916f45d..acb963b9aa42c8c4bdb2d285dd423bb6218ba573 100644 (file)
--- a/dacp.c
+++ b/dacp.c
@@ -56,7 +56,7 @@ typedef struct {
   int always_use_revision_number_1;    // for dealing with forked-daapd;
   uint32_t scope_id;                   // if it's an ipv6 connection, this will be its scope id
   char ip_string[INET6_ADDRSTRLEN];    // the ip string pointing to the client
-  uint32_t active_remote_id;           // send this when you want to send remote control commands
+  char *active_remote_id;              // send this when you want to send remote control commands
   void *port_monitor_private_storage;
 } dacp_server_record;
 
@@ -244,7 +244,7 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
             // debug(1,"DACP connect succeeded.");
 
             snprintf(message, sizeof(message),
-                     "GET /ctrl-int/1/%s HTTP/1.1\r\nHost: %s:%u\r\nActive-Remote: %u\r\n\r\n",
+                     "GET /ctrl-int/1/%s HTTP/1.1\r\nHost: %s:%u\r\nActive-Remote: %s\r\n\r\n",
                      command, dacp_server.ip_string, dacp_server.port,
                      dacp_server.active_remote_id);
 
@@ -443,10 +443,12 @@ void set_dacp_server_information(rtsp_conn_info *conn) {
       //      metadata_hub_modify_epilog(ch);
     }
   }
-  dacp_server.active_remote_id = conn->dacp_active_remote; // even if the dacp_id remains the same,
-                                                           // the active remote will change.
-  debug(3, "set_dacp_server_information set active-remote id to %" PRIu32 ".",
-        dacp_server.active_remote_id);
+  if (dacp_server.active_remote_id)
+    free(dacp_server.active_remote_id);
+  dacp_server.active_remote_id =
+      strdup(conn->dacp_active_remote); // even if the dacp_id remains the same,
+                                        // the active remote will change.
+  debug(3, "set_dacp_server_information set active-remote id to %s.", dacp_server.active_remote_id);
   pthread_cond_signal(&dacp_server_information_cv);
   debug_mutex_unlock(&dacp_server_information_lock, 3);
 }
@@ -457,20 +459,24 @@ void dacp_monitor_port_update_callback(char *dacp_id, uint16_t port) {
         "dacp_monitor_port_update_callback with Remote ID \"%s\", target ID \"%s\" and port "
         "number %d.",
         dacp_id, dacp_server.dacp_id, port);
-  if (strcmp(dacp_id, dacp_server.dacp_id) == 0) {
-    dacp_server.port = port;
-    if (port == 0)
-      dacp_server.scan_enable = 0;
-    else {
-      dacp_server.scan_enable = 1;
-      // debug(2, "dacp_monitor_port_update_callback enables scan");
-    }
-    //    metadata_hub_modify_prolog();
-    //    int ch = metadata_store.dacp_server_active != dacp_server.scan_enable;
-    //    metadata_store.dacp_server_active = dacp_server.scan_enable;
-    //    metadata_hub_modify_epilog(ch);
+  if ((dacp_id == NULL) || (dacp_server.dacp_id == NULL)) {
+    warn("dacp_id or dacp_server.dacp_id NULL detected");
   } else {
-    debug(1, "dacp port monitor reporting on an out-of-use remote.");
+    if (strcmp(dacp_id, dacp_server.dacp_id) == 0) {
+      dacp_server.port = port;
+      if (port == 0)
+        dacp_server.scan_enable = 0;
+      else {
+        dacp_server.scan_enable = 1;
+        // debug(2, "dacp_monitor_port_update_callback enables scan");
+      }
+      //    metadata_hub_modify_prolog();
+      //    int ch = metadata_store.dacp_server_active != dacp_server.scan_enable;
+      //    metadata_store.dacp_server_active = dacp_server.scan_enable;
+      //    metadata_hub_modify_epilog(ch);
+    } else {
+      debug(1, "dacp port monitor reporting on an out-of-use remote.");
+    }
   }
   pthread_cond_signal(&dacp_server_information_cv);
   debug_mutex_unlock(&dacp_server_information_lock, 3);
@@ -999,6 +1005,10 @@ void dacp_monitor_stop() {
     pthread_mutex_destroy(&dacp_conversation_lock);
     pthread_cond_destroy(&dacp_server_information_cv);
     debug(3, "DACP Server Information Condition Variable destroyed.");
+    if (dacp_server.active_remote_id) {
+      free(dacp_server.active_remote_id);
+      dacp_server.active_remote_id = NULL;
+    }
   }
 }
 
index 7b20ae18d2f6c99fddbeb61a3e1850eba092c62c..a899574ad0bcae79c269f761fe81edf112a196a2 100644 (file)
@@ -136,18 +136,20 @@ void _metadata_hub_modify_prolog(const char *filename, const int linenumber) {
   // debug(1, "locking metadata hub for writing");
   if (pthread_rwlock_trywrlock(&metadata_hub_re_lock) != 0) {
     if (last_metadata_hub_modify_prolog_file)
-       debug(2, "Metadata_hub write lock at \"%s:%d\" is already taken at \"%s:%d\" -- must wait.", filename, linenumber, last_metadata_hub_modify_prolog_file, last_metadata_hub_modify_prolog_line);
+      debug(2, "Metadata_hub write lock at \"%s:%d\" is already taken at \"%s:%d\" -- must wait.",
+            filename, linenumber, last_metadata_hub_modify_prolog_file,
+            last_metadata_hub_modify_prolog_line);
     else
-       debug(2, "Metadata_hub write lock is already taken by unknown -- must wait.");
+      debug(2, "Metadata_hub write lock is already taken by unknown -- must wait.");
     metadata_hub_re_lock_access_is_delayed = 0;
     pthread_rwlock_wrlock(&metadata_hub_re_lock);
     debug(2, "Okay -- acquired the metadata_hub write lock at \"%s:%d\".", filename, linenumber);
   } else {
-       if (last_metadata_hub_modify_prolog_file) {
-               free(last_metadata_hub_modify_prolog_file);
-       }
-       last_metadata_hub_modify_prolog_file = strdup(filename);
-       last_metadata_hub_modify_prolog_line = linenumber;
+    if (last_metadata_hub_modify_prolog_file) {
+      free(last_metadata_hub_modify_prolog_file);
+    }
+    last_metadata_hub_modify_prolog_file = strdup(filename);
+    last_metadata_hub_modify_prolog_line = linenumber;
     // debug(3, "Metadata_hub write lock acquired.");
   }
   metadata_hub_re_lock_access_is_delayed = 0;
@@ -160,13 +162,16 @@ void _metadata_hub_modify_epilog(int modified, const char *filename, const int l
     run_metadata_watchers();
   }
   if (metadata_hub_re_lock_access_is_delayed) {
-               if (last_metadata_hub_modify_prolog_file) {
-                               debug(1, "Metadata_hub write lock taken at \"%s:%d\" is freed at \"%s:%d\".", last_metadata_hub_modify_prolog_file, last_metadata_hub_modify_prolog_line, filename, linenumber);
-                               free(last_metadata_hub_modify_prolog_file);
-                               last_metadata_hub_modify_prolog_file = NULL;
-               } else {
-                               debug(1, "Metadata_hub write lock taken at an unknown place is freed at \"%s:%d\".", filename, linenumber);
-               }
+    if (last_metadata_hub_modify_prolog_file) {
+      debug(1, "Metadata_hub write lock taken at \"%s:%d\" is freed at \"%s:%d\".",
+            last_metadata_hub_modify_prolog_file, last_metadata_hub_modify_prolog_line, filename,
+            linenumber);
+      free(last_metadata_hub_modify_prolog_file);
+      last_metadata_hub_modify_prolog_file = NULL;
+    } else {
+      debug(1, "Metadata_hub write lock taken at an unknown place is freed at \"%s:%d\".", filename,
+            linenumber);
+    }
   }
   pthread_rwlock_unlock(&metadata_hub_re_lock);
   // debug(3, "Metadata_hub write lock unlocked.");
@@ -506,10 +511,11 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
       debug(2, "MH Picture received, length %u bytes.", length);
 
       char uri[2048];
-      if ((length > 16) && (strcmp(config.cover_art_cache_dir,"")!=0)) { // if it's okay to write the file
-       // make this uncancellable
-                               int oldState;
-                               pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable
+      if ((length > 16) &&
+          (strcmp(config.cover_art_cache_dir, "") != 0)) { // if it's okay to write the file
+                                                           // make this uncancellable
+        int oldState;
+        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable
         char *pathname = metadata_write_image_file(data, length);
         snprintf(uri, sizeof(uri), "file://%s", pathname);
         free(pathname);
@@ -524,7 +530,7 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
         changed = 1;
       else
         changed = 0;
-//      pthread_cleanup_pop(0); // don't remove the lock -- it'll have been done
+      //      pthread_cleanup_pop(0); // don't remove the lock -- it'll have been done
       break;
     case 'clip':
       cs = strndup(data, length);
index 760a848bdb1f0743285e85240294b346e66c9e20..bdbbf321e9f584c389952bf1e0a98210424d8391 100644 (file)
@@ -149,7 +149,9 @@ void metadata_hub_release_track_artwork(void);
 // these functions lock and unlock the read-write mutex on the metadata hub and run the watchers
 // afterwards
 void _metadata_hub_modify_prolog(const char *filename, const int linenumber);
-void _metadata_hub_modify_epilog(int modified, const char *filename, const int linenumber); // set to true if modifications occurred, 0 otherwise
+void _metadata_hub_modify_epilog(
+    int modified, const char *filename,
+    const int linenumber); // set to true if modifications occurred, 0 otherwise
 
 /*
 // these are for safe reading
@@ -158,7 +160,8 @@ void _metadata_hub_read_epilog(const char *filename, const int linenumber);
 */
 
 #define metadata_hub_modify_prolog(void) _metadata_hub_modify_prolog(__FILE__, __LINE__)
-#define metadata_hub_modify_epilog(modified) _metadata_hub_modify_epilog(modified, __FILE__, __LINE__)
+#define metadata_hub_modify_epilog(modified)                                                       \
+  _metadata_hub_modify_epilog(modified, __FILE__, __LINE__)
 
 #define metadata_hub_read_prolog(void) _metadata_hub_read_prolog(__FILE__, __LINE__)
 #define metadata_hub_read_epilog(void) _metadata_hub_modify_epilog(__FILE__, __LINE__)
index edca685fd6b58e0caf0b66efb7a3ca77581d2439..78912e3be9c862d87ca3ad4d0add1ad326c452bd 100644 (file)
--- a/player.c
+++ b/player.c
@@ -143,7 +143,6 @@ static void ab_resync(rtsp_conn_info *conn) {
   conn->ab_buffering = 1;
 }
 
-
 // given starting and ending points as unsigned 16-bit integers running modulo 2^16, returns the
 // position of x in the interval in *pos
 // returns true if x is actually within the buffer
@@ -174,25 +173,21 @@ int position_in_modulo_uint16_t_buffer(uint16_t x, uint16_t start, uint16_t end,
   return response;
 }
 
-static inline seq_t SUCCESSOR(seq_t x) {
-  return x + 1;
-}
+static inline seq_t SUCCESSOR(seq_t x) { return x + 1; }
 
 // a minus b
 int16_t seq_diff(seq_t a, seq_t b) {
-       int16_t response;
-       seq_t diff = a - b;
-       seq_t invdiff = b - a;
-       if (diff < invdiff)
-               response = diff;
-       else
-               response = -invdiff;
+  int16_t response;
+  seq_t diff = a - b;
+  seq_t invdiff = b - a;
+  if (diff < invdiff)
+    response = diff;
+  else
+    response = -invdiff;
   return response;
 }
 
-static inline seq_t seq_sum(seq_t a, seq_t b) {
-  return a + b;
-}
+static inline seq_t seq_sum(seq_t a, seq_t b) { return a + b; }
 
 // This orders u and v by picking the smaller of the two modulo differences
 // in unsigned modulo arithmetic and setting the sign of the result accordingly.
@@ -215,16 +210,15 @@ static inline seq_t seq_sum(seq_t a, seq_t b) {
 // If that ever happens and there is a real ambiguity in the application,
 // the modulo chosen is too small.
 
-
 int64_t int64_mod_difference(const uint64_t u, const uint64_t v, const uint64_t modulo) {
-       int64_t response;
-       uint64_t diff = (u - v) % modulo;
-       uint64_t invdiff = (v - u) % modulo;
-       if (diff < invdiff)
-               response = diff;
-       else
-               response = -invdiff;
-       return response;
+  int64_t response;
+  uint64_t diff = (u - v) % modulo;
+  uint64_t invdiff = (v - u) % modulo;
+  if (diff < invdiff)
+    response = diff;
+  else
+    response = -invdiff;
+  return response;
 }
 
 void reset_input_flow_metrics(rtsp_conn_info *conn) {
@@ -466,172 +460,173 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, uint8_t *data, in
   conn->packet_count_since_flush++;
   conn->time_of_last_audio_packet = time_now;
   if (conn->connection_state_to_output) { // if we are supposed to be processing these packets
-               abuf_t *abuf = 0;
-               if (!conn->ab_synced) {
-                       // if this is the first packet...
-                       debug(3, "syncing to seqno %u.", seqno);
-                       conn->ab_write = seqno;
-                       conn->ab_read = seqno;
-                       conn->ab_synced = 1;
-               }
-               int16_t write_point_gap = seq_diff(seqno,conn->ab_write); // this is the difference between
-               // the incoming packet number and the packet number that was expected.
-               if (write_point_gap == 0) { // if this is the expected packet (which could be the first packet...)
-                       if (conn->input_frame_rate_starting_point_is_valid == 0) {
-                               if ((conn->packet_count_since_flush >= 500) && (conn->packet_count_since_flush <= 510)) {
-                                       conn->frames_inward_measurement_start_time = time_now;
-                                       conn->frames_inward_frames_received_at_measurement_start_time = actual_timestamp;
-                                       conn->input_frame_rate_starting_point_is_valid = 1; // valid now
-                               }
-                       }
-                       conn->frames_inward_measurement_time = time_now;
-                       conn->frames_inward_frames_received_at_measurement_time = actual_timestamp;
-                       abuf = conn->audio_buffer + BUFIDX(seqno);
-                       conn->ab_write = SUCCESSOR(seqno); // move the write pointer to the next free space
-               } else if (write_point_gap > 0) { // newer than expected
-                       // initialise  the frames in between
-                       int i;
-                       for (i = 0; i < write_point_gap; i++) {
-                               abuf = conn->audio_buffer + BUFIDX(seq_sum(conn->ab_write, i));
-                               abuf->ready = 0; // to be sure, to be sure
-                               abuf->resend_request_number = 0;
-                               abuf->initialisation_time =
-                                               time_now;          // this represents when the packet was noticed to be missing
-                               abuf->status = 1 << 0; // signifying missing
-                               abuf->resend_time = 0;
-                               abuf->given_timestamp = 0;
-                               abuf->sequence_number = 0;
-                       }
-                       abuf = conn->audio_buffer + BUFIDX(seqno);
-                       conn->ab_write = SUCCESSOR(seqno);
-               } else if (seq_diff(seqno,conn->ab_read) > 0) { // older than expected but still not too late
-                       conn->late_packets++;
-                       abuf = conn->audio_buffer + BUFIDX(seqno);
-               } else { // too late.
-                       conn->too_late_packets++;
-               }
-
-               if (abuf) {
-                       int datalen = conn->max_frames_per_packet;
-                       abuf->initialisation_time = time_now;
-                       abuf->resend_time = 0;
-                       if (audio_packet_decode(abuf->data, &datalen, data, len, conn) == 0) {
-                               abuf->ready = 1;
-                               abuf->status = 0; // signifying that it was received
-                               abuf->length = datalen;
-                               abuf->given_timestamp = actual_timestamp;
-                               abuf->sequence_number = seqno;
-                       } else {
-                               debug(1, "Bad audio packet detected and discarded.");
-                               abuf->ready = 0;
-                               abuf->status = 1 << 1; // bad packet, discarded
-                               abuf->resend_request_number = 0;
-                               abuf->given_timestamp = 0;
-                               abuf->sequence_number = 0;
-                       }
-               }
-
-               int rc = pthread_cond_signal(&conn->flowcontrol);
-               if (rc)
-                       debug(1, "Error signalling flowcontrol.");
-
-               // resend checks
-               {
-                       uint64_t minimum_wait_time =
-                                       (uint64_t)(config.resend_control_first_check_time * (uint64_t)1000000000);
-                       uint64_t resend_repeat_interval =
-                                       (uint64_t)(config.resend_control_check_interval_time * (uint64_t)1000000000);
-                       uint64_t minimum_remaining_time = (uint64_t)(
-                                       (config.resend_control_last_check_time + config.audio_backend_buffer_desired_length) *
-                                       (uint64_t)1000000000);
-                       uint64_t latency_time = (uint64_t)(conn->latency * (uint64_t)1000000000);
-                       latency_time = latency_time / (uint64_t)conn->input_rate;
-
-                       int x; // this is the first frame to be checked
-                       // if we detected a first empty frame before and if it's still in the buffer!
-                       if ((first_possibly_missing_frame >= 0) &&
-                                       (position_in_modulo_uint16_t_buffer(first_possibly_missing_frame, conn->ab_read,
-                                                                                                                                                                                       conn->ab_write, NULL))) {
-                               x = first_possibly_missing_frame;
-                       } else {
-                               x = conn->ab_read;
-                       }
-
-                       first_possibly_missing_frame = -1; // has not been set
-
-                       int missing_frame_run_count = 0;
-                       int start_of_missing_frame_run = -1;
-                       int number_of_missing_frames = 0;
-                       while (x != conn->ab_write) {
-                               abuf_t *check_buf = conn->audio_buffer + BUFIDX(x);
-                               if (!check_buf->ready) {
-                                       if (first_possibly_missing_frame < 0)
-                                               first_possibly_missing_frame = x;
-                                       number_of_missing_frames++;
-                                       // debug(1, "frame %u's initialisation_time is 0x%" PRIx64 ", latency_time is 0x%"
-                                       // PRIx64 ", time_now is 0x%" PRIx64 ", minimum_remaining_time is 0x%" PRIx64 ".", x,
-                                       // check_buf->initialisation_time, latency_time, time_now, minimum_remaining_time);
-                                       int too_late = ((check_buf->initialisation_time < (time_now - latency_time)) ||
-                                                                                                       ((check_buf->initialisation_time - (time_now - latency_time)) <
-                                                                                                        minimum_remaining_time));
-                                       int too_early = ((time_now - check_buf->initialisation_time) < minimum_wait_time);
-                                       int too_soon_after_last_request =
-                                                       ((check_buf->resend_time != 0) &&
-                                                        ((time_now - check_buf->resend_time) <
-                                                               resend_repeat_interval)); // time_now can never be less than the time_tag
-
-                                       if (too_late)
-                                               check_buf->status |= 1 << 2; // too late
-                                       else
-                                               check_buf->status &= 0xFF - (1 << 2); // not too late
-                                       if (too_early)
-                                               check_buf->status |= 1 << 3; // too early
-                                       else
-                                               check_buf->status &= 0xFF - (1 << 3); // not too early
-                                       if (too_soon_after_last_request)
-                                               check_buf->status |= 1 << 4; // too soon after last request
-                                       else
-                                               check_buf->status &= 0xFF - (1 << 4); // not too soon after last request
-
-                                       if ((!too_soon_after_last_request) && (!too_late) && (!too_early)) {
-                                               if (start_of_missing_frame_run == -1) {
-                                                       start_of_missing_frame_run = x;
-                                                       missing_frame_run_count = 1;
-                                               } else {
-                                                       missing_frame_run_count++;
-                                               }
-                                               check_buf->resend_time = time_now; // setting the time to now because we are
-                                                                                                                                                                                        // definitely going to take action
-                                               check_buf->resend_request_number++;
-                                               debug(3, "Frame %d is missing with ab_read of %u and ab_write of %u.", x,
-                                                                       conn->ab_read, conn->ab_write);
-                                       }
-                                       // if (too_late) {
-                                       //   debug(1,"too late to get missing frame %u.", x);
-                                       // }
-                               }
-                               // if (number_of_missing_frames != 0)
-                               //  debug(1,"check with x = %u, ab_read = %u, ab_write = %u, first_possibly_missing_frame
-                               //  = %d.", x, conn->ab_read, conn->ab_write, first_possibly_missing_frame);
-                               x = (x + 1) & 0xffff;
-                               if (((check_buf->ready) || (x == conn->ab_write)) && (missing_frame_run_count > 0)) {
-                                       // send a resend request
-                                       if (missing_frame_run_count > 1)
-                                               debug(3, "request resend of %d packets starting at seqno %u.",
-                                                                       missing_frame_run_count, start_of_missing_frame_run);
-                                       if (config.disable_resend_requests == 0) {
-                                               debug_mutex_unlock(&conn->ab_mutex, 3);
-                                               rtp_request_resend(start_of_missing_frame_run, missing_frame_run_count, conn);
-                                               debug_mutex_lock(&conn->ab_mutex, 20000, 1);
-                                               conn->resend_requests++;
-                                       }
-                                       start_of_missing_frame_run = -1;
-                                       missing_frame_run_count = 0;
-                               }
-                       }
-                       if (number_of_missing_frames == 0)
-                               first_possibly_missing_frame = conn->ab_write;
-               }
+    abuf_t *abuf = 0;
+    if (!conn->ab_synced) {
+      // if this is the first packet...
+      debug(3, "syncing to seqno %u.", seqno);
+      conn->ab_write = seqno;
+      conn->ab_read = seqno;
+      conn->ab_synced = 1;
+    }
+    int16_t write_point_gap = seq_diff(seqno, conn->ab_write); // this is the difference between
+    // the incoming packet number and the packet number that was expected.
+    if (write_point_gap ==
+        0) { // if this is the expected packet (which could be the first packet...)
+      if (conn->input_frame_rate_starting_point_is_valid == 0) {
+        if ((conn->packet_count_since_flush >= 500) && (conn->packet_count_since_flush <= 510)) {
+          conn->frames_inward_measurement_start_time = time_now;
+          conn->frames_inward_frames_received_at_measurement_start_time = actual_timestamp;
+          conn->input_frame_rate_starting_point_is_valid = 1; // valid now
+        }
+      }
+      conn->frames_inward_measurement_time = time_now;
+      conn->frames_inward_frames_received_at_measurement_time = actual_timestamp;
+      abuf = conn->audio_buffer + BUFIDX(seqno);
+      conn->ab_write = SUCCESSOR(seqno); // move the write pointer to the next free space
+    } else if (write_point_gap > 0) {    // newer than expected
+      // initialise  the frames in between
+      int i;
+      for (i = 0; i < write_point_gap; i++) {
+        abuf = conn->audio_buffer + BUFIDX(seq_sum(conn->ab_write, i));
+        abuf->ready = 0; // to be sure, to be sure
+        abuf->resend_request_number = 0;
+        abuf->initialisation_time =
+            time_now;          // this represents when the packet was noticed to be missing
+        abuf->status = 1 << 0; // signifying missing
+        abuf->resend_time = 0;
+        abuf->given_timestamp = 0;
+        abuf->sequence_number = 0;
+      }
+      abuf = conn->audio_buffer + BUFIDX(seqno);
+      conn->ab_write = SUCCESSOR(seqno);
+    } else if (seq_diff(seqno, conn->ab_read) > 0) { // older than expected but still not too late
+      conn->late_packets++;
+      abuf = conn->audio_buffer + BUFIDX(seqno);
+    } else { // too late.
+      conn->too_late_packets++;
+    }
+
+    if (abuf) {
+      int datalen = conn->max_frames_per_packet;
+      abuf->initialisation_time = time_now;
+      abuf->resend_time = 0;
+      if (audio_packet_decode(abuf->data, &datalen, data, len, conn) == 0) {
+        abuf->ready = 1;
+        abuf->status = 0; // signifying that it was received
+        abuf->length = datalen;
+        abuf->given_timestamp = actual_timestamp;
+        abuf->sequence_number = seqno;
+      } else {
+        debug(1, "Bad audio packet detected and discarded.");
+        abuf->ready = 0;
+        abuf->status = 1 << 1; // bad packet, discarded
+        abuf->resend_request_number = 0;
+        abuf->given_timestamp = 0;
+        abuf->sequence_number = 0;
+      }
+    }
+
+    int rc = pthread_cond_signal(&conn->flowcontrol);
+    if (rc)
+      debug(1, "Error signalling flowcontrol.");
+
+    // resend checks
+    {
+      uint64_t minimum_wait_time =
+          (uint64_t)(config.resend_control_first_check_time * (uint64_t)1000000000);
+      uint64_t resend_repeat_interval =
+          (uint64_t)(config.resend_control_check_interval_time * (uint64_t)1000000000);
+      uint64_t minimum_remaining_time = (uint64_t)(
+          (config.resend_control_last_check_time + config.audio_backend_buffer_desired_length) *
+          (uint64_t)1000000000);
+      uint64_t latency_time = (uint64_t)(conn->latency * (uint64_t)1000000000);
+      latency_time = latency_time / (uint64_t)conn->input_rate;
+
+      int x; // this is the first frame to be checked
+      // if we detected a first empty frame before and if it's still in the buffer!
+      if ((first_possibly_missing_frame >= 0) &&
+          (position_in_modulo_uint16_t_buffer(first_possibly_missing_frame, conn->ab_read,
+                                              conn->ab_write, NULL))) {
+        x = first_possibly_missing_frame;
+      } else {
+        x = conn->ab_read;
+      }
+
+      first_possibly_missing_frame = -1; // has not been set
+
+      int missing_frame_run_count = 0;
+      int start_of_missing_frame_run = -1;
+      int number_of_missing_frames = 0;
+      while (x != conn->ab_write) {
+        abuf_t *check_buf = conn->audio_buffer + BUFIDX(x);
+        if (!check_buf->ready) {
+          if (first_possibly_missing_frame < 0)
+            first_possibly_missing_frame = x;
+          number_of_missing_frames++;
+          // debug(1, "frame %u's initialisation_time is 0x%" PRIx64 ", latency_time is 0x%"
+          // PRIx64 ", time_now is 0x%" PRIx64 ", minimum_remaining_time is 0x%" PRIx64 ".", x,
+          // check_buf->initialisation_time, latency_time, time_now, minimum_remaining_time);
+          int too_late = ((check_buf->initialisation_time < (time_now - latency_time)) ||
+                          ((check_buf->initialisation_time - (time_now - latency_time)) <
+                           minimum_remaining_time));
+          int too_early = ((time_now - check_buf->initialisation_time) < minimum_wait_time);
+          int too_soon_after_last_request =
+              ((check_buf->resend_time != 0) &&
+               ((time_now - check_buf->resend_time) <
+                resend_repeat_interval)); // time_now can never be less than the time_tag
+
+          if (too_late)
+            check_buf->status |= 1 << 2; // too late
+          else
+            check_buf->status &= 0xFF - (1 << 2); // not too late
+          if (too_early)
+            check_buf->status |= 1 << 3; // too early
+          else
+            check_buf->status &= 0xFF - (1 << 3); // not too early
+          if (too_soon_after_last_request)
+            check_buf->status |= 1 << 4; // too soon after last request
+          else
+            check_buf->status &= 0xFF - (1 << 4); // not too soon after last request
+
+          if ((!too_soon_after_last_request) && (!too_late) && (!too_early)) {
+            if (start_of_missing_frame_run == -1) {
+              start_of_missing_frame_run = x;
+              missing_frame_run_count = 1;
+            } else {
+              missing_frame_run_count++;
+            }
+            check_buf->resend_time = time_now; // setting the time to now because we are
+                                               // definitely going to take action
+            check_buf->resend_request_number++;
+            debug(3, "Frame %d is missing with ab_read of %u and ab_write of %u.", x, conn->ab_read,
+                  conn->ab_write);
+          }
+          // if (too_late) {
+          //   debug(1,"too late to get missing frame %u.", x);
+          // }
+        }
+        // if (number_of_missing_frames != 0)
+        //  debug(1,"check with x = %u, ab_read = %u, ab_write = %u, first_possibly_missing_frame
+        //  = %d.", x, conn->ab_read, conn->ab_write, first_possibly_missing_frame);
+        x = (x + 1) & 0xffff;
+        if (((check_buf->ready) || (x == conn->ab_write)) && (missing_frame_run_count > 0)) {
+          // send a resend request
+          if (missing_frame_run_count > 1)
+            debug(3, "request resend of %d packets starting at seqno %u.", missing_frame_run_count,
+                  start_of_missing_frame_run);
+          if (config.disable_resend_requests == 0) {
+            debug_mutex_unlock(&conn->ab_mutex, 3);
+            rtp_request_resend(start_of_missing_frame_run, missing_frame_run_count, conn);
+            debug_mutex_lock(&conn->ab_mutex, 20000, 1);
+            conn->resend_requests++;
+          }
+          start_of_missing_frame_run = -1;
+          missing_frame_run_count = 0;
+        }
+      }
+      if (number_of_missing_frames == 0)
+        first_possibly_missing_frame = conn->ab_write;
+    }
   }
   debug_mutex_unlock(&conn->ab_mutex, 0);
 }
@@ -944,77 +939,98 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
 
     debug_mutex_lock(&conn->flush_mutex, 1000, 0);
     if (conn->flush_requested == 1) {
-       if (conn->flush_output_flushed == 0)
-       if (config.output->flush) {
-         config.output->flush(); // no cancellation points
-         debug(2, "flush request: flush output device.");
+      if (conn->flush_output_flushed == 0)
+        if (config.output->flush) {
+          config.output->flush(); // no cancellation points
+          debug(2, "flush request: flush output device.");
         }
       conn->flush_output_flushed = 1;
     }
-               // now check to see it the flush request is for frames in the buffer or not
-               // if the first_packet_timestamp is zero, don't check
-               int flush_needed = 0;
-               int drop_request = 0;
-               if ((conn->flush_requested == 1) && (conn->flush_rtp_timestamp == 0)) {
-                       debug(1, "flush request: flush frame 0 -- flush assumed to be needed.");
-                       flush_needed = 1;
-                       drop_request = 1;
-               } else if (conn->flush_rtp_timestamp != 0) {
-                       if ((conn->ab_synced) && ((conn->ab_write - conn->ab_read) > 0)) {
-                               abuf_t *firstPacket = conn->audio_buffer + BUFIDX(conn->ab_read);
-                               abuf_t *lastPacket = conn->audio_buffer + BUFIDX(conn->ab_write - 1);
-                               if ((firstPacket != NULL) && (firstPacket->ready)) {
-                                       // discard flushes more than 10 seconds into the future -- they are probably bogus
-                                       uint32_t first_frame_in_buffer = firstPacket->given_timestamp;
-                                       int32_t offset_from_first_frame = (int32_t)(conn->flush_rtp_timestamp - first_frame_in_buffer);
-                                       if (offset_from_first_frame > (int)conn->input_rate * 10) {
-                                               debug(1, "flush request: sanity check -- flush frame %u is too far into the future from the first frame %u -- discarded.", conn->flush_rtp_timestamp, first_frame_in_buffer);
-                                               drop_request = 1;
-                                       } else {
-                                               if ((lastPacket != NULL) && (lastPacket->ready)) {
-                                                       // we have enough information to check if the flush is needed or can be discarded
-                                                       uint32_t last_frame_in_buffer = lastPacket->given_timestamp + lastPacket->length - 1;
-                                                       // now we have to work out if the flush frame is in the buffer
-                                                       // if it is later than the end of the buffer, flush everything and keep the request active.
-                                                       // if it is in the buffer, we need to flush part of the buffer. Actually we flush the entire buffer and drop the request.
-                                                       // if it is before the buffer, no flush is needed. Drop the request.
-                                                       if (offset_from_first_frame > 0) {
-                                                               int32_t offset_to_last_frame = (int32_t)(last_frame_in_buffer - conn->flush_rtp_timestamp);
-                                                               if (offset_to_last_frame >= 0) {
-                                                                       debug(2,"flush request: flush frame %u active -- buffer contains %u frames, from %u to %u", conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1, first_frame_in_buffer, last_frame_in_buffer);
-                                                                       drop_request = 1;
-                                                                       flush_needed = 1;
-                                                               } else {
-                                                                       debug(2,"flush request: flush frame %u pending -- buffer contains %u frames, from %u to %u", conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1, first_frame_in_buffer, last_frame_in_buffer);
-                                                                       flush_needed = 1;
-                                                               }
-                                                       } else {
-                                                                       debug(2,"flush request: flush frame %u expired -- buffer contains %u frames, from %u to %u", conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1, first_frame_in_buffer, last_frame_in_buffer);
-                                                                       drop_request = 1;
-                                                       }
-                                               }
-                                       }
-                               }
-                       } else {
-                               debug(3, "flush request: flush frame %u  -- buffer not synced or empty: synced: %d, ab_read: %u, ab_write: %u", conn->flush_rtp_timestamp, conn->ab_synced, conn->ab_read, conn->ab_write);
-                               // leave flush request pending and don't do a buffer flush, because there isn't one
-                       }
-               }
-               if (flush_needed) {
-                       debug(2, "flush request: flush done.");
-                       ab_resync(conn);          // no cancellation points
-                       conn->first_packet_timestamp = 0;
-                       conn->first_packet_time_to_play = 0;
-                       conn->time_since_play_started = 0;
-                       have_sent_prefiller_silence = 0;
-                       dac_delay = 0;
-               }
-               if (drop_request) {
-                       debug(2, "flush request: request dropped.");
-                       conn->flush_requested = 0;
-                       conn->flush_rtp_timestamp = 0;
-                       conn->flush_output_flushed = 0;
-               }
+    // now check to see it the flush request is for frames in the buffer or not
+    // if the first_packet_timestamp is zero, don't check
+    int flush_needed = 0;
+    int drop_request = 0;
+    if ((conn->flush_requested == 1) && (conn->flush_rtp_timestamp == 0)) {
+      debug(1, "flush request: flush frame 0 -- flush assumed to be needed.");
+      flush_needed = 1;
+      drop_request = 1;
+    } else if (conn->flush_rtp_timestamp != 0) {
+      if ((conn->ab_synced) && ((conn->ab_write - conn->ab_read) > 0)) {
+        abuf_t *firstPacket = conn->audio_buffer + BUFIDX(conn->ab_read);
+        abuf_t *lastPacket = conn->audio_buffer + BUFIDX(conn->ab_write - 1);
+        if ((firstPacket != NULL) && (firstPacket->ready)) {
+          // discard flushes more than 10 seconds into the future -- they are probably bogus
+          uint32_t first_frame_in_buffer = firstPacket->given_timestamp;
+          int32_t offset_from_first_frame =
+              (int32_t)(conn->flush_rtp_timestamp - first_frame_in_buffer);
+          if (offset_from_first_frame > (int)conn->input_rate * 10) {
+            debug(1,
+                  "flush request: sanity check -- flush frame %u is too far into the future from "
+                  "the first frame %u -- discarded.",
+                  conn->flush_rtp_timestamp, first_frame_in_buffer);
+            drop_request = 1;
+          } else {
+            if ((lastPacket != NULL) && (lastPacket->ready)) {
+              // we have enough information to check if the flush is needed or can be discarded
+              uint32_t last_frame_in_buffer = lastPacket->given_timestamp + lastPacket->length - 1;
+              // now we have to work out if the flush frame is in the buffer
+              // if it is later than the end of the buffer, flush everything and keep the request
+              // active. if it is in the buffer, we need to flush part of the buffer. Actually we
+              // flush the entire buffer and drop the request. if it is before the buffer, no flush
+              // is needed. Drop the request.
+              if (offset_from_first_frame > 0) {
+                int32_t offset_to_last_frame =
+                    (int32_t)(last_frame_in_buffer - conn->flush_rtp_timestamp);
+                if (offset_to_last_frame >= 0) {
+                  debug(2,
+                        "flush request: flush frame %u active -- buffer contains %u frames, from "
+                        "%u to %u",
+                        conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1,
+                        first_frame_in_buffer, last_frame_in_buffer);
+                  drop_request = 1;
+                  flush_needed = 1;
+                } else {
+                  debug(2,
+                        "flush request: flush frame %u pending -- buffer contains %u frames, from "
+                        "%u to %u",
+                        conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1,
+                        first_frame_in_buffer, last_frame_in_buffer);
+                  flush_needed = 1;
+                }
+              } else {
+                debug(2,
+                      "flush request: flush frame %u expired -- buffer contains %u frames, from %u "
+                      "to %u",
+                      conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1,
+                      first_frame_in_buffer, last_frame_in_buffer);
+                drop_request = 1;
+              }
+            }
+          }
+        }
+      } else {
+        debug(3,
+              "flush request: flush frame %u  -- buffer not synced or empty: synced: %d, ab_read: "
+              "%u, ab_write: %u",
+              conn->flush_rtp_timestamp, conn->ab_synced, conn->ab_read, conn->ab_write);
+        // leave flush request pending and don't do a buffer flush, because there isn't one
+      }
+    }
+    if (flush_needed) {
+      debug(2, "flush request: flush done.");
+      ab_resync(conn); // no cancellation points
+      conn->first_packet_timestamp = 0;
+      conn->first_packet_time_to_play = 0;
+      conn->time_since_play_started = 0;
+      have_sent_prefiller_silence = 0;
+      dac_delay = 0;
+    }
+    if (drop_request) {
+      debug(2, "flush request: request dropped.");
+      conn->flush_requested = 0;
+      conn->flush_rtp_timestamp = 0;
+      conn->flush_output_flushed = 0;
+    }
     debug_mutex_unlock(&conn->flush_mutex, 0);
     if (conn->ab_synced) {
       curframe = conn->audio_buffer + BUFIDX(conn->ab_read);
@@ -1037,7 +1053,6 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
         }
       }
 
-
       if ((curframe) && (curframe->ready)) {
         notified_buffer_empty = 0; // at least one buffer now -- diagnostic only.
         if (conn->ab_buffering) {  // if we are getting packets but not yet forwarding them to the
@@ -1058,7 +1073,6 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
               // Here, calculate when we should start playing. We need to know when to allow the
               // packets to be sent to the player.
 
-
               // every second or so, we get a reference on when a particular packet should be
               // played.
 
@@ -1093,8 +1107,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
                                   &should_be_time, conn);
 
               conn->first_packet_time_to_play = should_be_time;
-              debug(2,"first_packet_time set for frame %u.", conn->first_packet_timestamp);
-
+              debug(2, "first_packet_time set for frame %u.", conn->first_packet_timestamp);
 
               if (local_time_now > conn->first_packet_time_to_play) {
                 uint64_t lateness = local_time_now - conn->first_packet_time_to_play;
@@ -1105,172 +1118,180 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
             }
           }
 
+          if (conn->first_packet_time_to_play != 0) {
+            // Now that we know the timing of the first packet...
+            if (config.output->delay) {
+              // and that the output device is capable of synchronization...
 
+              // We may send packets of
+              // silence from now until the time the first audio packet should be sent
+              // and then we will send the first packet, which will be followed by
+              // the subsequent packets.
+              // here, we figure out whether and what silence to send.
 
-          if (conn->first_packet_time_to_play != 0) {
-                                               // Now that we know the timing of the first packet...
-                                               if (config.output->delay) {
-                                                       // and that the output device is capable of synchronization...
-
-                                                       // We may send packets of
-                                                       // silence from now until the time the first audio packet should be sent
-                                                       // and then we will send the first packet, which will be followed by
-                                                       // the subsequent packets.
-                                                       // here, we figure out whether and what silence to send.
-
-                                                               uint64_t should_be_time;
-                                                               uint32_t effective_latency = conn->latency;
-
-                                                               switch (get_and_check_effective_latency(conn, &effective_latency,
-                                                                                                                                                                                                                               config.audio_backend_latency_offset)) {
-                                                               case -1:
-                                                                       if (conn->unachievable_audio_backend_latency_offset_notified == 0) {
-                                                                               warn("Negative latency! A latency of %d frames requested by the player, when "
-                                                                                                "combined with an audio_backend_latency_offset of %f seconds, would make the "
-                                                                                                "overall latency negative. The audio_backend_latency_offset setting is "
-                                                                                                "ignored.",
-                                                                                                conn->latency, config.audio_backend_latency_offset);
-                                                                               config.audio_backend_latency_offset = 0; // set it to zero
-                                                                               conn->unachievable_audio_backend_latency_offset_notified = 1;
-                                                                       };
-                                                                       break;
-                                                               case 1:
-                                                                       if (conn->unachievable_audio_backend_latency_offset_notified == 0) {
-                                                                               warn("An audio_backend_latency_offset of %f seconds may exceed the frame buffering "
-                                                                                                "capacity -- the setting is ignored.",
-                                                                                                config.audio_backend_latency_offset);
-                                                                               config.audio_backend_latency_offset = 0; // set it to zero;
-                                                                               conn->unachievable_audio_backend_latency_offset_notified = 1;
-                                                                       };
-                                                                       break;
-                                                               default:
-                                                                       break;
-                                                               }
-
-                                                               // readjust first packet time to play
-                                                               frame_to_local_time(conn->first_packet_timestamp +
-                                                                                                                                                               effective_latency, // this will go modulo 2^32
-                                                                                                                                               &should_be_time, conn);
-
-                                                               int64_t change_in_should_be_time = (int64_t)(should_be_time - conn->first_packet_time_to_play);
-
-                                                               if (fabs(0.000001*change_in_should_be_time) > 0.001) // the clock drift estimation might be nudging the estimate, and we can ignore this unless if's more than a microsecond
-                                                                       debug(2,"Change in estimated first_packet_time: %8.4f milliseconds.", 0.000001*change_in_should_be_time);
-
-                                                               conn->first_packet_time_to_play = should_be_time;
-
-                                                               if (local_time_now > conn->first_packet_time_to_play) {
-                                                                       uint64_t lateness = local_time_now - conn->first_packet_time_to_play;
-                                                                       debug(2, "Gone past starting time by %" PRIu64 " nanoseconds.", lateness);
-                                                                       conn->ab_buffering = 0;
-                                                               } else {
-                                                                       // do some calculations
-                                                                       int64_t lead_time = conn->first_packet_time_to_play - local_time_now;
-                                                                       if ((config.audio_backend_silent_lead_in_time_auto == 1) ||
-                                                                                       (lead_time <=
-                                                                                        (int64_t)(config.audio_backend_silent_lead_in_time * (int64_t)1000000000))) {
-                                                                               // debug(1, "Lead time: %" PRId64 " nanoseconds.", lead_time);
-                                                                               int resp = 0;
-                                                                               dac_delay = 0;
-                                                                               if (have_sent_prefiller_silence != 0)
-                                                                                       resp = config.output->delay(&dac_delay); // we know the output device must have a delay function
-                                                                               if (resp == 0) {
-                                                                                       int64_t gross_frame_gap =
-                                                                                                       ((conn->first_packet_time_to_play - local_time_now) * config.output_rate) /
-                                                                                                       1000000000;
-                                                                                       int64_t exact_frame_gap = gross_frame_gap - dac_delay;
-                                                                                       int64_t frames_needed_to_maintain_desired_buffer =
-                                                                                                       (int64_t)(config.audio_backend_buffer_desired_length * config.output_rate) -
-                                                                                                       dac_delay;
-                                                                                       // below, remember that exact_frame_gap and
-                                                                                       // frames_needed_to_maintain_desired_buffer could both be negative
-                                                                                       int64_t fs = frames_needed_to_maintain_desired_buffer;
-
-                                                                                       // if there isn't enough time to have the desired buffer size
-                                                                                       if (exact_frame_gap <= frames_needed_to_maintain_desired_buffer) {
-                                                                                               fs = conn->max_frames_per_packet * 2;
-                                                                                       }
-
-                                                                                       // if we are very close to the end of buffering, i.e. within two frame-lengths,
-                                                                                       // add the remaining silence needed and end buffering
-                                                                                       if (exact_frame_gap <= conn->max_frames_per_packet * 2) {
-                                                                                               fs = exact_frame_gap;
-                                                                                               if (fs > first_frame_early_bias)
-                                                                                                       fs = fs - first_frame_early_bias; // deliberately make the first packet a tiny bit early so that the player may compensate for it at the last minute
-                                                                                               conn->ab_buffering = 0;
-                                                                                       }
-                                                                                       void *silence;
-                                                                                       if (fs > 0) {
-                                                                                               silence = malloc(conn->output_bytes_per_frame * fs);
-                                                                                               if (silence == NULL)
-                                                                                                       debug(1, "Failed to allocate %d byte silence buffer.", fs);
-                                                                                               else {
-                                                                                                       // generate frames of silence with dither if necessary
-                                                                                                       conn->previous_random_number =
-                                                                                                                       generate_zero_frames(silence, fs, config.output_format,
-                                                                                                                                                                                                        conn->enable_dither, conn->previous_random_number);
-                                                                                                       config.output->play(silence, fs);
-                                                                                                       // debug(1, "Sent %" PRId64 " frames of silence", fs);
-                                                                                                       free(silence);
-                                                                                                       have_sent_prefiller_silence = 1;
-                                                                                               }
-                                                                                       }
-                                                                               } else {
-
-                                                                                       if (resp == sps_extra_code_output_stalled) {
-                                                                                               if (conn->unfixable_error_reported == 0) {
-                                                                                                       conn->unfixable_error_reported = 1;
-                                                                                                       if (config.cmd_unfixable) {
-                                                                                                               command_execute(config.cmd_unfixable, "output_device_stalled", 1);
-                                                                                                       } else {
-                                                                                                               warn("an unrecoverable error, \"output_device_stalled\", has been "
-                                                                                                                                "detected.",
-                                                                                                                                conn->connection_number);
-                                                                                                       }
-                                                                                               }
-                                                                                       } else {
-                                                                                               debug(2, "Unexpected response to getting dac delay: %d.", resp);
-                                                                                       }
-                                                                               }
-                                                                       }
-                                                               }
-                                                       } else {
-                                                               // if the output device doesn't have a delay, we simply send the lead-in
-                                                               int64_t lead_time = conn->first_packet_time_to_play - local_time_now; // negative if we are late
-                                                               void *silence;
-                                                               int64_t frame_gap = (lead_time * config.output_rate) / 1000000000;
-                                                               // debug(1,"%d frames needed.",frame_gap);
-                                                               while (frame_gap > 0) {
-                                                                       ssize_t fs = config.output_rate / 10;
-                                                                       if (fs > frame_gap)
-                                                                               fs = frame_gap;
-
-                                                                       silence = malloc(conn->output_bytes_per_frame * fs);
-                                                                       if (silence == NULL)
-                                                                               debug(1, "Failed to allocate %d frame silence buffer.", fs);
-                                                                       else {
-                                                                               // debug(1, "No delay function -- outputting %d frames of silence.", fs);
-                                                                               conn->previous_random_number =
-                                                                                               generate_zero_frames(silence, fs, config.output_format,
-                                                                                                                                                                                conn->enable_dither, conn->previous_random_number);
-                                                                               config.output->play(silence, fs);
-                                                                               free(silence);
-                                                                       }
-                                                                       frame_gap -= fs;
-                                                               }
-                                                               conn->ab_buffering = 0;
-                                                       }
-                                               }
+              uint64_t should_be_time;
+              uint32_t effective_latency = conn->latency;
+
+              switch (get_and_check_effective_latency(conn, &effective_latency,
+                                                      config.audio_backend_latency_offset)) {
+              case -1:
+                if (conn->unachievable_audio_backend_latency_offset_notified == 0) {
+                  warn(
+                      "Negative latency! A latency of %d frames requested by the player, when "
+                      "combined with an audio_backend_latency_offset of %f seconds, would make the "
+                      "overall latency negative. The audio_backend_latency_offset setting is "
+                      "ignored.",
+                      conn->latency, config.audio_backend_latency_offset);
+                  config.audio_backend_latency_offset = 0; // set it to zero
+                  conn->unachievable_audio_backend_latency_offset_notified = 1;
+                };
+                break;
+              case 1:
+                if (conn->unachievable_audio_backend_latency_offset_notified == 0) {
+                  warn("An audio_backend_latency_offset of %f seconds may exceed the frame "
+                       "buffering "
+                       "capacity -- the setting is ignored.",
+                       config.audio_backend_latency_offset);
+                  config.audio_backend_latency_offset = 0; // set it to zero;
+                  conn->unachievable_audio_backend_latency_offset_notified = 1;
+                };
+                break;
+              default:
+                break;
+              }
+
+              // readjust first packet time to play
+              frame_to_local_time(conn->first_packet_timestamp +
+                                      effective_latency, // this will go modulo 2^32
+                                  &should_be_time, conn);
+
+              int64_t change_in_should_be_time =
+                  (int64_t)(should_be_time - conn->first_packet_time_to_play);
+
+              if (fabs(0.000001 * change_in_should_be_time) >
+                  0.001) // the clock drift estimation might be nudging the estimate, and we can
+                         // ignore this unless if's more than a microsecond
+                debug(2, "Change in estimated first_packet_time: %8.4f milliseconds.",
+                      0.000001 * change_in_should_be_time);
+
+              conn->first_packet_time_to_play = should_be_time;
+
+              if (local_time_now > conn->first_packet_time_to_play) {
+                uint64_t lateness = local_time_now - conn->first_packet_time_to_play;
+                debug(2, "Gone past starting time by %" PRIu64 " nanoseconds.", lateness);
+                conn->ab_buffering = 0;
+              } else {
+                // do some calculations
+                int64_t lead_time = conn->first_packet_time_to_play - local_time_now;
+                if ((config.audio_backend_silent_lead_in_time_auto == 1) ||
+                    (lead_time <=
+                     (int64_t)(config.audio_backend_silent_lead_in_time * (int64_t)1000000000))) {
+                  // debug(1, "Lead time: %" PRId64 " nanoseconds.", lead_time);
+                  int resp = 0;
+                  dac_delay = 0;
+                  if (have_sent_prefiller_silence != 0)
+                    resp = config.output->delay(
+                        &dac_delay); // we know the output device must have a delay function
+                  if (resp == 0) {
+                    int64_t gross_frame_gap =
+                        ((conn->first_packet_time_to_play - local_time_now) * config.output_rate) /
+                        1000000000;
+                    int64_t exact_frame_gap = gross_frame_gap - dac_delay;
+                    int64_t frames_needed_to_maintain_desired_buffer =
+                        (int64_t)(config.audio_backend_buffer_desired_length * config.output_rate) -
+                        dac_delay;
+                    // below, remember that exact_frame_gap and
+                    // frames_needed_to_maintain_desired_buffer could both be negative
+                    int64_t fs = frames_needed_to_maintain_desired_buffer;
+
+                    // if there isn't enough time to have the desired buffer size
+                    if (exact_frame_gap <= frames_needed_to_maintain_desired_buffer) {
+                      fs = conn->max_frames_per_packet * 2;
+                    }
+
+                    // if we are very close to the end of buffering, i.e. within two frame-lengths,
+                    // add the remaining silence needed and end buffering
+                    if (exact_frame_gap <= conn->max_frames_per_packet * 2) {
+                      fs = exact_frame_gap;
+                      if (fs > first_frame_early_bias)
+                        fs = fs - first_frame_early_bias; // deliberately make the first packet a
+                                                          // tiny bit early so that the player may
+                                                          // compensate for it at the last minute
+                      conn->ab_buffering = 0;
+                    }
+                    void *silence;
+                    if (fs > 0) {
+                      silence = malloc(conn->output_bytes_per_frame * fs);
+                      if (silence == NULL)
+                        debug(1, "Failed to allocate %d byte silence buffer.", fs);
+                      else {
+                        // generate frames of silence with dither if necessary
+                        conn->previous_random_number =
+                            generate_zero_frames(silence, fs, config.output_format,
+                                                 conn->enable_dither, conn->previous_random_number);
+                        config.output->play(silence, fs);
+                        // debug(1, "Sent %" PRId64 " frames of silence", fs);
+                        free(silence);
+                        have_sent_prefiller_silence = 1;
+                      }
+                    }
+                  } else {
+
+                    if (resp == sps_extra_code_output_stalled) {
+                      if (conn->unfixable_error_reported == 0) {
+                        conn->unfixable_error_reported = 1;
+                        if (config.cmd_unfixable) {
+                          command_execute(config.cmd_unfixable, "output_device_stalled", 1);
+                        } else {
+                          warn("an unrecoverable error, \"output_device_stalled\", has been "
+                               "detected.",
+                               conn->connection_number);
+                        }
+                      }
+                    } else {
+                      debug(2, "Unexpected response to getting dac delay: %d.", resp);
+                    }
+                  }
+                }
+              }
+            } else {
+              // if the output device doesn't have a delay, we simply send the lead-in
+              int64_t lead_time =
+                  conn->first_packet_time_to_play - local_time_now; // negative if we are late
+              void *silence;
+              int64_t frame_gap = (lead_time * config.output_rate) / 1000000000;
+              // debug(1,"%d frames needed.",frame_gap);
+              while (frame_gap > 0) {
+                ssize_t fs = config.output_rate / 10;
+                if (fs > frame_gap)
+                  fs = frame_gap;
+
+                silence = malloc(conn->output_bytes_per_frame * fs);
+                if (silence == NULL)
+                  debug(1, "Failed to allocate %d frame silence buffer.", fs);
+                else {
+                  // debug(1, "No delay function -- outputting %d frames of silence.", fs);
+                  conn->previous_random_number =
+                      generate_zero_frames(silence, fs, config.output_format, conn->enable_dither,
+                                           conn->previous_random_number);
+                  config.output->play(silence, fs);
+                  free(silence);
+                }
+                frame_gap -= fs;
+              }
+              conn->ab_buffering = 0;
+            }
+          }
 #ifdef CONFIG_METADATA
-                                               if (conn->ab_buffering == 0) {
-                                                       debug(2, "prsm");
-                                                       send_ssnc_metadata('prsm', NULL, 0,
-                                                                                                                                0); // "resume", but don't wait if the queue is locked
-                                               }
-#endif
+          if (conn->ab_buffering == 0) {
+            debug(2, "prsm");
+            send_ssnc_metadata('prsm', NULL, 0,
+                               0); // "resume", but don't wait if the queue is locked
           }
+#endif
         }
       }
+    }
 
     // Here, we work out whether to release a packet or wait
     // We release a packet when the time is right.
@@ -1665,8 +1686,8 @@ void player_thread_cleanup_handler(void *arg) {
   }
 
   if (conn->statistics) {
-       free(conn->statistics);
-       conn->statistics = NULL;
+    free(conn->statistics);
+    conn->statistics = NULL;
   }
   free_audio_buffers(conn);
   if (conn->stream.type == ast_apple_lossless)
@@ -1690,8 +1711,8 @@ void *player_thread_func(void *arg) {
   conn->first_packet_timestamp = 0;
   conn->flush_requested = 0;
   conn->flush_output_flushed = 0; // only send a flush command to the output device once
-  conn->flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to
-                                 // be used as a null operand, so we'll use it like that too
+  conn->flush_rtp_timestamp = 0;  // it seems this number has a special significance -- it seems to
+                                  // be used as a null operand, so we'll use it like that too
   conn->fix_volume = 0x10000;
 
   if (conn->latency == 0) {
@@ -1902,9 +1923,9 @@ void *player_thread_func(void *arg) {
   int sync_error_out_of_bounds =
       0; // number of times in a row that there's been a serious sync error
 
-  conn->statistics = malloc(sizeof(stats_t)*trend_interval);
+  conn->statistics = malloc(sizeof(stats_t) * trend_interval);
   if (conn->statistics == NULL)
-       die("Failed to allocate a statistics buffer");
+    die("Failed to allocate a statistics buffer");
 
   conn->framesProcessedInThisEpoch = 0;
   conn->framesGeneratedInThisEpoch = 0;
@@ -2002,7 +2023,8 @@ void *player_thread_func(void *arg) {
                 "status 0x%X after %u resend requests.",
                 SUCCESSOR(conn->last_seqno_read), play_number, inframe->status,
                 inframe->resend_request_number);
-          conn->last_seqno_read = SUCCESSOR(conn->last_seqno_read); // manage the packet out of sequence minder
+          conn->last_seqno_read =
+              SUCCESSOR(conn->last_seqno_read); // manage the packet out of sequence minder
 
           void *silence = malloc(conn->output_bytes_per_frame * conn->max_frames_per_packet *
                                  conn->output_sample_ratio);
@@ -2112,8 +2134,7 @@ void *player_thread_func(void *arg) {
             die("Shairport Sync only supports 16 bit input");
           }
 
-
-                                       at_least_one_frame_seen = 1;
+          at_least_one_frame_seen = 1;
 
           // We have a frame of data. We need to see if we want to add or remove a frame from it to
           // keep in sync.
@@ -2166,8 +2187,7 @@ void *player_thread_func(void *arg) {
             }
           }
 
-          conn->buffer_occupancy =
-              seq_diff(conn->ab_write, conn->ab_read); // int32_t from int16_t
+          conn->buffer_occupancy = seq_diff(conn->ab_write, conn->ab_read); // int32_t from int16_t
 
           if (conn->buffer_occupancy < minimum_buffer_occupancy)
             minimum_buffer_occupancy = conn->buffer_occupancy;
@@ -2175,9 +2195,6 @@ void *player_thread_func(void *arg) {
           if (conn->buffer_occupancy > maximum_buffer_occupancy)
             maximum_buffer_occupancy = conn->buffer_occupancy;
 
-
-
-
           // here, we want to check (a) if we are meant to do synchronisation,
           // (b) if we have a delay procedure, (c) if we can get the delay.
 
@@ -2191,7 +2208,7 @@ void *player_thread_func(void *arg) {
             if (resp == 0) { // no error
               current_delay = l_delay;
               if (l_delay >= 0)
-               current_delay = l_delay;
+                current_delay = l_delay;
               else {
                 debug(2, "Underrun of %ld frames reported, but ignored.", l_delay);
                 current_delay =
@@ -2229,15 +2246,16 @@ void *player_thread_func(void *arg) {
             local_time_to_frame(local_time_now, &should_be_frame_32, conn);
             // int64_t should_be_frame = ((int64_t)should_be_frame_32) * conn->output_sample_ratio;
 
-            int64_t delay = int64_mod_difference(should_be_frame_32 * conn->output_sample_ratio, nt - current_delay, UINT32_MAX * conn->output_sample_ratio);
+            int64_t delay =
+                int64_mod_difference(should_be_frame_32 * conn->output_sample_ratio,
+                                     nt - current_delay, UINT32_MAX * conn->output_sample_ratio);
 
-            //int64_t delay = should_be_frame - (nt - current_delay); // all int64_t
+            // int64_t delay = should_be_frame - (nt - current_delay); // all int64_t
 
             // the original frame numbers are unsigned 32-bit integers that roll over modulo 2^32
-            // hence these delay figures will be unsigned numbers that roll over modulo 2^32 * conn->output_sample_ratio;
-            // therefore, calculating the delay must be done in the light of possible rollover
-
-
+            // hence these delay figures will be unsigned numbers that roll over modulo 2^32 *
+            // conn->output_sample_ratio; therefore, calculating the delay must be done in the light
+            // of possible rollover
 
             sync_error =
                 delay - ((int64_t)conn->latency * conn->output_sample_ratio +
@@ -2245,38 +2263,51 @@ void *player_thread_func(void *arg) {
                                    config.output_rate)); // int64_t from int64_t - int32_t, so okay
 
             if (at_least_one_frame_seen_this_session == 0) {
-               at_least_one_frame_seen_this_session = 1;
+              at_least_one_frame_seen_this_session = 1;
 
-              // debug(2,"first frame real sync error (positive --> late): %" PRId64 " frames.", sync_error);
+              // debug(2,"first frame real sync error (positive --> late): %" PRId64 " frames.",
+              // sync_error);
 
-               // this is a sneaky attempt to make a final adjustment to the timing of the first packet
+              // this is a sneaky attempt to make a final adjustment to the timing of the first
+              // packet
 
-               // the very first packet generally has a first_frame_early_bias subtracted from its timing
-               // to make it more likely that it will be early than late,
-               // making it possible to compensate for it be adding a few frames of silence.
+              // the very first packet generally has a first_frame_early_bias subtracted from its
+              // timing to make it more likely that it will be early than late, making it possible
+              // to compensate for it be adding a few frames of silence.
 
-              // debug(2,"first frame real sync error (positive --> late): %" PRId64 " frames.", sync_error);
+              // debug(2,"first frame real sync error (positive --> late): %" PRId64 " frames.",
+              // sync_error);
 
-               // remove the bias when reporting the error to make it the true error
+              // remove the bias when reporting the error to make it the true error
 
-               debug(2,"first frame sync error (positive --> late): %" PRId64 " frames, %.3f mS at %d frames per second output.", sync_error+first_frame_early_bias, (1000.0*(sync_error+first_frame_early_bias))/config.output_rate, config.output_rate);
-
-               // if the packet is early, add the frames needed to put it in sync.
-               if (sync_error < 0) {
-                 size_t final_adjustment_length_sized = -sync_error;
-                char *final_adjustment_silence = malloc(conn->output_bytes_per_frame * final_adjustment_length_sized);
+              debug(2,
+                    "first frame sync error (positive --> late): %" PRId64
+                    " frames, %.3f mS at %d frames per second output.",
+                    sync_error + first_frame_early_bias,
+                    (1000.0 * (sync_error + first_frame_early_bias)) / config.output_rate,
+                    config.output_rate);
+
+              // if the packet is early, add the frames needed to put it in sync.
+              if (sync_error < 0) {
+                size_t final_adjustment_length_sized = -sync_error;
+                char *final_adjustment_silence =
+                    malloc(conn->output_bytes_per_frame * final_adjustment_length_sized);
                 if (final_adjustment_silence) {
 
-                  conn->previous_random_number =
-                      generate_zero_frames(final_adjustment_silence, final_adjustment_length_sized, config.output_format,
-                                           conn->enable_dither, conn->previous_random_number);
+                  conn->previous_random_number = generate_zero_frames(
+                      final_adjustment_silence, final_adjustment_length_sized, config.output_format,
+                      conn->enable_dither, conn->previous_random_number);
                   int final_adjustment = -sync_error;
                   final_adjustment = final_adjustment - first_frame_early_bias;
-                  debug(2, "final sync adjustment: %" PRId64 " silent frames added with a bias of %" PRId64 " frames.", -sync_error, first_frame_early_bias);
+                  debug(2,
+                        "final sync adjustment: %" PRId64
+                        " silent frames added with a bias of %" PRId64 " frames.",
+                        -sync_error, first_frame_early_bias);
                   config.output->play(final_adjustment_silence, final_adjustment_length_sized);
                   free(final_adjustment_silence);
                 } else {
-                  warn("Failed to allocate memory for a final_adjustment_silence buffer of %d frames for a "
+                  warn("Failed to allocate memory for a final_adjustment_silence buffer of %d "
+                       "frames for a "
                        "sync error of %d frames.",
                        final_adjustment_length_sized, sync_error);
                 }
@@ -2560,30 +2591,30 @@ void *player_thread_func(void *arg) {
             // if there is no delay procedure, then we should be sending the packet
             // to the output at the time determined by
             // the packet's time to play + requested latency + requested offset.
-/*
-                                               // This is just for checking during development
+            /*
+                                                            // This is just for checking during
+               development
 
-            uint32_t should_be_frame_32;
-            local_time_to_frame(local_time_now, &should_be_frame_32, conn);
-            // int64_t should_be_frame = ((int64_t)should_be_frame_32) * conn->output_sample_ratio;
+                        uint32_t should_be_frame_32;
+                        local_time_to_frame(local_time_now, &should_be_frame_32, conn);
+                        // int64_t should_be_frame = ((int64_t)should_be_frame_32) *
+               conn->output_sample_ratio;
 
-            int32_t ilatency = (int32_t)((config.audio_backend_latency_offset - config.audio_backend_buffer_desired_length) * conn->input_rate) + conn->latency;
-            if (ilatency < 0)
-               debug(1,"incorrect latency %d.", ilatency);
+                        int32_t ilatency = (int32_t)((config.audio_backend_latency_offset -
+               config.audio_backend_buffer_desired_length) * conn->input_rate) + conn->latency; if
+               (ilatency < 0) debug(1,"incorrect latency %d.", ilatency);
 
-            int32_t idelay = (int32_t)(should_be_frame_32 - inframe->given_timestamp);
+                        int32_t idelay = (int32_t)(should_be_frame_32 - inframe->given_timestamp);
 
-            idelay = idelay - ilatency;
+                        idelay = idelay - ilatency;
 
-            debug(2,"delay is %d input frames.", idelay);
-*/
+                        debug(2,"delay is %d input frames.", idelay);
+            */
 
             // 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) {
-               at_least_one_frame_seen_this_session = 1;
-
-
+              at_least_one_frame_seen_this_session = 1;
             }
 
             play_samples =
@@ -2779,11 +2810,10 @@ void *player_thread_func(void *arg) {
                        "%*.2f,"        /* source actual (average) frame rate */
                        "%*.2f,"        /* source clock drift */
                        "%*d",          /* source clock drift sample count */
-                       12, play_number,
-                       7, conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets,
-                       7, conn->resend_requests, 5, minimum_buffer_occupancy, 5,
-                       maximum_buffer_occupancy, 11, conn->remote_frame_rate, 11,
-                       conn->input_frame_rate, 10,
+                       12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
+                       conn->too_late_packets, 7, conn->resend_requests, 5,
+                       minimum_buffer_occupancy, 5, maximum_buffer_occupancy, 11,
+                       conn->remote_frame_rate, 11, conn->input_frame_rate, 10,
                        (conn->local_to_remote_time_gradient - 1.0) * 1000000, 6,
                        conn->local_to_remote_time_gradient_sample_count);
               }
@@ -2791,7 +2821,7 @@ void *player_thread_func(void *arg) {
               inform("No frames received in the last sampling interval.");
             }
           }
-          minimum_dac_queue_size = UINT64_MAX;   // hack reset
+          minimum_dac_queue_size = UINT64_MAX;  // hack reset
           maximum_buffer_occupancy = INT32_MIN; // can't be less than this
           minimum_buffer_occupancy = INT32_MAX; // can't be more than this
           at_least_one_frame_seen = 0;
@@ -2997,17 +3027,17 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
       // here, send the 'pvol' metadata message when the airplay volume information
       // is being used by shairport sync to control the output volume
       char dv[128];
-                       memset(dv, 0, 128);
-                       if (volume_mode == vol_both) {
-                               // normalise the maximum output to the hardware device's max output
-                               snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
-                                                                (scaled_attenuation - max_db + hw_max_db) / 100.0,
-                                                                (min_db - max_db + hw_max_db) / 100.0, (max_db - max_db + hw_max_db) / 100.0);
-                       } else {
-                               snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, scaled_attenuation / 100.0,
-                                                                min_db / 100.0, max_db / 100.0);
-                       }
-                       send_ssnc_metadata('pvol', dv, strlen(dv), 1);
+      memset(dv, 0, 128);
+      if (volume_mode == vol_both) {
+        // normalise the maximum output to the hardware device's max output
+        snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
+                 (scaled_attenuation - max_db + hw_max_db) / 100.0,
+                 (min_db - max_db + hw_max_db) / 100.0, (max_db - max_db + hw_max_db) / 100.0);
+      } else {
+        snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, scaled_attenuation / 100.0,
+                 min_db / 100.0, max_db / 100.0);
+      }
+      send_ssnc_metadata('pvol', dv, strlen(dv), 1);
 #endif
 
       if (config.output->mute)
@@ -3026,10 +3056,10 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
   else {
     // here, send the 'pvol' metadata message when the airplay volume information
     // is being used by shairport sync to control the output volume
-               char dv[128];
-               memset(dv, 0, 128);
-               snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, 0.0, 0.0, 0.0);
-               send_ssnc_metadata('pvol', dv, strlen(dv), 1);
+    char dv[128];
+    memset(dv, 0, 128);
+    snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, 0.0, 0.0, 0.0);
+    send_ssnc_metadata('pvol', dv, strlen(dv), 1);
   }
 #endif
 
@@ -3057,10 +3087,10 @@ void player_flush(uint32_t timestamp, rtsp_conn_info *conn) {
   debug(3, "player_flush");
   do_flush(timestamp, conn);
 #ifdef CONFIG_METADATA
-       debug(2, "pfls");
-       char numbuf[32];
-       snprintf(numbuf, sizeof(numbuf),"%u",timestamp);
-       send_ssnc_metadata('pfls', numbuf, strlen(numbuf), 1); // contains cancellation points
+  debug(2, "pfls");
+  char numbuf[32];
+  snprintf(numbuf, sizeof(numbuf), "%u", timestamp);
+  send_ssnc_metadata('pfls', numbuf, strlen(numbuf), 1); // contains cancellation points
 #endif
 }
 
index f6b86cd43127ceef33a90b4da12429d3fa7e8717..105ce869810ac80876340531337ddeb8c742eb3c 100644 (file)
--- a/player.h
+++ b/player.h
@@ -25,7 +25,9 @@
 #include "audio.h"
 
 #define time_ping_history_power_of_two 7
-#define time_ping_history (1 << time_ping_history_power_of_two) // 2^7 is 128. At 1 per three seconds, approximately six minutes of records
+#define time_ping_history                                                                          \
+  (1 << time_ping_history_power_of_two) // 2^7 is 128. At 1 per three seconds, approximately six
+                                        // minutes of records
 
 typedef struct time_ping_record {
   uint64_t dispersion;
@@ -195,7 +197,6 @@ typedef struct {
                                            // could be one of many, so we need to know it
   uint32_t self_scope_id;                  // if it's an ipv6 connection, this will be its scope
   short connection_ip_family;              // AF_INET / AF_INET6
-  uint32_t client_active_remote;           // used when you want to control the client...
 
   SOCKADDR rtp_client_control_socket; // a socket pointing to the control port of the client
   SOCKADDR rtp_client_timing_socket;  // a socket pointing to the timing port of the client
@@ -263,8 +264,8 @@ typedef struct {
   char *dacp_id; // id of the client -- used to find the port to be used
   //  uint16_t dacp_port;          // port on the client to send remote control messages to, else
   //  zero
-  uint32_t dacp_active_remote; // key to send to the remote controller
-  void *dapo_private_storage;  // this is used for compatibility, if dacp stuff isn't enabled.
+  char *dacp_active_remote;   // key to send to the remote controller
+  void *dapo_private_storage; // this is used for compatibility, if dacp stuff isn't enabled.
 
   int enable_dither; // needed for filling silences before play actually starts
   uint64_t dac_buffer_queue_minimum_length;
diff --git a/rtp.c b/rtp.c
index e56c5454f8db4e925cc6ea7973249992c5bcd36a..c558645ee1df460ac60683000d6c88ddf0d892e8 100644 (file)
--- a/rtp.c
+++ b/rtp.c
@@ -46,9 +46,9 @@
 #include <unistd.h>
 
 struct Nvll {
-       char* name;
-       double value;
-       struct Nvll *next;
+  char *name;
+  double value;
+  struct Nvll *next;
 };
 
 typedef struct Nvll nvll;
@@ -263,8 +263,8 @@ void *rtp_control_receiver(void *arg) {
                                                                 obfp += 2;
                                                               };
                                                               *obfp = 0;
-
-
+                                             
+                                             
                                                               // get raw timestamp information
                                                               // I think that a good way to understand these timestamps is that
                                                               // (1) the rtlt below is the timestamp of the frame that should be playing at the
@@ -275,19 +275,19 @@ void *rtp_control_receiver(void *arg) {
                                                               // Thus, (3) the latency can be calculated by subtracting the second from the
                                                               // first.
                                                               // There must be more to it -- there something missing.
-
+                                             
                                                               // In addition, it seems that if the value of the short represented by the second
                                                               // pair of bytes in the packet is 7
                                                               // then an extra time lag is expected to be added, presumably by
                                                               // the AirPort Express.
-
+                                             
                                                               // Best guess is that this delay is 11,025 frames.
-
+                                             
                                                               uint32_t rtlt = nctohl(&packet[4]); // raw timestamp less latency
                                                               uint32_t rt = nctohl(&packet[16]);  // raw timestamp
-
+                                             
                                                               uint32_t fl = nctohs(&packet[2]); //
-
+                                             
                                                               debug(1,"Sync Packet of %d bytes received: \"%s\", flags: %d, timestamps %u and %u,
                                                           giving a latency of %d frames.",plen,obf,fl,rt,rtlt,rt-rtlt);
                                                               //debug(1,"Monotonic timestamps are: %" PRId64 " and %" PRId64 "
@@ -527,22 +527,25 @@ void rtp_timing_receiver_cleanup_handler(void *arg) {
   // walk down the list of DACP / gradient pairs, if any
   nvll *gradients = config.gradients;
   if (conn->dacp_id)
-       while ((gradients) && (strcasecmp((const char *)&conn->client_ip_string,gradients->name) != 0))
-               gradients = gradients->next;
+    while ((gradients) && (strcasecmp((const char *)&conn->client_ip_string, gradients->name) != 0))
+      gradients = gradients->next;
 
-  // if gradients comes out of this non-null, it is pointing to the DACP and it's last-known gradient
+  // if gradients comes out of this non-null, it is pointing to the DACP and it's last-known
+  // gradient
   if (gradients) {
-       gradients->value = conn->local_to_remote_time_gradient;
-       // debug(1,"Updating a drift of %.2f ppm for \"%s\".", (conn->local_to_remote_time_gradient - 1.0)*1000000, gradients->name);
+    gradients->value = conn->local_to_remote_time_gradient;
+    // debug(1,"Updating a drift of %.2f ppm for \"%s\".", (conn->local_to_remote_time_gradient
+    // - 1.0)*1000000, gradients->name);
   } else {
-       nvll *new_entry = (nvll*)malloc(sizeof(nvll));
-       if (new_entry) {
-               new_entry->name = strdup((const char *)&conn->client_ip_string);
-               new_entry->value = conn->local_to_remote_time_gradient;
-               new_entry->next = config.gradients;
-               config.gradients = new_entry;
-               // debug(1,"Setting a new drift of %.2f ppm for \"%s\".", (conn->local_to_remote_time_gradient - 1.0)*1000000, new_entry->name);
-       }
+    nvll *new_entry = (nvll *)malloc(sizeof(nvll));
+    if (new_entry) {
+      new_entry->name = strdup((const char *)&conn->client_ip_string);
+      new_entry->value = conn->local_to_remote_time_gradient;
+      new_entry->next = config.gradients;
+      config.gradients = new_entry;
+      // debug(1,"Setting a new drift of %.2f ppm for \"%s\".", (conn->local_to_remote_time_gradient
+      // - 1.0)*1000000, new_entry->name);
+    }
   }
 
   debug(3, "Cancel Timing Requester.");
@@ -574,13 +577,14 @@ void *rtp_timing_receiver(void *arg) {
   conn->local_to_remote_time_gradient = 1.0; // initial value.
   // walk down the list of DACP / gradient pairs, if any
   nvll *gradients = config.gradients;
-       while ((gradients) && (strcasecmp((const char *)&conn->client_ip_string,gradients->name) != 0))
-               gradients = gradients->next;
+  while ((gradients) && (strcasecmp((const char *)&conn->client_ip_string, gradients->name) != 0))
+    gradients = gradients->next;
 
   // if gradients comes out of this non-null, it is pointing to the IP and it's last-known gradient
   if (gradients) {
-       conn->local_to_remote_time_gradient = gradients->value;
-       // debug(1,"Using a stored drift of %.2f ppm for \"%s\".", (conn->local_to_remote_time_gradient - 1.0)*1000000, gradients->name);
+    conn->local_to_remote_time_gradient = gradients->value;
+    // debug(1,"Using a stored drift of %.2f ppm for \"%s\".", (conn->local_to_remote_time_gradient
+    // - 1.0)*1000000, gradients->name);
   }
 
   // calculate diffusion factor
@@ -591,13 +595,12 @@ void *rtp_timing_receiver(void *arg) {
   // be the nth root of diffusion_expansion_factor
   // where n is the number of elements in the array
 
-       const double diffusion_expansion_factor = 10;
-  double log_of_multiplier = log10(diffusion_expansion_factor)/time_ping_history;
-  double multiplier = pow(10,log_of_multiplier);
+  const double diffusion_expansion_factor = 10;
+  double log_of_multiplier = log10(diffusion_expansion_factor) / time_ping_history;
+  double multiplier = pow(10, log_of_multiplier);
   uint64_t dispersion_factor = (uint64_t)(multiplier * 100);
   // debug(1,"dispersion factor is %" PRIu64 ".", dispersion_factor);
 
-
   // uint64_t first_local_to_remote_time_difference_time;
   // uint64_t l2rtd = 0;
   int sequence_number = 0;
@@ -621,7 +624,8 @@ void *rtp_timing_receiver(void *arg) {
         if (packet[1] == 0xd3) { // timing reply
 
           return_time = arrival_time - conn->departure_time;
-          debug(3,"clock synchronisation request: return time is %8.3f milliseconds.",0.000001*return_time);
+          debug(3, "clock synchronisation request: return time is %8.3f milliseconds.",
+                0.000001 * return_time);
 
           if (return_time < 200000000) { // must be less than 0.2 seconds
             // distant_receive_time =
@@ -671,11 +675,11 @@ void *rtp_timing_receiver(void *arg) {
               //                  conn->time_pings[cc].dispersion * pow(2.14,
               //                  1.0/conn->time_ping_count);
               if (conn->time_pings[cc].dispersion > UINT64_MAX / dispersion_factor)
-               debug(1,"dispersion factor is too large at %" PRIu64 ".");
+                debug(1, "dispersion factor is too large at %" PRIu64 ".");
               else
-               conn->time_pings[cc].dispersion =
-                  (conn->time_pings[cc].dispersion * dispersion_factor) /
-                  100; // make the dispersions 'age' by this rational factor
+                conn->time_pings[cc].dispersion =
+                    (conn->time_pings[cc].dispersion * dispersion_factor) /
+                    100; // make the dispersions 'age' by this rational factor
             }
             // these are used for doing a least squares calculation to get the drift
             conn->time_pings[0].local_time = arrival_time;
@@ -752,7 +756,8 @@ void *rtp_timing_receiver(void *arg) {
               if ((conn->time_pings[cc].chosen) &&
                   (conn->time_pings[cc].sequence_number >
                    (settling_time / 3))) { // wait for a approximate settling time
-                                                               // have to scale them down so that the sum, possibly over every term in the array, doesn't overflow
+                                           // have to scale them down so that the sum, possibly over
+                                           // every term in the array, doesn't overflow
                 y_bar += (conn->time_pings[cc].remote_time >> time_ping_history_power_of_two);
                 x_bar += (conn->time_pings[cc].local_time >> time_ping_history_power_of_two);
                 sample_count++;
@@ -762,8 +767,6 @@ void *rtp_timing_receiver(void *arg) {
               y_bar = y_bar / sample_count;
               x_bar = x_bar / sample_count;
 
-
-
               int64_t xid, yid;
               double mtl, mbl;
               mtl = 0;
@@ -791,19 +794,21 @@ void *rtp_timing_receiver(void *arg) {
                 conn->local_to_remote_time_gradient = mtl / mbl;
               else {
                 // conn->local_to_remote_time_gradient = 1.0;
-                       debug(1,"mbl is zero. Drift remains at %.2f ppm.", (conn->local_to_remote_time_gradient - 1.0)*1000000);
+                debug(1, "mbl is zero. Drift remains at %.2f ppm.",
+                      (conn->local_to_remote_time_gradient - 1.0) * 1000000);
               }
 
-                                                       // scale the numbers back up
-                                                       uint64_t ybf = y_bar << time_ping_history_power_of_two;
-                                                       uint64_t xbf = x_bar << time_ping_history_power_of_two;
+              // scale the numbers back up
+              uint64_t ybf = y_bar << time_ping_history_power_of_two;
+              uint64_t xbf = x_bar << time_ping_history_power_of_two;
 
-               conn->local_to_remote_time_difference =
-                       ybf - xbf;  // make this the new local-to-remote-time-difference
-               conn->local_to_remote_time_difference_measurement_time = xbf;
+              conn->local_to_remote_time_difference =
+                  ybf - xbf; // make this the new local-to-remote-time-difference
+              conn->local_to_remote_time_difference_measurement_time = xbf;
 
             } else {
-               debug(3,"not enough samples to estimate drift -- remaining at %.2f ppm.", (conn->local_to_remote_time_gradient - 1.0)*1000000);
+              debug(3, "not enough samples to estimate drift -- remaining at %.2f ppm.",
+                    (conn->local_to_remote_time_gradient - 1.0) * 1000000);
               // conn->local_to_remote_time_gradient = 1.0;
             }
             // debug(1,"local to remote time gradient is %12.2f ppm, based on %d
diff --git a/rtsp.c b/rtsp.c
index 1f1cb9f9e5d0049f8f50354b8c1861dc4cbcd547..abfabc4fb6ed9b4da9458f1814bb954303fc660f 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -3,7 +3,7 @@
  * Copyright (c) James Laird 2013
 
  * Modifications associated with audio synchronization, mutithreading and
- * metadata handling copyright (c) Mike Brady 2014-2019
+ * metadata handling copyright (c) Mike Brady 2014-2020
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person
@@ -115,7 +115,7 @@ typedef struct {
   pthread_cond_t pc_queue_item_added_signal;
   pthread_cond_t pc_queue_item_removed_signal;
   char *name;
-       size_t item_size;  // number of bytes in each item
+  size_t item_size;  // number of bytes in each item
   uint32_t count;    // number of items in the queue
   uint32_t capacity; // maximum number of items
   uint32_t toq;      // first item to take
@@ -152,11 +152,12 @@ typedef struct {
   rtsp_message *carrier;
 } metadata_package;
 
-void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size, uint32_t number_of_items, const char* name) {
-       if (name)
-               debug(2, "Creating metadata queue \"%s\".", name);
-       else
-               debug(1, "Creating an unnamed metadata queue.");
+void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size, uint32_t number_of_items,
+                   const char *name) {
+  if (name)
+    debug(2, "Creating metadata queue \"%s\".", name);
+  else
+    debug(1, "Creating an unnamed metadata queue.");
   pthread_mutex_init(&the_queue->pc_queue_lock, NULL);
   pthread_cond_init(&the_queue->pc_queue_item_added_signal, NULL);
   pthread_cond_init(&the_queue->pc_queue_item_removed_signal, NULL);
@@ -167,25 +168,25 @@ void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size, uint32_t
   the_queue->toq = 0;
   the_queue->eoq = 0;
   if (name == NULL)
-       the_queue->name = NULL;
+    the_queue->name = NULL;
   else
-       the_queue->name = strdup(name);
+    the_queue->name = strdup(name);
 }
 
 void pc_queue_delete(pc_queue *the_queue) {
-       if (the_queue->name)
-               debug(2, "Deleting metadata queue \"%s\".", the_queue->name);
-       else
-               debug(1, "Deleting an unnamed metadata queue.");
-       if (the_queue->name != NULL)
-               free(the_queue->name);
-       // debug(2, "destroying pc_queue_item_removed_signal");
+  if (the_queue->name)
+    debug(2, "Deleting metadata queue \"%s\".", the_queue->name);
+  else
+    debug(1, "Deleting an unnamed metadata queue.");
+  if (the_queue->name != NULL)
+    free(the_queue->name);
+  // debug(2, "destroying pc_queue_item_removed_signal");
   pthread_cond_destroy(&the_queue->pc_queue_item_removed_signal);
-       // debug(2, "destroying pc_queue_item_added_signal");
+  // debug(2, "destroying pc_queue_item_added_signal");
   pthread_cond_destroy(&the_queue->pc_queue_item_added_signal);
-       // debug(2, "destroying pc_queue_lock");
+  // debug(2, "destroying pc_queue_lock");
   pthread_mutex_destroy(&the_queue->pc_queue_lock);
-       // debug(2, "destroying signals and locks done");
+  // debug(2, "destroying signals and locks done");
 }
 
 int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, rtsp_message *carrier,
@@ -204,7 +205,7 @@ void pc_queue_cleanup_handler(void *arg) {
 }
 
 int pc_queue_add_item(pc_queue *the_queue, const void *the_stuff, int block) {
-       int response = 0;
+  int response = 0;
   int rc;
   if (the_queue) {
     if (block == 0) {
@@ -219,34 +220,39 @@ int pc_queue_add_item(pc_queue *the_queue, const void *the_stuff, int block) {
     // leave this out if you want this to return if the queue is already full
     // irrespective of the block flag.
     /*
-               while (the_queue->count == the_queue->capacity) {
-                       rc = pthread_cond_wait(&the_queue->pc_queue_item_removed_signal, &the_queue->pc_queue_lock);
-                       if (rc)
-                               debug(1, "Error waiting for item to be removed");
-               }
-               */
+                while (the_queue->count == the_queue->capacity) {
+                        rc = pthread_cond_wait(&the_queue->pc_queue_item_removed_signal,
+       &the_queue->pc_queue_lock); if (rc) debug(1, "Error waiting for item to be removed");
+                }
+                */
     if (the_queue->count < the_queue->capacity) {
-                       uint32_t i = the_queue->eoq;
-                       void *p = the_queue->items + the_queue->item_size * i;
-                       //    void * p = &the_queue->qbase + the_queue->item_size*the_queue->eoq;
-                       memcpy(p, the_stuff, the_queue->item_size);
-
-                       // update the pointer
-                       i++;
-                       if (i == the_queue->capacity)
-                               // fold pointer if necessary
-                               i = 0;
-                       the_queue->eoq = i;
-                       the_queue->count++;
-                       //debug(2,"metadata queue+ \"%s\" %d/%d.", the_queue->name, the_queue->count, the_queue->capacity);
-                       if (the_queue->count == the_queue->capacity)
-                               debug(3, "metadata queue \"%s\": is now full with %d items in it!", the_queue->name, the_queue->count);
-                       rc = pthread_cond_signal(&the_queue->pc_queue_item_added_signal);
-                       if (rc)
-                               debug(1, "metadata queue \"%s\": error signalling after pc_queue_add_item", the_queue->name);
+      uint32_t i = the_queue->eoq;
+      void *p = the_queue->items + the_queue->item_size * i;
+      //    void * p = &the_queue->qbase + the_queue->item_size*the_queue->eoq;
+      memcpy(p, the_stuff, the_queue->item_size);
+
+      // update the pointer
+      i++;
+      if (i == the_queue->capacity)
+        // fold pointer if necessary
+        i = 0;
+      the_queue->eoq = i;
+      the_queue->count++;
+      // debug(2,"metadata queue+ \"%s\" %d/%d.", the_queue->name, the_queue->count,
+      // the_queue->capacity);
+      if (the_queue->count == the_queue->capacity)
+        debug(3, "metadata queue \"%s\": is now full with %d items in it!", the_queue->name,
+              the_queue->count);
+      rc = pthread_cond_signal(&the_queue->pc_queue_item_added_signal);
+      if (rc)
+        debug(1, "metadata queue \"%s\": error signalling after pc_queue_add_item",
+              the_queue->name);
     } else {
-       response = EWOULDBLOCK; // a bit arbitrary, this.
-       debug(3,"metadata queue \"%s\": is already full with %d items in it. Not adding this item to the queue.", the_queue->name, the_queue->count);
+      response = EWOULDBLOCK; // a bit arbitrary, this.
+      debug(3,
+            "metadata queue \"%s\": is already full with %d items in it. Not adding this item to "
+            "the queue.",
+            the_queue->name, the_queue->count);
     }
     pthread_cleanup_pop(1); // unlock the queue lock.
   } else {
@@ -279,7 +285,8 @@ int pc_queue_get_item(pc_queue *the_queue, void *the_stuff) {
       i = 0;
     the_queue->toq = i;
     the_queue->count--;
-    debug(3,"metadata queue- \"%s\" %d/%d.", the_queue->name, the_queue->count, the_queue->capacity);
+    debug(3, "metadata queue- \"%s\" %d/%d.", the_queue->name, the_queue->count,
+          the_queue->capacity);
     rc = pthread_cond_signal(&the_queue->pc_queue_item_removed_signal);
     if (rc)
       debug(1, "metadata queue \"%s\": error signalling after pc_queue_get_item", the_queue->name);
@@ -317,15 +324,17 @@ void *player_watchdog_thread_code(void *arg) {
       uint64_t last_watchdog_bark_time = conn->watchdog_bark_time;
       debug_mutex_unlock(&conn->watchdog_mutex, 0);
       if (last_watchdog_bark_time != 0) {
-        uint64_t time_since_last_bark = (get_absolute_time_in_ns() - last_watchdog_bark_time) / 1000000000;
+        uint64_t time_since_last_bark =
+            (get_absolute_time_in_ns() - last_watchdog_bark_time) / 1000000000;
         uint64_t ct = config.timeout; // go from int to 64-bit int
 
         if (time_since_last_bark >= ct) {
           conn->watchdog_barks++;
           if (conn->watchdog_barks == 1) {
             // debuglev = 3; // tell us everything.
-            debug(1, "Connection %d: As Yeats almost said, \"Too long a silence / can make a stone "
-                     "of the heart\".",
+            debug(1,
+                  "Connection %d: As Yeats almost said, \"Too long a silence / can make a stone "
+                  "of the heart\".",
                   conn->connection_number);
             conn->stop = 1;
             pthread_cancel(conn->thread);
@@ -446,7 +455,8 @@ void msg_retain(rtsp_message *msg) {
     debug(1, "Error %d locking reference counter lock");
   if (msg > (rtsp_message *)0x00010000) {
     msg->referenceCount++;
-       debug(3,"msg_free increment reference counter message %d to %d.", msg->index_number,  msg->referenceCount);
+    debug(3, "msg_free increment reference counter message %d to %d.", msg->index_number,
+          msg->referenceCount);
     // debug(1,"msg_retain -- item %d reference count %d.", msg->index_number, msg->referenceCount);
     rc = pthread_mutex_unlock(&reference_counter_lock);
     if (rc)
@@ -462,7 +472,7 @@ rtsp_message *msg_init(void) {
     memset(msg, 0, sizeof(rtsp_message));
     msg->referenceCount = 1; // from now on, any access to this must be protected with the lock
     msg->index_number = msg_indexes++;
-    debug(3,"msg_init message %d", msg->index_number);
+    debug(3, "msg_init message %d", msg->index_number);
   } else {
     die("msg_init -- can not allocate memory for rtsp_message %d.", msg_indexes);
   }
@@ -526,8 +536,9 @@ void msg_free(rtsp_message **msgh) {
   if (*msgh > (rtsp_message *)0x00010000) {
     rtsp_message *msg = *msgh;
     msg->referenceCount--;
-       if (msg->referenceCount)
-               debug(3,"msg_free decrement reference counter message %d to %d", msg->index_number, msg->referenceCount);
+    if (msg->referenceCount)
+      debug(3, "msg_free decrement reference counter message %d to %d", msg->index_number,
+            msg->referenceCount);
     if (msg->referenceCount == 0) {
       unsigned int i;
       for (i = 0; i < msg->nheaders; i++) {
@@ -542,7 +553,7 @@ void msg_free(rtsp_message **msgh) {
         index = 0x10000; // ensure it doesn't fold to zero.
       *msgh =
           (rtsp_message *)(index); // put a version of the index number of the freed message in here
-                 debug(3,"msg_free freed message %d", msg->index_number);
+      debug(3, "msg_free freed message %d", msg->index_number);
       free(msg);
     } else {
       // debug(1,"msg_free item %d -- decrement reference to
@@ -607,7 +618,7 @@ int msg_handle_line(rtsp_message **pmsg, char *line) {
   }
 
 fail:
-  debug(3,"msg_handle_line fail");
+  debug(3, "msg_handle_line fail");
   msg_free(pmsg);
   *pmsg = NULL;
   return 0;
@@ -650,7 +661,8 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
       if (errno == EINTR)
         continue;
       if (errno == EAGAIN) {
-        debug(1, "Connection %d: getting Error 11 -- EAGAIN from a blocking read!", conn->connection_number);
+        debug(1, "Connection %d: getting Error 11 -- EAGAIN from a blocking read!",
+              conn->connection_number);
         continue;
       }
       if (errno != ECONNRESET) {
@@ -663,15 +675,15 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
       goto shutdown;
     }
 
-/* // this outputs the message received
-    {
-    void *pt = malloc(nread+1);
-    memset(pt, 0, nread+1);
-    memcpy(pt, buf + inbuf, nread);
-    debug(1, "Incoming string on port: \"%s\"",pt);
-    free(pt);
-    }
-*/
+    /* // this outputs the message received
+        {
+        void *pt = malloc(nread+1);
+        memset(pt, 0, nread+1);
+        memcpy(pt, buf + inbuf, nread);
+        debug(1, "Incoming string on port: \"%s\"",pt);
+        free(pt);
+        }
+    */
 
     inbuf += nread;
 
@@ -680,7 +692,8 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
       msg_size = msg_handle_line(the_packet, buf);
 
       if (!(*the_packet)) {
-        debug(1,"Connection %d: rtsp_read_request can't find an RTSP header.", conn->connection_number);
+        debug(1, "Connection %d: rtsp_read_request can't find an RTSP header.",
+              conn->connection_number);
         reply = rtsp_read_request_response_bad_packet;
         goto shutdown;
       }
@@ -887,9 +900,10 @@ void handle_options(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *
                     rtsp_message *resp) {
   debug(3, "Connection %d: OPTIONS", conn->connection_number);
   resp->respcode = 200;
-  msg_add_header(resp, "Public", "ANNOUNCE, SETUP, RECORD, "
-                                 "PAUSE, FLUSH, TEARDOWN, "
-                                 "OPTIONS, GET_PARAMETER, SET_PARAMETER");
+  msg_add_header(resp, "Public",
+                 "ANNOUNCE, SETUP, RECORD, "
+                 "PAUSE, FLUSH, TEARDOWN, "
+                 "OPTIONS, GET_PARAMETER, SET_PARAMETER");
 }
 
 void handle_teardown(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
@@ -929,17 +943,17 @@ void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
           rtptime = uatoi(p + 1); // unsigned integer -- up to 2^32-1
       }
     }
-// debug(1,"RTSP Flush Requested: %u.",rtptime);
+    // debug(1,"RTSP Flush Requested: %u.",rtptime);
 
-// the following is now done better by the player_flush routine as a 'pfls'
-/*
-#ifdef CONFIG_METADATA
-    if (p)
-      send_metadata('ssnc', 'flsr', p + 1, strlen(p + 1), req, 1);
-    else
-      send_metadata('ssnc', 'flsr', NULL, 0, NULL, 0);
-#endif
-*/
+    // the following is now done better by the player_flush routine as a 'pfls'
+    /*
+    #ifdef CONFIG_METADATA
+        if (p)
+          send_metadata('ssnc', 'flsr', p + 1, strlen(p + 1), req, 1);
+        else
+          send_metadata('ssnc', 'flsr', NULL, 0, NULL, 0);
+    #endif
+    */
 
     player_flush(rtptime, conn); // will not crash even it there is no player thread.
     resp->respcode = 200;
@@ -961,15 +975,19 @@ void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
       debug(2, "Connection %d: SETUP -- Active-Remote string seen: \"%s\".",
             conn->connection_number, ar);
       // get the active remote
-      char *p;
-      conn->dacp_active_remote = strtoul(ar, &p, 10);
+      if (conn->dacp_active_remote) // this is in case SETUP was previously called
+        free(conn->dacp_active_remote);
+      conn->dacp_active_remote = strdup(ar);
 #ifdef CONFIG_METADATA
       send_metadata('ssnc', 'acre', ar, strlen(ar), req, 1);
 #endif
     } else {
       debug(2, "Connection %d: SETUP -- Note: no Active-Remote information  the SETUP Record.",
             conn->connection_number);
-      conn->dacp_active_remote = 0;
+      if (conn->dacp_active_remote) { // this is in case SETUP was previously called
+        free(conn->dacp_active_remote);
+        conn->dacp_active_remote = NULL;
+      }
     }
 
     ar = msg_get_header(req, "DACP-ID");
@@ -984,9 +1002,10 @@ void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
     } else {
       debug(2, "Connection %d: SETUP doesn't include DACP-ID string information.",
             conn->connection_number);
-      if (conn->dacp_id) // this is in case SETUP was previously called
+      if (conn->dacp_id) // this is in case SETUP was previously called
         free(conn->dacp_id);
-      conn->dacp_id = NULL;
+        conn->dacp_id = NULL;
+      }
     }
 
     char *hdr = msg_get_header(req, "Transport");
@@ -1035,8 +1054,9 @@ void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
             msg_add_header(resp, "Session", "1");
 
             resp->respcode = 200; // it all worked out okay
-            debug(1, "Connection %d: SETUP DACP-ID \"%s\" from %s to %s with UDP ports Control: "
-                     "%d, Timing: %d and Audio: %d.",
+            debug(1,
+                  "Connection %d: SETUP DACP-ID \"%s\" from %s to %s with UDP ports Control: "
+                  "%d, Timing: %d and Audio: %d.",
                   conn->connection_number, conn->dacp_id, &conn->client_ip_string,
                   &conn->self_ip_string, conn->local_control_port, conn->local_timing_port,
                   conn->local_audio_port);
@@ -1265,8 +1285,6 @@ char *base64_encode_so(const unsigned char *data, size_t input_length, char *enc
 static int fd = -1;
 // static int dirty = 0;
 
-
-
 pc_queue metadata_queue;
 #define metadata_queue_size 500
 metadata_package metadata_queue_items[metadata_queue_size];
@@ -1294,7 +1312,6 @@ pc_queue metadata_multicast_queue;
 metadata_package metadata_multicast_queue_items[metadata_queue_size];
 pthread_t metadata_multicast_thread;
 
-
 void metadata_create_multicast_socket(void) {
   if (config.metadata_enabled == 0)
     return;
@@ -1308,7 +1325,6 @@ void metadata_create_multicast_socket(void) {
     } else {
       int buffer_size = METADATA_SNDBUF;
       setsockopt(metadata_sock, SOL_SOCKET, SO_SNDBUF, &buffer_size, sizeof(buffer_size));
-      fcntl(fd, F_SETFL, O_NONBLOCK);
       bzero((char *)&metadata_sockaddr, sizeof(metadata_sockaddr));
       metadata_sockaddr.sin_family = AF_INET;
       metadata_sockaddr.sin_addr.s_addr = inet_addr(config.metadata_sockaddr);
@@ -1332,7 +1348,6 @@ void metadata_delete_multicast_socket(void) {
     free(metadata_sockmsg);
 }
 
-
 void metadata_open(void) {
   if (config.metadata_enabled == 0)
     return;
@@ -1354,7 +1369,8 @@ static void metadata_close(void) {
 }
 
 void metadata_multicast_process(uint32_t type, uint32_t code, char *data, uint32_t length) {
-  // debug(1, "Process multicast metadata with type %x, code %x and length %u.", type, code, length);
+  // debug(1, "Process multicast metadata with type %x, code %x and length %u.", type, code,
+  // length);
   if (metadata_sock >= 0 && length < config.metadata_sockmsglength - 8) {
     char *ptr = metadata_sockmsg;
     uint32_t v;
@@ -1455,7 +1471,7 @@ void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length)
         debug(1, "Error encoding base64 data.");
       // debug(1,"Remaining count: %d ret: %d, outbuf_size:
       // %d.",remaining_count,ret,outbuf_size);
-      //ret = non_blocking_write(fd, outbuf, outbuf_size);
+      // ret = non_blocking_write(fd, outbuf, outbuf_size);
       ret = write(fd, outbuf, outbuf_size);
       if (ret < 0) {
         // debug(1,"metadata_process error %d exit 3",ret);
@@ -1473,7 +1489,7 @@ void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length)
     }
   }
   snprintf(thestring, 1024, "</item>\n");
-  //ret = non_blocking_write(fd, thestring, strlen(thestring));
+  // ret = non_blocking_write(fd, thestring, strlen(thestring));
   ret = write(fd, thestring, strlen(thestring));
   if (ret < 0) {
     // debug(1,"metadata_process error %d exit 5",ret);
@@ -1508,11 +1524,12 @@ void *metadata_thread_function(__attribute__((unused)) void *ignore) {
     pc_queue_get_item(&metadata_queue, &pack);
     pthread_cleanup_push(metadata_pack_cleanup_function, (void *)&pack);
     if (config.metadata_enabled) {
-       if (pack.carrier) {
-               debug(3, "     pipe: type %x, code %x, length %u, message %d.", pack.type, pack.code, pack.length, pack.carrier->index_number);
-       } else {
-               debug(3, "     pipe: type %x, code %x, length %u.", pack.type, pack.code, pack.length);
-       }
+      if (pack.carrier) {
+        debug(3, "     pipe: type %x, code %x, length %u, message %d.", pack.type, pack.code,
+              pack.length, pack.carrier->index_number);
+      } else {
+        debug(3, "     pipe: type %x, code %x, length %u.", pack.type, pack.code, pack.length);
+      }
       metadata_process(pack.type, pack.code, pack.data, pack.length);
       debug(3, "     pipe: done.");
     }
@@ -1530,8 +1547,8 @@ void metadata_multicast_thread_cleanup_function(__attribute__((unused)) void *ar
 
 void *metadata_multicast_thread_function(__attribute__((unused)) void *ignore) {
   // create a pc_queue for passing information to a threaded metadata handler
-  pc_queue_init(&metadata_multicast_queue, (char *)&metadata_multicast_queue_items, sizeof(metadata_package),
-                metadata_multicast_queue_size, "multicast");
+  pc_queue_init(&metadata_multicast_queue, (char *)&metadata_multicast_queue_items,
+                sizeof(metadata_package), metadata_multicast_queue_size, "multicast");
   metadata_create_multicast_socket();
   metadata_package pack;
   pthread_cleanup_push(metadata_multicast_thread_cleanup_function, NULL);
@@ -1539,13 +1556,20 @@ void *metadata_multicast_thread_function(__attribute__((unused)) void *ignore) {
     pc_queue_get_item(&metadata_multicast_queue, &pack);
     pthread_cleanup_push(metadata_pack_cleanup_function, (void *)&pack);
     if (config.metadata_enabled) {
-       if (pack.carrier) {
-               debug(3, "                                                                    multicast: type %x, code %x, length %u, message %d.", pack.type, pack.code, pack.length, pack.carrier->index_number);
-       } else {
-               debug(3, "                                                                    multicast: type %x, code %x, length %u.", pack.type, pack.code, pack.length);
-       }
+      if (pack.carrier) {
+        debug(3,
+              "                                                                    multicast: type "
+              "%x, code %x, length %u, message %d.",
+              pack.type, pack.code, pack.length, pack.carrier->index_number);
+      } else {
+        debug(3,
+              "                                                                    multicast: type "
+              "%x, code %x, length %u.",
+              pack.type, pack.code, pack.length);
+      }
       metadata_multicast_process(pack.type, pack.code, pack.data, pack.length);
-      debug(3, "                                                                    multicast: done.");
+      debug(3,
+            "                                                                    multicast: done.");
     }
     pthread_cleanup_pop(1);
   }
@@ -1553,10 +1577,8 @@ void *metadata_multicast_thread_function(__attribute__((unused)) void *ignore) {
   pthread_exit(NULL);
 }
 
-
 #ifdef CONFIG_METADATA_HUB
-void metadata_hub_close(void) {
-}
+void metadata_hub_close(void) {}
 
 void metadata_hub_thread_cleanup_function(__attribute__((unused)) void *arg) {
   // debug(2, "metadata_hub_thread_cleanup_function called");
@@ -1565,33 +1587,6 @@ void metadata_hub_thread_cleanup_function(__attribute__((unused)) void *arg) {
 }
 
 void *metadata_hub_thread_function(__attribute__((unused)) void *ignore) {
-
-  // create the fifo, if necessary
-  size_t pl = strlen(config.metadata_pipename) + 1;
-  char *path = malloc(pl + 1);
-  snprintf(path, pl + 1, "%s", config.metadata_pipename);
-
-  mode_t oldumask = umask(000);
-  if (mkfifo(path, 0666) && errno != EEXIST)
-    die("Could not create metadata pipe \"%s\".", path);
-  umask(oldumask);
-  debug(1, "metadata pipe name is \"%s\".", path);
-
-  // try to open it
-  fd = try_to_open_pipe_for_writing(path);
-  // we check that it's not a "real" error. From the "man 2 open" page:
-  // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
-  // open for reading." Which is okay.
-       if ((fd == -1) && (errno != ENXIO)) {
-               char errorstring[1024];
-               strerror_r(errno, (char *)errorstring, sizeof(errorstring));
-               debug(1, "metadata_hub_thread_function -- error %d (\"%s\") opening pipe: \"%s\".", errno,
-                                       (char *)errorstring, path);
-               warn("can not open metadata pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
-                                       (char *)errorstring, path);
-       }
-  free(path);
-
   // create a pc_queue for passing information to a threaded metadata handler
   pc_queue_init(&metadata_hub_queue, (char *)&metadata_hub_queue_items, sizeof(metadata_package),
                 metadata_hub_queue_size, "hub");
@@ -1600,13 +1595,15 @@ void *metadata_hub_thread_function(__attribute__((unused)) void *ignore) {
   while (1) {
     pc_queue_get_item(&metadata_hub_queue, &pack);
     pthread_cleanup_push(metadata_pack_cleanup_function, (void *)&pack);
-       if (pack.carrier) {
-               debug(3, "                    hub: type %x, code %x, length %u, message %d.", pack.type, pack.code, pack.length, pack.carrier->index_number);
-       } else {
-               debug(3, "                    hub: type %x, code %x, length %u.", pack.type, pack.code, pack.length);
-       }
-               metadata_hub_process_metadata(pack.type, pack.code, pack.data, pack.length);
-               debug(3, "                    hub: done.");
+    if (pack.carrier) {
+      debug(3, "                    hub: type %x, code %x, length %u, message %d.", pack.type,
+            pack.code, pack.length, pack.carrier->index_number);
+    } else {
+      debug(3, "                    hub: type %x, code %x, length %u.", pack.type, pack.code,
+            pack.length);
+    }
+    metadata_hub_process_metadata(pack.type, pack.code, pack.data, pack.length);
+    debug(3, "                    hub: done.");
     pthread_cleanup_pop(1);
   }
   pthread_cleanup_pop(1); // will never happen
@@ -1615,8 +1612,7 @@ void *metadata_hub_thread_function(__attribute__((unused)) void *ignore) {
 #endif
 
 #ifdef CONFIG_MQTT
-void metadata_mqtt_close(void) {
-}
+void metadata_mqtt_close(void) {}
 
 void metadata_mqtt_thread_cleanup_function(__attribute__((unused)) void *arg) {
   // debug(2, "metadata_mqtt_thread_cleanup_function called");
@@ -1634,15 +1630,19 @@ void *metadata_mqtt_thread_function(__attribute__((unused)) void *ignore) {
   while (1) {
     pc_queue_get_item(&metadata_mqtt_queue, &pack);
     pthread_cleanup_push(metadata_pack_cleanup_function, (void *)&pack);
-               if (config.mqtt_enabled) {
-       if (pack.carrier) {
-               debug(3, "                                        mqtt: type %x, code %x, length %u, message %d.", pack.type, pack.code, pack.length, pack.carrier->index_number);
-       } else {
-               debug(3, "                                        mqtt: type %x, code %x, length %u.", pack.type, pack.code, pack.length);
-       }
-                       mqtt_process_metadata(pack.type, pack.code, pack.data, pack.length);
-                       debug(3, "                                        mqtt: done.");
-               }
+    if (config.mqtt_enabled) {
+      if (pack.carrier) {
+        debug(3,
+              "                                        mqtt: type %x, code %x, length %u, message "
+              "%d.",
+              pack.type, pack.code, pack.length, pack.carrier->index_number);
+      } else {
+        debug(3, "                                        mqtt: type %x, code %x, length %u.",
+              pack.type, pack.code, pack.length);
+      }
+      mqtt_process_metadata(pack.type, pack.code, pack.data, pack.length);
+      debug(3, "                                        mqtt: done.");
+    }
 
     pthread_cleanup_pop(1);
   }
@@ -1652,6 +1652,33 @@ void *metadata_mqtt_thread_function(__attribute__((unused)) void *ignore) {
 #endif
 
 void metadata_init(void) {
+
+  // create the metadata pipe, if necessary
+  size_t pl = strlen(config.metadata_pipename) + 1;
+  char *path = malloc(pl + 1);
+  snprintf(path, pl + 1, "%s", config.metadata_pipename);
+
+  mode_t oldumask = umask(000);
+  if (mkfifo(path, 0666) && errno != EEXIST)
+    die("Could not create metadata pipe \"%s\".", path);
+  umask(oldumask);
+  debug(1, "metadata pipe name is \"%s\".", path);
+
+  // try to open it
+  fd = try_to_open_pipe_for_writing(path);
+  // we check that it's not a "real" error. From the "man 2 open" page:
+  // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
+  // open for reading." Which is okay.
+  if ((fd == -1) && (errno != ENXIO)) {
+    char errorstring[1024];
+    strerror_r(errno, (char *)errorstring, sizeof(errorstring));
+    debug(1, "metadata_hub_thread_function -- error %d (\"%s\") opening pipe: \"%s\".", errno,
+          (char *)errorstring, path);
+    warn("can not open metadata pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
+         (char *)errorstring, path);
+  }
+  free(path);
+
   int ret = pthread_create(&metadata_thread, NULL, metadata_thread_function, NULL);
   if (ret)
     debug(1, "Failed to create metadata thread!");
@@ -1700,8 +1727,8 @@ void metadata_stop(void) {
   }
 }
 
-int send_metadata_to_queue(pc_queue* queue, uint32_t type, uint32_t code, char *data, uint32_t length, rtsp_message *carrier,
-                  int block) {
+int send_metadata_to_queue(pc_queue *queue, uint32_t type, uint32_t code, char *data,
+                           uint32_t length, rtsp_message *carrier, int block) {
 
   // parameters: type, code, pointer to data or NULL, length of data or NULL,
   // the rtsp_message or
@@ -1737,20 +1764,27 @@ int send_metadata_to_queue(pc_queue* queue, uint32_t type, uint32_t code, char *
   if (pack.carrier) {
     msg_retain(pack.carrier);
   } else {
-       if (data)
-               pack.data = memdup(data,length); // only if it's not a null
+    if (data)
+      pack.data = memdup(data, length); // only if it's not a null
   }
   int rc = pc_queue_add_item(queue, &pack, block);
   if (rc != 0) {
     if (pack.carrier) {
-       if (rc == EWOULDBLOCK)
-               debug(2, "metadata queue \"%s\" full, dropping message item: type %x, code %x, data %x, length %u, message %d.", queue->name, pack.type, pack.code, pack.data, pack.length, pack.carrier->index_number);
+      if (rc == EWOULDBLOCK)
+        debug(2,
+              "metadata queue \"%s\" full, dropping message item: type %x, code %x, data %x, "
+              "length %u, message %d.",
+              queue->name, pack.type, pack.code, pack.data, pack.length,
+              pack.carrier->index_number);
       msg_free(&pack.carrier);
     } else {
-       if (rc == EWOULDBLOCK)
-               debug(2, "metadata queue \"%s\" full, dropping data item: type %x, code %x, data %x, length %u.", queue->name, pack.type, pack.code, pack.data, pack.length);
-       if (pack.data)
-       free(pack.data);
+      if (rc == EWOULDBLOCK)
+        debug(
+            2,
+            "metadata queue \"%s\" full, dropping data item: type %x, code %x, data %x, length %u.",
+            queue->name, pack.type, pack.code, pack.data, pack.length);
+      if (pack.data)
+        free(pack.data);
     }
   }
   return rc;
@@ -1758,23 +1792,20 @@ int send_metadata_to_queue(pc_queue* queue, uint32_t type, uint32_t code, char *
 
 int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, rtsp_message *carrier,
                   int block) {
-       int rc;
-       rc = send_metadata_to_queue(&metadata_queue, type, code, data, length, carrier, block);
+  int rc;
+  rc = send_metadata_to_queue(&metadata_queue, type, code, data, length, carrier, block);
 
 #ifdef CONFIG_METADATA_HUB
-       rc = send_metadata_to_queue(&metadata_hub_queue, type, code, data, length, carrier, block);
+  rc = send_metadata_to_queue(&metadata_hub_queue, type, code, data, length, carrier, block);
 #endif
 
 #ifdef CONFIG_MQTT
-       rc = send_metadata_to_queue(&metadata_mqtt_queue, type, code, data, length, carrier, block);
+  rc = send_metadata_to_queue(&metadata_mqtt_queue, type, code, data, length, carrier, block);
 #endif
 
-       return rc;
+  return rc;
 }
 
-
-
-
 static void handle_set_parameter_metadata(__attribute__((unused)) rtsp_conn_info *conn,
                                           rtsp_message *req,
                                           __attribute__((unused)) rtsp_message *resp) {
@@ -1838,7 +1869,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
   char *ct = msg_get_header(req, "Content-Type");
 
   if (ct) {
-// debug(2, "SET_PARAMETER Content-Type:\"%s\".", ct);
+    // debug(2, "SET_PARAMETER Content-Type:\"%s\".", ct);
 
 #ifdef CONFIG_METADATA
     // It seems that the rtptime of the message is used as a kind of an ID that
@@ -2136,7 +2167,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
 
       unsigned int i = 0;
       unsigned int max_param = sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]);
-      charfound;
+      char *found;
       while ((found = strsep(&pfmtp, " \t")) != NULL && i < max_param) {
         conn->stream.fmtp[i++] = atoi(found);
       }
@@ -2617,8 +2648,9 @@ static void *rtsp_conversation_thread_func(void *pconn) {
       if (strcmp(req->method, "OPTIONS") !=
           0) // the options message is very common, so don't log it until level 3
         debug_level = 2;
-      debug(debug_level, "Connection %d: Received an RTSP Packet of type \"%s\":",
-            conn->connection_number, req->method),
+      debug(debug_level,
+            "Connection %d: Received an RTSP Packet of type \"%s\":", conn->connection_number,
+            req->method),
           debug_print_msg_headers(debug_level, req);
 
       apple_challenge(conn->fd, req, resp);
@@ -2667,8 +2699,9 @@ static void *rtsp_conversation_thread_func(void *pconn) {
       if (conn->stop == 0) {
         int err = msg_write_response(conn->fd, resp);
         if (err) {
-          debug(1, "Connection %d: Unable to write an RTSP message response. Terminating the "
-                   "connection.",
+          debug(1,
+                "Connection %d: Unable to write an RTSP message response. Terminating the "
+                "connection.",
                 conn->connection_number);
           struct linger so_linger;
           so_linger.l_onoff = 1; // "true"
@@ -2721,10 +2754,11 @@ static void *rtsp_conversation_thread_func(void *pconn) {
         if (reply == -1) {
           char errorstring[1024];
           strerror_r(errno, (char *)errorstring, sizeof(errorstring));
-          debug(1, "rtsp_read_request_response_bad_packet write response error %d: \"%s\".", errno, (char *)errorstring);
+          debug(1, "rtsp_read_request_response_bad_packet write response error %d: \"%s\".", errno,
+                (char *)errorstring);
         } else if (reply != (ssize_t)strlen(response_text)) {
-          debug(1, "rtsp_read_request_response_bad_packet write %d bytes requested but %d written.", strlen(response_text),
-                reply);
+          debug(1, "rtsp_read_request_response_bad_packet write %d bytes requested but %d written.",
+                strlen(response_text), reply);
         }
       } else {
         debug(1, "Connection %d: rtsp_read_request error %d, packet ignored.",
@@ -2937,7 +2971,7 @@ void rtsp_listen_loop(void) {
             debug(2, "Connection %d: new connection from %s:%u to self at %s:%u.",
                   conn->connection_number, remote_ip4, rport, ip4, tport);
           }
-  #ifdef AF_INET6
+#ifdef AF_INET6
           if (local_info->SAFAMILY == AF_INET6) {
             // IPv6:
 
@@ -2954,7 +2988,7 @@ void rtsp_listen_loop(void) {
             debug(2, "Connection %d: new connection from [%s]:%u to self at [%s]:%u.",
                   conn->connection_number, remote_ip6, rport, ip6, tport);
           }
-  #endif
+#endif
 
         } else {
           debug(1, "Error figuring out Shairport Sync's own IP number.");
index efa349965fb3a2112c5e1f451b5089a01138dcd9..6444b8a5e736d88fde8d1cb3184afc365245d8c6 100644 (file)
@@ -159,7 +159,7 @@ jack =
 // --with-pipe
 pipe =
 {
-//     name = "/path/to/pipe"; // there is no default pipe name for the output
+//     name = "/tmp/shairport-sync-audio"; // this is the default
 };
 
 // There are no configuration file parameters for the "stdout" audio back end. No interpolation is done.
index 975b71fc6100c51b17ad265f6340d635c2cde852..ba99523330b72fa32517ce386544fc0b738fc994 100644 (file)
@@ -61,6 +61,7 @@
 #endif
 
 #include "activity_monitor.h"
+#include "audio.h"
 #include "common.h"
 #include "rtp.h"
 #include "rtsp.h"
@@ -117,6 +118,8 @@ int daemonisewithout = 0;
 char configuration_file_path[4096 + 1];
 char actual_configuration_file_path[4096 + 1];
 
+char first_backend_name[256];
+
 void print_version(void) {
   char *version_string = get_version_string();
   if (version_string) {
@@ -126,7 +129,6 @@ void print_version(void) {
     debug(1, "Can't print version string!");
   }
 }
-
 #ifdef CONFIG_SOXR
 pthread_t soxr_time_check_thread;
 void *soxr_time_check(__attribute__((unused)) void *arg) {
@@ -419,15 +421,15 @@ int parse_options(int argc, char **argv) {
   // for unexpected circumstances
 
 #ifdef CONFIG_METADATA
-      /* Get the metadata setting. */
-      config.metadata_enabled = 1; // if metadata support is included, then enable it by default
-      config.get_coverart = 1; // if metadata support is included, then enable it by default
+  /* Get the metadata setting. */
+  config.metadata_enabled = 1; // if metadata support is included, then enable it by default
+  config.get_coverart = 1;     // if metadata support is included, then enable it by default
 #endif
 
 #ifdef CONFIG_CONVOLUTION
-      config.convolution_max_length = 8192;
+  config.convolution_max_length = 8192;
 #endif
-      config.loudness_reference_volume_db = -20;
+  config.loudness_reference_volume_db = -20;
 
 #ifdef CONFIG_METADATA_HUB
   config.cover_art_cache_dir = "/tmp/shairport-sync/.cache/coverart";
@@ -682,9 +684,9 @@ int parse_options(int argc, char **argv) {
         } else if (strcasecmp(str, "stderr") == 0) {
           log_to_stderr();
         } else {
-               config.log_file_path = (char *)str;
-               config.log_fd = -1;
-               log_to_file();
+          config.log_file_path = (char *)str;
+          config.log_fd = -1;
+          log_to_file();
         }
       }
       /* Get the ignore_volume_control setting. */
@@ -1313,113 +1315,114 @@ const char *pid_file_proc(void) {
 
 void exit_function() {
 
-       if (emergency_exit == 0) {
-               // the following is to ensure that if libdaemon has been included
-               // that most of this code will be skipped when the parent process is exiting
-               // exec
+  if (emergency_exit == 0) {
+    // the following is to ensure that if libdaemon has been included
+    // that most of this code will be skipped when the parent process is exiting
+    // exec
 #ifdef CONFIG_LIBDAEMON
-               if ((this_is_the_daemon_process) || (config.daemonise == 0)) { // if this is the daemon process that is exiting or it's not actually deamonised at all
-#endif
-                       debug(2, "exit function called...");
-                       /*
-                       Actually, there is no terminate_mqtt() function.
-                       #ifdef CONFIG_MQTT
-                               if (config.mqtt_enabled) {
-                                       terminate_mqtt();
-                               }
-                       #endif
-                       */
+    if ((this_is_the_daemon_process) ||
+        (config.daemonise == 0)) { // if this is the daemon process that is exiting or it's not
+                                   // actually deamonised at all
+#endif
+      debug(2, "exit function called...");
+      /*
+      Actually, there is no terminate_mqtt() function.
+      #ifdef CONFIG_MQTT
+              if (config.mqtt_enabled) {
+                      terminate_mqtt();
+              }
+      #endif
+      */
 
 #if defined(CONFIG_DBUS_INTERFACE) || defined(CONFIG_MPRIS_INTERFACE)
-                       /*
-                       Actually, there is no stop_mpris_service() function.
-                       #ifdef CONFIG_MPRIS_INTERFACE
-                               stop_mpris_service();
-                       #endif
-                       */
+      /*
+      Actually, there is no stop_mpris_service() function.
+      #ifdef CONFIG_MPRIS_INTERFACE
+              stop_mpris_service();
+      #endif
+      */
 #ifdef CONFIG_DBUS_INTERFACE
-                       stop_dbus_service();
+      stop_dbus_service();
 #endif
-                       if (g_main_loop) {
-                               debug(2, "Stopping DBUS Loop Thread");
-                               g_main_loop_quit(g_main_loop);
-                               pthread_join(dbus_thread, NULL);
-                       }
+      if (g_main_loop) {
+        debug(2, "Stopping DBUS Loop Thread");
+        g_main_loop_quit(g_main_loop);
+        pthread_join(dbus_thread, NULL);
+      }
 #endif
 
 #ifdef CONFIG_DACP_CLIENT
-                       debug(2, "Stopping DACP Monitor");
-                       dacp_monitor_stop();
+      debug(2, "Stopping DACP Monitor");
+      dacp_monitor_stop();
 #endif
 
 #ifdef CONFIG_METADATA_HUB
-                       debug(2, "Stopping metadata hub");
-                       metadata_hub_stop();
+      debug(2, "Stopping metadata hub");
+      metadata_hub_stop();
 #endif
 
 #ifdef CONFIG_METADATA
-                       metadata_stop(); // close down the metadata pipe
+      metadata_stop(); // close down the metadata pipe
 #endif
 
-                       activity_monitor_stop(0);
+      activity_monitor_stop(0);
 
-                       if ((config.output) && (config.output->deinit)) {
-                               debug(2, "Deinitialise the audio backend.");
-                               config.output->deinit();
-                       }
+      if ((config.output) && (config.output->deinit)) {
+        debug(2, "Deinitialise the audio backend.");
+        config.output->deinit();
+      }
 
 #ifdef CONFIG_SOXR
-                       // be careful -- not sure if the thread can be cancelled cleanly, so wait for it to shut down
-                       pthread_join(soxr_time_check_thread, NULL);
+      // be careful -- not sure if the thread can be cancelled cleanly, so wait for it to shut down
+      pthread_join(soxr_time_check_thread, NULL);
 #endif
 
-                       if (conns)
-                               free(conns); // make sure the connections have been deleted first
+      if (conns)
+        free(conns); // make sure the connections have been deleted first
 
-                       if (config.service_name)
-                               free(config.service_name);
+      if (config.service_name)
+        free(config.service_name);
 
 #ifdef CONFIG_CONVOLUTION
-                       if (config.convolution_ir_file)
-                               free(config.convolution_ir_file);
+      if (config.convolution_ir_file)
+        free(config.convolution_ir_file);
 #endif
 
-                       if (config.regtype)
-                               free(config.regtype);
+      if (config.regtype)
+        free(config.regtype);
 
 #ifdef CONFIG_LIBDAEMON
-                       if (this_is_the_daemon_process) {
-                               daemon_retval_send(0);
-                               daemon_pid_file_remove();
-                               daemon_signal_done();
-                               if (config.computed_piddir)
-                                       free(config.computed_piddir);
-                       }
-               }
+      if (this_is_the_daemon_process) {
+        daemon_retval_send(0);
+        daemon_pid_file_remove();
+        daemon_signal_done();
+        if (config.computed_piddir)
+          free(config.computed_piddir);
+      }
+    }
 #endif
 
-               if (config.cfg)
-                       config_destroy(config.cfg);
-               if (config.appName)
-                       free(config.appName);
-               // probably should be freeing malloc'ed memory here, including strdup-created strings...
-
+    if (config.cfg)
+      config_destroy(config.cfg);
+    if (config.appName)
+      free(config.appName);
+      // probably should be freeing malloc'ed memory here, including strdup-created strings...
 
 #ifdef CONFIG_LIBDAEMON
-               if (this_is_the_daemon_process) { // this is the daemon that is exiting
-                       debug(1,"libdaemon daemon exit");
-               } else {
-                       if (config.daemonise)
-                               debug(1,"libdaemon parent exit");
-                       else
-                               debug(1,"exit");
-               }
+    if (this_is_the_daemon_process) { // this is the daemon that is exiting
+      debug(1, "libdaemon daemon exit");
+    } else {
+      if (config.daemonise)
+        debug(1, "libdaemon parent exit");
+      else
+        debug(1, "exit");
+    }
 #else
-               debug(1,"exit");
+    debug(1, "exit");
 #endif
-       } else {
-               debug(1,"emergency exit");
-       }
+  } else {
+    debug(1, "emergency exit");
+  }
 }
 
 // for removing zombie script processes
@@ -1434,11 +1437,10 @@ void handle_sigchld(__attribute__((unused)) int sig) {
 }
 
 void main_thread_cleanup_handler(__attribute__((unused)) void *arg) {
-  debug(2,"main thread cleanup handler called");
+  debug(2, "main thread cleanup handler called");
   exit(EXIT_SUCCESS);
 }
 
-
 int main(int argc, char **argv) {
   /* Check if we are called with -V or --version parameter */
   if (argc >= 2 && ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0))) {
@@ -1455,7 +1457,7 @@ int main(int argc, char **argv) {
 #ifdef CONFIG_LIBDAEMON
   pid = getpid();
 #endif
-       config.log_fd = -1;
+  config.log_fd = -1;
   conns = NULL; // no connections active
   memset((void *)&main_thread_id, 0, sizeof(main_thread_id));
   memset(&config, 0, sizeof(config)); // also clears all strings, BTW
@@ -1476,7 +1478,7 @@ int main(int argc, char **argv) {
   setlogmask(LOG_UPTO(LOG_DEBUG));
   openlog(NULL, 0, LOG_DAEMON);
 #endif
-       emergency_exit = 0; // what to do or skip in the exit_function
+  emergency_exit = 0; // what to do or skip in the exit_function
   atexit(exit_function);
 
   // set defaults
@@ -1504,6 +1506,15 @@ int main(int argc, char **argv) {
   // set non-zero / non-NULL default values here
   // but note that audio back ends also have a chance to set defaults
 
+  // get the first output backend in the list and make it the default
+  audio_output *first_backend = audio_get_output(NULL);
+  if (first_backend == NULL) {
+    die("No audio backend found! Check your build of Shairport Sync.");
+  } else {
+    strncpy(first_backend_name, first_backend->name, sizeof(first_backend_name) - 1);
+    config.output_name = first_backend_name;
+  }
+
   strcpy(configuration_file_path, SYSCONFDIR);
   // strcat(configuration_file_path, "/shairport-sync"); // thinking about adding a special
   // shairport-sync directory
@@ -1598,13 +1609,16 @@ int main(int argc, char **argv) {
       if (errno == ENOENT)
         daemon_log(LOG_WARNING, "Failed to kill %s daemon: PID file not found.", config.appName);
       else
-        daemon_log(LOG_WARNING, "Failed to kill %s daemon: \"%s\", errno %u.", config.appName, strerror(errno), errno);
+        daemon_log(LOG_WARNING, "Failed to kill %s daemon: \"%s\", errno %u.", config.appName,
+                   strerror(errno), errno);
     } else {
-        // debug(1,"Successfully killed the %s daemon.", config.appName);
+      // debug(1,"Successfully killed the %s daemon.", config.appName);
       if (daemon_pid_file_remove() == 0)
         debug(2, "killed the %s daemon.", config.appName);
       else
-        daemon_log(LOG_WARNING, "killed the %s deamon, but cannot remove old PID file: \"%s\", errno %u.", config.appName, strerror(errno), errno);
+        daemon_log(LOG_WARNING,
+                   "killed the %s deamon, but cannot remove old PID file: \"%s\", errno %u.",
+                   config.appName, strerror(errno), errno);
     }
     return ret < 0 ? 1 : 0;
 #else
@@ -1651,14 +1665,19 @@ int main(int argc, char **argv) {
       case 0:
         break;
       case 1:
-        daemon_log(LOG_ERR,
-                   "the %s daemon failed to launch: could not close open file descriptors after forking.", config.appName);
+        daemon_log(
+            LOG_ERR,
+            "the %s daemon failed to launch: could not close open file descriptors after forking.",
+            config.appName);
         break;
       case 2:
-        daemon_log(LOG_ERR, "the %s daemon failed to launch: could not create PID file.", config.appName);
+        daemon_log(LOG_ERR, "the %s daemon failed to launch: could not create PID file.",
+                   config.appName);
         break;
       case 3:
-        daemon_log(LOG_ERR, "the %s daemon failed to launch: could not create or access PID directory.", config.appName);
+        daemon_log(LOG_ERR,
+                   "the %s daemon failed to launch: could not create or access PID directory.",
+                   config.appName);
         break;
       default:
         daemon_log(LOG_ERR, "the %s daemon failed to launch, error %i.", config.appName, ret);
@@ -1709,8 +1728,8 @@ int main(int argc, char **argv) {
 #endif
   debug(1, "Started!");
 
-       // stop a pipe signal from killing the program
-       signal(SIGPIPE, SIG_IGN);
+  // stop a pipe signal from killing the program
+  signal(SIGPIPE, SIG_IGN);
 
   // install a zombie process reaper
   // see: http://www.microhowto.info/howto/reap_zombie_processes_using_a_sigchld_handler.html
@@ -1744,8 +1763,8 @@ int main(int argc, char **argv) {
 
   config.output = audio_get_output(config.output_name);
   if (!config.output) {
-    audio_ls_outputs();
-    die("Invalid audio output specified!");
+    die("Invalid audio backend \"%s\" selected!",
+        config.output_name == NULL ? "<unspecified>" : config.output_name);
   }
   config.output->init(argc - audio_arg, argv + audio_arg);