]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add ability for the jack back end to automaticlly connect a client when the jack...
authorMike Brady <mikebrady@eircom.net>
Sun, 2 Sep 2018 16:25:29 +0000 (17:25 +0100)
committerMike Brady <mikebrady@eircom.net>
Sun, 2 Sep 2018 16:25:29 +0000 (17:25 +0100)
audio_jack.c
common.c
common.h
scripts/shairport-sync.conf
shairport.c

index e8cd51a8e0b0bf87cf0031ca0e11c90cecb1f374..ec36ed198d157b997b61e2b4df02bf0b1137e49f 100644 (file)
@@ -42,10 +42,13 @@ enum ift_type {
 #define buffer_size 44100 * 4 * 2 * 2
 
 static pthread_mutex_t buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t client_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 char *audio_lmb, *audio_umb, *audio_toq, *audio_eoq;
 size_t audio_occupancy; // this is in frames, not bytes. A frame is a left and
                         // right sample, each 16 bits, hence 4 bytes
+pthread_t *open_client_if_necessary_thread = NULL;
+
 
 // static void help(void);
 int init(int, char **);
@@ -220,6 +223,7 @@ int jack_is_running() {
 }
 
 int jack_client_open_if_needed(void) {
+  pthread_mutex_lock(&client_mutex);
   if (client_is_open == 0) {
     jack_status_t status;
     client = jack_client_open(config.jack_client_name, JackNoStartServer, &status);
@@ -245,21 +249,46 @@ int jack_client_open_if_needed(void) {
       }
     }
   }
+  pthread_mutex_unlock(&client_mutex);
   return client_is_open;
 }
 
