Store the UserAgent so as to recognise forked-daapd so as to always send a revision_number of 1 when asking for playerstatus of forked-daapd.

This commit is contained in:
Mike Brady
2020-01-10 17:20:25 +00:00
parent 98a091420c
commit 27e42a666a
3 changed files with 37 additions and 18 deletions
+26 -14
View File
@@ -53,6 +53,7 @@ typedef struct {
char dacp_id[256]; // the DACP ID string
uint16_t port; // zero if no port discovered
short connection_family; // AF_INET6 or AF_INET
int always_use_revision_number_1; // for dealing with forked-daapd;
uint32_t scope_id; // if it's an ipv6 connection, this will be its scope id
char ip_string[INET6_ADDRSTRLEN]; // the ip string pointing to the client
uint32_t active_remote_id; // send this when you want to send remote control commands
@@ -226,10 +227,8 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 500000;
// Don't place a timeout on the receive side of these calls, as some clients may provide
// a "long poll" mechanism whereby a reply will not be sent until a change has occurred
// if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1)
// debug(1, "dacp_send_command: error %d setting receive timeout.", errno);
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "dacp_send_command: error %d setting receive timeout.", errno);
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "dacp_send_command: error %d setting send timeout.", errno);
@@ -284,12 +283,8 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
memset(buffer, 0, sizeof(buffer));
while (needmore && !looperror) {
const char *data = buffer;
// Don't place a timeout on the receive, as some clients may provide
// a "long poll" mechanism whereby a reply will not be sent until a change has occurred
// if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1)
// debug(1, "dacp_send_command: error %d setting receive timeout.", errno);
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "dacp_send_command: error %d setting receive timeout.", errno);
ssize_t ndata = recv(sockfd, buffer, sizeof(buffer), 0);
// debug(3, "Received %d bytes: \"%s\".", ndata, buffer);
if (ndata <= 0) {
@@ -413,9 +408,21 @@ void set_dacp_server_information(rtsp_conn_info *conn) {
dacp_server.connection_family = conn->connection_ip_family;
dacp_server.scope_id = conn->self_scope_id;
strncpy(dacp_server.ip_string, conn->client_ip_string, INET6_ADDRSTRLEN);
debug(3, "set_dacp_server_information set IP to \"%s\" and DACP id to \"%s\".",
debug(2, "set_dacp_server_information set IP to \"%s\" and DACP id to \"%s\".",
dacp_server.ip_string, dacp_server.dacp_id);
// If the client is forked-daapd, then we always use revision number 1
// because otherwise the return read will hang in a "long poll" if there
// are no changes.
// This is different to other AirPlay clients
// which return immediately with a 403 code if there are no changes.
dacp_server.always_use_revision_number_1 = 0;
char *p = strstr(conn->UserAgent, "forked-daapd");
if ((p != 0) && (p == conn->UserAgent)) {// must exist and be at the start of the UserAgent string
dacp_server.always_use_revision_number_1 = 1;
}
mdns_dacp_monitor_set_id(dacp_server.dacp_id);
metadata_hub_modify_prolog();
@@ -480,6 +487,7 @@ void dacp_monitor_thread_code_cleanup(__attribute__((unused)) void *arg) {
void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
int scan_index = 0;
int always_use_revision_number_1 = 0;
// char server_reply[10000];
// debug(1, "DACP monitor thread started.");
// wait until we get a valid port number to begin monitoring it
@@ -516,6 +524,8 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
idle_scan_count = 0;
}
always_use_revision_number_1 = dacp_server.always_use_revision_number_1; // set this while access is locked
result = dacp_get_volume(&the_volume); // just want the http code
pthread_cleanup_pop(1);
@@ -604,6 +614,8 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
char *response = NULL;
int32_t item_size;
char command[1024] = "";
if (always_use_revision_number_1 != 0) // for forked-daapd
revision_number = 1;
snprintf(command, sizeof(command) - 1, "playstatusupdate?revision-number=%d",
revision_number);
// debug(1,"dacp_monitor_thread_code: command: \"%s\"",command);
@@ -641,7 +653,7 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
case 'cmsr': // revision number
t = sp - item_size;
revision_number = ntohl(*(uint32_t *)(t));
// debug(1," Serial Number: %d", revision_number);
// debug(1,"New revision number received: %d", revision_number);
break;
case 'caps': // play status
t = sp - item_size;
@@ -1003,7 +1015,7 @@ int dacp_set_include_speaker_volume(int64_t machine_number, int32_t vo) {
snprintf(message, sizeof(message),
"setproperty?include-speaker-id=%" PRId64 "&dmcp.volume=%" PRId32 "", machine_number,
vo);
debug(1, "sending \"%s\"", message);
debug(2, "sending \"%s\"", message);
return send_simple_dacp_command(message);
// should return 204
}
@@ -1013,7 +1025,7 @@ int dacp_set_speaker_volume(int64_t machine_number, int32_t vo) {
memset(message, 0, sizeof(message));
snprintf(message, sizeof(message), "setproperty?speaker-id=%" PRId64 "&dmcp.volume=%" PRId32 "",
machine_number, vo);
debug(1, "sending \"%s\"", message);
debug(2, "sending \"%s\"", message);
return send_simple_dacp_command(message);
// should return 204
}
+1
View File
@@ -79,6 +79,7 @@ typedef struct {
typedef struct {
int connection_number; // for debug ID purposes, nothing else...
int resend_interval; // this is really just for debugging
char *UserAgent; // free this on teardown
int AirPlayVersion; // zero if not an AirPlay session. Used to help calculate latency
uint32_t latency; // the actual latency used for this play session
uint32_t minimum_latency; // set if an a=min-latency: line appears in the ANNOUNCE message; zero
+10 -4
View File
@@ -626,16 +626,16 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
goto shutdown;
}
/* // this outputs the message received
/* // this outputs the message received
{
void *pt = malloc(nread+1);
memset(pt, 0, nread+1);
memcpy(pt, buf + inbuf, nread);
debug(1, "Incoming string on port: \"%s\"",pt);
free(pt);
free(pt);
}
*/
inbuf += nread;
char *next;
@@ -1889,7 +1889,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
unsigned int max_param = sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]);
char* found;
while ((found = strsep(&pfmtp, " \t")) != NULL && i < max_param) {
conn->stream.fmtp[i++] = atoi(found);
conn->stream.fmtp[i++] = atoi(found);
}
// here we should check the sanity of the fmtp values
// for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++)
@@ -1930,6 +1930,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
}
hdr = msg_get_header(req, "User-Agent");
if (hdr) {
conn->UserAgent = strdup(hdr);
debug(2, "Play connection from user agent \"%s\" on RTSP conversation thread %d.", hdr,
conn->connection_number);
// if the user agent is AirPlay and has a version number of 353 or less (from iOS 11.1,2)
@@ -2267,6 +2268,11 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
conn->dacp_id = NULL;
}
if (conn->UserAgent) {
free(conn->UserAgent);
conn->UserAgent = NULL;
}
// remove flow control and mutexes
int rc = pthread_mutex_destroy(&conn->volume_control_mutex);
if (rc)