From: Mike Brady Date: Sun, 18 Mar 2018 19:10:45 +0000 (+0000) Subject: Add more basic remote control stuff, but SPS gets confused about who it can control. X-Git-Tag: 3.2RC1~7^2~51 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fba40733f33dcefbb907c288d0132d115809d00e;p=thirdparty%2Fshairport-sync.git Add more basic remote control stuff, but SPS gets confused about who it can control. --- diff --git a/common.c b/common.c index 8c6e1882..1071749a 100644 --- 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; } diff --git a/common.h b/common.h index ac063779..ae678507 100644 --- a/common.h +++ b/common.h @@ -1,6 +1,7 @@ #ifndef _COMMON_H #define _COMMON_H +#include #include #include #include @@ -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 338c650e..fbafe810 100644 --- 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); diff --git a/dbus-basic-remote-control.c b/dbus-basic-remote-control.c index ded1457a..11aeebde 100644 --- a/dbus-basic-remote-control.c +++ b/dbus-basic-remote-control.c @@ -17,6 +17,80 @@ 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), diff --git a/player.c b/player.c index c5a850b7..6dabd4fc 100644 --- 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 7b2f318c..461deeb1 100644 --- 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