]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add quit commands to the MPRIS and native D-Bus command set. Not tested ecologically.
authorMike Brady <mikebrady@eircom.net>
Wed, 18 Jul 2018 14:32:07 +0000 (15:32 +0100)
committerMike Brady <mikebrady@eircom.net>
Wed, 18 Jul 2018 14:32:07 +0000 (15:32 +0100)
common.h
dbus-service.c
mpris-service.c
player.c
player.h
rtsp.c
shairport.c

index 86cfa1a16c6193b6705b83cc7f191c7384ba6f73..7d556b96b4debda0fcbc40777710f2cba19054ae 100644 (file)
--- a/common.h
+++ b/common.h
@@ -2,6 +2,7 @@
 #define _COMMON_H
 
 #include <libconfig.h>
+#include <pthread.h>
 #include <signal.h>
 #include <stdint.h>
 #include <sys/socket.h>
@@ -79,6 +80,7 @@ typedef struct {
   char *password;
   char *service_name; // the name for the shairport service, e.g. "Shairport Sync Version %v running
                       // on host %h"
+
 #ifdef CONFIG_PA
   char *pa_application_name; // the name under which Shairport Sync shows up as an "Application" in
                              // the Sound Preferences in most desktop Linuxes.
@@ -263,6 +265,9 @@ uint64_t fp_time_at_startup, fp_time_at_last_debug_message;
 long endianness;
 uint32_t uatoi(const char *nptr);
 
+// this is for allowing us to cancel the whole program
+pthread_t main_thread_id;
+
 shairport_cfg config;
 config_t config_file_stuff;
 
index b16b22da6ccb4dfc1146084c962bddfdf3d927d5..e8d50c2f574f53902ee69fe20f948613e32a7f52 100644 (file)
@@ -545,9 +545,13 @@ gboolean notify_loop_status_callback(ShairportSyncAdvancedRemoteControl *skeleto
 }
 
 static gboolean on_handle_quit(ShairportSync *skeleton, GDBusMethodInvocation *invocation,
-                                         __attribute__((unused)) const gchar *command,
-                                         __attribute__((unused)) gpointer user_data) {
+                               __attribute__((unused)) const gchar *command,
+                               __attribute__((unused)) gpointer user_data) {
   debug(1, "quit requested (native interface)");
+  if (main_thread_id)
+    debug(1, "Cancelling main thread results in %d.", pthread_cancel(main_thread_id));
+  else
+    debug(1, "Main thread ID is NULL.");
   shairport_sync_complete_quit(skeleton, invocation);
   return TRUE;
 }
@@ -597,8 +601,7 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
   g_signal_connect(shairportSyncSkeleton, "notify::loudness-threshold",
                    G_CALLBACK(notify_loudness_threshold_callback), NULL);
 
-  g_signal_connect(shairportSyncSkeleton, "handle-quit",
-                   G_CALLBACK(on_handle_quit), NULL);
+  g_signal_connect(shairportSyncSkeleton, "handle-quit", G_CALLBACK(on_handle_quit), NULL);
 
   g_signal_connect(shairportSyncSkeleton, "handle-remote-command",
                    G_CALLBACK(on_handle_remote_command), NULL);
index 982623e11d64a184d7c2949744533611770f29b6..668d776e2e0cc4d3e2416a52ff3dd6db90e1dee2 100644 (file)
@@ -185,7 +185,8 @@ void mpris_metadata_watcher(struct metadata_bundle *argc, __attribute__((unused)
 
 static gboolean on_handle_quit(MediaPlayer2 *skeleton, GDBusMethodInvocation *invocation,
                                __attribute__((unused)) gpointer user_data) {
-  debug(1,"quit requested (MPRIS interface).");
+  debug(1, "quit requested (MPRIS interface).");
+  pthread_cancel(main_thread_id);
   media_player2_complete_quit(skeleton, invocation);
   return TRUE;
 }
index ff1150648da29a639cd5a9fc4cde857e997b783b..ff0f73921d980b61ef69ae1d3b88bd710272aaf6 100644 (file)
--- a/player.c
+++ b/player.c
@@ -785,12 +785,12 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
   int notified_buffer_empty = 0; // diagnostic only
 
   debug_mutex_lock(&conn->ab_mutex, 30000, 1);
-  
-  
+
   int wait;
   long dac_delay = 0; // long because alsa returns a long
-  
-  pthread_cleanup_push(buffer_get_frame_cleanup_handler, (void *)conn); // undo what's been done so far
+
+  pthread_cleanup_push(buffer_get_frame_cleanup_handler,
+                       (void *)conn); // undo what's been done so far
   do {
     // get the time
     local_time_now = get_absolute_time_in_fp(); // type okay
@@ -830,7 +830,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
     if (conn->flush_requested == 1) {
       if (config.output->flush)
         config.output->flush(); // no cancellation points
-      ab_resync(conn); // no cancellation points
+      ab_resync(conn);          // no cancellation points
       conn->first_packet_timestamp = 0;
       conn->first_packet_time_to_play = 0;
       conn->time_since_play_started = 0;
@@ -1215,7 +1215,8 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
       time_of_wakeup.tv_sec = sec;
       time_of_wakeup.tv_nsec = nsec;
       //      pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex, &time_of_wakeup);
-      int rc = pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex, &time_of_wakeup);  // this is a pthread cancellation point
+      int rc = pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex,
+                                      &time_of_wakeup); // this is a pthread cancellation point
       if (rc != 0)
         debug(3, "pthread_cond_timedwait returned error code %d.", rc);
 #endif
@@ -1231,17 +1232,17 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
   } while (wait);
 
   // seq_t read = conn->ab_read;
-    if (!curframe->ready) {
-      // debug(1, "Supplying a silent frame for frame %u", read);
-      conn->missing_packets++;
-      curframe->timestamp = 0; // indicate a silent frame should be substituted
-    }
-    curframe->ready = 0;
-    curframe->resend_level = 0;
-    conn->ab_read = SUCCESSOR(conn->ab_read);
-  
-    pthread_cleanup_pop(1);
-    return curframe;
+  if (!curframe->ready) {
+    // debug(1, "Supplying a silent frame for frame %u", read);
+    conn->missing_packets++;
+    curframe->timestamp = 0; // indicate a silent frame should be substituted
+  }
+  curframe->ready = 0;
+  curframe->resend_level = 0;
+  conn->ab_read = SUCCESSOR(conn->ab_read);
+
+  pthread_cleanup_pop(1);
+  return curframe;
 }
 
 static inline short shortmean(short a, short b) {
@@ -1435,7 +1436,8 @@ void player_thread_cleanup_handler(void *arg) {
 
 #ifdef HAVE_DACP_CLIENT
 
-  relinquish_dacp_server_information(conn); // say it doesn't belong to this conversation thread any more...
+  relinquish_dacp_server_information(
+      conn); // say it doesn't belong to this conversation thread any more...
 
 #else
   // stop watching for DACP port number stuff
@@ -1468,11 +1470,11 @@ void player_thread_cleanup_handler(void *arg) {
   if (conn->outbuf) {
     free(conn->outbuf);
     conn->outbuf = NULL;
-  }  
+  }
   if (conn->sbuf) {
     free(conn->sbuf);
     conn->sbuf = NULL;
-  }  
+  }
   if (conn->tbuf) {
     free(conn->tbuf);
     conn->tbuf = NULL;
@@ -1647,15 +1649,17 @@ void *player_thread_func(void *arg) {
   // if ((input_rate!=config.output_rate) || (input_bit_depth!=output_bit_depth)) {
   // debug(1,"Define tbuf of length
   // %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change));
-  conn->tbuf = malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
-                                       conn->max_frame_size_change));
+  conn->tbuf =
+      malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
+                                    conn->max_frame_size_change));
   if (conn->tbuf == NULL)
     die("Failed to allocate memory for the transition buffer.");
 
   // initialise this, because soxr stuffing might be chosen later
 
