]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add more basic remote control stuff, but SPS gets confused about who it can control.
authorMike Brady <mikebrady@eircom.net>
Sun, 18 Mar 2018 19:10:45 +0000 (19:10 +0000)
committerMike Brady <mikebrady@eircom.net>
Sun, 18 Mar 2018 19:10:45 +0000 (19:10 +0000)
common.c
common.h
dacp.c
dbus-basic-remote-control.c
player.c
rtsp.c

index 8c6e18821d557a5cd4a6137df799023527027c9a..1071749adbfb31693eb90a9579cd04f418ca8df0 100644 (file)
--- a/common.c
+++ b/common.c
@@ -984,25 +984,22 @@ void memory_barrier() {
   pthread_mutex_unlock(&barrier_mutex);
 }
 
-int ss_pthread_mutex_timedlock(pthread_mutex_t *mutex, time_t sec, long nsec, char * debugmessage, int debuglevel) {
-       // Do a timed mutex lock for the time specified.
-       // If it is unsuccessful, print the debug message at the debug level
-       // return the reply from the pthread lock 
-       
-       uint64_t time_now_fp = get_absolute_time_in_fp();
-       uint64_t delta_fp =
-      ((uint64_t)sec << 32) + ((uint64_t)nsec << 32) / 1000000000; 
-       uint64_t wait_until_fp = time_now_fp + delta_fp;
-       struct timespec wait_until;
-       wait_until.tv_sec = wait_until_fp>>32; // the seconds
-       uint64_t wtf = wait_until_fp&0xFFFFFFFF;
-       wtf = wtf*1000000000;
-       wtf = wtf>>32;
-       wait_until.tv_nsec = wtf;
-       int r = pthread_mutex_timedlock(mutex,
-       &wait_until); 
-  if (r!=0)
-       debug(debuglevel,"timed out waiting for a mutex: \"%s\".",debugmessage);
+int ss_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time, const char * debugmessage, int debuglevel) {
+
+  int time_to_wait = dally_time;
+  int r = pthread_mutex_trylock(mutex);
+  while ((r) && (time_to_wait>0)) {
+    int st = time_to_wait;
+    if (st>20000)
+      st=20000;
+    usleep(st);
+    time_to_wait -= st;       
+    r = pthread_mutex_trylock(mutex);
+  }
+  if (r!=0) {
+    char errstr[1000];
+       debug(debuglevel,"error %d: \"%s\" waiting for a mutex: \"%s\".",r,strerror_r(r,errstr,sizeof(errstr)),debugmessage);
+       }
   return r;
 }
 
index ac0637791b1b0084725c369a71251d3aff5e1286..ae6785070406a4e46cbdd5e4a0ec39e8e1cb1c6f 100644 (file)
--- a/common.h
+++ b/common.h
@@ -1,6 +1,7 @@
 #ifndef _COMMON_H
 #define _COMMON_H
 
+#include <unistd.h>
 #include <libconfig.h>
 #include <signal.h>
 #include <stdint.h>
@@ -250,6 +251,7 @@ void shairport_shutdown();
 
 extern sigset_t pselect_sigset;
 
-int ss_pthread_mutex_timedlock(pthread_mutex_t *mutex, time_t sec, long nsec, char * debugmessage, int debuglevel);
+// wait for the specified time in microseconds -- it checks every 20 milliseconds
+int ss_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time, const char * debugmessage, int debuglevel);
 
 #endif // _COMMON_H
diff --git a/dacp.c b/dacp.c
index 338c650e0688f143fd05e93d891c7ef0349d1c55..fbafe81080b8e04017a9a0a03be83f92564a821f 100644 (file)
--- a/dacp.c
+++ b/dacp.c
@@ -157,8 +157,9 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
 
     // only do this one at a time -- not sure it is necessary, but better safe than sorry
 
-    int mutex_reply = ss_pthread_mutex_timedlock(&dacp_conversation_lock,1,0,"Couldn't get DACP conversation lock in 1 second!.",1);
+    int mutex_reply = ss_pthread_mutex_timedlock(&dacp_conversation_lock,1000000,command,1);
     if (mutex_reply == 0) {
+      // debug(1,"dacp_conversation_lock acquired for command \"%s\".",command);
 
       // make a socket:
       sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
@@ -235,6 +236,7 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
         // debug(1,"DACP socket closed.");
       }
       pthread_mutex_unlock(&dacp_conversation_lock);
