Send rtsp events to the metadata thteread for handling. Begin to clean up signals.
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user