]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Call the unfixable error if the output device can't be opened or disappears. Clang...
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Fri, 30 Dec 2022 18:36:33 +0000 (18:36 +0000)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Fri, 30 Dec 2022 18:36:33 +0000 (18:36 +0000)
audio_alsa.c
audio_stdout.c
common.h
dbus-service.c
metadata_hub.c
metadata_hub.h
nqptp-shm-structures.h
player.c
player.h
rtsp.c

index 9a37f3f64ae9b84405549b36d12dfe77acee322a..3c8cebd0faad52cddff0ffe074a251a223841db2 100644 (file)
@@ -444,13 +444,19 @@ static int actual_open_alsa_device(int do_auto_setup) {
         warn("The output device \"%s\" is busy and can't be used by Shairport Sync at present.",
              alsa_out_dev);
       debug(2, "the alsa output_device \"%s\" is busy.", alsa_out_dev);
-    } else if (ret == -ENOENT) {
-      die("the alsa output_device \"%s\" can not be found.", alsa_out_dev);
     } else {
-      char errorstring[1024];
-      strerror_r(-ret, (char *)errorstring, sizeof(errorstring));
-      die("alsa: error %d (\"%s\") opening alsa device \"%s\".", ret, (char *)errorstring,
-          alsa_out_dev);
+      if (config.unfixable_error_reported == 0) {
+        config.unfixable_error_reported = 1;        
+        char messageString[1024];
+        messageString[0] = '\0';
+        snprintf(messageString, sizeof(messageString), "output_device_error %d", -ret);            
+        if (config.cmd_unfixable) {
+          command_execute(config.cmd_unfixable, messageString, 1);
+        } else {
+          die("an unrecoverable error, \"output_device_error %d\", has been "
+              "detected.", -ret);
+        }
+      }
     }
     alsa_handle_status = ret;
     frames_sent_break_occurred = 1;
@@ -1795,10 +1801,23 @@ static int do_play(void *buf, int samples) {
             }
           }
         } else {
-          char errorstring[1024];
-          strerror_r(-ret, (char *)errorstring, sizeof(errorstring));
-          debug(1, "alsa: error %d (\"%s\") writing %d samples to alsa device.", ret,
-                (char *)errorstring, samples);
+
+          if (ret == -ENODEV) {
+            if (config.unfixable_error_reported == 0) {
+              config.unfixable_error_reported = 1;
+              if (config.cmd_unfixable) {
+                command_execute(config.cmd_unfixable, "output_device_error 19", 1);
+              } else {
+                die("an unrecoverable error, \"output_device_error 19\", has been "
+                    "detected.");
+              }
+            }
+          } else {
+            char errorstring[1024];
+            strerror_r(-ret, (char *)errorstring, sizeof(errorstring));
+            debug(1, "alsa: error %d (\"%s\") writing %d samples to alsa device.", ret,
+                  (char *)errorstring, samples);
+          }
         }
       }
     }
index 2a54f072e2cc9353ae5575676487ea08c00c1262..ef9df61d6dfb258ad8b191804d665e50422d9ae3 100644 (file)
 static int fd = -1;
 static int warned = 0;
 
