Make scanning for DACP port part of the dacp handler. Only emit 'clip' and 'svip' for a play connection, suppress 'pfls' until 'pffr' has been emitted
This commit is contained in:
+2
-2
@@ -503,14 +503,14 @@ int open_alsa_device(void) {
|
||||
(snd_pcm_hw_params_set_access(alsa_handle, alsa_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) >=
|
||||
0)) {
|
||||
if (output_method_signalled == 0) {
|
||||
debug(1, "Output written using MMAP");
|
||||
debug(3, "Output written using MMAP");
|
||||
output_method_signalled = 1;
|
||||
}
|
||||
access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
||||
alsa_pcm_write = snd_pcm_mmap_writei;
|
||||
} else {
|
||||
if (output_method_signalled == 0) {
|
||||
debug(1, "Output written with RW");
|
||||
debug(3, "Output written with RW");
|
||||
output_method_signalled = 1;
|
||||
}
|
||||
access = SND_PCM_ACCESS_RW_INTERLEAVED;
|
||||
|
||||
@@ -49,11 +49,13 @@ typedef struct {
|
||||
int players_connection_thread_index; // the connection thread index when a player thread is
|
||||
// associated with this, zero otherwise
|
||||
int scan_enable; // set to 1 if if sacanning should be considered
|
||||
char dacp_id[256]; // the DACP ID string
|
||||
uint16_t port; // zero if no port discovered
|
||||
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
|
||||
void *port_monitor_private_storage;
|
||||
} dacp_server_record;
|
||||
|
||||
pthread_t dacp_monitor_thread;
|
||||
@@ -175,8 +177,8 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
|
||||
response.code = 497; // Can't establish a socket to the DACP server
|
||||
} else {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 250000;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1)
|
||||
debug(1, "Error %d setting receive timeout for DACP service.", errno);
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof tv) == -1)
|
||||
@@ -294,43 +296,69 @@ void relinquish_dacp_server_information(rtsp_conn_info *conn) {
|
||||
}
|
||||
|
||||
// this will be running on the thread of its caller, not of the conversation thread...
|
||||
void set_dacp_server_information(rtsp_conn_info *conn) { // tell the DACP conversation thread that
|
||||
// the port has been set or changed
|
||||
// tell the DACP conversation thread what DACP server we are listening to
|
||||
// if the active_remote_id is the same we don't change anything apart from
|
||||
// the conversation number
|
||||
// Thus, we can keep the DACP port that might have previously been discovered
|
||||
void set_dacp_server_information(rtsp_conn_info *conn) {
|
||||
sps_pthread_mutex_timedlock(
|
||||
&dacp_server_information_lock, 500000,
|
||||
"set_dacp_server_information couldn't get DACP server information lock in 0.5 second!.", 1);
|
||||
dacp_server.players_connection_thread_index = conn->connection_number;
|
||||
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;
|
||||
if (dacp_server.port)
|
||||
dacp_server.scan_enable = 1;
|
||||
else {
|
||||
debug(1, "DACP server port has been set to zero.");
|
||||
if (strcmp(conn->dacp_id, dacp_server.dacp_id) != 0) {
|
||||
strncpy(dacp_server.dacp_id, conn->dacp_id, sizeof(dacp_server.dacp_id));
|
||||
dacp_server.port = 0;
|
||||
dacp_server.scan_enable = 0;
|
||||
}
|
||||
metadata_hub_modify_prolog();
|
||||
int ch = metadata_store.dacp_server_active != dacp_server.scan_enable;
|
||||
metadata_store.dacp_server_active = dacp_server.scan_enable;
|
||||
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;
|
||||
|
||||
if ((metadata_store.client_ip == NULL) ||
|
||||
(strncmp(metadata_store.client_ip, conn->client_ip_string, INET6_ADDRSTRLEN) != 0)) {
|
||||
if (metadata_store.client_ip)
|
||||
free(metadata_store.client_ip);
|
||||
metadata_store.client_ip = strndup(conn->client_ip_string, INET6_ADDRSTRLEN);
|
||||
debug(1, "MH Client IP set to: \"%s\"", metadata_store.client_ip);
|
||||
metadata_store.client_ip_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
ch = 1;
|
||||
}
|
||||
metadata_hub_modify_epilog(ch);
|
||||
if (dacp_server.port_monitor_private_storage) // if there's is a monitor already active...
|
||||
mdns_dacp_dont_monitor(dacp_server.port_monitor_private_storage); // let it go.
|
||||
dacp_server.port_monitor_private_storage =
|
||||
mdns_dacp_monitor(dacp_server.dacp_id); // create a new one for us
|
||||
|
||||
metadata_hub_modify_prolog();
|
||||
int ch = metadata_store.dacp_server_active != dacp_server.scan_enable;
|
||||
metadata_store.dacp_server_active = dacp_server.scan_enable;
|
||||
if ((metadata_store.client_ip == NULL) ||
|
||||
(strncmp(metadata_store.client_ip, conn->client_ip_string, INET6_ADDRSTRLEN) != 0)) {
|
||||
if (metadata_store.client_ip)
|
||||
free(metadata_store.client_ip);
|
||||
metadata_store.client_ip = strndup(conn->client_ip_string, INET6_ADDRSTRLEN);
|
||||
debug(3, "MH Client IP set to: \"%s\"", metadata_store.client_ip);
|
||||
ch = 1;
|
||||
}
|
||||
metadata_hub_modify_epilog(ch);
|
||||
}
|
||||
pthread_cond_signal(&dacp_server_information_cv);
|
||||
pthread_mutex_unlock(&dacp_server_information_lock);
|
||||
}
|
||||
|
||||
void dacp_monitor_port_update_callback(char *dacp_id, uint16_t port) {
|
||||
debug(3, "dacp_monitor_port_update_callback with Remote ID \"%s\" and port number %d.", dacp_id,
|
||||
port);
|
||||
sps_pthread_mutex_timedlock(
|
||||
&dacp_server_information_lock, 500000,
|
||||
"dacp_monitor_port_update_callback couldn't get DACP server information lock in 0.5 second!.",
|
||||
1);
|
||||
if (strcmp(dacp_id, dacp_server.dacp_id) == 0) {
|
||||
dacp_server.port = port;
|
||||
if (port == 0)
|
||||
dacp_server.scan_enable = 0;
|
||||
else
|
||||
dacp_server.scan_enable = 1;
|
||||
metadata_hub_modify_prolog();
|
||||
int ch = metadata_store.dacp_server_active != dacp_server.scan_enable;
|
||||
metadata_store.dacp_server_active = dacp_server.scan_enable;
|
||||
metadata_hub_modify_epilog(ch);
|
||||
pthread_cond_signal(&dacp_server_information_cv);
|
||||
} else {
|
||||
debug(1, "dacp port monitor reporting on and out-of-use remote.");
|
||||
}
|
||||
pthread_mutex_unlock(&dacp_server_information_lock);
|
||||
}
|
||||
void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
|
||||
int scan_index = 0;
|
||||
// char server_reply[10000];
|
||||
@@ -361,8 +389,10 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
|
||||
// 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);
|
||||
|
||||
if (result != 494) { // this just means that it couldn't send the query because something else
|
||||
// was sending a command
|
||||
int transient_problem = (result == 494) || (result == 495);
|
||||
if (!transient_problem) { // this just means that it couldn't send the query because something
|
||||
// else
|
||||
// was sending a command or something
|
||||
int adv = (result == 200);
|
||||
// a result of 200 means the advanced features of, e.g., iTunes, are available
|
||||
// so, turn the advanced_dacp_server flag on or off and flag if it's changed.
|
||||
|
||||
@@ -26,6 +26,8 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_array, int max_size_of_array,
|
||||
void set_dacp_server_information(rtsp_conn_info *conn); // tell the DACP conversation thread that
|
||||
// the dacp server information has been set
|
||||
// or changed
|
||||
void dacp_monitor_port_update_callback(
|
||||
char *dacp_id, uint16_t port); // a callback to say the port is no longer in use
|
||||
int send_simple_dacp_command(const char *command);
|
||||
|
||||
int dacp_set_include_speaker_volume(int64_t machine_number, int32_t vo);
|
||||
|
||||
@@ -104,21 +104,23 @@ void mdns_unregister(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void mdns_dacp_monitor(rtsp_conn_info *conn) {
|
||||
void *mdns_dacp_monitor(char *dacp_id) {
|
||||
void *reply = NULL;
|
||||
if ((config.mdns) && (config.mdns->mdns_dacp_monitor)) {
|
||||
int error = config.mdns->mdns_dacp_monitor(conn);
|
||||
if (error) {
|
||||
reply = config.mdns->mdns_dacp_monitor(dacp_id);
|
||||
if (reply == NULL) {
|
||||
debug(1, "Error starting a DACP monitor.");
|
||||
}
|
||||
} else
|
||||
debug(1, "Can't start a DACP monitor.");
|
||||
debug(1, "Can't start a DACP monitor -- none registered.");
|
||||
return reply;
|
||||
}
|
||||
|
||||
void mdns_dacp_dont_monitor(rtsp_conn_info *conn) {
|
||||
void mdns_dacp_dont_monitor(void *userdata) {
|
||||
if ((config.mdns) && (config.mdns->mdns_dacp_dont_monitor)) {
|
||||
config.mdns->mdns_dacp_dont_monitor(conn);
|
||||
config.mdns->mdns_dacp_dont_monitor(userdata);
|
||||
} else
|
||||
debug(1, "Can't stop a DACP monitor.");
|
||||
debug(1, "Can't stop a DACP monitor -- none registered.");
|
||||
}
|
||||
void mdns_ls_backends(void) {
|
||||
mdns_backend **b = NULL;
|
||||
|
||||
@@ -9,8 +9,8 @@ extern int mdns_pid;
|
||||
|
||||
void mdns_unregister(void);
|
||||
void mdns_register(void);
|
||||
void mdns_dacp_monitor(rtsp_conn_info *conn);
|
||||
void mdns_dacp_dont_monitor(rtsp_conn_info *conn);
|
||||
void *mdns_dacp_monitor(char *dacp_id);
|
||||
void mdns_dacp_dont_monitor(void *userdata);
|
||||
|
||||
void mdns_ls_backends(void);
|
||||
|
||||
@@ -18,8 +18,8 @@ typedef struct {
|
||||
char *name;
|
||||
int (*mdns_register)(char *apname, int port);
|
||||
void (*mdns_unregister)(void);
|
||||
int (*mdns_dacp_monitor)(rtsp_conn_info *conn);
|
||||
void (*mdns_dacp_dont_monitor)(rtsp_conn_info *conn);
|
||||
void *(*mdns_dacp_monitor)(char *);
|
||||
void (*mdns_dacp_dont_monitor)(void *);
|
||||
} mdns_backend;
|
||||
|
||||
#ifdef CONFIG_METADATA
|
||||
|
||||
+50
-69
@@ -51,6 +51,7 @@ typedef struct {
|
||||
AvahiThreadedPoll *service_poll;
|
||||
AvahiClient *service_client;
|
||||
AvahiServiceBrowser *service_browser;
|
||||
char *dacp_id;
|
||||
} dacp_browser_struct;
|
||||
|
||||
// static AvahiServiceBrowser *sb = NULL;
|
||||
@@ -72,8 +73,7 @@ static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIn
|
||||
__attribute__((unused)) AvahiLookupResultFlags flags, void *userdata) {
|
||||
assert(r);
|
||||
|
||||
rtsp_conn_info *conn = (rtsp_conn_info *)userdata;
|
||||
// dacp_browser_struct *dbs = (dacp_browser_struct *)conn->mdns_private_pointer;
|
||||
dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
|
||||
|
||||
/* Called whenever a service has been resolved successfully or timed out */
|
||||
switch (event) {
|
||||
@@ -87,20 +87,17 @@ 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, conn->dacp_id) == 0) {
|
||||
if (conn->dacp_port != port) {
|
||||
debug(2, "Client's DACP port: %u.", port);
|
||||
conn->dacp_port = port;
|
||||
if (strcmp(dacpid, dbs->dacp_id) == 0) {
|
||||
debug(3, "Client's DACP port: %u.", port);
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
set_dacp_server_information(conn);
|
||||
dacp_monitor_port_update_callback(dacpid, port);
|
||||
#endif
|
||||
#ifdef CONFIG_METADATA
|
||||
char portstring[20];
|
||||
memset(portstring, 0, sizeof(portstring));
|
||||
sprintf(portstring, "%u", port);
|
||||
send_ssnc_metadata('dapo', strdup(portstring), strlen(portstring), 0);
|
||||
char portstring[20];
|
||||
memset(portstring, 0, sizeof(portstring));
|
||||
sprintf(portstring, "%u", port);
|
||||
send_ssnc_metadata('dapo', strdup(portstring), strlen(portstring), 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug(1, "Resolve callback: Can't see a DACP string in a DACP Record!");
|
||||
@@ -113,8 +110,7 @@ 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) {
|
||||
rtsp_conn_info *conn = (rtsp_conn_info *)userdata;
|
||||
dacp_browser_struct *dbs = (dacp_browser_struct *)conn->mdns_private_pointer;
|
||||
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) {
|
||||
@@ -135,29 +131,17 @@ static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, Avah
|
||||
avahi_strerror(avahi_client_errno(dbs->service_client)));
|
||||
break;
|
||||
case AVAHI_BROWSER_REMOVE:
|
||||
debug(3, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'.", name, type, domain);
|
||||
debug(1, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'.", name, type, domain);
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
char *dacpid = strstr(name, "iTunes_Ctrl_");
|
||||
if (dacpid) {
|
||||
dacpid += strlen("iTunes_Ctrl_");
|
||||
if (strcmp(dacpid, conn->dacp_id) == 0) {
|
||||
if (conn->dacp_id != 0) {
|
||||
debug(3, "Client's DACP status withdrawn.");
|
||||
conn->dacp_port = 0;
|
||||
/*
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
// this might be in a race condition with another connection that could come into effect
|
||||
before this one has terminated.
|
||||
set_dacp_server_information(conn); // this will have the effect of telling the
|
||||
scanner
|
||||
// that the DACP server is no longer working
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
}
|
||||
if (strcmp(dacpid, dbs->dacp_id) == 0)
|
||||
dacp_monitor_port_update_callback(dbs->dacp_id, 0); // say the port is withdrawn
|
||||
} else {
|
||||
debug(1, "Browse callback: Can't see a DACP string in a DACP Record!");
|
||||
}
|
||||
|
||||
#endif
|
||||
break;
|
||||
case AVAHI_BROWSER_ALL_FOR_NOW:
|
||||
case AVAHI_BROWSER_CACHE_EXHAUSTED:
|
||||
@@ -309,8 +293,7 @@ static void client_callback(AvahiClient *c, AvahiClientState state,
|
||||
static void service_client_callback(AvahiClient *c, AvahiClientState state, void *userdata) {
|
||||
int err;
|
||||
|
||||
rtsp_conn_info *conn = (rtsp_conn_info *)userdata;
|
||||
dacp_browser_struct *dbs = (dacp_browser_struct *)conn->mdns_private_pointer;
|
||||
dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
|
||||
|
||||
switch (state) {
|
||||
case AVAHI_CLIENT_S_REGISTERING:
|
||||
@@ -390,71 +373,68 @@ static void avahi_unregister(void) {
|
||||
service_name = NULL;
|
||||
}
|
||||
|
||||
int avahi_dacp_monitor(rtsp_conn_info *conn) {
|
||||
|
||||
void *avahi_dacp_monitor(char *dacp_id) {
|
||||
dacp_browser_struct *dbs = (dacp_browser_struct *)malloc(sizeof(dacp_browser_struct));
|
||||
|
||||
if (dbs == NULL)
|
||||
die("can not allocate a dacp_browser_struct.");
|
||||
|
||||
conn->mdns_private_pointer = (void *)dbs;
|
||||
char *t = strdup(dacp_id);
|
||||
if (t)
|
||||
dbs->dacp_id = t;
|
||||
else {
|
||||
die("can not allocate a dacp_id string in dacp_browser_struct.");
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
conn->mdns_private_pointer = NULL;
|
||||
return -1;
|
||||
free(dbs->dacp_id);
|
||||
free((char *)dbs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 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 *)conn, &err))) {
|
||||
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);
|
||||
}
|
||||
conn->mdns_private_pointer = NULL;
|
||||
return -1;
|
||||
avahi_threaded_poll_free(dbs->service_poll);
|
||||
free(dbs->dacp_id);
|
||||
free((char *)dbs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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 *)conn))) {
|
||||
"_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);
|
||||
}
|
||||
conn->mdns_private_pointer = NULL;
|
||||
return -1;
|
||||
avahi_client_free(dbs->service_client);
|
||||
avahi_threaded_poll_free(dbs->service_poll);
|
||||
free(dbs->dacp_id);
|
||||
free((char *)dbs);
|
||||
return NULL;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
conn->mdns_private_pointer = NULL;
|
||||
return -1;
|
||||
avahi_service_browser_free(dbs->service_browser);
|
||||
avahi_client_free(dbs->service_client);
|
||||
avahi_threaded_poll_free(dbs->service_poll);
|
||||
free(dbs->dacp_id);
|
||||
free((char *)dbs);
|
||||
return NULL;
|
||||
}
|
||||
return 0;
|
||||
debug(3, "DACP monitor successfully started");
|
||||
return (void *)dbs;
|
||||
}
|
||||
|
||||
void avahi_dacp_dont_monitor(rtsp_conn_info *conn) {
|
||||
dacp_browser_struct *dbs = (dacp_browser_struct *)conn->mdns_private_pointer;
|
||||
if (dbs) {
|
||||
void avahi_dacp_dont_monitor(void *userdata) {
|
||||
if (userdata) {
|
||||
dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
|
||||
// stop and dispose of everything
|
||||
if ((dbs)->service_poll)
|
||||
avahi_threaded_poll_stop((dbs)->service_poll);
|
||||
@@ -464,8 +444,9 @@ void avahi_dacp_dont_monitor(rtsp_conn_info *conn) {
|
||||
avahi_client_free((dbs)->service_client);
|
||||
if ((dbs)->service_poll)
|
||||
avahi_threaded_poll_free((dbs)->service_poll);
|
||||
free(dbs->dacp_id);
|
||||
free((char *)(dbs));
|
||||
conn->mdns_private_pointer = NULL;
|
||||
debug(3, "DACP monitor successfully stopped");
|
||||
} else {
|
||||
debug(1, "DHCP Monitor is not running.");
|
||||
}
|
||||
|
||||
+2
-2
@@ -87,9 +87,9 @@ void metadata_hub_modify_prolog(void) {
|
||||
// always run this before changing an entry or a sequence of entries in the metadata_hub
|
||||
// debug(1, "locking metadata hub for writing");
|
||||
if (pthread_rwlock_trywrlock(&metadata_hub_re_lock) != 0) {
|
||||
debug(1, "Metadata_hub write lock is already taken -- must wait.");
|
||||
debug(2, "Metadata_hub write lock is already taken -- must wait.");
|
||||
pthread_rwlock_wrlock(&metadata_hub_re_lock);
|
||||
debug(1, "Okay -- acquired the metadata_hub write lock.");
|
||||
debug(2, "Okay -- acquired the metadata_hub write lock.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co
|
||||
#ifdef HAVE_APPLE_ALAC
|
||||
if (config.use_apple_decoder) {
|
||||
if (conn->decoder_in_use != 1 << decoder_apple_alac) {
|
||||
debug(1, "Apple ALAC Decoder used on encrypted audio.");
|
||||
debug(2, "Apple ALAC Decoder used on encrypted audio.");
|
||||
conn->decoder_in_use = 1 << decoder_apple_alac;
|
||||
}
|
||||
apple_alac_decode_frame(packet, len, (unsigned char *)dest, &outsize);
|
||||
@@ -286,7 +286,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co
|
||||
#endif
|
||||
{
|
||||
if (conn->decoder_in_use != 1 << decoder_hammerton) {
|
||||
debug(1, "Hammerton Decoder used on encrypted audio.");
|
||||
debug(2, "Hammerton Decoder used on encrypted audio.");
|
||||
conn->decoder_in_use = 1 << decoder_hammerton;
|
||||
}
|
||||
alac_decode_frame(conn->decoder_info, packet, (unsigned char *)dest, &outsize);
|
||||
@@ -296,7 +296,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co
|
||||
#ifdef HAVE_APPLE_ALAC
|
||||
if (config.use_apple_decoder) {
|
||||
if (conn->decoder_in_use != 1 << decoder_apple_alac) {
|
||||
debug(1, "Apple ALAC Decoder used on unencrypted audio.");
|
||||
debug(2, "Apple ALAC Decoder used on unencrypted audio.");
|
||||
conn->decoder_in_use = 1 << decoder_apple_alac;
|
||||
}
|
||||
apple_alac_decode_frame(buf, len, (unsigned char *)dest, &outsize);
|
||||
@@ -305,7 +305,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co
|
||||
#endif
|
||||
{
|
||||
if (conn->decoder_in_use != 1 << decoder_hammerton) {
|
||||
debug(1, "Hammerton Decoder used on unencrypted audio.");
|
||||
debug(2, "Hammerton Decoder used on unencrypted audio.");
|
||||
conn->decoder_in_use = 1 << decoder_hammerton;
|
||||
}
|
||||
alac_decode_frame(conn->decoder_info, buf, dest, &outsize);
|
||||
@@ -824,13 +824,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
reference_timestamp *= conn->output_sample_ratio;
|
||||
if (conn->first_packet_timestamp == 0) { // if this is the very first packet
|
||||
// debug(1,"First frame seen, time %u, with %d
|
||||
// frames...",curframe->timestamp,seq_diff(ab_read, ab_write));
|
||||
|
||||
// say we have started playing here
|
||||
#ifdef CONFIG_METADATA
|
||||
send_ssnc_metadata('pffr', NULL, 0,
|
||||
0); // "first frame received", but don't wait if the queue is locked
|
||||
#endif
|
||||
// frames...",curframe->timestamp,seq_diff(ab_read, ab_write));
|
||||
|
||||
if (reference_timestamp) { // if we have a reference time
|
||||
// debug(1,"First frame seen with timestamp...");
|
||||
@@ -839,6 +833,13 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
// supposed to start playing this
|
||||
have_sent_prefiller_silence = 0;
|
||||
|
||||
// say we have started playing here
|
||||
#ifdef CONFIG_METADATA
|
||||
debug(1, "pffr");
|
||||
send_ssnc_metadata(
|
||||
'pffr', NULL, 0,
|
||||
0); // "first frame received", but don't wait if the queue is locked
|
||||
#endif
|
||||
// Here, calculate when we should start playing. We need to know when to allow the
|
||||
// packets to be sent to the player.
|
||||
// We will send packets of silence from now until that time and then we will send the
|
||||
@@ -1059,6 +1060,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
&conn->play_segment_reference_frame_remote_time, conn);
|
||||
conn->play_segment_reference_frame *= conn->output_sample_ratio;
|
||||
#ifdef CONFIG_METADATA
|
||||
debug(1, "prsm");
|
||||
send_ssnc_metadata('prsm', NULL, 0,
|
||||
0); // "resume", but don't wait if the queue is locked
|
||||
#endif
|
||||
@@ -1384,9 +1386,9 @@ static void *player_thread_func(void *arg) {
|
||||
conn->fix_volume = 0x10000;
|
||||
|
||||
if (conn->latency == 0) {
|
||||
debug(1,
|
||||
"No latency has (yet) been specified. Setting 99225 (2.25 seconds) frames as a default.");
|
||||
conn->latency = 99225;
|
||||
debug(3, "No latency has (yet) been specified. Setting 99,226 (2.25 seconds + 1 frame) frames "
|
||||
"as a default.");
|
||||
conn->latency = 99226;
|
||||
}
|
||||
|
||||
int rc = pthread_mutex_init(&conn->ab_mutex, NULL);
|
||||
@@ -1463,7 +1465,7 @@ static void *player_thread_func(void *arg) {
|
||||
conn->output_bytes_per_frame = 4;
|
||||
}
|
||||
|
||||
debug(1, "Output frame bytes is %d.", conn->output_bytes_per_frame);
|
||||
debug(3, "Output frame bytes is %d.", conn->output_bytes_per_frame);
|
||||
|
||||
// create and start the timing, control and audio receiver threads
|
||||
pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread;
|
||||
@@ -1548,7 +1550,7 @@ static void *player_thread_func(void *arg) {
|
||||
die("Unknown format choosing output bit depth");
|
||||
}
|
||||
|
||||
debug(1, "Output bit depth is %d.", output_bit_depth);
|
||||
debug(3, "Output bit depth is %d.", output_bit_depth);
|
||||
|
||||
if (conn->input_bit_depth > output_bit_depth) {
|
||||
debug(1, "Dithering will be enabled because the input bit depth is greater than the output bit "
|
||||
@@ -1601,11 +1603,12 @@ static void *player_thread_func(void *arg) {
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
set_dacp_server_information(conn); // this will start scanning when a port is registered by the
|
||||
// code initiated by the mdns_dacp_monitor
|
||||
#endif
|
||||
#else
|
||||
// this is only used for compatability, if dacp stuff isn't enabled.
|
||||
// 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);
|
||||
mdns_dacp_monitor(conn);
|
||||
conn->dapo_private_storage = mdns_dacp_monitor(conn->dacp_id);
|
||||
#endif
|
||||
|
||||
conn->framesProcessedInThisEpoch = 0;
|
||||
conn->framesGeneratedInThisEpoch = 0;
|
||||
@@ -2223,10 +2226,11 @@ static void *player_thread_func(void *arg) {
|
||||
elapsedSec);
|
||||
}
|
||||
|
||||
#ifndef HAVE_DACP_CLIENT
|
||||
// stop watching for DACP port number stuff
|
||||
mdns_dacp_dont_monitor(conn); // begin looking out for information about the client
|
||||
// as a remote control. Specifically we might need
|
||||
// the port number
|
||||
// this is only used for compatability, if dacp stuff isn't enabled.
|
||||
mdns_dacp_dont_monitor(conn->dapo_private_storage);
|
||||
#endif
|
||||
|
||||
if (config.output->stop)
|
||||
config.output->stop();
|
||||
@@ -2525,7 +2529,12 @@ void player_flush(int64_t timestamp, rtsp_conn_info *conn) {
|
||||
conn->play_segment_reference_frame = 0;
|
||||
conn->play_number_after_flush = 0;
|
||||
#ifdef CONFIG_METADATA
|
||||
send_ssnc_metadata('pfls', NULL, 0, 1);
|
||||
// only send a flush metadata message if the first packet has been seen -- it's a bogus message
|
||||
// otherwise
|
||||
if (conn->first_packet_timestamp) {
|
||||
debug(1, "pfls");
|
||||
send_ssnc_metadata('pfls', NULL, 0, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2538,6 +2547,7 @@ int player_play(rtsp_conn_info *conn) {
|
||||
BUFFER_FRAMES);
|
||||
command_start();
|
||||
#ifdef CONFIG_METADATA
|
||||
debug(1, "pbeg");
|
||||
send_ssnc_metadata('pbeg', NULL, 0, 1);
|
||||
#endif
|
||||
pthread_t *pt = malloc(sizeof(pthread_t));
|
||||
@@ -2562,6 +2572,7 @@ void player_stop(rtsp_conn_info *conn) {
|
||||
pthread_kill(*conn->player_thread, SIGUSR1);
|
||||
pthread_join(*conn->player_thread, NULL);
|
||||
#ifdef CONFIG_METADATA
|
||||
debug(1, "pend");
|
||||
send_ssnc_metadata('pend', NULL, 0, 1);
|
||||
#endif
|
||||
command_stop();
|
||||
|
||||
@@ -173,11 +173,11 @@ typedef struct {
|
||||
// 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
|
||||
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 *mdns_private_pointer; // private storage (just a pointer) for the dacp_port resolver
|
||||
|
||||
void *dapo_private_storage; // this is used for compatibility, if dacp stuff isn't enabled.
|
||||
} rtsp_conn_info;
|
||||
|
||||
int player_play(rtsp_conn_info *conn);
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "common.h"
|
||||
#include "player.h"
|
||||
#include "rtp.h"
|
||||
#include "rtsp.h"
|
||||
|
||||
uint64_t local_to_remote_time_jitters;
|
||||
uint64_t local_to_remote_time_jitters_count;
|
||||
@@ -246,10 +247,10 @@ void *rtp_control_receiver(void *arg) {
|
||||
|
||||
if (la != conn->latency) {
|
||||
conn->latency = la;
|
||||
debug(1, "New latency: %lld, sync latency: %lld, minimum latency: %lld, maximum "
|
||||
"latency: %lld, fixed offset: %lld.",
|
||||
la, sync_rtp_timestamp - rtp_timestamp_less_latency, conn->minimum_latency,
|
||||
conn->maximum_latency, config.fixedLatencyOffset);
|
||||
// debug(1, "New latency: %lld, sync latency: %lld, minimum latency: %lld, maximum "
|
||||
// "latency: %lld, fixed offset: %lld.",
|
||||
// la, sync_rtp_timestamp - rtp_timestamp_less_latency, conn->minimum_latency,
|
||||
// conn->maximum_latency, config.fixedLatencyOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,6 +800,11 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, int *lsp
|
||||
|
||||
conn->request_sent = 0;
|
||||
conn->rtp_running = 1;
|
||||
|
||||
#ifdef CONFIG_METADATA
|
||||
send_ssnc_metadata('clip', strdup(conn->client_ip_string), strlen(conn->client_ip_string), 1);
|
||||
send_ssnc_metadata('svip', strdup(conn->self_ip_string), strlen(conn->self_ip_string), 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time,
|
||||
|
||||
@@ -768,7 +768,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
|
||||
|
||||
char *ar = msg_get_header(req, "Active-Remote");
|
||||
if (ar) {
|
||||
debug(1, "Active-Remote string seen: \"%s\".", ar);
|
||||
debug(2, "Active-Remote string seen: \"%s\".", ar);
|
||||
// get the active remote
|
||||
char *p;
|
||||
conn->dacp_active_remote = strtoul(ar, &p, 10);
|
||||
@@ -779,7 +779,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
|
||||
|
||||
ar = msg_get_header(req, "DACP-ID");
|
||||
if (ar) {
|
||||
debug(1, "DACP-ID string seen: \"%s\".", ar);
|
||||
debug(2, "DACP-ID string seen: \"%s\".", ar);
|
||||
conn->dacp_id = strdup(ar);
|
||||
#ifdef CONFIG_METADATA
|
||||
send_metadata('ssnc', 'daid', ar, strlen(ar), req, 1);
|
||||
@@ -915,7 +915,7 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r
|
||||
// 'pfls' -- play stream flush. No arguments
|
||||
// 'prsm' -- play stream resume. No arguments
|
||||
// `pffr` -- the first frame of a play session has been received and has been validly
|
||||
//timed.
|
||||
// timed.
|
||||
// 'pvol' -- play volume. The volume is sent as a string --
|
||||
// "airplay_volume,volume,lowest_volume,highest_volume"
|
||||
// volume, lowest_volume and highest_volume are given in dB.
|
||||
@@ -1579,7 +1579,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
|
||||
}
|
||||
hdr = msg_get_header(req, "User-Agent");
|
||||
if (hdr) {
|
||||
debug(1, "Play connection from user agent \"%s\" on RTSP conversation thread %d.", hdr,
|
||||
debug(2, "Play connection from user agent \"%s\" on RTSP conversation thread %d.", hdr,
|
||||
conn->connection_number);
|
||||
#ifdef CONFIG_METADATA
|
||||
send_metadata('ssnc', 'snua', hdr, strlen(hdr), req, 1);
|
||||
@@ -2118,11 +2118,7 @@ void rtsp_listen_loop(void) {
|
||||
sa = (struct sockaddr_in *)&conn->remote;
|
||||
inet_ntop(AF_INET, &(sa->sin_addr), remote_ip4, INET_ADDRSTRLEN);
|
||||
unsigned short int rport = ntohs(sa->sin_port);
|
||||
#ifdef CONFIG_METADATA
|
||||
send_ssnc_metadata('clip', strdup(remote_ip4), strlen(remote_ip4), 1);
|
||||
send_ssnc_metadata('svip', strdup(ip4), strlen(ip4), 1);
|
||||
#endif
|
||||
debug(1, "New RTSP connection from %s:%u to self at %s:%u on conversation thread %d.",
|
||||
debug(2, "New RTSP connection from %s:%u to self at %s:%u on conversation thread %d.",
|
||||
remote_ip4, rport, ip4, tport, conn->connection_number);
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
@@ -2139,11 +2135,7 @@ void rtsp_listen_loop(void) {
|
||||
sa6 = (struct sockaddr_in6 *)&conn->remote; // pretend this is loaded with something
|
||||
inet_ntop(AF_INET6, &(sa6->sin6_addr), remote_ip6, INET6_ADDRSTRLEN);
|
||||
u_int16_t rport = ntohs(sa6->sin6_port);
|
||||
#ifdef CONFIG_METADATA
|
||||
send_ssnc_metadata('clip', strdup(remote_ip6), strlen(remote_ip6), 1);
|
||||
send_ssnc_metadata('svip', strdup(ip6), strlen(ip6), 1);
|
||||
#endif
|
||||
debug(1, "New RTSP connection from [%s]:%u to self at [%s]:%u on conversation thread %d.",
|
||||
debug(2, "New RTSP connection from [%s]:%u to self at [%s]:%u on conversation thread %d.",
|
||||
remote_ip6, rport, ip6, tport, conn->connection_number);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user