]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add a new D-Bus method called "DropSession" to forcibly terminate the current play...
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Sun, 7 Aug 2022 09:02:56 +0000 (10:02 +0100)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Sun, 7 Aug 2022 09:02:56 +0000 (10:02 +0100)
dbus-service.c
org.gnome.ShairportSync.xml
rtsp.c
rtsp.h

index e51330bfd882069c23828e66226a278f26fe4583..c993223a30c20fa537ccdfcaa74a54b23e7c93a4 100644 (file)
@@ -807,6 +807,16 @@ static gboolean on_handle_remote_command(ShairportSync *skeleton, GDBusMethodInv
   return TRUE;
 }
 
+static gboolean on_handle_drop_session(ShairportSync *skeleton,
+                                       GDBusMethodInvocation *invocation,
+                                       __attribute__((unused)) gpointer user_data) {
+  if (playing_conn != NULL)
+    debug(1, ">> stopping current play session");
+  get_play_lock(NULL, 1); // stop any current session and don't replace it
+  shairport_sync_complete_drop_session(skeleton, invocation);
+  return TRUE;
+}
+
 static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name,
                                   __attribute__((unused)) gpointer user_data) {
 
@@ -862,6 +872,9 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
   g_signal_connect(shairportSyncSkeleton, "handle-remote-command",
                    G_CALLBACK(on_handle_remote_command), NULL);
 
+  g_signal_connect(shairportSyncSkeleton, "handle-drop-session",
+                   G_CALLBACK(on_handle_drop_session), NULL);
+
   g_signal_connect(shairportSyncDiagnosticsSkeleton, "notify::verbosity",
                    G_CALLBACK(notify_verbosity_callback), NULL);
 
index efa00fd00e0b87e3c2d57b5db4531c04bf754c5a..1051bab618de47974712ce076dc7303795355a2a 100644 (file)
@@ -12,6 +12,7 @@
     <property name="ConvolutionImpulseResponseFile" type="s" access="readwrite" />
     <property name="DriftTolerance" type="d" access="readwrite" />
     <property name='Volume' type='d' access='readwrite'/>
+    <method name="DropSession"/>
     <method name="RemoteCommand">
       <arg name="command" type="s" direction="in" />
       <arg name="reply" type="i" direction="out" />
diff --git a/rtsp.c b/rtsp.c
index 2a9d8aae47dcaba8cf987ba86a92f13b360c81cb..de09541290657f33bcfcca6217dce537eb747461 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -542,19 +542,30 @@ void release_hold_on_play_lock(__attribute__((unused)) rtsp_conn_info *conn) {
 
 // make conn no longer the playing_conn
 void release_play_lock(rtsp_conn_info *conn) {
-  debug(2, "Connection %d: release play lock.", conn->connection_number);
+  if (conn != NULL)
+    debug(2, "Connection %d: release play lock.", conn->connection_number);
+  else
+    debug(2, "Release play lock.");
   lock_player();
   if (playing_conn == conn) { // if we have the player
+    if (conn != NULL)
+      debug(2, "Connection %d: play lock released.", conn->connection_number);
+    else
+      debug(2, "Play lock released.");
     playing_conn = NULL;      // let it go
-    debug(2, "Connection %d: release play lock.", conn->connection_number);
   }
   unlock_player();
 }
 
 
-// make conn the playing_conn, 
-int get_play_lock(rtsp_conn_info *conn) {
-  debug(2, "Connection %d: request play lock.", conn->connection_number);
+// make conn the playing_conn, and kill the current session if permitted
+int get_play_lock(rtsp_conn_info *conn, int allow_session_interruption) {
+  if (conn != NULL)
+    debug(2, "Connection %d: request play lock.", conn->connection_number);
+  else if (playing_conn != NULL)
+    debug(2, "Connection %d: request release.", playing_conn->connection_number);
+  else
+    debug(2, "Request release of non-existent player.");
   // returns -1 if it failed, 0 if it succeeded and 1 if it succeeded but
   // interrupted an existing session
   int response = 0;
@@ -572,19 +583,14 @@ int get_play_lock(rtsp_conn_info *conn) {
     have_the_player = 1;
   } else if (playing_conn == conn) {
     have_the_player = 1;
-    warn("Duplicate attempt to acquire the player by the same connection, by the look of it!");
+    if (conn != NULL)
+      warn("Duplicate attempt to acquire the player by the same connection, by the look of it!");
   } else if (playing_conn->stop) {
     debug(1, "Connection %d: Waiting for Connection %d to stop playing.", conn->connection_number,
           playing_conn->connection_number);
     should_wait = 1;
-#ifdef CONFIG_AIRPLAY_2
-  } else { // ignore the allow_session_interruption in AirPlay 2 -- it is always permissible, it
-           // seems
-#else
-  } else if (config.allow_session_interruption == 1) {
-#endif
-    debug(2, "Connection %d: Asking Connection %d to stop playing.", conn->connection_number,
-          playing_conn->connection_number);
+  } else if (allow_session_interruption != 0) {
+    debug(2, "Asking Connection %d to stop playing.", playing_conn->connection_number);
     playing_conn->stop = 1;
     interrupting_current_session = 1;
     should_wait = 1;
@@ -608,18 +614,23 @@ int get_play_lock(rtsp_conn_info *conn) {
         time_remaining -= 100000;
       }
     }
-
     if ((have_the_player == 1) && (interrupting_current_session == 1)) {
-      debug(2, "Connection %d: Got player lock", conn->connection_number);
+      if (conn != NULL)
+        debug(2, "Connection %d: Got player lock", conn->connection_number);
+      else
+        debug(2, "Player released.");
       response = 1;
     } else {
-      debug(1, "Connection %d: failed to get player lock after waiting.", conn->connection_number);
+      debug(2, "Connection %d: failed to get player lock after waiting.", conn->connection_number);
       response = -1;
     }
   }
 
   if ((have_the_player == 1) && (interrupting_current_session == 0)) {
-    debug(2, "Connection %d: Got player lock.", conn->connection_number);
+    if (conn != NULL)
+      debug(2, "Connection %d: Got player lock.", conn->connection_number);
+    else
+      debug(2, "Player released.");      
     response = 0;
   }
   return response;
@@ -2609,7 +2620,7 @@ void handle_teardown_2(rtsp_conn_info *conn, __attribute__((unused)) rtsp_messag
     } else {
       teardown_phase_one(conn); // try to do phase one anyway
       teardown_phase_two(conn);
-      debug(2, "Connection %d: TEARDOWN phase two complete", conn->connection_number);
+      debug(1, "Connection %d: TEARDOWN phase two complete", conn->connection_number);
     }
     //} else {
     //  warn("Connection %d TEARDOWN received without having the player (no ANNOUNCE?)",
@@ -2751,7 +2762,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
           send_ssnc_metadata('conn', conn->client_ip_string, strlen(conn->client_ip_string),
                              1); // before disconnecting an existing play
 #endif
-          get_play_lock(conn);
+          get_play_lock(conn, 1); // airplay 2 always allows interruption
 #ifdef CONFIG_METADATA
           send_ssnc_metadata('clip', conn->client_ip_string, strlen(conn->client_ip_string), 1);
           send_ssnc_metadata('svip', conn->self_ip_string, strlen(conn->self_ip_string), 1);
@@ -4269,7 +4280,7 @@ 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(3, "Connection %d: ANNOUNCE", conn->connection_number);
-  int get_play_status = get_play_lock(conn);
+  int get_play_status = get_play_lock(conn, config.allow_session_interruption);
   if (get_play_status != -1) {
     debug(3, "Connection %d: ANNOUNCE has acquired play lock.", conn->connection_number);
 
diff --git a/rtsp.h b/rtsp.h
index b12c07ea86f2bd4252d0e7ca2af781766672d8cf..0725f6642657bfab623b612e34ff888eb7f91d0f 100644 (file)
--- a/rtsp.h
+++ b/rtsp.h
@@ -11,6 +11,9 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg);
 void lock_player();
 void unlock_player();
 
+// this can be used to forcibly stop a play session
+int get_play_lock(rtsp_conn_info *conn, int allow_session_interruption);
+
 // initialise and completely delete the metadata stuff
 
 void metadata_init(void);