-
 static void start(__attribute__((unused)) int sample_rate,
                   __attribute__((unused)) int sample_format) {
   fd = STDOUT_FILENO;
-  warned = 0;  
+  warned = 0;
 }
 
 static int play(void *buf, int samples, __attribute__((unused)) int sample_type,
index 639c1c0f8ceef836607e03d3a0c0edd0f363a3df..66c02ca6bc216062399f3975b57d5954aa7c4e4b 100644 (file)
--- a/common.h
+++ b/common.h
@@ -37,7 +37,8 @@ typedef enum {
 typedef enum {
   TOE_normal,
   TOE_emergency,
-  TOE_dbus // a request was made on a D-Bus interface (the native D-Bus or MPRIS interfaces)-- don't wait for the dbus thread to exit
+  TOE_dbus // a request was made on a D-Bus interface (the native D-Bus or MPRIS interfaces)-- don't
+           // wait for the dbus thread to exit
 } type_of_exit_type;
 
 #define sps_extra_code_output_stalled 32768
@@ -160,7 +161,7 @@ typedef struct {
   int mqtt_enable_remote;
   char *mqtt_empty_payload_substitute;
 #endif
-  uint8_t ap1_prefix[6]; 
+  uint8_t ap1_prefix[6];
   uint8_t hw_addr[8]; // only needs 6 but 8 is handy when converting this to a number
   int port;
   int udp_port_base;
@@ -313,6 +314,7 @@ typedef struct {
   char *airplay_pi;        // UUID in the Bonjour advertisement and the GETINFO Plist
   char *nqptp_shared_memory_interface_name; // client name for nqptp service
 #endif
+  int unfixable_error_reported; // only report once.
 } shairport_cfg;
 
 // accessors to config for multi-thread access
index 4cfc8254a6008309402d6723b37e87be8ca36a6a..7079224815df72a05c67090232dadf16fa356b10 100644 (file)
@@ -111,7 +111,8 @@ void dbus_metadata_watcher(struct metadata_bundle *argc, __attribute__((unused))
     th = shairport_sync_get_first_frame_position(shairportSyncSkeleton);
     if ((th == NULL) || (strcasecmp(th, argc->first_frame_position_string) != 0)) {
       // debug(1, "First frame position string should be changed");
-      shairport_sync_set_first_frame_position(shairportSyncSkeleton, argc->first_frame_position_string);
+      shairport_sync_set_first_frame_position(shairportSyncSkeleton,
+                                              argc->first_frame_position_string);
     }
   }
 
index e39752fea94dc6779e5339eb2a56cbf610cb9e09..796e0927d6a34842f34cab24dde4b257b718544e 100644 (file)
@@ -598,7 +598,8 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
       if (string_update(&metadata_store.first_frame_position_string,
                         &metadata_store.first_frame_position_string_changed, cs)) {
         changed = 1;
-        debug(2, "MH First Frame Position String set to: \"%s\"", metadata_store.first_frame_position_string);
+        debug(2, "MH First Frame Position String set to: \"%s\"",
+              metadata_store.first_frame_position_string);
       }
       free(cs);
       break;
index 8235c6e4886b7ca3386261844ae6623fae663f30..94b3acaa4325250435f9f557fb7f50ced04e143a 100644 (file)
@@ -48,7 +48,7 @@ typedef struct metadata_bundle {
 
   char *server_ip; // IP number used by Shairport Sync
   int server_ip_changed;
-  
+
   char *stream_type; // Realtime or Buffered
   int stream_type_changed;
 
@@ -79,7 +79,7 @@ typedef struct metadata_bundle {
 
   char *cover_art_pathname;
   int cover_art_pathname_changed;
-  
+
   uint64_t item_id; // seems to be a track ID -- see itemid in DACP.c
   int item_id_changed;
   int item_id_is_valid;
@@ -89,11 +89,10 @@ typedef struct metadata_bundle {
   int item_composite_id_changed;
   int item_composite_id_is_valid;
 
-
   int song_data_kind;
   int song_data_kind_changed;
   int song_data_kind_is_valid;
-  
+
   char *track_name;
   int track_name_changed;
 
@@ -139,7 +138,6 @@ typedef struct metadata_bundle {
   uint32_t songtime_in_milliseconds;
   int songtime_in_milliseconds_changed;
   int songtime_in_milliseconds_is_valid;
-  
 
   // end
 
index 251d06c1ea0c9b5e798c8620491862dbd25f535d..5982a7305d87beb78913ea61ee8b46d26e823583 100644 (file)
@@ -50,8 +50,7 @@
 // When the clock is inactive, it can stop running. This causes the offset to decrease.
 // NQPTP clock smoothing would treat this as a network delay, causing true sync to be lost.
 // To avoid this, when the clock goes from inactive to active,
-// NQPTP resets clock smoothing to the new offset. 
-
+// NQPTP resets clock smoothing to the new offset.
 
 #include <inttypes.h>
 #include <pthread.h>
index b920971c63570587f0e6b74e3b7b06be7a5a4737..0898fedab4c7335f1427475fc444b8d7bbaba5f3 100644 (file)
--- a/player.c
+++ b/player.c
@@ -106,7 +106,7 @@ int64_t first_frame_early_bias = 8;
 
 // default buffer size
 // needs to be a power of 2 because of the way BUFIDX(seqno) works
-//#define BUFFER_FRAMES 512
+// #define BUFFER_FRAMES 512
 #define MAX_PACKET 2048
 
 // DAC buffer occupancy stuff
@@ -531,9 +531,9 @@ void player_put_packet(int original_format, seq_t seqno, uint32_t actual_timesta
           (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 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;
 
@@ -1271,14 +1271,13 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
                     } else {
 
                       if (resp == sps_extra_code_output_stalled) {
-                        if (conn->unfixable_error_reported == 0) {
-                          conn->unfixable_error_reported = 1;
+                        if (config.unfixable_error_reported == 0) {
+                          config.unfixable_error_reported = 1;
                           if (config.cmd_unfixable) {
                             command_execute(config.cmd_unfixable, "output_device_stalled", 1);
                           } else {
                             die("an unrecoverable error, \"output_device_stalled\", has been "
-                                "detected.",
-                                conn->connection_number);
+                                "detected.");
                           }
                         }
                       } else {
@@ -1838,7 +1837,8 @@ void player_thread_cleanup_handler(void *arg) {
 void *player_thread_func(void *arg) {
   rtsp_conn_info *conn = (rtsp_conn_info *)arg;
 #ifdef CONFIG_METADATA
-  uint64_t time_of_last_metadata_progress_update = 0; // the assignment is to stop a compiler warning...
+  uint64_t time_of_last_metadata_progress_update =
+      0; // the assignment is to stop a compiler warning...
 #endif
   uint64_t previous_frames_played = 0; // initialised to avoid a "possibly uninitialised" warning
   uint64_t previous_raw_measurement_time =
@@ -1982,15 +1982,16 @@ void *player_thread_func(void *arg) {
 
   debug(3, "Output frame bytes is %d.", conn->output_bytes_per_frame);
 
-  conn->dac_buffer_queue_minimum_length = (uint64_t)(
-      config.audio_backend_buffer_interpolation_threshold_in_seconds * config.output_rate);
+  conn->dac_buffer_queue_minimum_length =
+      (uint64_t)(config.audio_backend_buffer_interpolation_threshold_in_seconds *
+                 config.output_rate);
   debug(3, "dac_buffer_queue_minimum_length is %" PRIu64 " frames.",
         conn->dac_buffer_queue_minimum_length);
 
   conn->session_corrections = 0;
   conn->connection_state_to_output = get_requested_connection_state_to_output();
 // this is about half a minute
-//#define trend_interval 3758
+// #define trend_interval 3758
 
 // this is about 8 seconds
 #define trend_interval 1003
@@ -2629,8 +2630,8 @@ void *player_thread_func(void *arg) {
             } else {
               current_delay = 0;
               if ((resp == sps_extra_code_output_stalled) &&
-                  (conn->unfixable_error_reported == 0)) {
-                conn->unfixable_error_reported = 1;
+                  (config.unfixable_error_reported == 0)) {
+                config.unfixable_error_reported = 1;
                 if (config.cmd_unfixable) {
                   warn("Connection %d: An unfixable error has been detected -- output device is "
                        "stalled. Executing the "
@@ -2780,7 +2781,8 @@ void *player_thread_func(void *arg) {
               send_ssnc_metadata('styp', "Classic", strlen("Classic"), 1);
 #endif
               if (config.statistics_requested)
-                inform("Connection %d: Playback started at frame %" PRId64 " -- Classic AirPlay (\"AirPlay 1\").",
+                inform("Connection %d: Playback started at frame %" PRId64
+                       " -- Classic AirPlay (\"AirPlay 1\").",
                        conn->connection_number, inframe->given_timestamp);
 #endif
             }
index 1c18567a97661e88390bd45f288218787c00941a..14e352ff578fd1fcf946858d9dc8203124e68d60 100644 (file)
--- a/player.h
+++ b/player.h
@@ -168,8 +168,7 @@ typedef struct {
   volatile int stop;
   volatile int running;
   volatile uint64_t watchdog_bark_time;
-  volatile int watchdog_barks;  // number of times the watchdog has timed out and done something
-  int unfixable_error_reported; // set when an unfixable error command has been executed.
+  volatile int watchdog_barks; // number of times the watchdog has timed out and done something
 
   uint64_t playstart;
   uint64_t connection_start_time; // the time the device is selected, which could be a long time
diff --git a/rtsp.c b/rtsp.c
index 02c6c9752af716df2cfb447240a5ed03cf935a39..ac3ce652686b9ca61edec2a1306ab4eb8ee8610b 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -37,6 +37,7 @@
 #include <net/if.h>
 #include <netdb.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>
 #include <poll.h>
 #include <pthread.h>
 #include <stdio.h>
@@ -47,7 +48,6 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <netinet/tcp.h>
 
 #include <sys/ioctl.h>
 
@@ -665,8 +665,8 @@ void *player_watchdog_thread_code(void *arg) {
             conn->stop = 1;
             pthread_cancel(conn->thread);
           } else if (conn->watchdog_barks == 3) {
-            if ((config.cmd_unfixable) && (conn->unfixable_error_reported == 0)) {
-              conn->unfixable_error_reported = 1;
+            if ((config.cmd_unfixable) && (config.unfixable_error_reported == 0)) {
+              config.unfixable_error_reported = 1;
               command_execute(config.cmd_unfixable, "unable_to_cancel_play_session", 1);
             } else {
               die("an unrecoverable error, \"unable_to_cancel_play_session\", has been detected.",
@@ -1223,10 +1223,10 @@ ssize_t timed_read_from_rtsp_connection(rtsp_conn_info *conn, uint64_t wait_time
     uint64_t time_to_wait_to = get_absolute_time_in_ns();
     ;
     time_to_wait_to = time_to_wait_to + wait_time;
-    
+
     int flags = 1;
     if (setsockopt(conn->fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags))) {
-      debug(1,"can't enable keepalive checking on the RTSP socket");
+      debug(1, "can't enable keepalive checking on the RTSP socket");
     }
 
     // remaining_time will be zero if wait_time is zero
@@ -1356,7 +1356,7 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
       // Note: the socket will be closed when the thread exits
       goto shutdown;
     }
-    
+
     // An ETIMEDOUT error usually means keepalive has failed.
 
     if (nread < 0) {
@@ -2070,7 +2070,7 @@ struct pairings {
   uint8_t public_key[32];
 
   struct pairings *next;
-} * pairings;
+} *pairings;
 
 static struct pairings *pairing_find(const char *device_id) {
   for (struct pairings *pairing = pairings; pairing; pairing = pairing->next) {
@@ -3165,7 +3165,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
           conn->connection_number, get_category_string(conn->airplay_stream_category));
     if (conn->airplay_stream_category == ptp_stream) {
       ptp_send_control_message_string("B"); // signify play is "B"eginning
-      
+
       // get stream[0]
       plist_t stream0 = plist_array_get_item(streams, 0);
 
@@ -5502,39 +5502,40 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
         if (getsockname(conn->fd, (struct sockaddr *)&conn->local, &size_of_reply) == 0) {
 
           // Thanks to https://holmeshe.me/network-essentials-setsockopt-SO_KEEPALIVE/ for this.
-  
-          // Turn on keepalive stuff -- wait for keepidle + (keepcnt * keepinttvl time) seconds before giving up
-          // An ETIMEOUT error is returned if the keepalive check fails
+
+          // Turn on keepalive stuff -- wait for keepidle + (keepcnt * keepinttvl time) seconds
+          // before giving up An ETIMEOUT error is returned if the keepalive check fails
 
           int keepAliveIdleTime = 10; // wait this many seconds before checking for a dropped client
-          int keepAliveCount = 5; // check this many times
-          int keepAliveInterval = 1; // wait this many seconds between checks
-          
+          int keepAliveCount = 5;     // check this many times
+          int keepAliveInterval = 1;  // wait this many seconds between checks
 
 #if defined COMPILE_FOR_BSD || defined COMPILE_FOR_OSX
-          #define SOL_OPTION IPPROTO_TCP
+#define SOL_OPTION IPPROTO_TCP
 #else
-          #define SOL_OPTION SOL_TCP
+#define SOL_OPTION SOL_TCP
 #endif
 
 #ifdef COMPILE_FOR_OSX
-          #define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPALIVE
+#define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPALIVE
 #else
-          #define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPIDLE
+#define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPIDLE
 #endif
-          
 
-          if (setsockopt(conn->fd, SOL_OPTION, KEEP_ALIVE_OR_IDLE_OPTION, (void *)&keepAliveIdleTime, sizeof(keepAliveIdleTime))) {
-            debug(1,"can't set the keepidle wait time");
+          if (setsockopt(conn->fd, SOL_OPTION, KEEP_ALIVE_OR_IDLE_OPTION,
+                         (void *)&keepAliveIdleTime, sizeof(keepAliveIdleTime))) {
+            debug(1, "can't set the keepidle wait time");
           }
 
-          if (setsockopt(conn->fd, SOL_OPTION, TCP_KEEPCNT, (void *)&keepAliveCount, sizeof(keepAliveCount))) {
-            debug(1,"can't set the keepidle missing count");
+          if (setsockopt(conn->fd, SOL_OPTION, TCP_KEEPCNT, (void *)&keepAliveCount,
+                         sizeof(keepAliveCount))) {
+            debug(1, "can't set the keepidle missing count");
           }
-          if (setsockopt(conn->fd, SOL_OPTION  , TCP_KEEPINTVL, (void *)&keepAliveInterval, sizeof(keepAliveInterval))) {
-            debug(1,"can't set the keepidle missing count interval");
+          if (setsockopt(conn->fd, SOL_OPTION, TCP_KEEPINTVL, (void *)&keepAliveInterval,
+                         sizeof(keepAliveInterval))) {
+            debug(1, "can't set the keepidle missing count interval");
           };
-       
+
           // initialise the connection info
           void *client_addr = NULL, *self_addr = NULL;
           conn->connection_ip_family = conn->local.SAFAMILY;