]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Start using get_play_lock and release_play_lock and enable them to turn on and off...
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Mon, 8 Dec 2025 09:50:54 +0000 (09:50 +0000)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Mon, 8 Dec 2025 09:50:54 +0000 (09:50 +0000)
ap2_event_receiver.c
rtsp.c

index c1053e33e908e3d118f074db795c808d500a7a1e..debf301bb16bee16488f41b603f3ea064e7a0291 100644 (file)
@@ -34,7 +34,7 @@
 
 void ap2_event_receiver_cleanup_handler(void *arg) {
   rtsp_conn_info *conn = (rtsp_conn_info *)arg;
-  debug(3, "Connection %d: AP2 Event Receiver Cleanup start.", conn->connection_number);
+  debug(1, "Connection %d: AP2 Event Receiver Cleanup start.", conn->connection_number);
   // only update these things if you're (still) the principal conn
 
 #ifdef CONFIG_METADATA
@@ -55,18 +55,24 @@ void ap2_event_receiver_cleanup_handler(void *arg) {
     free(conn->ap2_client_name);
     conn->ap2_client_name = NULL;
   }
+  /*
   pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed
   pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
+  if (principal_conn)
+    debug(1, "principal_conn: %d.", principal_conn->connection_number);
+  else
+    debug(1, "principal_conn: is NULL.");
   if (principal_conn == conn) {
     config.airplay_statusflags &= (0xffffffff - (1 << 11)); // DeviceSupportsRelay
     build_bonjour_strings(conn);
-    debug(3, "Connection %d: SETUP mdns_update on %s.", conn->connection_number,
+    debug(1, "Connection %d: SETUP mdns_update on %s.", conn->connection_number,
           get_category_string(conn->airplay_stream_category));
     mdns_update(NULL, secondary_txt_records);
     principal_conn = NULL;
   }
   pthread_cleanup_pop(1); // release the principal_conn lock
-  debug(2, "Connection %d: AP2 Event Receiver Cleanup exit.", conn->connection_number);
+  */
+  debug(1, "Connection %d: AP2 Event Receiver Cleanup exit.", conn->connection_number);
 }
 
 void *ap2_event_receiver(void *arg) {
@@ -77,6 +83,8 @@ void *ap2_event_receiver(void *arg) {
   structured_buffer *sbuf = sbuf_new(4096);
   if (sbuf != NULL) {
     pthread_cleanup_push(sbuf_cleanup, sbuf);
+    
+    /*
     // only update these things if you're (still) the principal conn
     pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed
     pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
@@ -89,6 +97,7 @@ void *ap2_event_receiver(void *arg) {
       mdns_update(NULL, secondary_txt_records);
     }
     pthread_cleanup_pop(1); // release the principal_conn lock
+    */
     pthread_cleanup_push(ap2_event_receiver_cleanup_handler, arg);
 
     // listen(conn->event_socket, 5); // this is now done in the handle_setup_2 code
@@ -178,7 +187,7 @@ void *ap2_event_receiver(void *arg) {
           debug(3, "Connection %d: Packet Received on Event Port with contents: \"%s\".",
                 conn->connection_number, packet);
         } else {
-          debug(2, "Connection %d: Event Port connection closed by client",
+          debug(1, "Connection %d: Event Port connection closed by client",
                 conn->connection_number);
           finished = 1;
         }
diff --git a/rtsp.c b/rtsp.c
index c8da16689d5731a275a456537d7de7aa24c23a0e..8d6a7a5d98c8ae2e41c0c237a133fce3dc0db2b6 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -398,8 +398,18 @@ void release_play_lock(rtsp_conn_info *conn) {
   // no need thread cancellation points in here
   pthread_rwlock_wrlock(&principal_conn_lock);
   if (principal_conn == conn) { // if we have the player
-    if (conn != NULL)
-      debug(2, "Connection %d: principal_conn released.", conn->connection_number);
+    if (conn != NULL) {
+#ifdef CONFIG_AIRPLAY_2
+      config.airplay_statusflags &= (0xffffffff - (1 << 11)); // DeviceSupportsRelay
+      if (conn->airplay_gid) {
+        free(conn->airplay_gid);
+        conn->airplay_gid = NULL; // stop using the client's GID as our GID. 
+      }
+      build_bonjour_strings(conn);
+      mdns_update(NULL, secondary_txt_records);
+#endif
+      debug(1,"Connection %d: %s released principal_conn.", conn->connection_number, get_category_string(conn->airplay_stream_category));
+    }
     principal_conn = NULL; // let it go
   }
   pthread_rwlock_unlock(&principal_conn_lock);
@@ -408,18 +418,20 @@ void release_play_lock(rtsp_conn_info *conn) {
 // stop the current principal_conn from playing if necessary and make conn the principal_conn.
 
 int get_play_lock(rtsp_conn_info *conn, int allow_session_interruption) {
+  debug(1,"Connection %d: %s get_play_lock.", conn->connection_number, get_category_string(conn->airplay_stream_category));
   int response = 0;
   pthread_rwlock_wrlock(&principal_conn_lock);
   pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
   if (principal_conn != NULL)
-    debug(2, "Connection %d: is requested to relinquish principal_conn.",
+    debug(1, "Connection %d: is requested to relinquish principal_conn.",
           principal_conn->connection_number);
   if (conn != NULL)
-    debug(2, "Connection %d: request to acquire principal_conn.", conn->connection_number);
+    debug(1, "Connection %d: request to acquire principal_conn.", conn->connection_number);
   // returns -1 if it failed, 0 if it succeeded and 1 if it succeeded but
   // interrupted an existing session
   if (principal_conn == NULL) {
     principal_conn = conn;
+    config.airplay_statusflags |= (1 << 11); // DeviceSupportsRelay
   } else if (principal_conn == conn) {
     if (conn != NULL)
       warn("Connection %d: request to re-acquire principal_conn!",
@@ -427,33 +439,32 @@ int get_play_lock(rtsp_conn_info *conn, int allow_session_interruption) {
   } else if (allow_session_interruption != 0) {
     rtsp_conn_info *previous_principal_conn = principal_conn;
     // important -- demote the principal conn before cancelling it
-
     if (principal_conn->fd > 0) {
       debug(2,
-            "Connection %d: get_play_lock forced termination in favour of connection %d. Closing "
+            "Connection %d: has acquired play_lock and is forcing termination of Connection %d. Closing "
             "RTSP connection socket %d: "
             "from %s:%u to self at "
             "%s:%u.",
-            principal_conn->connection_number, conn->connection_number, principal_conn->fd,
+            conn->connection_number, principal_conn->connection_number, principal_conn->fd,
             principal_conn->client_ip_string, principal_conn->client_rtsp_port,
             principal_conn->self_ip_string, principal_conn->self_rtsp_port);
       close(principal_conn->fd);
       // principal_conn->fd = 0;
     }
-    principal_conn = NULL;
-
-    pthread_cancel(previous_principal_conn->thread);
-    // the previous principal thread will block on the principal conn lock when exiting
-    // so it's important not to wait for it here, e.g. don't put in a pthread_join here.
-    // threads are garbage-collected later
+    principal_conn = conn; // make the conn the new principal_conn  
+    pthread_cancel(previous_principal_conn->thread);  // cancel the previous one...    
     usleep(1000000);       // don't know why this delay is needed.
-    principal_conn = conn; // make the conn the new principal_conn
+#ifdef CONFIG_AIRPLAY_2
+      config.airplay_statusflags |= (1 << 11); // DeviceSupportsRelay
+      // build_bonjour_strings(conn);
+      // mdns_update(NULL, secondary_txt_records);
+#endif
     response = 1;          // interrupted an existing session
   } else {
     response = -1; // can't get it...
   }
   if (principal_conn != NULL)
-    debug(3, "Connection %d has principal_conn.", principal_conn->connection_number);
+    debug(1,"Connection %d: %s has principal_conn.", conn->connection_number, get_category_string(conn->airplay_stream_category));
   pthread_cleanup_pop(1); // release the principal_conn lock
   return response;
 }
@@ -2511,6 +2522,9 @@ void handle_options(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *
                  "OPTIONS, POST, GET, PUT");
 }
 
+
+// TEARDOWN and TEARDOWN for AP2 look the same!
+
 void handle_teardown_2(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
                        rtsp_message *resp) {
 
@@ -2532,38 +2546,19 @@ void handle_teardown_2(rtsp_conn_info *conn, __attribute__((unused)) rtsp_messag
 
 void handle_teardown(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
                      rtsp_message *resp) {
-  debug(1, "Connection %d: TEARDOWN (Classic AirPlay)", conn->connection_number);
-  debug_log_rtsp_message(1, "TEARDOWN (Classic AirPlay) request", req);
+  debug(2, "Connection %d: TEARDOWN (Classic AirPlay)", conn->connection_number);
+  debug_log_rtsp_message(2, "TEARDOWN (Classic AirPlay) request", req);
+  
+  // most of the cleanup here is done by the exiting player_thread, if any, and by the event receiver if and when it exits.
   
   if (conn->player_thread) {
+    debug(1, "TEARDOWN is stopping a player...");
     player_stop(conn);                    // this nulls the player_thread and cancels the threads...
     activity_monitor_signify_activity(0); // inactive, and should be after command_stop()
   }
 
-  if (conn->dacp_active_remote != NULL) {
-    free(conn->dacp_active_remote);
-    conn->dacp_active_remote = NULL;
-  }
-  // only update these things if you're (still) the principal conn
-  pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed
-  pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
-  if (principal_conn == conn) {
-#ifdef CONFIG_AIRPLAY_2
-    config.airplay_statusflags &= (0xffffffff - (1 << 11)); // DeviceSupportsRelay
-    build_bonjour_strings(conn);
-    mdns_update(NULL, secondary_txt_records);
-#endif
-    principal_conn = NULL; // stop being principal_conn
-  }
-  pthread_cleanup_pop(1); // release the principal_conn lock
-  
-#ifdef CONFIG_FFMPEG
-  clear_decoding_chain(conn);
-#endif
   resp->respcode = 200;
   msg_add_header(resp, "Connection", "close");
-  debug(3, "TEARDOWN: successful termination of playing thread of RTSP conversation thread %d.",
-        conn->connection_number);
   // debug(1,"Bogus exit for valgrind -- remember to comment it out!.");
   // exit(EXIT_SUCCESS);
 }
@@ -2714,6 +2709,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
 
           // airplay 2 always allows interruption, so should never return -1
           if (get_play_lock(conn, 1) != -1) {
+             debug(1, "Connection %d: %s AP2 setup -- play lock acquired.", conn->connection_number, get_category_string(conn->airplay_stream_category));
 
 #ifdef CONFIG_METADATA
             send_ssnc_metadata('conn', conn->client_ip_string, strlen(conn->client_ip_string),
@@ -2880,6 +2876,13 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
               debug(1, "SETUP on Connection %d: PTP setup -- no timingPeerInfo plist.",
                     conn->connection_number);
             }
+            
+            // since the GID from the client has been acquired, update the airplay bonjour strings.
+            build_bonjour_strings(conn);
+            debug(1, "Connection %d: SETUP mdns_update on %s.", conn->connection_number,
+                  get_category_string(conn->airplay_stream_category));
+            mdns_update(NULL, secondary_txt_records);
+
 
 #ifdef CONFIG_METADATA
             check_and_send_plist_metadata(messagePlist, "name", 'snam');
@@ -4281,10 +4284,10 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
 }
 
 static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
-  debug(2, "Connection %d: ANNOUNCE", conn->connection_number);
+  debug(1, "Connection %d: ANNOUNCE", conn->connection_number);
   int get_play_status = get_play_lock(conn, config.allow_session_interruption);
   if (get_play_status != -1) {
-    debug(2, "Connection %d: ANNOUNCE has acquired play lock.", conn->connection_number);
+    debug(1, "Connection %d: ANNOUNCE has acquired play lock.", conn->connection_number);
 
     // now, if this new session did not break in, then it's okay to reset the next UDP ports
     // to the start of the range
@@ -4318,7 +4321,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
     pthread_rwlock_rdlock(&principal_conn_lock); // don't let the principal_conn be changed
     pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
     if (principal_conn == conn) {
-      config.airplay_statusflags |= 1 << 11; // DeviceSupportsRelay -- should this be on?
+      // config.airplay_statusflags |= 1 << 11; // DeviceSupportsRelay -- should this be on?
       build_bonjour_strings(conn);
       mdns_update(NULL, secondary_txt_records);
     }
@@ -4852,20 +4855,6 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState);
     debug(3, "Connection %d: %s rtsp_conversation_thread_func_cleanup_function called.",
           conn->connection_number, get_category_string(conn->airplay_stream_category));
-    
-    // only update these things if you're (still) the principal conn
-    pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed
-    pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
-    if (principal_conn == conn) {
-#ifdef CONFIG_AIRPLAY_2
-      config.airplay_statusflags &= (0xffffffff - (1 << 11)); // DeviceSupportsRelay
-      build_bonjour_strings(conn);
-      mdns_update(NULL, secondary_txt_records);
-#endif
-      principal_conn = NULL; // stop being principal_conn
-    }
-    pthread_cleanup_pop(1); // release the principal_conn lock
-
 
     if (conn->player_thread) {
       player_stop(conn); // this nulls the player_thread and cancels the threads...
@@ -4998,6 +4987,7 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
       debug(1, "Connection %d: error %d destroying flush_mutex.", conn->connection_number, rc);
     debug(3, "Connection %d: Closed.", conn->connection_number);
     conn->running = 0; // for the garbage collector
+    release_play_lock(conn);
     pthread_setcancelstate(oldState, NULL);
   }
 }