From: Mike Brady Date: Sat, 2 Dec 2017 19:52:39 +0000 (+0000) Subject: hooking up a dacp scanner X-Git-Tag: 3.2d16~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=88c550663caca4ba1ace0552054e2d03d651b482;p=thirdparty%2Fshairport-sync.git hooking up a dacp scanner --- diff --git a/common.h b/common.h index 719ff702..82ff60f7 100644 --- a/common.h +++ b/common.h @@ -8,6 +8,7 @@ #include "audio.h" #include "config.h" +#include "definitions.h" #include "mdns.h" #if defined(__APPLE__) && defined(__MACH__) diff --git a/dacp.c b/dacp.c index 9a916ce9..2dcd5fdf 100644 --- a/dacp.c +++ b/dacp.c @@ -39,44 +39,55 @@ #include #include -uint16_t dacp_port; +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 + 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 +} dacp_server_record; + pthread_t dacp_monitor_thread; +dacp_server_record dacp_server; 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; // this will be running on the thread of its caller, not of the conversation thread... -void set_dacp_port( - uint16_t port) { // tell the DACP conversation thread that the port has been set or changed - pthread_mutex_lock(&dacp_server_information_lock); - dacp_port = port; - pthread_cond_signal(&dacp_server_information_cv); - pthread_mutex_unlock(&dacp_server_information_lock); -} - -// this will be running on the thread of its caller, not of the conversation thread... -void unset_dacp_port() { // tell the DACP conversation thread that that port has gone offline. +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_port = 0; + + 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.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; + 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_port == 0) + while (dacp_server.port == 0) { + 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 Monitor Thread active now."); + 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++); sleep(3); } + debug(1, "DACP monitor thread exiting."); pthread_exit(NULL); } void dacp_monitor_start() { + memset(&dacp_server,0,sizeof(dacp_server_record)); pthread_create(&dacp_monitor_thread, NULL, dacp_monitor_thread_code, NULL); } diff --git a/dacp.h b/dacp.h index a7bdebe2..493a6932 100644 --- a/dacp.h +++ b/dacp.h @@ -17,6 +17,8 @@ typedef struct dacp_speaker_stuff { char *name; // this is really just for debugging } dacp_spkr_stuff; +void dacp_monitor_start(); + uint32_t dacp_tlv_crawl( char **p, int32_t *length); // return the code of the next TLV entity and advance the pointer beyond it. @@ -27,5 +29,5 @@ int dacp_set_include_speaker_volume(rtsp_conn_info *conn, int64_t machine_number int dacp_set_speaker_volume(rtsp_conn_info *conn, int64_t machine_number, int32_t vo); int dacp_get_speaker_list(rtsp_conn_info *conn, dacp_spkr_stuff *speaker_array, int max_size_of_array); -void set_dacp_port(uint16_t port); // tell the DACP conversation thread that the port has been set or changed -void unset_dacp_port(); // tell the DACP conversation thread that that port has gone offline. +void set_dacp_server_information(rtsp_conn_info* conn); // tell the DACP conversation thread that the dacp server information has been set or changed + diff --git a/definitions.h b/definitions.h new file mode 100644 index 00000000..5fe42b41 --- /dev/null +++ b/definitions.h @@ -0,0 +1,37 @@ +#ifndef _DEFINITIONS_H +#define _DEFINITIONS_H + +//#include +//#include +//#include +#include + +//#include "audio.h" +#include "config.h" +//#include "mdns.h" + +#if defined(__APPLE__) && defined(__MACH__) +/* Apple OSX and iOS (Darwin). ------------------------------ */ +#include +#if TARGET_OS_MAC == 1 +/* OSX */ +#define COMPILE_FOR_OSX 1 +#endif +#endif + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__CYGWIN__) +/* Linux and FreeBSD */ +#define COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN 1 +#endif + +// struct sockaddr_in6 is bigger than struct sockaddr. derp +#ifdef AF_INET6 +#define SOCKADDR struct sockaddr_storage +#define SAFAMILY ss_family +#else +#define SOCKADDR struct sockaddr +#define SAFAMILY sa_family +#endif + + +#endif // _DEFINITIONS_H diff --git a/mdns_avahi.c b/mdns_avahi.c index cb99f462..a506d491 100644 --- a/mdns_avahi.c +++ b/mdns_avahi.c @@ -49,8 +49,6 @@ 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; @@ -69,8 +67,9 @@ static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIn 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; + + rtsp_conn_info *conn = (rtsp_conn_info *)userdata; + dacp_browser_struct *dbs = (dacp_browser_struct *)conn->mdns_private_pointer; /* Called whenever a service has been resolved successfully or timed out */ switch (event) { @@ -84,12 +83,13 @@ static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIn 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) { + if (strcmp(dacpid, conn->dacp_id) == 0) { + if (conn->dacp_port != port) { debug(1, "Client's DACP port: %u.", port); - *p = port; - set_dacp_port(port); + conn->dacp_port = port; +#if defined(HAVE_DBUS) || defined(HAVE_MPRIS) + set_dacp_server_information(conn); +#endif #ifdef CONFIG_METADATA char portstring[20]; memset(portstring, 0, sizeof(portstring)); @@ -109,7 +109,8 @@ static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, Avah 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; + rtsp_conn_info *conn = (rtsp_conn_info *)userdata; + dacp_browser_struct *dbs = (dacp_browser_struct *)conn->mdns_private_pointer; assert(b); /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ switch (event) { @@ -134,12 +135,13 @@ static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, Avah 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) { + if (strcmp(dacpid, conn->dacp_id) == 0) { + if (conn->dacp_id != 0) { debug(1, "Client's DACP status withdrawn."); - *p = 0; - unset_dacp_port(); + conn->dacp_id = 0; +#if defined(HAVE_DBUS) || defined(HAVE_MPRIS) + set_dacp_server_information(conn); // this will have the effect of telling the scanner that the DACP server is no longer working +#endif } } } else { @@ -297,7 +299,8 @@ 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; + rtsp_conn_info *conn = (rtsp_conn_info *)userdata; + dacp_browser_struct *dbs = (dacp_browser_struct *)conn->mdns_private_pointer; switch (state) { case AVAHI_CLIENT_S_REGISTERING: @@ -380,12 +383,12 @@ static void avahi_unregister(void) { int avahi_dacp_monitor(rtsp_conn_info *conn) { 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; + + conn->mdns_private_pointer = (void *)dbs; // create the threaded poll code int err; @@ -394,25 +397,27 @@ int avahi_dacp_monitor(rtsp_conn_info *conn) { if (dbs) { free((char *)dbs); } + conn->mdns_private_pointer = NULL; 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))) { + service_client_callback, (void *)conn, &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); } + conn->mdns_private_pointer = NULL; 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))) { + "_dacp._tcp", NULL, 0, browse_callback, (void *)conn))) { 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 @@ -420,6 +425,7 @@ int avahi_dacp_monitor(rtsp_conn_info *conn) { avahi_threaded_poll_free(dbs->service_poll); free((char *)dbs); } + conn->mdns_private_pointer = NULL; return -1; } // start the polling thread @@ -431,9 +437,9 @@ int avahi_dacp_monitor(rtsp_conn_info *conn) { avahi_threaded_poll_free(dbs->service_poll); free((char *)dbs); } + conn->mdns_private_pointer = NULL; return -1; } - conn->mdns_private_pointer = (void *)dbs; return 0; } diff --git a/player.h b/player.h index b0e923ea..6ee4f4d0 100644 --- a/player.h +++ b/player.h @@ -5,6 +5,7 @@ #include #include "config.h" +#include "definitions.h" #ifdef HAVE_LIBMBEDTLS #include @@ -183,7 +184,7 @@ typedef struct { 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 + void *mdns_private_pointer; // private storage (just a pointer) for the dacp_port resolver } rtsp_conn_info; diff --git a/shairport.c b/shairport.c index b2a94649..1d3602e7 100644 --- a/shairport.c +++ b/shairport.c @@ -58,6 +58,10 @@ #include #endif +#if defined(HAVE_DBUS) || defined(HAVE_MPRIS) +#include "dacp.h" +#endif + #ifdef HAVE_DBUS #include "dbus-service.h" #endif @@ -1065,7 +1069,7 @@ const char *pid_file_proc(void) { } void exit_function() { - debug(1, "exit function called..."); + // debug(1, "exit function called..."); if (config.cfg) config_destroy(config.cfg); if (config.appName) @@ -1534,6 +1538,11 @@ int main(int argc, char **argv) { metadata_init(); // create the metadata pipe if necessary #endif +#if defined(HAVE_DBUS) || defined(HAVE_MPRIS) + debug(1,"Requesting DACP Monitor"); + dacp_monitor_start(); +#endif + #if defined(HAVE_DBUS) || defined(HAVE_MPRIS) // Start up DBUS services after initial settings are all made debug(1, "Starting up D-Bus services");