#include "audio.h"
#include "config.h"
+#include "definitions.h"
#include "mdns.h"
#if defined(__APPLE__) && defined(__MACH__)
#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
- 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);
}
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.
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
+
--- /dev/null
+#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
AvahiThreadedPoll *service_poll;
AvahiClient *service_client;
AvahiServiceBrowser *service_browser;
- char *dacp_id;
- uint16_t *dacp_port;
} dacp_browser_struct;
// static AvahiServiceBrowser *sb = NULL;
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) {
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));
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) {
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 {
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:
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;
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
avahi_threaded_poll_free(dbs->service_poll);
free((char *)dbs);
}
+ conn->mdns_private_pointer = NULL;
return -1;
}
// start the polling thread
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;
}
#include <pthread.h>
#include "config.h"
+#include "definitions.h"
#ifdef HAVE_LIBMBEDTLS
#include <mbedtls/aes.h>
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;
#include <glib.h>
#endif
+#if defined(HAVE_DBUS) || defined(HAVE_MPRIS)
+#include "dacp.h"
+#endif
+
#ifdef HAVE_DBUS
#include "dbus-service.h"
#endif
}
void exit_function() {
- debug(1, "exit function called...");
+ // debug(1, "exit function called...");
if (config.cfg)
config_destroy(config.cfg);
if (config.appName)
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");