]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Started implementing a scanner with just playstatusupdate message
authorMike Brady <mikebrady@eircom.net>
Sun, 3 Dec 2017 20:11:23 +0000 (20:11 +0000)
committerMike Brady <mikebrady@eircom.net>
Sun, 3 Dec 2017 20:11:23 +0000 (20:11 +0000)
dacp.c

diff --git a/dacp.c b/dacp.c
index 2dcd5fdf46c0496063397c2affd00fbdd570d727..727611464c7bcc5dcb985a8221f9b13d5709d8a2 100644 (file)
--- a/dacp.c
+++ b/dacp.c
 #include <time.h>
 #include <unistd.h>
 
-typedef struct  {
+typedef struct {
   uint16_t port;
-  short connection_family; // AF_INET6 or AF_INET
-  uint32_t scope_id; // if it's an ipv6 connection, this will be its scope id
+  short connection_family;          // AF_INET6 or AF_INET
+  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
+  uint32_t active_remote_id;        // send this when you want to send remote control commands
 } dacp_server_record;
 
 pthread_t dacp_monitor_thread;
@@ -54,32 +54,147 @@ static pthread_mutex_t dacp_conversation_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t dacp_server_information_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t dacp_server_information_cv = PTHREAD_COND_INITIALIZER;
 
+ssize_t dacp_send_command(const char *command, char *response, size_t max_response_length) {
+  ssize_t reply_size = -1;
+  // try to do this transaction on the DACP server, but don't wait for more than 20 ms to be allowed
+  // to do it.
+  struct timespec mutex_wait_time;
+  mutex_wait_time.tv_sec = 0;
+  mutex_wait_time.tv_nsec = 20000000; // 20 ms
+
+  struct addrinfo hints, *res;
+  int sockfd;
+
+  char message[20000], server_reply[2000], portstring[10], server[256];
+  memset(&message, 0, sizeof(message));
+  if ((response) && (max_response_length))
+    memset(response, 0, max_response_length);
+  else
+    memset(&server_reply, 0, sizeof(server_reply));
+  memset(&portstring, 0, sizeof(portstring));
+
+  if (dacp_server.connection_family == AF_INET6) {
+    sprintf(server, "%s%%%u", dacp_server.ip_string, dacp_server.scope_id);
+  } else {
+    strcpy(server, dacp_server.ip_string);
+  }
+
+  sprintf(portstring, "%u", dacp_server.port);
+
+  // first, load up address structs with getaddrinfo():
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_UNSPEC;
+  hints.ai_socktype = SOCK_STREAM;
+
+  // debug(1, "DHCP port string is \"%s:%u\".", dacp_server.ip_string, dacp_server.port);
+
+  getaddrinfo(server, portstring, &hints, &res);
+
+  // only do this one at a time -- not sure it is necessary, but better safe than sorry
+
+  int mutex_reply = pthread_mutex_timedlock(&dacp_conversation_lock, &mutex_wait_time);
+  if (mutex_reply == 0) {
+
+    // make a socket:
+
+    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+
+    if (sockfd == -1) {
+      debug(1, "Could not create socket");
+    } else {
+
+      // connect!
+
+      if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
+        debug(1, "connect failed. Error");
+      } else {
+
+        sprintf(message, "GET /ctrl-int/1/%s HTTP/1.1\r\nHost: %s:%u\r\nActive-Remote: %u\r\n\r\n",
+                command, dacp_server.ip_string, dacp_server.port, dacp_server.active_remote_id);
+
+        // Send command
+
+        if (send(sockfd, message, strlen(message), 0) < 0) {
+          debug(1, "Send failed");
+        }
+
+        // Receive a reply from the server
+        if ((response) && (max_response_length))
+          reply_size = recv(sockfd, response, max_response_length, 0);
+        else
+          reply_size = recv(sockfd, server_reply, sizeof(server_reply), 0);
+        if (reply_size < 0) {
+          debug(1, "recv failed");
+        }
+        close(sockfd);
+      }
+    }
+    pthread_mutex_unlock(&dacp_conversation_lock);
+  } else {
+    debug(1, "Could not acquire a lock on the dacp transmit/receive section. Possible timeout?");
+  }
+  return reply_size;
+}
+
+
 // 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
+void set_dacp_server_information(rtsp_conn_info *conn) { // tell the DACP conversation thread that
+                                                         // the port has been set or changed
   pthread_mutex_lock(&dacp_server_information_lock);
-  
+
   dacp_server.port = conn->dacp_port;
   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);
+  dacp_server.scope_id = conn->self_scope_id;
+  strncpy(dacp_server.ip_string, conn->client_ip_string, INET6_ADDRSTRLEN);
   dacp_server.active_remote_id = conn->dacp_active_remote;
-  
+
   pthread_cond_signal(&dacp_server_information_cv);
   pthread_mutex_unlock(&dacp_server_information_lock);
 }
 
 void *dacp_monitor_thread_code(void *na) {
   int scan_index = 0;
+  char server_reply[2000];
   debug(1, "DACP monitor thread started.");
   // wait until we get a valid port number to begin monitoring it
   while (1) {
     pthread_mutex_lock(&dacp_server_information_lock);
     while (dacp_server.port == 0) {
-      debug(1,"Wait for a valid DACP port");
+      debug(1, "Wait for a valid DACP port");
       pthread_cond_wait(&dacp_server_information_cv, &dacp_server_information_lock);
     }
     pthread_mutex_unlock(&dacp_server_information_lock);
-    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++);
+    //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++);
+
+    ssize_t reply_size =
+        dacp_send_command("playstatusupdate", server_reply, sizeof(server_reply));
+    if (reply_size >= 0) {
+      // not interested in the response.
+      if (strstr(server_reply, "HTTP/1.1 204") == server_reply) {
+        debug(1,"Client response is No Content");        
+      } else if (strstr(server_reply, "HTTP/1.1 501") == server_reply) {
+        debug(1,"Client response is \"Not Implemented\". DACP Server has disconnnected.");
+        dacp_server.port = 0; // stop scanning until the next time it's used
+/*
+      } else {
+        debug(1,
+              "Client request to server responded with %d characters starting with this response:",
+              strlen(server_reply));
+        int i;
+        for (i = 0; i < reply_size; i++)
+          if (server_reply[i] < ' ')
+            debug(1, "%d  %02x", i, server_reply[i]);
+          else
+            debug(1, "%d  %02x  '%c'", i, server_reply[i], server_reply[i]);
+        // sprintf((char *)message + 2 * i, "%02x", server_reply[i]);
+        // debug(1,"Content is \"%s\".",message);
+*/
+      }
+    } else {
+        debug(1, "Error at rtp_send_client_command");
+    }
     sleep(3);
   }
   debug(1, "DACP monitor thread exiting.");
@@ -87,7 +202,7 @@ void *dacp_monitor_thread_code(void *na) {
 }
 
 void dacp_monitor_start() {
-  memset(&dacp_server,0,sizeof(dacp_server_record));
+  memset(&dacp_server, 0, sizeof(dacp_server_record));
   pthread_create(&dacp_monitor_thread, NULL, dacp_monitor_thread_code, NULL);
 }