-void jack_deinit() {
+void jack_close(void) {
+  pthread_mutex_lock(&client_mutex);
   if (client_is_open) {
     if (jack_deactivate(client))
       debug(1, "Error deactivating jack client");
     if (jack_client_close(client))
       debug(1, "Error closing jack client");
+    client_is_open = 0;
+  }
+  pthread_mutex_unlock(&client_mutex);
+}
+
+void jack_deinit() {
+  jack_close();
+  if (open_client_if_necessary_thread) {
+    pthread_cancel(*open_client_if_necessary_thread);
+    free((char *)open_client_if_necessary_thread);
   }
 }
 
+void *open_client_if_necessary_thread_function(void *arg) {
+  int *interval = (int *)arg;
+  while (*interval != 0) {
+    if (client_is_open == 0) {
+      debug(1, "Try to open the jack client");
+      jack_client_open_if_needed();
+    }
+    sleep(*interval);
+  }  
+  pthread_exit(NULL);
+}
+
 int init(__attribute__((unused)) int argc, __attribute__((unused)) char **argv) {
   config.audio_backend_latency_offset = 0;
   config.audio_backend_buffer_desired_length = 0.15;
+  config.jack_auto_client_open_interval = 1; // check every second
 
   // get settings from settings file first, allow them to be overridden by
   // command line options
@@ -272,6 +301,7 @@ int init(__attribute__((unused)) int argc, __attribute__((unused)) char **argv)
   // now the specific options
   if (config.cfg != NULL) {
     const char *str;
+    int value;
     /* Get the Client Name. */
     if (config_lookup_string(config.cfg, "jack.client_name", &str)) {
       config.jack_client_name = (char *)str;
@@ -284,6 +314,21 @@ int init(__attribute__((unused)) int argc, __attribute__((unused)) char **argv)
     if (config_lookup_string(config.cfg, "jack.right_channel_name", &str)) {
       config.jack_right_channel_name = (char *)str;
     }
+    
+    /* See if we should attempt to connect to the jack server automatically, and, if so, how often we should try. */
+    if (config_lookup_int(config.cfg, "jack.auto_client_open_interval", &value)) {
+      if ((value < 0) || (value > 300))
+        die("Invalid jack auto_client_open_interval \"%sd\". It should be between 0 and 300, default is %d",
+              value,config.jack_auto_client_open_interval);
+      else
+        config.jack_auto_client_open_interval = value;
+    }
+
+    /* See if we should close the client at then end of a play session. */
+    config_set_lookup_bool(config.cfg, "jack.auto_client_disconnect", &config.jack_auto_client_disconnect);
+    
+    // now, start a thread to automatically open a client when there is a server.
+    
   }
 
   if (config.jack_client_name == NULL)
@@ -305,16 +350,22 @@ int init(__attribute__((unused)) int argc, __attribute__((unused)) char **argv)
   audio_occupancy = 0; // frames
 
   client_is_open = 0;
-  jack_client_open_if_needed();
+  
+  if (config.jack_auto_client_open_interval != 0) {
+    open_client_if_necessary_thread = malloc(sizeof(pthread_t));
+    if (open_client_if_necessary_thread == NULL)
+      die("Couldn't allocate space for jack server scanner thread");
+    pthread_create(open_client_if_necessary_thread, NULL, open_client_if_necessary_thread_function, &config.jack_auto_client_open_interval);
+  } else {
+    jack_client_open_if_needed();
+  }
 
   return 0;
 }
 
 void jack_start(__attribute__((unused)) int i_sample_rate,
                 __attribute__((unused)) int i_sample_format) {
-  debug(1, "jack start");
-  // int reply = -1;
-
+  // debug(1, "jack start");
   // see if the client is running. If not, try to open and initialise it
 
   if (jack_client_open_if_needed() == 0)
@@ -358,4 +409,8 @@ void jack_flush() {
   // unlock
 }
 
-void jack_stop(void) { debug(1, "jack stop"); }
\ No newline at end of file
+void jack_stop(void) {
+  // debug(1, "jack stop");
+  if (config.jack_auto_client_disconnect)
+    jack_close();
+}
\ No newline at end of file
index 85aeceecd6a97939bbcea01d30371d438ff725d6..3ecb7751596b27a09583f5724f49ca5077355e32 100644 (file)
--- a/common.c
+++ b/common.c
@@ -568,6 +568,26 @@ uint8_t *rsa_apply(uint8_t *input, int inlen, int *outlen, int mode) {
 }
 #endif
 
+int config_set_lookup_bool(config_t *cfg, char *where, int *dst) {
+  const char *str = 0;
+  if (config_lookup_string(cfg, where, &str)) {
+    if (strcasecmp(str, "no") == 0) {
+      (*dst) = 0;
+      return 1;
+    } else if (strcasecmp(str, "yes") == 0) {
+      (*dst) = 1;
+      return 1;
+    } else {
+      die("Invalid %s option choice \"%s\". It should be \"yes\" or \"no\"", where, str);
+      return 0;
+    }
+  } else {
+    return 0;
+  }
+}
+
+
+
 void command_set_volume(double volume) {
   if (config.cmd_set_volume) {
     /*Spawn a child to run the program.*/
index 10d8d1f8fb7af4e3954db409e8283935c9a377b4..fccd4b8c4039b5f33f5bf5193911db4a3cac6f0b 100644 (file)
--- a/common.h
+++ b/common.h
@@ -205,6 +205,8 @@ typedef struct {
                                           // debugging. Currently audio packets only...
 #ifdef CONFIG_JACK
   char *jack_client_name, *jack_left_channel_name, *jack_right_channel_name;
+  int jack_auto_client_open_interval; // will try to open a client automatically every second
+  int jack_auto_client_disconnect; // will disconnect from the server on end of session if set, normally clear.
 #endif
 
 } shairport_cfg;
@@ -276,6 +278,8 @@ pthread_t main_thread_id;
 shairport_cfg config;
 config_t config_file_stuff;
 
+int config_set_lookup_bool(config_t *cfg, char *where, int *dst);
+
 void command_start(void);
 void command_stop(void);
 void command_set_volume(double volume);
index 23314d67c14e949f21c11c61239371a21b26f862..028a3758a5f243953bcd8556b52bdcaf5ec0e20f 100644 (file)
@@ -97,6 +97,8 @@ jack =
 //  client_name = "Shairport Sync"; //Set this to the name of the client that should appear in "Connections" when Shairport Sync is active.
 //  left_channel_name = "left"; //Set this to the name of the left output port that should appear in "Connections" when Shairport Sync is active.
 //  right_channel_name = "right"; //Set this to the name of the right output port that should appear in "Connections" when Shairport Sync is active.
+//  auto_client_open_interval = 1; // Set this to the interval in seconds between automatic attempts to open a client on the jack server. Set to zero to disable this behaviour.
+//  auto_client_disconnet = "no"; // Set this to "yes" to close the jack client automatically at then end of a play session. Default is no -- the client stays connected.
 };
 
 // Parameters for the "pipe" audio back end, a back end that directs raw CD-style audio output to a pipe. No interpolation is done.
index bd4025dc3efafbe11ad9728755ede9b3b8d7c447..214e0d6e61c55ae2713c45183b1dcc90c923e4ba 100644 (file)
 #include <FFTConvolver/convolver.h>
 #endif
 
-static inline int config_set_lookup_bool(config_t *cfg, char *where, int *dst) {
-  const char *str = 0;
-  if (config_lookup_string(cfg, where, &str)) {
-    if (strcasecmp(str, "no") == 0) {
-      (*dst) = 0;
-      return 1;
-    } else if (strcasecmp(str, "yes") == 0) {
-      (*dst) = 1;
-      return 1;
-    } else {
-      die("Invalid %s option choice \"%s\". It should be \"yes\" or \"no\"", where, str);
-      return 0;
-    }
-  } else {
-    return 0;
-  }
-}
-
 static int shutting_down = 0;
 char configuration_file_path[4096 + 1];
 char actual_configuration_file_path[4096 + 1];