-  conn->sbuf = malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
-                                       conn->max_frame_size_change));
+  conn->sbuf =
+      malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
+                                    conn->max_frame_size_change));
   if (conn->sbuf == NULL)
     die("Failed to allocate memory for the sbuf buffer.");
 
@@ -1685,7 +1689,7 @@ void *player_thread_func(void *arg) {
   if (conn->dapo_private_storage)
     debug(1, "DACP monitor already initialised?");
   else
-  // this does not have pthread cancellation points in it (assuming avahi doesn't)
+    // this does not have pthread cancellation points in it (assuming avahi doesn't)
     conn->dapo_private_storage = mdns_dacp_monitor(conn->dacp_id); // ??
 #endif
 
@@ -1734,12 +1738,12 @@ void *player_thread_func(void *arg) {
   debug(3, "Set initial volume to %f.", config.airplay_volume);
   player_volume(config.airplay_volume, conn); // ??
   int64_t frames_to_drop = 0;
-  
-   // create and start the timing, control and audio receiver threads
+
+  // create and start the timing, control and audio receiver threads
   pthread_create(&conn->rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)conn);
   pthread_create(&conn->rtp_control_thread, NULL, &rtp_control_receiver, (void *)conn);
   pthread_create(&conn->rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)conn);
-   
+
   pthread_cleanup_push(player_thread_cleanup_handler, arg); // undo what's been done so far
 
   // debug(1, "Play begin");
