]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add avahi code to look for the rmeote control information for the client and get...
authorMike Brady <mikebrady@eircom.net>
Thu, 5 Oct 2017 16:39:32 +0000 (17:39 +0100)
committerMike Brady <mikebrady@eircom.net>
Thu, 5 Oct 2017 16:39:32 +0000 (17:39 +0100)
12 files changed:
.gitignore
mdns.c
mdns.h
mdns_avahi.c
mdns_dns_sd.c
mdns_external.c
mdns_tinysvcmdns.c
player.c
player.h
rtp.c
rtp.h
rtsp.c

index d2a7772d3607460e772a880a6508499af8c9cd7d..cbdde0ba8e5309efbc3d05af885c4182afb23aab 100644 (file)
@@ -23,6 +23,7 @@ man/Makefile
 man/Makefile.in
 scripts/shairport-sync.service
 scripts/shairport-sync
+shairport-sync.core
 
 #Some dbus files that are automatically generated
 dbus/data/org.gnome.ShairportSync.service
diff --git a/mdns.c b/mdns.c
index ad8d877518e56ca29da2ecc422eef1bdf3e5bfda..4e5ca21e74fbc202debab8649bc13e94c436d99b 100644 (file)
--- a/mdns.c
+++ b/mdns.c
@@ -104,6 +104,22 @@ void mdns_unregister(void) {
   }
 }
 
