From 139c18bf3ec2e5499e96066547809d16e015f93d Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Thu, 5 Oct 2017 17:39:32 +0100 Subject: [PATCH] Add avahi code to look for the rmeote control information for the client and get the port number from it. --- .gitignore | 1 + mdns.c | 16 ++ mdns.h | 6 + mdns_avahi.c | 367 ++++++++++++++++++++++++++++++--------------- mdns_dns_sd.c | 6 +- mdns_external.c | 10 +- mdns_tinysvcmdns.c | 4 +- player.c | 12 ++ player.h | 8 + rtp.c | 10 +- rtp.h | 2 +- rtsp.c | 11 +- 12 files changed, 315 insertions(+), 138 deletions(-) diff --git a/.gitignore b/.gitignore index d2a7772d3..cbdde0ba8 100644 --- a/.gitignore +++ b/.gitignore @@ -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 ad8d87751..4e5ca21e7 100644 --- 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 49bae0081..247fcd117 100644 --- a/mdns.h +++ b/mdns.h @@ -1,18 +1,24 @@ #ifndef _MDNS_H #define _MDNS_H +#include #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 diff --git a/mdns_avahi.c b/mdns_avahi.c index f8e75d179..c017043fc 100644 --- a/mdns_avahi.c +++ b/mdns_avahi.c @@ -26,6 +26,7 @@ */ #include +#include #include "common.h" #include "mdns.h" @@ -40,113 +41,120 @@ #include #include -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 +}; diff --git a/mdns_dns_sd.c b/mdns_dns_sd.c index 5785d103a..722aadcfd 100644 --- a/mdns_dns_sd.c +++ b/mdns_dns_sd.c @@ -24,8 +24,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include "common.h" #include "mdns.h" +#include "common.h" #include #include #include @@ -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}; diff --git a/mdns_external.c b/mdns_external.c index b8698b8c8..684ab1e26 100644 --- a/mdns_external.c +++ b/mdns_external.c @@ -24,8 +24,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include "common.h" #include "mdns.h" +#include "common.h" #include #include #include @@ -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}; diff --git a/mdns_tinysvcmdns.c b/mdns_tinysvcmdns.c index 34137ef01..238b68b25 100644 --- a/mdns_tinysvcmdns.c +++ b/mdns_tinysvcmdns.c @@ -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}; diff --git a/player.c b/player.c index d50c3da3a..6f6fe2033 100644 --- 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) diff --git a/player.h b/player.h index a8661f57c..c7d748ae4 100644 --- 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 ee7f02c5c..73d9d3b93 100644 --- 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 3da1c0897..fdd5f9723 100644 --- 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 d937a09e2..d972e35d9 100644 --- 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, <port, + rtp_setup(&conn->local, &conn->remote, cport, tport, &lsport, &lcport, <port, conn); if (!lsport) goto error;