hooking up a dacp scanner
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "audio.h"
|
||||
#include "config.h"
|
||||
#include "definitions.h"
|
||||
#include "mdns.h"
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user