Send rtsp events to the metadata thteread for handling. Begin to clean up signals.

This commit is contained in:
Mike Brady
2018-03-31 12:39:26 +01:00
parent 8094bb4d6f
commit 69b3b5d776
9 changed files with 281 additions and 243 deletions
+4
View File
@@ -1,3 +1,7 @@
Version 3.2d33
====
A new metadata token -- 'pffr' The First Frame of a play session has been Received. Not sure we'll keep it...
Version 3.2d30
====
**Enhancements**
+1 -1
View File
@@ -947,7 +947,7 @@ void do_volume(double vol) { // caller is assumed to have the alsa_mutex when us
// debug(1,"Set alsa volume.");
do_snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol);
} else {
debug(1, "Not setting volume because volume-based mute is active");
debug(2, "Not setting volume because volume-based mute is active");
}
}
volume_set_request = 0; // any external request that has been made is now satisfied
+18 -5
View File
@@ -984,16 +984,29 @@ void memory_barrier() {
pthread_mutex_unlock(&barrier_mutex);
}
int ss_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time,
const char *debugmessage, int debuglevel) {
void sps_nanosleep(const time_t sec, const long nanosec) {
struct timespec req, rem;
int result;
req.tv_sec = sec;
req.tv_nsec = nanosec;
do {
result = nanosleep(&req, &rem);
rem = req;
} while ((result == -1) && (errno == EINTR));
if (result == -1)
debug(1, "Error in sps_nanosleep of %d sec and %ld nanoseconds: %d.", sec, nanosec, errno);
}
int time_to_wait = dally_time;
int sps_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time,
const char *debugmessage, int debuglevel) {
useconds_t time_to_wait = dally_time;
int r = pthread_mutex_trylock(mutex);
while ((r) && (time_to_wait > 0)) {
int st = time_to_wait;
useconds_t st = time_to_wait;
if (st > 20000)
st = 20000;
usleep(st);
sps_nanosleep(0, st * 1000);
time_to_wait -= st;
r = pthread_mutex_trylock(mutex);
}
+5 -2
View File
@@ -251,9 +251,12 @@ void shairport_shutdown();
extern sigset_t pselect_sigset;
// 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);
int sps_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time,
const char *debugmessage, int debuglevel);
char *get_version_string(); // mallocs a string space -- remember to free it afterwards
void sps_nanosleep(const time_t sec,
const long nanosec); // waits for this time, even through interruptions
#endif // _COMMON_H
+46 -23
View File
@@ -67,11 +67,14 @@ struct HttpResponse {
int code;
};
static void *response_realloc(__attribute__((unused)) void *opaque, void *ptr, int size) {
return realloc(ptr, size);
void *response_realloc(__attribute__((unused)) void *opaque, void *ptr, int size) {
void *t = realloc(ptr, size);
if ((t == NULL) && (size != 0))
debug(1, "Response realloc of size %d failed!", size);
return t;
}
static void response_body(void *opaque, const char *data, int size) {
void response_body(void *opaque, const char *data, int size) {
struct HttpResponse *response = (struct HttpResponse *)opaque;
ssize_t space_available = response->malloced_size - response->size;
@@ -159,7 +162,8 @@ 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, 1000000, command, 1);
int mutex_reply = sps_pthread_mutex_timedlock(&dacp_conversation_lock, 2000000, command, 1);
// int mutex_reply = pthread_mutex_lock(&dacp_conversation_lock);
if (mutex_reply == 0) {
// debug(1,"dacp_conversation_lock acquired for command \"%s\".",command);
@@ -170,6 +174,13 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
// debug(1, "DACP socket could not be created -- error %d: \"%s\".",errno,strerror(errno));
response.code = 497; // Can't establish a socket to the DACP server
} else {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 250000;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "Error %d setting receive timeout for DACP service.", errno);
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "Error %d setting send timeout for DACP service.", errno);
// connect!
// debug(1, "DACP socket created.");
@@ -185,24 +196,28 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
// Send command
// debug(1,"DACP connect message: \"%s\".",message);
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "Error %d setting send timeout for DACP service.", errno);
if (send(sockfd, message, strlen(message), 0) != (ssize_t)strlen(message)) {
// debug(1, "Send failed");
response.code = 493; // Client failed to send a message
} else {
response.body = malloc(2048); // it can resize this if necessary
response.malloced_size = 2048;
response.body = malloc(32768); // it can resize this if necessary
response.malloced_size = 32768;
struct http_roundtripper rt;
http_init(&rt, responseFuncs, &response);
int needmore = 1;
int looperror = 0;
char buffer[1024];
char buffer[8192];
memset(buffer, 0, sizeof(buffer));
while (needmore && !looperror) {
const char *data = buffer;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "Error %d setting receive timeout for DACP service.", errno);
int ndata = recv(sockfd, buffer, sizeof(buffer), 0);
// debug(1,"Received %d bytes: \"%s\".",ndata,buffer);
if (ndata <= 0) {
@@ -238,10 +253,12 @@ 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,"Sent command\"%s\" with a response body of size %d.",command,response.size);
// debug(1,"dacp_conversation_lock released.");
} else {
// debug(1, "Could not acquire a lock on the dacp transmit/receive section. Possible
// timeout?");
debug(1, "Could not acquire a lock on the dacp transmit/receive section when attempting to "
"send the command \"%s\". Possible timeout?",
command);
response.code = 494; // This client is already busy
}
}
@@ -268,7 +285,7 @@ void relinquish_dacp_server_information(rtsp_conn_info *conn) {
// as the conn's connection number
// this is to signify that the player has stopped, but only if another thread (with a different
// index) hasn't already taken over the dacp service
ss_pthread_mutex_timedlock(
sps_pthread_mutex_timedlock(
&dacp_server_information_lock, 500000,
"set_dacp_server_information couldn't get DACP server information lock in 0.5 second!.", 1);
if (dacp_server.players_connection_thread_index == conn->connection_number)
@@ -279,7 +296,7 @@ void relinquish_dacp_server_information(rtsp_conn_info *conn) {
// 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(
sps_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.players_connection_thread_index = conn->connection_number;
@@ -290,8 +307,10 @@ void set_dacp_server_information(rtsp_conn_info *conn) { // tell the DACP conver
dacp_server.active_remote_id = conn->dacp_active_remote;
if (dacp_server.port)
dacp_server.scan_enable = 1;
else
else {
debug(1, "DACP server port has been set to zero.");
dacp_server.scan_enable = 0;
}
metadata_hub_modify_prolog();
int ch = metadata_store.dacp_server_active != dacp_server.scan_enable;
metadata_store.dacp_server_active = dacp_server.scan_enable;
@@ -320,7 +339,7 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
int32_t revision_number = 1;
while (1) {
int result;
ss_pthread_mutex_timedlock(
sps_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) {
@@ -331,7 +350,7 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
int32_t the_volume;
result = dacp_get_volume(&the_volume); // just want the http code
if ((result == 496) || (result == 403) || (result == 501)) {
// debug(1,"Stopping scan because the response to \"dacp_get_volume(NULL)\" is %d.",result);
debug(1, "Stopping scan because the response to \"dacp_get_volume(NULL)\" is %d.", result);
dacp_server.scan_enable = 0;
metadata_hub_modify_prolog();
int ch = metadata_store.dacp_server_active != 0;
@@ -342,17 +361,21 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
// debug(1, "DACP Server ID \"%u\" at \"%s:%u\", scan %d.", dacp_server.active_remote_id,
// dacp_server.ip_string, dacp_server.port, scan_index);
int adv = (result == 200);
// a result of 200 means the advanced features of, e.g., iTunes, are available
// so, turn the advanced_dacp_server flag on or off and flag if it's changed.
metadata_hub_modify_prolog();
int diff = metadata_store.advanced_dacp_server_active != adv;
if (diff)
metadata_store.advanced_dacp_server_active = adv;
metadata_hub_modify_epilog(diff);
if (result != 494) { // this just means that it couldn't send the query because something else
// was sending a command
int adv = (result == 200);
// a result of 200 means the advanced features of, e.g., iTunes, are available
// so, turn the advanced_dacp_server flag on or off and flag if it's changed.
metadata_hub_modify_prolog();
int diff = metadata_store.advanced_dacp_server_active != adv;
if (diff) {
metadata_store.advanced_dacp_server_active = adv;
debug(1, "Setting dacp_server_active to %d because of a response of %d.", adv, result);
}
metadata_hub_modify_epilog(diff);
}
if (result == 200) {
metadata_hub_modify_prolog();
int diff = metadata_store.speaker_volume != the_volume;
if (diff)
+155 -155
View File
@@ -20,174 +20,175 @@ ShairportSyncRemoteControl *shairportSyncRemoteControlSkeleton = NULL;
ShairportSyncAdvancedRemoteControl *shairportSyncAdvancedRemoteControlSkeleton = NULL;
void dbus_metadata_watcher(struct metadata_bundle *argc, __attribute__((unused)) void *userdata) {
char response[100];
char response[100];
shairport_sync_advanced_remote_control_set_volume(shairportSyncAdvancedRemoteControlSkeleton,
argc->speaker_volume);
shairport_sync_advanced_remote_control_set_volume(shairportSyncAdvancedRemoteControlSkeleton,
argc->speaker_volume);
shairport_sync_remote_control_set_airplay_volume(shairportSyncRemoteControlSkeleton,
argc->airplay_volume);
shairport_sync_remote_control_set_airplay_volume(shairportSyncRemoteControlSkeleton,
argc->airplay_volume);
shairport_sync_remote_control_set_server(shairportSyncRemoteControlSkeleton, argc->client_ip);
shairport_sync_remote_control_set_server(shairportSyncRemoteControlSkeleton, argc->client_ip);
if (argc->dacp_server_active) {
shairport_sync_remote_control_set_available(shairportSyncRemoteControlSkeleton, TRUE);
} else {
shairport_sync_remote_control_set_available(shairportSyncRemoteControlSkeleton, FALSE);
}
if (argc->dacp_server_active) {
shairport_sync_remote_control_set_available(shairportSyncRemoteControlSkeleton, TRUE);
} else {
shairport_sync_remote_control_set_available(shairportSyncRemoteControlSkeleton, FALSE);
}
if (argc->advanced_dacp_server_active) {
shairport_sync_advanced_remote_control_set_available(shairportSyncAdvancedRemoteControlSkeleton,
TRUE);
} else {
shairport_sync_advanced_remote_control_set_available(shairportSyncAdvancedRemoteControlSkeleton,
FALSE);
}
if (argc->advanced_dacp_server_active) {
shairport_sync_advanced_remote_control_set_available(shairportSyncAdvancedRemoteControlSkeleton,
TRUE);
} else {
shairport_sync_advanced_remote_control_set_available(shairportSyncAdvancedRemoteControlSkeleton,
FALSE);
}
switch (argc->player_state) {
case PS_NOT_AVAILABLE:
shairport_sync_remote_control_set_player_state(shairportSyncRemoteControlSkeleton,
"Not Available");
case PS_STOPPED:
shairport_sync_remote_control_set_player_state(shairportSyncRemoteControlSkeleton, "Stopped");
break;
case PS_PAUSED:
shairport_sync_remote_control_set_player_state(shairportSyncRemoteControlSkeleton, "Paused");
break;
case PS_PLAYING:
shairport_sync_remote_control_set_player_state(shairportSyncRemoteControlSkeleton, "Playing");
break;
default:
debug(1, "This should never happen.");
}
switch (argc->player_state) {
case PS_NOT_AVAILABLE:
shairport_sync_remote_control_set_player_state(shairportSyncRemoteControlSkeleton,
"Not Available");
case PS_STOPPED:
shairport_sync_remote_control_set_player_state(shairportSyncRemoteControlSkeleton, "Stopped");
break;
case PS_PAUSED:
shairport_sync_remote_control_set_player_state(shairportSyncRemoteControlSkeleton, "Paused");
break;
case PS_PLAYING:
shairport_sync_remote_control_set_player_state(shairportSyncRemoteControlSkeleton, "Playing");
break;
default:
debug(1, "This should never happen.");
}
switch (argc->play_status) {
case PS_NOT_AVAILABLE:
shairport_sync_advanced_remote_control_set_playback_status(
shairportSyncAdvancedRemoteControlSkeleton, "Not Available");
case PS_STOPPED:
shairport_sync_advanced_remote_control_set_playback_status(
shairportSyncAdvancedRemoteControlSkeleton, "Stopped");
break;
case PS_PAUSED:
shairport_sync_advanced_remote_control_set_playback_status(
shairportSyncAdvancedRemoteControlSkeleton, "Paused");
break;
case PS_PLAYING:
shairport_sync_advanced_remote_control_set_playback_status(
shairportSyncAdvancedRemoteControlSkeleton, "Playing");
break;
default:
debug(1, "This should never happen.");
}
switch (argc->play_status) {
case PS_NOT_AVAILABLE:
shairport_sync_advanced_remote_control_set_playback_status(
shairportSyncAdvancedRemoteControlSkeleton, "Not Available");
case PS_STOPPED:
shairport_sync_advanced_remote_control_set_playback_status(
shairportSyncAdvancedRemoteControlSkeleton, "Stopped");
break;
case PS_PAUSED:
shairport_sync_advanced_remote_control_set_playback_status(
shairportSyncAdvancedRemoteControlSkeleton, "Paused");
break;
case PS_PLAYING:
shairport_sync_advanced_remote_control_set_playback_status(
shairportSyncAdvancedRemoteControlSkeleton, "Playing");
break;
default:
debug(1, "This should never happen.");
}
switch (argc->repeat_status) {
case RS_NOT_AVAILABLE:
strcpy(response,"Not Available");
break;
case RS_OFF:
strcpy(response,"Off");
break;
case RS_ONE:
strcpy(response,"One");
break;
case RS_ALL:
strcpy(response,"All");
break;
default:
debug(1, "This should never happen.");
}
const char *th = shairport_sync_advanced_remote_control_get_loop_status(shairportSyncAdvancedRemoteControlSkeleton);
switch (argc->repeat_status) {
case RS_NOT_AVAILABLE:
strcpy(response, "Not Available");
break;
case RS_OFF:
strcpy(response, "Off");
break;
case RS_ONE:
strcpy(response, "One");
break;
case RS_ALL:
strcpy(response, "All");
break;
default:
debug(1, "This should never happen.");
}
const char *th = shairport_sync_advanced_remote_control_get_loop_status(
shairportSyncAdvancedRemoteControlSkeleton);
// only set this if it's different
if ((th==NULL) || (strcasecmp(th,response)!=0)) {
debug(1,"Loop Status should be changed");
shairport_sync_advanced_remote_control_set_loop_status(shairportSyncAdvancedRemoteControlSkeleton, response);
}
// only set this if it's different
if ((th == NULL) || (strcasecmp(th, response) != 0)) {
debug(1, "Loop Status should be changed");
shairport_sync_advanced_remote_control_set_loop_status(
shairportSyncAdvancedRemoteControlSkeleton, response);
}
switch (argc->shuffle_status) {
case SS_NOT_AVAILABLE:
shairport_sync_advanced_remote_control_set_shuffle(shairportSyncAdvancedRemoteControlSkeleton,
FALSE);
break;
case SS_OFF:
shairport_sync_advanced_remote_control_set_shuffle(shairportSyncAdvancedRemoteControlSkeleton,
FALSE);
break;
case SS_ON:
shairport_sync_advanced_remote_control_set_shuffle(shairportSyncAdvancedRemoteControlSkeleton,
TRUE);
break;
default:
debug(1, "This should never happen.");
}
switch (argc->shuffle_status) {
case SS_NOT_AVAILABLE:
shairport_sync_advanced_remote_control_set_shuffle(shairportSyncAdvancedRemoteControlSkeleton,
FALSE);
break;
case SS_OFF:
shairport_sync_advanced_remote_control_set_shuffle(shairportSyncAdvancedRemoteControlSkeleton,
FALSE);
break;
case SS_ON:
shairport_sync_advanced_remote_control_set_shuffle(shairportSyncAdvancedRemoteControlSkeleton,
TRUE);
break;
default:
debug(1, "This should never happen.");
}
GVariantBuilder *dict_builder, *aa;
GVariantBuilder *dict_builder, *aa;
/* Build the metadata array */
// debug(1,"Build metadata");
dict_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
/* 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);
}
// 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 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 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 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 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);
}
// 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);
GVariant *dict = g_variant_builder_end(dict_builder);
g_variant_builder_unref(dict_builder);
// debug(1,"Set metadata");
shairport_sync_remote_control_set_metadata(shairportSyncRemoteControlSkeleton, dict);
// debug(1,"Set metadata");
shairport_sync_remote_control_set_metadata(shairportSyncRemoteControlSkeleton, dict);
}
static gboolean on_handle_set_volume(ShairportSyncAdvancedRemoteControl *skeleton,
@@ -485,7 +486,6 @@ gboolean notify_shuffle_callback(ShairportSyncAdvancedRemoteControl *skeleton,
send_simple_dacp_command("setproperty?dacp.shufflestate=1");
else
send_simple_dacp_command("setproperty?dacp.shufflestate=0");
;
return TRUE;
}
@@ -495,7 +495,7 @@ gboolean notify_loop_status_callback(ShairportSyncAdvancedRemoteControl *skeleto
char *th = (char *)shairport_sync_advanced_remote_control_get_loop_status(skeleton);
// enum volume_control_profile_type previous_volume_control_profile =
// config.volume_control_profile;
debug(1,"notify_loop_status_callback called with loop status of \"%s\".",th);
debug(1, "notify_loop_status_callback called with loop status of \"%s\".", th);
if (strcasecmp(th, "off") == 0)
send_simple_dacp_command("setproperty?dacp.repeatstate=0");
else if (strcasecmp(th, "one") == 0)
@@ -555,7 +555,7 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
shairportSyncAdvancedRemoteControlSkeleton =
shairport_sync_advanced_remote_control_skeleton_new();
g_dbus_interface_skeleton_export(
G_DBUS_INTERFACE_SKELETON(shairportSyncAdvancedRemoteControlSkeleton), connection,
"/org/gnome/ShairportSync", NULL);
@@ -623,7 +623,7 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
G_CALLBACK(notify_loop_status_callback), NULL);
add_metadata_watcher(dbus_metadata_watcher, NULL);
shairport_sync_set_loudness_threshold(SHAIRPORT_SYNC(shairportSyncSkeleton),
config.loudness_reference_volume_db);
@@ -701,9 +701,9 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
"Not Available");
shairport_sync_advanced_remote_control_set_playback_status(
shairportSyncAdvancedRemoteControlSkeleton, "Not Available");
shairport_sync_advanced_remote_control_set_loop_status(
shairportSyncAdvancedRemoteControlSkeleton, "Not Available");
shairport_sync_advanced_remote_control_set_loop_status(shairportSyncAdvancedRemoteControlSkeleton,
"Not Available");
debug(1, "Shairport Sync native D-Bus service started at \"%s\" on the %s bus.", name,
(config.dbus_service_bus_type == DBT_session) ? "session" : "system");
+43 -5
View File
@@ -457,11 +457,49 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
break;
// these could tell us about play / pause etc. but will only occur if metadata is enabled, so
// we'll just ignore them
case 'pbeg':
case 'pend':
case 'pfls':
case 'prsm':
break;
case 'pbeg': {
metadata_hub_modify_prolog();
int changed = (metadata_store.player_state != PS_PLAYING);
metadata_store.player_state = PS_PLAYING;
metadata_hub_modify_epilog(changed);
} break;
case 'pend': {
metadata_hub_modify_prolog();
metadata_store.player_state = PS_STOPPED;
// debug(1,"player_stop release track metadata and artwork");
metadata_hub_reset_track_metadata();
metadata_hub_release_track_artwork();
metadata_hub_modify_epilog(1);
} break;
case 'pfls': {
metadata_hub_modify_prolog();
int changed = (metadata_store.player_state != PS_PAUSED);
metadata_store.player_state = PS_PAUSED;
metadata_hub_modify_epilog(changed);
} break;
case 'pffr': // this is sent when the first frame has been received
case 'prsm': {
metadata_hub_modify_prolog();
int changed = (metadata_store.player_state != PS_PLAYING);
metadata_store.player_state = PS_PLAYING;
metadata_hub_modify_epilog(changed);
} break;
case 'pvol': {
// Note: it's assumed that the config.airplay volume has already been correctly set.
int modified = 0;
int32_t actual_volume;
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 != config.airplay_volume) {
metadata_store.airplay_volume = config.airplay_volume;
modified = 1;
}
metadata_hub_modify_epilog(modified); // change
} break;
default: {
char typestring[5];
+6 -50
View File
@@ -827,12 +827,11 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
// frames...",curframe->timestamp,seq_diff(ab_read, ab_write));
// say we have started playing here
#ifdef HAVE_METADATA_HUB
metadata_hub_modify_prolog();
int changed = (metadata_store.player_state != PS_PLAYING);
metadata_store.player_state = PS_PLAYING;
metadata_hub_modify_epilog(changed);
#ifdef CONFIG_METADATA
send_ssnc_metadata('pffr', NULL, 0,
0); // "first frame received", but don't wait if the queue is locked
#endif
if (reference_timestamp) { // if we have a reference time
// debug(1,"First frame seen with timestamp...");
conn->first_packet_timestamp =
@@ -1062,12 +1061,6 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
#ifdef CONFIG_METADATA
send_ssnc_metadata('prsm', NULL, 0,
0); // "resume", but don't wait if the queue is locked
#endif
#ifdef HAVE_METADATA_HUB
metadata_hub_modify_prolog();
int changed = (metadata_store.player_state != PS_PLAYING);
metadata_store.player_state = PS_PLAYING;
metadata_hub_modify_epilog(changed);
#endif
}
}
@@ -1604,10 +1597,9 @@ static void *player_thread_func(void *arg) {
int sync_error_out_of_bounds =
0; // number of times in a row that there's been a serious sync error
// stop looking elsewhere for DACP stuff
conn->dacp_port = 0;
// stop looking elsewhere for DACP stuff
#ifdef HAVE_DACP_CLIENT
set_dacp_server_information(conn); // this will stop scanning until a port is registered by the
set_dacp_server_information(conn); // this will start scanning when a port is registered by the
// code initiated by the mdns_dacp_monitor
#endif
// start an mdns/zeroconf thread to look for DACP messages containing our DACP_ID and getting the
@@ -2520,21 +2512,6 @@ 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;
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);
}
@@ -2550,13 +2527,6 @@ void player_flush(int64_t timestamp, rtsp_conn_info *conn) {
#ifdef CONFIG_METADATA
send_ssnc_metadata('pfls', NULL, 0, 1);
#endif
#ifdef HAVE_METADATA_HUB
metadata_hub_modify_prolog();
int changed = (metadata_store.player_state != PS_PAUSED);
metadata_store.player_state = PS_PAUSED;
metadata_hub_modify_epilog(changed);
#endif
}
int player_play(rtsp_conn_info *conn) {
@@ -2582,12 +2552,6 @@ int player_play(rtsp_conn_info *conn) {
debug(1, "Error setting stack size for player_thread: %s", strerror(errno));
pthread_create(pt, &tattr, player_thread_func, (void *)conn);
pthread_attr_destroy(&tattr);
#ifdef HAVE_METADATA_HUB
metadata_hub_modify_prolog();
int changed = (metadata_store.player_state != PS_PLAYING);
metadata_store.player_state = PS_PLAYING;
metadata_hub_modify_epilog(changed);
#endif
return 0;
}
@@ -2603,14 +2567,6 @@ void player_stop(rtsp_conn_info *conn) {
command_stop();
free(conn->player_thread);
conn->player_thread = NULL;
#ifdef HAVE_METADATA_HUB
metadata_hub_modify_prolog();
metadata_store.player_state = PS_STOPPED;
// debug(1,"player_stop release track metadata and artwork");
metadata_hub_reset_track_metadata();
metadata_hub_release_track_artwork();
metadata_hub_modify_epilog(1);
#endif
} else {
debug(3, "player thread of RTSP conversation %d is already deleted.", conn->connection_number);
}
+3 -2
View File
@@ -188,7 +188,7 @@ int pc_queue_add_item(pc_queue *the_queue, const void *the_stuff, int block) {
the_queue->eoq = i;
the_queue->count++;
if (the_queue->count == the_queue->capacity)
debug(1, "pc_queue is full!");
debug(1, "pc_queue is full with %d items in it!", the_queue->count);
rc = pthread_cond_signal(&the_queue->pc_queue_item_added_signal);
if (rc)
debug(1, "Error signalling after pc_queue_add_item");
@@ -914,6 +914,8 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r
// 'pend' -- play stream end. No arguments
// 'pfls' -- play stream flush. No arguments
// 'prsm' -- play stream resume. No arguments
// `pffr` -- the first frame of a play session has been received and has been validly
//timed.
// 'pvol' -- play volume. The volume is sent as a string --
// "airplay_volume,volume,lowest_volume,highest_volume"
// volume, lowest_volume and highest_volume are given in dB.
@@ -952,7 +954,6 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r
// Can be an IPv4 or an IPv6 number.
// `dapo` -- the payload is the port number (as text) on the server to which remote
// control commands should be sent. It is 3689 for iTunes but varies for iOS devices.
// A special sub-protocol is used for sending large data items over UDP
// If the payload exceeded 4 MB, it is chunked using the following format:
// "ssnc", "chnk", packet_ix, packet_counts, packet_tag, packet_type, chunked_data.