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;
}
// 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);
// 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?");
// 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;
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);
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");
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");
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),