+void mdns_dacp_monitor(char* dacp_id,uint16_t *port,void** private_pointer) {
+  if ((config.mdns) && (config.mdns->mdns_dacp_monitor)) {
+    int error = config.mdns->mdns_dacp_monitor(dacp_id,port,private_pointer);
+    if (error) {
+               debug(1,"Error starting a DACP monitor.");
+    }
+  } else
+       debug(1,"Can't start a DACP monitor.");
+}
+
+void mdns_dacp_dont_monitor(void** private_pointer) {
+  if ((config.mdns) && (config.mdns->mdns_dacp_dont_monitor)) {
+    config.mdns->mdns_dacp_dont_monitor(private_pointer);
+  } else
+       debug(1,"Can't stop a DACP monitor.");
+}
 void mdns_ls_backends(void) {
   mdns_backend **b = NULL;
   printf("Available mDNS backends: \n");
diff --git a/mdns.h b/mdns.h
index 49bae0081f6cc15adb750a7bbcd9f4a82b24aa5c..247fcd117480019e65a151a0d86ff531292ca497 100644 (file)
--- a/mdns.h
+++ b/mdns.h
@@ -1,18 +1,24 @@
 #ifndef _MDNS_H
 #define _MDNS_H
 
+#include <stdint.h>
 #include "config.h"
 
 extern int mdns_pid;
 
 void mdns_unregister(void);
 void mdns_register(void);
+void mdns_dacp_monitor(char* dacp_id,uint16_t *port,void** private_pointer);
+void mdns_dacp_dont_monitor(void** private_pointer);
+
 void mdns_ls_backends(void);
 
 typedef struct {
   char *name;
   int (*mdns_register)(char *apname, int port);
   void (*mdns_unregister)(void);
+  int (*mdns_dacp_monitor)(char* dacp_id,uint16_t *port,void** private_pointer);
+  void (*mdns_dacp_dont_monitor)(void** private_pointer);
 } mdns_backend;
 
 #ifdef CONFIG_METADATA
index f8e75d179d2d77ed0b49565d82cec33730639a5b..c017043fcaa872b73bf7ec359c93a560452f0511 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include <stdlib.h>
+#include <pthread.h>
 
 #include "common.h"
 #include "mdns.h"
 #include <avahi-client/lookup.h>
 #include <avahi-common/alternative.h>
 
-static AvahiServiceBrowser *sb = NULL;
+
+typedef struct {
+       AvahiThreadedPoll *service_poll;
+       AvahiClient *service_client;
+       AvahiServiceBrowser *service_browser;
+       char *dacp_id;
+       uint16_t *dacp_port;
+} dacp_browser_struct;
+
+//static AvahiServiceBrowser *sb = NULL;
 static AvahiClient *client = NULL;
+// static AvahiClient *service_client = NULL;
 static AvahiEntryGroup *group = NULL;
 static AvahiThreadedPoll *tpoll = NULL;
+// static AvahiThreadedPoll *service_poll = NULL;
 
-static char *name = NULL;
+static char *service_name = NULL;
 static int port = 0;
 
-static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface,
-                             AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event,
-                             const char *name, const char *type, const char *domain,
-                             const char *host_name, const AvahiAddress *address, uint16_t port,
-                             AvahiStringList *txt, AvahiLookupResultFlags flags,
-                             AVAHI_GCC_UNUSED void *userdata) {
-
-  assert(r);
-
-  /* Called whenever a service has been resolved successfully or timed out */
-
-  switch (event) {
-  case AVAHI_RESOLVER_FAILURE:
-    debug(2, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name,
-          type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
-    break;
-
-  case AVAHI_RESOLVER_FOUND: {
-    if (flags & AVAHI_LOOKUP_RESULT_OUR_OWN) {
-      char a[AVAHI_ADDRESS_STR_MAX], *t;
-
-      //              debug(1, "avahi: service '%s' of type '%s' in domain '%s' added.", name, type,
-      //              domain);
-      avahi_address_snprint(a, sizeof(a), address);
-      debug(1, "avahi: address advertised is: \"%s\".", a);
-      /*
-      t = avahi_string_list_to_string(txt);
-      debug(1,
-              "\t%s:%u (%s)\n"
-              "\tTXT=%s\n"
-              "\tcookie is %u\n"
-              "\tis_local: %i\n"
-              "\tour_own: %i\n"
-              "\twide_area: %i\n"
-              "\tmulticast: %i\n"
-              "\tcached: %i\n",
-              host_name, port, a,
-              t,
-              avahi_string_list_get_service_cookie(txt),
-              !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
-              !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
-              !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
-              !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
-              !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
-
-      avahi_free(t);
-      */
+static void resolve_callback(
+    AvahiServiceResolver *r,
+    AVAHI_GCC_UNUSED AvahiIfIndex interface,
+    AVAHI_GCC_UNUSED AvahiProtocol protocol,
+    AvahiResolverEvent event,
+    const char *name,
+    const char *type,
+    const char *domain,
+    const char *host_name,
+    const AvahiAddress *address,
+    uint16_t port,
+    AvahiStringList *txt,
+    AvahiLookupResultFlags flags,
+    void* userdata) {
+    assert(r);
+    
+    dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
+    
+    /* Called whenever a service has been resolved successfully or timed out */
+    switch (event) {
+        case AVAHI_RESOLVER_FAILURE:
+            debug(1, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s.", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
+            break;
+        case AVAHI_RESOLVER_FOUND: {
+            char a[AVAHI_ADDRESS_STR_MAX], *t;
+            //debug(1, "Resolve callback: Service '%s' of type '%s' in domain '%s':", name, type, domain);
+               char* dacpid = strstr(name,"iTunes_Ctrl_");
+            if (dacpid) {
+               dacpid+=strlen("iTunes_Ctrl_");
+               if (strcmp(dacpid,dbs->dacp_id)==0) {
+                       uint16_t *p = dbs->dacp_port;
+                       if (*p != port) {
+                               debug(1,"Client's DACP port: %u.",port);
+                               *p = port;
+                       }
+               }
+            } else {
+               debug(1,"Resolve callback: Can't see a DACP string in a DACP Record!");
+            }
+        }
     }
-  }
-  }
-
-  avahi_service_resolver_free(r);
+    avahi_service_resolver_free(r);
 }
-
-static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol,
-                            AvahiBrowserEvent event, const char *name, const char *type,
-                            const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
-                            void *userdata) {
-
-  AvahiClient *c = userdata;
-  assert(b);
-
-  /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
-
-  switch (event) {
-  case AVAHI_BROWSER_FAILURE:
-
-    //            debug(1, "(Browser) %s\n",
-    //            avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
-    return;
-
-  case AVAHI_BROWSER_NEW:
-    //            debug(1, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type,
-    //            domain);
-
-    /* We ignore the returned resolver object. In the callback
-       function we free it. If the server is terminated before
-       the callback function is called the server will free
-       the resolver for us. */
-
-    if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC,
-                                     0, resolve_callback, c)))
-      debug(1, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
-
-    break;
-
-  case AVAHI_BROWSER_REMOVE:
-    //            debug(1, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name,
-    //            type, domain);
-    break;
-
-  case AVAHI_BROWSER_ALL_FOR_NOW:
-  case AVAHI_BROWSER_CACHE_EXHAUSTED:
-    //            debug(1, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ?
-    //            "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
-    break;
-  }
+static void browse_callback(
+    AvahiServiceBrowser *b,
+    AvahiIfIndex interface,
+    AvahiProtocol protocol,
+    AvahiBrowserEvent event,
+    const char *name,
+    const char *type,
+    const char *domain,
+    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
+    void* userdata) {
+    dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
+    assert(b);
+    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
+    switch (event) {
+        case AVAHI_BROWSER_FAILURE:
+            warn("avahi: browser failure.", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
+            avahi_threaded_poll_quit(tpoll);
+            break;
+        case AVAHI_BROWSER_NEW:
+            // debug(1, "(Browser) NEW: service '%s' of type '%s' in domain '%s'.", name, type, domain);
+            /* We ignore the returned resolver object. In the callback
+               function we free it. If the server is terminated before
+               the callback function is called the server will free
+               the resolver for us. */
+            if (!(avahi_service_resolver_new(dbs->service_client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
+                debug(1, "Failed to resolve service '%s': %s.", name, avahi_strerror(avahi_client_errno(dbs->service_client)));
+            break;
+        case AVAHI_BROWSER_REMOVE:
+            debug(1, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'.", name, type, domain);
+            char* dacpid = strstr(name,"iTunes_Ctrl_");
+            if (dacpid) {
+               dacpid+=strlen("iTunes_Ctrl_");
+               if (strcmp(dacpid,dbs->dacp_id)==0) {
+                       uint16_t *p = dbs->dacp_port;
+                       if (*p != 0) {
+                               debug(1,"Client's DACP status withdrawn.");
+                               *p = 0;
+                       }
+               }
+            } else {
+               debug(1,"Browse callback: Can't see a DACP string in a DACP Record!");
+            }
+
+            break;
+        case AVAHI_BROWSER_ALL_FOR_NOW:
+        case AVAHI_BROWSER_CACHE_EXHAUSTED:
+            // debug(1, "(Browser) %s.", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
+            break;
+    }
 }
 
+
 static void register_service(AvahiClient *c);
 
 static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
@@ -154,7 +162,7 @@ static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
   switch (state) {
   case AVAHI_ENTRY_GROUP_ESTABLISHED:
     /* The entry group has been established successfully */
-    debug(1, "avahi: service '%s' successfully added.", name);
+    debug(1, "avahi: service '%s' successfully added.", service_name);
     break;
 
   case AVAHI_ENTRY_GROUP_COLLISION: {
@@ -162,11 +170,11 @@ static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
 
     /* A service name collision with a remote service
      * happened. Let's pick a new name */
-    n = avahi_alternative_service_name(name);
-    avahi_free(name);
-    name = n;
+    n = avahi_alternative_service_name(service_name);
+    avahi_free(service_name);
+    service_name = n;
 
-    debug(2, "avahi: service name collision, renaming service to '%s'", name);
+    debug(2, "avahi: service name collision, renaming service to '%s'", service_name);
 
     /* And recreate the services */
     register_service(avahi_entry_group_get_client(g));
@@ -179,11 +187,11 @@ static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
     break;
 
   case AVAHI_ENTRY_GROUP_UNCOMMITED:
-    debug(2, "avahi: service '%s' group is not yet committed.", name);
+    debug(2, "avahi: service '%s' group is not yet committed.", service_name);
     break;
 
   case AVAHI_ENTRY_GROUP_REGISTERING:
-    debug(2, "avahi: service '%s' group is registering.", name);
+    debug(2, "avahi: service '%s' group is registering.", service_name);
     break;
 
   default:
@@ -211,14 +219,14 @@ static void register_service(AvahiClient *c) {
       selected_interface = AVAHI_IF_UNSPEC;
 #ifdef CONFIG_METADATA
     if (config.metadata_enabled) {
-      ret = avahi_entry_group_add_service(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, name,
+      ret = avahi_entry_group_add_service(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, service_name,
                                           config.regtype, NULL, NULL, port,
                                           MDNS_RECORD_WITH_METADATA, NULL);
       if (ret == 0)
         debug(1, "avahi: request to add \"%s\" service with metadata", config.regtype);
     } else {
 #endif
-      ret = avahi_entry_group_add_service(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, name,
+      ret = avahi_entry_group_add_service(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, service_name,
                                           config.regtype, NULL, NULL, port,
                                           MDNS_RECORD_WITHOUT_METADATA, NULL);
       if (ret == 0)
@@ -273,7 +281,7 @@ static void client_callback(AvahiClient *c, AvahiClientState state,
     break;
 
   case AVAHI_CLIENT_S_COLLISION:
-    debug(2, "avahi: state is AVAHI_CLIENT_S_COLLISION...needs a rename: %s", name);
+    debug(2, "avahi: state is AVAHI_CLIENT_S_COLLISION...needs a rename: %s", service_name);
     break;
 
   case AVAHI_CLIENT_CONNECTING:
@@ -286,9 +294,56 @@ static void client_callback(AvahiClient *c, AvahiClientState state,
   }
 }
 
+static void service_client_callback(AvahiClient *c, AvahiClientState state,
+                            void *userdata) {
+  int err;
+  
+  dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
+
+  switch (state) {
+  case AVAHI_CLIENT_S_REGISTERING:
+    break;
+
+  case AVAHI_CLIENT_S_RUNNING:
+    break;
+
+  case AVAHI_CLIENT_FAILURE:
+    err = avahi_client_errno(c);
+    debug(1, "avahi: service client failure: %s", avahi_strerror(err));
+
+    if (err == AVAHI_ERR_DISCONNECTED) {
+      /* We have been disconnected, so lets reconnect */
+      avahi_client_free(c);
+      c = NULL;
+
+      if (!(dbs->service_client = avahi_client_new(avahi_threaded_poll_get(dbs->service_poll), AVAHI_CLIENT_NO_FAIL,
+                                      service_client_callback, userdata, &err))) {
+        warn("avahi: failed to create service client object: %s", avahi_strerror(err));
+        avahi_threaded_poll_quit(dbs->service_poll);
+      }
+    } else {
+      warn("avahi: service client failure: %s", avahi_strerror(err));
+      avahi_threaded_poll_quit(dbs->service_poll);
+    }
+    break;
+
+  case AVAHI_CLIENT_S_COLLISION:
+    debug(2, "avahi: service client state is AVAHI_CLIENT_S_COLLISION...needs a rename: %s", service_name);
+    break;
+
+  case AVAHI_CLIENT_CONNECTING:
+    debug(2, "avahi: service client received AVAHI_CLIENT_CONNECTING");
+    break;
+
+  default:
+    debug(1, "avahi: unexpected and unhandled avahi service client state: %d", state);
+    break;
+  }
+}
+
 static int avahi_register(char *srvname, int srvport) {
   debug(1, "avahi: avahi_register.");
-  name = strdup(srvname);
+  service_name = strdup(srvname);
   port = srvport;
 
   int err;
@@ -302,13 +357,6 @@ static int avahi_register(char *srvname, int srvport) {
     return -1;
   }
 
-  // we need this to detect the IPv6 number we're advertising...
-  // if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC,  AVAHI_PROTO_UNSPEC,
-  // config.regtype, NULL, 0, browse_callback, client))) {
-  //     warn("Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
-  //     return -1;
-  // }
-
   if (avahi_threaded_poll_start(tpoll) < 0) {
     warn("couldn't start avahi tpoll thread");
     return -1;
@@ -323,10 +371,91 @@ static void avahi_unregister(void) {
     avahi_threaded_poll_stop(tpoll);
   tpoll = NULL;
 
-  if (name)
-    free(name);
-  name = NULL;
+  if (service_name)
+    free(service_name);
+  service_name = NULL;
+}
+
+int avahi_dacp_monitor(char* dacp_id,uint16_t *port,void** private_pointer) {
+       
+       dacp_browser_struct **pdbs = (dacp_browser_struct **)private_pointer;
+       
+       dacp_browser_struct *dbs = (dacp_browser_struct*)malloc(sizeof(dacp_browser_struct));
+       
+       if (dbs==NULL)
+               die("can not allocate a dacp_browser_struct.");
+
+       dbs->dacp_id=dacp_id;
+       dbs->dacp_port=port;
+       
+
+       // create the threaded poll code
+  int err;
+  if (!(dbs->service_poll = avahi_threaded_poll_new())) {
+    warn("couldn't create avahi threaded service_poll!");
+    if(dbs) {
+       free((char*)dbs);
+    }
+    return -1;
+  }    
+
+       // create the service client
+  if (!(dbs->service_client = avahi_client_new(avahi_threaded_poll_get(dbs->service_poll), AVAHI_CLIENT_NO_FAIL,
+                                  service_client_callback, (void*)dbs, &err))) {
+    warn("couldn't create avahi service client: %s!", avahi_strerror(err));
+    if(dbs) { //should free the threaded poll code
+       avahi_threaded_poll_free(dbs->service_poll);
+       free((char*)dbs);
+    }
+    return -1;
+  }
+
+  /* Create the service browser */
+       if (!(dbs->service_browser = avahi_service_browser_new(dbs->service_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_dacp._tcp", NULL, 0, browse_callback, (void *)dbs))) {
+               warn("Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(dbs->service_client)));
+    if(dbs) { //should free the threaded poll code and the service client
+       avahi_client_free(dbs->service_client);
+       avahi_threaded_poll_free(dbs->service_poll);
+       free((char*)dbs);
+    }
+               return -1;
+       }
+       // start the polling thread
+  if (avahi_threaded_poll_start(dbs->service_poll) < 0) {
+    warn("couldn't start avahi service_poll thread");
+    if(dbs) { //should free the threaded poll code and the service client and the service browser
+       avahi_service_browser_free(dbs->service_browser);
+       avahi_client_free(dbs->service_client);
+       avahi_threaded_poll_free(dbs->service_poll);
+       free((char*)dbs);
+    }
+    return -1;
+  }
+       *pdbs = dbs;
+  return 0;
+
+}
+
+void avahi_dacp_dont_monitor(void** private_pointer) {
+       dacp_browser_struct **pdbs = (dacp_browser_struct **)private_pointer;
+       
+       // stop and dispose of everything
+       if ((*pdbs)->service_poll)
+               avahi_threaded_poll_stop((*pdbs)->service_poll);
+       if ((*pdbs)->service_browser)
+                       avahi_service_browser_free((*pdbs)->service_browser);
+       if ((*pdbs)->service_client)
+                       avahi_client_free((*pdbs)->service_client);
+       if ((*pdbs)->service_poll)
+                       avahi_threaded_poll_free((*pdbs)->service_poll);
+       free((char*)(*pdbs));
+       *pdbs = NULL;
 }
 
 mdns_backend mdns_avahi = {
-    .name = "avahi", .mdns_register = avahi_register, .mdns_unregister = avahi_unregister};
+    .name = "avahi",
+    .mdns_register = avahi_register,
+    .mdns_unregister = avahi_unregister,
+    .mdns_dacp_monitor = avahi_dacp_monitor,
+    .mdns_dacp_dont_monitor = avahi_dacp_dont_monitor
+};
index 5785d103a733914561001156fe2a7ad734675531..722aadcfd7c81a3a40c22b842f04df43f94bdeef 100644 (file)
@@ -24,8 +24,8 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include "common.h"
 #include "mdns.h"
+#include "common.h"
 #include <arpa/inet.h>
 #include <dns_sd.h>
 #include <stdlib.h>
@@ -92,4 +92,6 @@ static void mdns_dns_sd_unregister(void) {
 
 mdns_backend mdns_dns_sd = {.name = "dns-sd",
                             .mdns_register = mdns_dns_sd_register,
-                            .mdns_unregister = mdns_dns_sd_unregister};
+                            .mdns_unregister = mdns_dns_sd_unregister,
+                            .mdns_dacp_monitor = NULL,
+                            .mdns_dacp_dont_monitor = NULL};
index b8698b8c82dcc762d6d015a64c90a3c3dcdb57f7..684ab1e26c532efc202bb515e771e585895ca219 100644 (file)
@@ -24,8 +24,8 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include "common.h"
 #include "mdns.h"
+#include "common.h"
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -161,8 +161,12 @@ static void kill_mdns_child(void) {
 
 mdns_backend mdns_external_avahi = {.name = "external-avahi",
                                     .mdns_register = mdns_external_avahi_register,
-                                    .mdns_unregister = kill_mdns_child};
+                                    .mdns_unregister = kill_mdns_child,
+                                    .mdns_dacp_monitor = NULL,
+                                    .mdns_dacp_dont_monitor = NULL};
 
 mdns_backend mdns_external_dns_sd = {.name = "external-dns-sd",
                                      .mdns_register = mdns_external_dns_sd_register,
-                                     .mdns_unregister = kill_mdns_child};
+                                     .mdns_unregister = kill_mdns_child,
+                                     .mdns_dacp_monitor = NULL,
+                                     .mdns_dacp_dont_monitor = NULL};
index 34137ef0129d39cf320bfbde63da73e8029ed92c..238b68b25abd4ff1f396cd6c8ea258b3472dca88 100644 (file)
@@ -163,4 +163,6 @@ static void mdns_tinysvcmdns_unregister(void) {
 
 mdns_backend mdns_tinysvcmdns = {.name = "tinysvcmdns",
                                  .mdns_register = mdns_tinysvcmdns_register,
-                                 .mdns_unregister = mdns_tinysvcmdns_unregister};
+                                 .mdns_unregister = mdns_tinysvcmdns_unregister,
+                                 .mdns_dacp_monitor = NULL,
+                                 .mdns_dacp_dont_monitor = NULL};
index d50c3da3a23f6babb5616bc4bb3a75f86dc8a3c9..6f6fe20338d6dbbba919b2705ecefb35a3cb3ff9 100644 (file)
--- a/player.c
+++ b/player.c
@@ -1561,6 +1561,9 @@ static void *player_thread_func(void *arg) {
          // as a null operand, so we'll use it like that too
   int sync_error_out_of_bounds =
       0; // number of times in a row that there's been a serious sync error
+  
+  // start an mdns/zeroconf thread to look for DACP messages containing our DACP_ID and getting the port number
+  mdns_dacp_monitor(conn->dacp_id,&conn->dacp_port,&conn->dacp_private);
 
   conn->framesProcessedInThisEpoch = 0;
   conn->framesGeneratedInThisEpoch = 0;
@@ -2166,10 +2169,15 @@ static void *player_thread_func(void *arg) {
            elapsedSec);
   }
 
+       // stop watching for DACP port number stuff
+       mdns_dacp_dont_monitor(&conn->dacp_private); // begin looking out for information about the client as a remote control. Specifically we might need the port number
+
   if (config.output->stop)
     config.output->stop();
   usleep(100000); // allow this time to (?) allow the alsa subsystem to finish cleaning up after
                   // itself. 50 ms seems too short
+
+
   debug(2, "Shut down audio, control and timing threads");
   conn->please_stop = 1;
   pthread_kill(rtp_audio_thread, SIGUSR1);
@@ -2201,6 +2209,10 @@ static void *player_thread_func(void *arg) {
     debug(1, "Error destroying vol_mutex variable.");
 
   debug(1, "Player thread exit on RTSP conversation thread %d.", conn->connection_number);
+       if (conn->dacp_id) {
+               free(conn->dacp_id);
+               conn->dacp_id = NULL;
+       }
   if (outbuf)
     free(outbuf);
   if (silence)
index a8661f57cf9c25c569947de1da9c81f2ddebb6f5..c7d748ae40f0ee0220e7394c5d6d438f49e631d6 100644 (file)
--- a/player.h
+++ b/player.h
@@ -158,6 +158,14 @@ typedef struct {
   int64_t session_corrections;
 
   int play_number_after_flush;
+  
+  // remote control stuff. The port to which to send commands is not specified, so you have to use mdns to find it.
+  // at present, only avahi can do this
+  
+  char* dacp_id; // id of the client -- used to find the port to be used
+  uint16_t dacp_port; // port on the client to send remote control messages to, else zero
+  uint32_t dacp_active_remote; // key to send to the remote controller
+  void* dacp_private; // private storage (just a pointer) for the dacp_port resolver
 
 } rtsp_conn_info;
 
diff --git a/rtp.c b/rtp.c
index ee7f02c5cfb569bbf45a66cefc246a2516e98283..73d9d3b93c3107a194a891f42c97af1a83699200 100644 (file)
--- a/rtp.c
+++ b/rtp.c
@@ -593,7 +593,7 @@ static int bind_port(int ip_family, const char *self_ip_address, uint32_t scope_
   return sport;
 }
 
-void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t active_remote,
+void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport,
                int *lsport, int *lcport, int *ltport, rtsp_conn_info *conn) {
 
   // this gets the local and remote ip numbers (and ports used for the TCD stuff)
@@ -605,8 +605,6 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t
 
   debug(2, "rtp_setup: cport=%d tport=%d.", cport, tport);
 
-  conn->client_active_remote = active_remote;
-
   // print out what we know about the client
   void *client_addr, *self_addr;
   int client_port, self_port;
@@ -762,11 +760,11 @@ void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) {
 
 void rtp_request_client_pause(rtsp_conn_info *conn) {
   if (conn->rtp_running) {
-    if (conn->client_active_remote == 0) {
+    if (conn->dacp_active_remote == 0) {
       debug(1, "Can't request a client pause: no valid active remote.");
     } else {
       // debug(1,"Send a client pause request to %s:3689 with active remote
-      // %u.",client_ip_string,client_active_remote);
+      // %u.",client_ip_string,dacp_active_remote);
 
       struct addrinfo hints, *res;
       int sockfd;
@@ -799,7 +797,7 @@ void rtp_request_client_pause(rtsp_conn_info *conn) {
 
       sprintf(message,
               "GET /ctrl-int/1/pause HTTP/1.1\r\nHost: %s:3689\r\nActive-Remote: %u\r\n\r\n",
-              conn->client_ip_string, conn->client_active_remote);
+              conn->client_ip_string, conn->dacp_active_remote);
       // debug(1,"Sending this message: \"%s\".",message);
 
       // Send some data
diff --git a/rtp.h b/rtp.h
index 3da1c08974e95fb62c53630f2155a7eb1b2189c5..fdd5f9723d9bb2891088a3251e35bd05834afd41 100644 (file)
--- a/rtp.h
+++ b/rtp.h
@@ -13,7 +13,7 @@ void *rtp_control_receiver(void *arg);
 void *rtp_timing_receiver(void *arg);
 
 void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int controlport, int timingport,
-               uint32_t active_remote, int *local_server_port, int *local_control_port,
+               int *local_server_port, int *local_control_port,
                int *local_timing_port, rtsp_conn_info *conn);
 void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn);
 void rtp_request_client_pause(rtsp_conn_info *conn); // ask the client to pause
diff --git a/rtsp.c b/rtsp.c
index d937a09e2caea45db7ecd931cfaf0844db55cb50..d972e35d9c61c1278b79f653ae97d7c8771c4e24 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -59,7 +59,6 @@
 #endif
 
 #include "common.h"
-#include "mdns.h"
 #include "player.h"
 #include "rtp.h"
 #include "rtsp.h"
@@ -696,26 +695,26 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
   debug(3, "Connection %d: SETUP", conn->connection_number);
   int cport, tport;
   int lsport, lcport, ltport;
-  uint32_t active_remote = 0;
 
   char *ar = msg_get_header(req, "Active-Remote");
   if (ar) {
     debug(1, "Active-Remote string seen: \"%s\".", ar);
     // get the active remote
     char *p;
-    active_remote = strtoul(ar, &p, 10);
+    conn->dacp_active_remote = strtoul(ar, &p, 10);
 #ifdef CONFIG_METADATA
     send_metadata('ssnc', 'acre', ar, strlen(ar), req, 1);
 #endif
   }
 
-#ifdef CONFIG_METADATA
   ar = msg_get_header(req, "DACP-ID");
   if (ar) {
     debug(1, "DACP-ID string seen: \"%s\".", ar);
+    conn->dacp_id = strdup(ar);
+#ifdef CONFIG_METADATA
     send_metadata('ssnc', 'daid', ar, strlen(ar), req, 1);
-  }
 #endif
+  }
 
   // This latency-setting mechanism is deprecated and will be removed.
   // If no non-standard latency is chosen, automatic negotiated latency setting
@@ -793,7 +792,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
   tport = atoi(p);
 
   //  rtsp_take_player();
-  rtp_setup(&conn->local, &conn->remote, cport, tport, active_remote, &lsport, &lcport, &ltport,
+  rtp_setup(&conn->local, &conn->remote, cport, tport, &lsport, &lcport, &ltport,
             conn);
   if (!lsport)
     goto error;