hooking up a dacp scanner

This commit is contained in:
Mike Brady
2017-12-02 19:52:39 +00:00
parent af50e91232
commit 88c550663c
7 changed files with 107 additions and 40 deletions
+1
View File
@@ -8,6 +8,7 @@
#include "audio.h"
#include "config.h"
#include "definitions.h"
#include "mdns.h"
#if defined(__APPLE__) && defined(__MACH__)
+25 -14
View File
@@ -39,44 +39,55 @@
#include <time.h>
#include <unistd.h>
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
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 = 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.
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);
}
+4 -2
View File
@@ -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
+37
View File
@@ -0,0 +1,37 @@
#ifndef _DEFINITIONS_H
#define _DEFINITIONS_H
//#include <libconfig.h>
//#include <signal.h>
//#include <stdint.h>
#include <sys/socket.h>
//#include "audio.h"
#include "config.h"
//#include "mdns.h"
#if defined(__APPLE__) && defined(__MACH__)
/* Apple OSX and iOS (Darwin). ------------------------------ */
#include <TargetConditionals.h>
#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
+28 -22
View File
@@ -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;
}
+2 -1
View File
@@ -5,6 +5,7 @@
#include <pthread.h>
#include "config.h"
#include "definitions.h"
#ifdef HAVE_LIBMBEDTLS
#include <mbedtls/aes.h>
@@ -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;
+10 -1
View File
@@ -58,6 +58,10 @@
#include <glib.h>
#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");