+      // debug(1,"dacp_conversation_lock released.");
     } else {
       // debug(1, "Could not acquire a lock on the dacp transmit/receive section. Possible
       // timeout?");
@@ -262,7 +264,7 @@ int send_simple_dacp_command(const char *command) {
 // this will be running on the thread of its caller, not of the conversation thread...
 void set_dacp_server_information(rtsp_conn_info *conn) { // tell the DACP conversation thread that
                                                          // the port has been set or changed
-       ss_pthread_mutex_timedlock(&dacp_server_information_lock,1,0,"set_dacp_server_information couldn't get DACP server information lock in 1 second!.",1);
+       ss_pthread_mutex_timedlock(&dacp_server_information_lock,500000,"set_dacp_server_information couldn't get DACP server information lock in 0.5 second!.",1);
 
   dacp_server.port = conn->dacp_port;
   dacp_server.connection_family = conn->connection_ip_family;
@@ -285,7 +287,7 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
   int32_t revision_number = 1;
   while (1) {
     int result;
-               ss_pthread_mutex_timedlock(&dacp_server_information_lock,1,0,"dacp_monitor_thread_code couldn't get DACP server information lock in 1 second!.",1);
+               ss_pthread_mutex_timedlock(&dacp_server_information_lock,500000,"dacp_monitor_thread_code couldn't get DACP server information lock in 0.5 second!.",1);
     while (dacp_server.scan_enable == 0) {
       // debug(1, "Wait for a valid DACP port");
       pthread_cond_wait(&dacp_server_information_cv, &dacp_server_information_lock);
index ded1457a9d6cf7da0ee1512a2b1ebf058d968c65..11aeebde34de5866785fa924fb5ae5f3fcd7479a 100644 (file)
 
 ShairportSyncBasicRemoteControl *shairportSyncBasicRemoteControlSkeleton;
 
+
+void dbus_basic_remote_control_metadata_watcher(struct metadata_bundle *argc, __attribute__((unused)) void *userdata) {
+  // debug(1, "DBUS basic remote control watcher called");
+  shairport_sync_basic_remote_control_set_airplay_volume(shairportSyncBasicRemoteControlSkeleton, argc->airplay_volume);
+  
+    GVariantBuilder *dict_builder, *aa;
+
+  /* Build the metadata array */
+  // debug(1,"Build metadata");
+  dict_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+  // Make up the artwork URI if we have one
+  if (argc->cover_art_pathname) {
+    char artURIstring[1024];
+    sprintf(artURIstring, "file://%s", argc->cover_art_pathname);
+    // sprintf(artURIstring,"");
+    // debug(1,"artURI String: \"%s\".",artURIstring);
+    GVariant *artUrl = g_variant_new("s", artURIstring);
+    g_variant_builder_add(dict_builder, "{sv}", "mpris:artUrl", artUrl);
+  }
+
+  // Add the TrackID if we have one
+  if (argc->item_id) {
+    char trackidstring[128];
+    // debug(1, "Set ID using mper ID: \"%u\".",argc->item_id);
+    sprintf(trackidstring, "/org/gnome/ShairportSync/mper_%u", argc->item_id);
+    GVariant *trackid = g_variant_new("o", trackidstring);
+    g_variant_builder_add(dict_builder, "{sv}", "mpris:trackid", trackid);
+  }
+  
+  // Add the track name if there is one
+  if (argc->track_name) {
+    // debug(1, "Track name set to \"%s\".", argc->track_name);
+    GVariant *trackname = g_variant_new("s", argc->track_name);
+    g_variant_builder_add(dict_builder, "{sv}", "xesam:title", trackname);
+  }
+
+  // Add the album name if there is one
+  if (argc->album_name) {
+    // debug(1, "Album name set to \"%s\".", argc->album_name);
+    GVariant *albumname = g_variant_new("s", argc->album_name);
+    g_variant_builder_add(dict_builder, "{sv}", "xesam:album", albumname);
+  }
+
+  // Add the artists if there are any (actually there will be at most one, but put it in an array)
+  if (argc->artist_name) {
+    /* Build the artists array */
+    // debug(1,"Build artist array");
+    aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
+    g_variant_builder_add(aa, "s", argc->artist_name);
+    GVariant *artists = g_variant_builder_end(aa);
+    g_variant_builder_unref(aa);
+    g_variant_builder_add(dict_builder, "{sv}", "xesam:artist", artists);
+  }
+
+  // Add the genres if there are any (actually there will be at most one, but put it in an array)
+  if (argc->genre) {
+    // debug(1,"Build genre");
+    aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
+    g_variant_builder_add(aa, "s", argc->genre);
+    GVariant *genres = g_variant_builder_end(aa);
+    g_variant_builder_unref(aa);
+    g_variant_builder_add(dict_builder, "{sv}", "xesam:genre", genres);
+  }
+
+  GVariant *dict = g_variant_builder_end(dict_builder);
+  g_variant_builder_unref(dict_builder);
+
+  // debug(1,"Set metadata");
+  shairport_sync_basic_remote_control_set_metadata(shairportSyncBasicRemoteControlSkeleton, dict);
+}
+
+
+
 static gboolean on_handle_fast_forward(ShairportSyncBasicRemoteControl *skeleton, GDBusMethodInvocation *invocation,
                                __attribute__((unused)) gpointer user_data) {
   send_simple_dacp_command("beginff");
@@ -87,14 +161,14 @@ static gboolean on_handle_resume(ShairportSyncBasicRemoteControl *skeleton, GDBu
   return TRUE;
 }
 
-/*
+
 static gboolean on_handle_shuffle_songs(ShairportSyncBasicRemoteControl *skeleton, GDBusMethodInvocation *invocation,
                                __attribute__((unused)) gpointer user_data) {
   send_simple_dacp_command("shuffle_songs");
   shairport_sync_basic_remote_control_complete_shuffle_songs(skeleton, invocation);
   return TRUE;
 }
-*/
+
 static gboolean on_handle_volume_up(ShairportSyncBasicRemoteControl *skeleton, GDBusMethodInvocation *invocation,
                                __attribute__((unused)) gpointer user_data) {
   send_simple_dacp_command("volumeup");
@@ -183,9 +257,11 @@ void dbus_basic_remote_control_on_dbus_name_acquired(GDBusConnection *connection
  g_signal_connect(shairportSyncBasicRemoteControlSkeleton, "handle-play", G_CALLBACK(on_handle_play), NULL);
  g_signal_connect(shairportSyncBasicRemoteControlSkeleton, "handle-stop", G_CALLBACK(on_handle_stop), NULL);
  g_signal_connect(shairportSyncBasicRemoteControlSkeleton, "handle-resume", G_CALLBACK(on_handle_resume), NULL);
-// g_signal_connect(shairportSyncBasicRemoteControlSkeleton, "handle-shuffle-songs", G_CALLBACK(on_handle_shuffle_songs), NULL);
+ g_signal_connect(shairportSyncBasicRemoteControlSkeleton, "handle-shuffle-songs", G_CALLBACK(on_handle_shuffle_songs), NULL);
   g_signal_connect(shairportSyncBasicRemoteControlSkeleton, "handle-volume-up", G_CALLBACK(on_handle_volume_up), NULL);
   g_signal_connect(shairportSyncBasicRemoteControlSkeleton, "handle-volume-down", G_CALLBACK(on_handle_volume_down), NULL);
+ add_metadata_watcher(dbus_basic_remote_control_metadata_watcher, NULL);
 
   /*                                 
   shairport_sync_diagnostics_set_verbosity(SHAIRPORT_SYNC_DIAGNOSTICS(shairportSyncDiagnosticsSkeleton),
index c5a850b7ec5872ff89c3568ccfcfe78c3da2d583..6dabd4fc2c5d84b2a81a729a01a024246dcd4b0d 100644 (file)
--- a/player.c
+++ b/player.c
@@ -2512,19 +2512,20 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
 void player_volume(double airplay_volume, rtsp_conn_info *conn) {
   command_set_volume(airplay_volume);
 #ifdef HAVE_METADATA_HUB
+  int modified = 0;
   int32_t actual_volume;
-  if (dacp_get_volume(&actual_volume) == 200) {
-    metadata_hub_modify_prolog();
-    if (metadata_store.speaker_volume == actual_volume)
-      metadata_hub_modify_epilog(0); // no change
-    else {
-      metadata_store.speaker_volume = actual_volume;
-      metadata_hub_modify_epilog(1); // change
-    }
+  int gv = dacp_get_volume(&actual_volume);
+  metadata_hub_modify_prolog();
+  if ((gv==200) && (metadata_store.speaker_volume != actual_volume)) {
+    metadata_store.speaker_volume = actual_volume;
+    modified = 1;
   }
-
+  if (metadata_store.airplay_volume != airplay_volume) {
+    metadata_store.airplay_volume = airplay_volume;
+    modified = 1;
+  }
+  metadata_hub_modify_epilog(modified); // change
 #endif
-
   player_volume_without_notification(airplay_volume, conn);
 }
 
diff --git a/rtsp.c b/rtsp.c
index 7b2f318c2c65cb95185fbc84835041942b04ba73..461deeb1ae2f7ad009242efa3e710b5b53599a8d 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -865,7 +865,7 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r
 
     if (!strncmp(cp, "volume: ", 8)) {
       float volume = atof(cp + 8);
-      // debug(2, "AirPlay request to set volume to: %f.", volume);
+      debug(2, "AirPlay request to set volume to: %f.", volume);
       player_volume(volume, conn);
     } else
 #ifdef CONFIG_METADATA