@@ -2144,9 +2148,9 @@ void *player_thread_func(void *arg) {
               case ST_soxr:
 #ifdef HAVE_LIBSOXR
                 //                if (amount_to_stuff) debug(1,"Soxr stuff...");
-                play_samples = stuff_buffer_soxr_32((int32_t *)conn->tbuf, (int32_t *)conn->sbuf, inbuflength,
-                                                    config.output_format, conn->outbuf, amount_to_stuff,
-                                                    enable_dither, conn);
+                play_samples = stuff_buffer_soxr_32((int32_t *)conn->tbuf, (int32_t *)conn->sbuf,
+                                                    inbuflength, config.output_format, conn->outbuf,
+                                                    amount_to_stuff, enable_dither, conn);
 #endif
                 break;
               }
@@ -2201,8 +2205,9 @@ void *player_thread_func(void *arg) {
           } else {
             // if there is no delay procedure, or it's not working or not allowed, there can be no
             // synchronising
-            play_samples = stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format,
-                                                 conn->outbuf, 0, enable_dither, conn);
+            play_samples =
+                stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format,
+                                      conn->outbuf, 0, enable_dither, conn);
             if (conn->outbuf == NULL)
               debug(1, "NULL outbuf to play -- skipping it.");
             else
@@ -2275,28 +2280,9 @@ void *player_thread_func(void *arg) {
             if (at_least_one_frame_seen) {
               if ((config.output->delay)) {
                 if (config.no_sync == 0) {
-                  inform(
-                      "|%*.1f," /* Sync error in milliseconds */
-                      "%*.1f,"  /* net correction in ppm */
-                      "%*.1f,"  /* corrections in ppm */
-                      "%*d,"    /* total packets */
-                      "%*llu,"  /* missing packets */
-                      "%*llu,"  /* late packets */
-                      "%*llu,"  /* too late packets */
-                      "%*llu,"  /* resend requests */
-                      "%*lli,"  /* min DAC queue size */
-                      "%*d,"    /* min buffer occupancy */
-                      "%*d",    /* max buffer occupancy */
-                      10,
-                      1000 * moving_average_sync_error / config.output_rate,
-                      10, moving_average_correction * 1000000 / (352 * conn->output_sample_ratio),
-                      10, moving_average_insertions_plus_deletions * 1000000 /
-                              (352 * conn->output_sample_ratio),
-                      12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
-                      conn->too_late_packets, 7, conn->resend_requests, 7, minimum_dac_queue_size,
-                      5, minimum_buffer_occupancy, 5, maximum_buffer_occupancy);
-                } else {
                   inform("|%*.1f," /* Sync error in milliseconds */
+                         "%*.1f,"  /* net correction in ppm */
+                         "%*.1f,"  /* corrections in ppm */
                          "%*d,"    /* total packets */
                          "%*llu,"  /* missing packets */
                          "%*llu,"  /* late packets */
@@ -2306,11 +2292,29 @@ void *player_thread_func(void *arg) {
                          "%*d,"    /* min buffer occupancy */
                          "%*d",    /* max buffer occupancy */
                          10,
-                         1000 * moving_average_sync_error / config.output_rate,
+                         1000 * moving_average_sync_error / config.output_rate, 10,
+                         moving_average_correction * 1000000 / (352 * conn->output_sample_ratio),
+                         10, moving_average_insertions_plus_deletions * 1000000 /
+                                 (352 * conn->output_sample_ratio),
                          12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
                          conn->too_late_packets, 7, conn->resend_requests, 7,
                          minimum_dac_queue_size, 5, minimum_buffer_occupancy, 5,
                          maximum_buffer_occupancy);
+                } else {
+                  inform("|%*.1f," /* Sync error in milliseconds */
+                         "%*d,"    /* total packets */
+                         "%*llu,"  /* missing packets */
+                         "%*llu,"  /* late packets */
+                         "%*llu,"  /* too late packets */
+                         "%*llu,"  /* resend requests */
+                         "%*lli,"  /* min DAC queue size */
+                         "%*d,"    /* min buffer occupancy */
+                         "%*d",    /* max buffer occupancy */
+                         10,
+                         1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7,
+                         conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7,
+                         conn->resend_requests, 7, minimum_dac_queue_size, 5,
+                         minimum_buffer_occupancy, 5, maximum_buffer_occupancy);
                 }
               } else {
                 inform("|%*.1f," /* Sync error in milliseconds */
@@ -2322,10 +2326,10 @@ void *player_thread_func(void *arg) {
                        "%*d,"    /* min buffer occupancy */
                        "%*d",    /* max buffer occupancy */
                        10,
-                       1000 * moving_average_sync_error / config.output_rate,
-                       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);
+                       1000 * moving_average_sync_error / config.output_rate, 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);
               }
             } else {
               inform("No frames received in the last sampling interval.");
@@ -2339,73 +2343,74 @@ void *player_thread_func(void *arg) {
       }
     }
   }
-  
-  debug(1,"This should never be called.");
-
-/* all done in the cleanup...
-
-  debug(3, "Connection %d: player thread main loop exit.", conn->connection_number);
-
-  if (config.statistics_requested) {
-    int rawSeconds = (int)difftime(time(NULL), conn->playstart);
-    int elapsedHours = rawSeconds / 3600;
-    int elapsedMin = (rawSeconds / 60) % 60;
-    int elapsedSec = rawSeconds % 60;
-    inform("Playback Stopped. Total playing time %02d:%02d:%02d.", elapsedHours, elapsedMin,
-           elapsedSec);
-  }
-   
-#ifdef HAVE_DACP_CLIENT
 
-  relinquish_dacp_server_information(conn); // say it doesn't belong to this conversation thread any more...
+  debug(1, "This should never be called.");
 
-#else
-  // stop watching for DACP port number stuff
-  // this is only used for compatability, if dacp stuff isn't enabled.
-  if (conn->dapo_private_storage) {
-    mdns_dacp_dont_monitor(conn->dapo_private_storage);
-    conn->dapo_private_storage = NULL;
-  } else {
-    debug(2, "DACP Monitor already stopped");
-  }
-#endif
+  /* all done in the cleanup...
 
-  debug(2, "Cancelling timing, control and audio threads...");
-  debug(2, "Cancel timing thread.");
-  pthread_cancel(rtp_timing_thread);
-  debug(2, "Join timing thread.");
-  pthread_join(rtp_timing_thread, NULL);
-  debug(2, "Timing thread terminated.");
-  debug(2, "Cancel control thread.");
-  pthread_cancel(rtp_control_thread);
-  debug(2, "Join control thread.");
-  pthread_join(rtp_control_thread, NULL);
-  debug(2, "Control thread terminated.");
-  debug(2, "Cancel audio thread.");
-  pthread_cancel(rtp_audio_thread);
-  debug(2, "Join audio thread.");
-  pthread_join(rtp_audio_thread, NULL);
-  debug(2, "Audio thread terminated.");
-  clear_reference_timestamp(conn);
-  conn->rtp_running = 0;
+    debug(3, "Connection %d: player thread main loop exit.", conn->connection_number);
 
-  debug(3, "Connection %d: stopping output device.", conn->connection_number);
+    if (config.statistics_requested) {
+      int rawSeconds = (int)difftime(time(NULL), conn->playstart);
+      int elapsedHours = rawSeconds / 3600;
+      int elapsedMin = (rawSeconds / 60) % 60;
+      int elapsedSec = rawSeconds % 60;
+      inform("Playback Stopped. Total playing time %02d:%02d:%02d.", elapsedHours, elapsedMin,
+             elapsedSec);
+    }
 
-  if (config.output->stop)
-    config.output->stop();
+  #ifdef HAVE_DACP_CLIENT
 
-  debug(2, "Freeing audio buffers and decoders.");
+    relinquish_dacp_server_information(conn); // say it doesn't belong to this conversation thread
+  any more...
 
-  free_audio_buffers(conn);
-  terminate_decoders(conn);
-  debug(2, "Connection %d: player thread terminated.", conn->connection_number);
-  if (outbuf)
-    free(outbuf);
-  if (tbuf)
-    free(tbuf);
-  if (sbuf)
-    free(sbuf);
-  */
+  #else
+    // stop watching for DACP port number stuff
+    // this is only used for compatability, if dacp stuff isn't enabled.
+    if (conn->dapo_private_storage) {
+      mdns_dacp_dont_monitor(conn->dapo_private_storage);
+      conn->dapo_private_storage = NULL;
+    } else {
+      debug(2, "DACP Monitor already stopped");
+    }
+  #endif
+
+    debug(2, "Cancelling timing, control and audio threads...");
+    debug(2, "Cancel timing thread.");
+    pthread_cancel(rtp_timing_thread);
+    debug(2, "Join timing thread.");
+    pthread_join(rtp_timing_thread, NULL);
+    debug(2, "Timing thread terminated.");
+    debug(2, "Cancel control thread.");
+    pthread_cancel(rtp_control_thread);
+    debug(2, "Join control thread.");
+    pthread_join(rtp_control_thread, NULL);
+    debug(2, "Control thread terminated.");
+    debug(2, "Cancel audio thread.");
+    pthread_cancel(rtp_audio_thread);
+    debug(2, "Join audio thread.");
+    pthread_join(rtp_audio_thread, NULL);
+    debug(2, "Audio thread terminated.");
+    clear_reference_timestamp(conn);
+    conn->rtp_running = 0;
+
+    debug(3, "Connection %d: stopping output device.", conn->connection_number);
+
+    if (config.output->stop)
+      config.output->stop();
+
+    debug(2, "Freeing audio buffers and decoders.");
+
+    free_audio_buffers(conn);
+    terminate_decoders(conn);
+    debug(2, "Connection %d: player thread terminated.", conn->connection_number);
+    if (outbuf)
+      free(outbuf);
+    if (tbuf)
+      free(tbuf);
+    if (sbuf)
+      free(sbuf);
+    */
   pthread_cleanup_pop(1);
   pthread_exit(NULL);
 }
