Add avahi code to look for the rmeote control information for the client and get the port number from it.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
+247
-118
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
@@ -40,112 +41,119 @@
|
||||
#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);
|
||||
}
|
||||
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!");
|
||||
}
|
||||
|
||||
avahi_service_resolver_free(r);
|
||||
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 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 register_service(AvahiClient *c);
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
+4
-2
@@ -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};
|
||||
|
||||
+7
-3
@@ -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};
|
||||
|
||||
+3
-1
@@ -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};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user