From 32c7a535a13dc8db33dd5978aaacc21963d9f473 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sat, 31 Mar 2018 17:34:59 +0100 Subject: [PATCH] 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 --- audio_alsa.c | 4 +- dacp.c | 92 +++++++++++++++++++++++++------------- dacp.h | 2 + mdns.c | 16 ++++--- mdns.h | 8 ++-- mdns_avahi.c | 119 +++++++++++++++++++++---------------------------- metadata_hub.c | 4 +- player.c | 57 +++++++++++++---------- player.h | 8 ++-- rtp.c | 14 ++++-- rtsp.c | 20 +++------ 11 files changed, 184 insertions(+), 160 deletions(-) diff --git a/audio_alsa.c b/audio_alsa.c index 7a60db22a..beb8158cf 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -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; diff --git a/dacp.c b/dacp.c index cb6581ca2..b6ad72ee7 100644 --- a/dacp.c +++ b/dacp.c @@ -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; + 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_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); } - 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(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); - 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. diff --git a/dacp.h b/dacp.h index 1a04e0166..09dd477db 100644 --- a/dacp.h +++ b/dacp.h @@ -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); diff --git a/mdns.c b/mdns.c index 0651cdcfe..6634d1d02 100644 --- a/mdns.c +++ b/mdns.c @@ -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; diff --git a/mdns.h b/mdns.h index e5360e260..9f96a9f72 100644 --- a/mdns.h +++ b/mdns.h @@ -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 diff --git a/mdns_avahi.c b/mdns_avahi.c index 05bbbe3db..b1f8c31b9 100644 --- a/mdns_avahi.c +++ b/mdns_avahi.c @@ -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."); } diff --git a/metadata_hub.c b/metadata_hub.c index 3f912cf0c..049ec0fa4 100644 --- a/metadata_hub.c +++ b/metadata_hub.c @@ -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."); } } diff --git a/player.c b/player.c index 3e36940d7..6e3f533d8 100644 --- a/player.c +++ b/player.c @@ -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(); diff --git a/player.h b/player.h index a4dcfe4a5..a6deb7c80 100644 --- a/player.h +++ b/player.h @@ -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); diff --git a/rtp.c b/rtp.c index ec3f2fc8c..03002fa72 100644 --- a/rtp.c +++ b/rtp.c @@ -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, diff --git a/rtsp.c b/rtsp.c index 530fdbfa4..ca6e48d41 100644 --- a/rtsp.c +++ b/rtsp.c @@ -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