@@ -2413,7 +2418,8 @@ void *player_thread_func(void *arg) {
 // takes the volume as specified by the airplay protocol
 void player_volume_without_notification(double airplay_volume, rtsp_conn_info *conn) {
 
-  // no cancellation points here if we assume that the mute call to the back end has no cancellation points
+  // no cancellation points here if we assume that the mute call to the back end has no cancellation
+  // points
 
   // The volume ranges -144.0 (mute) or -30 -- 0. See
   // http://git.zx2c4.com/Airtunes2/about/#setting-volume
@@ -2578,9 +2584,9 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
     if (config.ignore_volume_control == 1)
       scaled_attenuation = max_db;
     else if (config.volume_control_profile == VCP_standard)
-      scaled_attenuation = vol2attn(airplay_volume, max_db, min_db); // no cancellation points 
+      scaled_attenuation = vol2attn(airplay_volume, max_db, min_db); // no cancellation points
     else if (config.volume_control_profile == VCP_flat)
-      scaled_attenuation = flat_vol2attn(airplay_volume, max_db, min_db); // no cancellation points 
+      scaled_attenuation = flat_vol2attn(airplay_volume, max_db, min_db); // no cancellation points
     else
       debug(1, "Unrecognised volume control profile");
 
@@ -2615,7 +2621,7 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
   // %f",software_attenuation,temp_fix_volume,airplay_volume);
 
   conn->fix_volume = temp_fix_volume;
-  memory_barrier(); // no cancellation points 
+  memory_barrier(); // no cancellation points
 
   if (config.loudness)
     loudness_set_volume(software_attenuation / 100);
index 295b0ccd132bdf5f6d08d4b58a475ea58f6322b1..99dcecb89eece5d8a02b64d759169cb0c88688c9 100644 (file)
--- a/player.h
+++ b/player.h
@@ -74,9 +74,9 @@ typedef struct {
                            // otherwise
   int64_t maximum_latency; // set if an a=max-latency: line appears in the ANNOUNCE message; zero
                            // otherwise
-  
+
   int fd;
-  int authorized; // set if a password is required and has been supplied
+  int authorized;   // set if a password is required and has been supplied
   char *auth_nonce; // the session nonce, if needed
   stream_cfg stream;
   SOCKADDR remote, local;
diff --git a/rtsp.c b/rtsp.c
index 5b5a34288f1f392cbe5ece6f622176589242ea87..2c0560167ce63e3a6ddb882b1b2b7ef0c04e2e69 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -1889,7 +1889,7 @@ authenticate:
 }
 
 void rtsp_conversation_thread_cleanup_function(void *arg) {
-  debug(1,"rtsp_conversation_thread_func_cleanup_function called.");
+  debug(1, "rtsp_conversation_thread_func_cleanup_function called.");
   rtsp_conn_info *conn = (rtsp_conn_info *)arg;
   if (conn->fd > 0)
     close(conn->fd);
@@ -1923,10 +1923,10 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
   rc = pthread_mutex_destroy(&conn->flush_mutex);
   if (rc)
     debug(1, "Connection %d: error %d destroying flush_mutex.", conn->connection_number, rc);
- }
+}
 
 void msg_cleanup_function(void *arg) {
-  debug(1,"msg_cleanup_function called.");
+  debug(1, "msg_cleanup_function called.");
   msg_free((rtsp_message *)arg);
 }
 
@@ -1961,14 +1961,14 @@ static void *rtsp_conversation_thread_func(void *pconn) {
   int rtsp_read_request_attempt_count = 1; // 1 means exit immediately
   rtsp_message *req, *resp;
 
-  pthread_cleanup_push(rtsp_conversation_thread_cleanup_function,(void *)conn);
+  pthread_cleanup_push(rtsp_conversation_thread_cleanup_function, (void *)conn);
   while (conn->stop == 0) {
     int debug_level = 3; // for printing the request and response
-    reply = rtsp_read_request(conn,&req);
+    reply = rtsp_read_request(conn, &req);
     if (reply == rtsp_read_request_response_ok) {
-      pthread_cleanup_push(msg_cleanup_function,(void*)req);
+      pthread_cleanup_push(msg_cleanup_function, (void *)req);
       resp = msg_init();
-      pthread_cleanup_push(msg_cleanup_function,(void*)resp);
+      pthread_cleanup_push(msg_cleanup_function, (void *)resp);
       resp->respcode = 400;
 
       if (strcmp(req->method, "OPTIONS") !=
@@ -2176,6 +2176,7 @@ void rtsp_listen_loop(void) {
   int acceptfd;
   struct timeval tv;
   do {
+    pthread_testcancel();
     tv.tv_sec = 60;
     tv.tv_usec = 0;
 
index 925211075e1dda7c12581c7dc4852f4b849cdd51..a2a049d9282f95bde24f129fa9d46a9e7053d871 100644 (file)
 #include <glib.h>
 #endif
 
+#include "common.h"
+#include "mdns.h"
+#include "rtp.h"
+#include "rtsp.h"
+
 #if defined(HAVE_DACP_CLIENT)
 #include "dacp.h"
 #endif
 #include "mpris-service.h"
 #endif
 
-#include "common.h"
-#include "mdns.h"
-#include "rtp.h"
-#include "rtsp.h"
-
 #include <libdaemon/dexec.h>
 #include <libdaemon/dfork.h>
 #include <libdaemon/dlog.h>
@@ -1131,7 +1131,7 @@ const char *pid_file_proc(void) {
 }
 
 void exit_function() {
-  // debug(1, "exit function called...");
+  debug(1, "exit function called...");
   if (config.cfg)
     config_destroy(config.cfg);
   if (config.appName)
@@ -1139,7 +1139,19 @@ void exit_function() {
   // probably should be freeing malloc'ed memory here, including strdup-created strings...
 }
 
+void main_cleanup_handler(__attribute__((unused)) void *arg) {
+
+  debug(1, "main cleanup handler called.");
+  shairport_shutdown();
+  daemon_log(LOG_NOTICE, "Unexpected exit...");
+  daemon_retval_send(0);
+  daemon_pid_file_remove();
+  daemon_signal_done();
+  exit(0);
+}
+
 int main(int argc, char **argv) {
+  memset((void *)&main_thread_id, 0, sizeof(main_thread_id));
   fp_time_at_startup = get_absolute_time_in_fp();
   fp_time_at_last_debug_message = fp_time_at_startup;
   //  debug(1,"startup");
@@ -1362,10 +1374,11 @@ int main(int argc, char **argv) {
       /* Close FDs */
       if (daemon_close_all(-1) < 0) {
         daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
-
         /* Send the error condition to the parent process */
         daemon_retval_send(1);
-        goto finish;
+
+        daemon_signal_done();
+        return 0;
       }
 
       /* Create the PID file if required */
@@ -1376,12 +1389,16 @@ int main(int argc, char **argv) {
         if ((result != 0) && (result != -EEXIST)) {
           // error creating or accessing the PID file directory
           daemon_retval_send(3);
-          goto finish;
+
+          daemon_signal_done();
+          return 0;
         }
         if (daemon_pid_file_create() < 0) {
           daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
+
           daemon_retval_send(2);
-          goto finish;
+          daemon_signal_done();
+          return 0;
         }
       }
 
@@ -1391,11 +1408,22 @@ int main(int argc, char **argv) {
     /* end libdaemon stuff */
   }
 
+  // int old_cancel_state = 0;
+  // pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+  // pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state);
+  main_thread_id = pthread_self();
+  if (main_thread_id)
+    debug(1, "Main thread ID set up.");
+  else
+    debug(1, "Main thread is set up to be NULL!");
+
   signal_setup();
 
   // make sure the program can create files that group and world can read
   umask(S_IWGRP | S_IWOTH);
 
+  pthread_cleanup_push(main_cleanup_handler, NULL);
+
   config.output = audio_get_output(config.output_name);
   if (!config.output) {
     audio_ls_outputs();
@@ -1587,10 +1615,11 @@ int main(int argc, char **argv) {
   rtsp_listen_loop();
 
   // should not reach this...
-  shairport_shutdown();
-finish:
-  daemon_log(LOG_NOTICE, "Unexpected exit...");
-  daemon_retval_send(255);
-  daemon_pid_file_remove();
-  return 1;
+  // shairport_shutdown();
+  // daemon_log(LOG_NOTICE, "Unexpected exit...");
+  // daemon_retval_send(0);
+  // daemon_pid_file_remove();
+  pthread_cleanup_pop(1);
+  debug(1, "Odd exit point");
+  pthread_exit(NULL);
 }