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:
Mike Brady
2018-03-31 17:34:59 +01:00
parent 69b3b5d776
commit 32c7a535a1
11 changed files with 183 additions and 159 deletions
+2 -2
View File
@@ -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;
+60 -30
View File
@@ -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.
+2
View File
@@ -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);
+9 -7
View File
@@ -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;
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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.");
}
}
+34 -23
View File
@@ -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();
+4 -4
View File
@@ -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);
+10 -4
View File
@@ -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,
+6 -14
View File
@@ -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