From: Mike Brady Date: Wed, 25 Mar 2020 10:16:21 +0000 (+0000) Subject: If the DACP port is zero, do a zeroconf re-broswe every two seconds in case it has... X-Git-Tag: 3.3.7d12~111 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a6acb6062afa51a6550d7dde872269000f80aaf7;p=thirdparty%2Fshairport-sync.git If the DACP port is zero, do a zeroconf re-broswe every two seconds in case it has been missed. --- diff --git a/common.h b/common.h index ba20078a..95f4decc 100644 --- a/common.h +++ b/common.h @@ -100,6 +100,7 @@ typedef enum { const char *sps_format_description_string(sps_format_t format); typedef struct { + double missing_port_dacp_scan_interval_seconds; // if no DACP port number can be found, check at these intervals double resend_control_first_check_time; // wait this long before asking for a missing packet to be resent double resend_control_check_interval_time; // wait this long between making requests double resend_control_last_check_time; // if the packet is missing this close to the time of use, give up diff --git a/dacp.c b/dacp.c index 4c36de34..dc794d4d 100644 --- a/dacp.c +++ b/dacp.c @@ -1,6 +1,6 @@ /* * DACP protocol handler. This file is part of Shairport Sync. - * Copyright (c) Mike Brady 2017 -- 2019 + * Copyright (c) Mike Brady 2017 -- 2020 * All rights reserved. * * Permission is hereby granted, free of charge, to any person @@ -49,7 +49,7 @@ 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 + int scan_enable; // set to 1 if scanning 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 @@ -123,7 +123,7 @@ static const struct http_funcs responseFuncs = { // static pthread_mutex_t dacp_server_information_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t dacp_conversation_lock; static pthread_mutex_t dacp_server_information_lock; -static pthread_cond_t dacp_server_information_cv = PTHREAD_COND_INITIALIZER; +static pthread_cond_t dacp_server_information_cv; void addrinfo_cleanup(void *arg) { // debug(1, "addrinfo cleanup called."); @@ -154,7 +154,7 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) { // debug(1,"dacp_send_command: command is: \"%s\".",command); if (dacp_server.port == 0) { - debug(1, "No DACP port specified yet"); + debug(2, "No DACP port specified yet"); result = 490; // no port specified } else { @@ -169,6 +169,7 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) { // 493 Client failed to send a message // 492 Argument out of range // 491 Client refused connection + // 490 No port specified struct addrinfo hints, *res; int sockfd; @@ -421,9 +422,6 @@ void set_dacp_server_information(rtsp_conn_info *conn) { dacp_server.always_use_revision_number_1 = 1; } - - mdns_dacp_monitor_set_id(dacp_server.dacp_id); - metadata_hub_modify_prolog(); int ch = metadata_store.dacp_server_active != dacp_server.scan_enable; metadata_store.dacp_server_active = dacp_server.scan_enable; @@ -513,14 +511,40 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) { "flag value of %d", ch); metadata_hub_modify_epilog(ch); - while (dacp_server.scan_enable == 0) { - // debug(1, "dacp_monitor_thread_code wait for an event to possible enable scan"); - pthread_cond_wait(&dacp_server_information_cv, &dacp_server_information_lock); - // debug(1,"dacp_monitor_thread_code wake up."); + + uint64_t time_to_wait_for_wakeup_ns = (uint64_t)(1000000000 * config.missing_port_dacp_scan_interval_seconds); + +#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD + uint64_t time_of_wakeup_ns = get_absolute_time_in_ns() + time_to_wait_for_wakeup_ns; + uint64_t sec = time_of_wakeup_ns / 1000000000; + uint64_t nsec = time_of_wakeup_ns % 1000000000; +#endif +#ifdef COMPILE_FOR_OSX + uint64_t sec = time_to_wait_for_wakeup_ns / 1000000000; + uint64_t nsec = time_to_wait_for_wakeup_ns % 1000000000; +#endif + + struct timespec time_to_wait; + time_to_wait.tv_sec = sec; + time_to_wait.tv_nsec = nsec; + + while ((dacp_server.scan_enable == 0) && (result != ETIMEDOUT)) { + // debug(1, "dacp_monitor_thread_code wait for an event to possibly enable scan"); + +#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD + result = pthread_cond_timedwait(&dacp_server_information_cv, &dacp_server_information_lock, + &time_to_wait); // this is a pthread cancellation point + // debug(1, "result is %d, dacp_server.scan_enable is %d, time_to_wait_for_wakeup_ns is %" PRId64 ".", result, dacp_server.scan_enable, time_to_wait_for_wakeup_ns); + +#endif +#ifdef COMPILE_FOR_OSX + result = pthread_cond_timedwait_relative_np(&dacp_server_information_cv, &dacp_server_information_lock, &time_to_wait); +#endif + } + if (dacp_server.scan_enable == 1) { + bad_result_count = 0; + idle_scan_count = 0; } - // so dacp_server.scan_enable will be true at this point - bad_result_count = 0; - idle_scan_count = 0; } always_use_revision_number_1 = dacp_server.always_use_revision_number_1; // set this while access is locked @@ -528,360 +552,367 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) { result = dacp_get_volume(&the_volume); // just want the http code pthread_cleanup_pop(1); - scan_index++; - // debug(1,"DACP Scan Result: %d.", result); - - if ((result == 200) || (result == 400)) { - bad_result_count = 0; + if (result == 490) { // 490 means no port was specified + if ((dacp_server.dacp_id != NULL) && (strlen(dacp_server.dacp_id) != 0)) { + // debug(1,"mdns_dacp_monitor_set_id"); + mdns_dacp_monitor_set_id(dacp_server.dacp_id); + } } else { - if (bad_result_count < config.scan_max_bad_response_count) // limit to some reasonable value - bad_result_count++; - } - - // here, do the debouncing calculations to see - // if the dacp server and the - // advanced dacp server are available + scan_index++; + // debug(1,"DACP Scan Result: %d.", result); - // -1 means we don't know because some bad statuses have been reported - // 0 means definitely no - // +1 means definitely yes - - int dacp_server_status_now = -1; - int advanced_dacp_server_status_now = -1; + if ((result == 200) || (result == 400)) { + bad_result_count = 0; + } else { + if (bad_result_count < config.scan_max_bad_response_count) // limit to some reasonable value + bad_result_count++; + } - if (bad_result_count == 0) { - dacp_server_status_now = 1; - if (result == 200) - advanced_dacp_server_status_now = 1; - else if (result == 400) + // here, do the debouncing calculations to see + // if the dacp server and the + // advanced dacp server are available + + // -1 means we don't know because some bad statuses have been reported + // 0 means definitely no + // +1 means definitely yes + + int dacp_server_status_now = -1; + int advanced_dacp_server_status_now = -1; + + if (bad_result_count == 0) { + dacp_server_status_now = 1; + if (result == 200) + advanced_dacp_server_status_now = 1; + else if (result == 400) + advanced_dacp_server_status_now = 0; + } else if (bad_result_count == + config.scan_max_bad_response_count) { // if a sequence of bad return codes occurs, + // then it's gone + dacp_server_status_now = 0; advanced_dacp_server_status_now = 0; - } else if (bad_result_count == - config.scan_max_bad_response_count) { // if a sequence of bad return codes occurs, - // then it's gone - dacp_server_status_now = 0; - advanced_dacp_server_status_now = 0; - } + } - if (metadata_store.player_thread_active == 0) - idle_scan_count++; - else - idle_scan_count = 0; + if (metadata_store.player_thread_active == 0) + idle_scan_count++; + else + idle_scan_count = 0; - debug(3, "Scan Result: %d, Bad Scan Count: %d, Idle Scan Count: %d.", result, bad_result_count, - idle_scan_count); + debug(3, "Scan Result: %d, Bad Scan Count: %d, Idle Scan Count: %d.", result, bad_result_count, + idle_scan_count); - /* not used - // decide if idle for too long - if (idle_scan_count == config.scan_max_inactive_count) { - debug(2, "DACP server status scanning stopped."); - dacp_server.scan_enable = 0; - } - */ + /* not used + // decide if idle for too long + if (idle_scan_count == config.scan_max_inactive_count) { + debug(2, "DACP server status scanning stopped."); + dacp_server.scan_enable = 0; + } + */ - int update_needed = 0; - metadata_hub_modify_prolog(); - if (dacp_server_status_now != -1) { // if dacp_server_status_now is actually known... - if (metadata_store.dacp_server_active != dacp_server_status_now) { - debug(2, "metadata_store.dacp_server_active set to %d.", dacp_server_status_now); - metadata_store.dacp_server_active = dacp_server_status_now; - update_needed = 1; + int update_needed = 0; + metadata_hub_modify_prolog(); + if (dacp_server_status_now != -1) { // if dacp_server_status_now is actually known... + if (metadata_store.dacp_server_active != dacp_server_status_now) { + debug(2, "metadata_store.dacp_server_active set to %d.", dacp_server_status_now); + metadata_store.dacp_server_active = dacp_server_status_now; + update_needed = 1; + } } - } - if (advanced_dacp_server_status_now != - -1) { // if advanced_dacp_server_status_now is actually known... - if (metadata_store.advanced_dacp_server_active != advanced_dacp_server_status_now) { - debug(2, "metadata_store.advanced_dacp_server_active set to %d.", dacp_server_status_now); - metadata_store.advanced_dacp_server_active = advanced_dacp_server_status_now; - update_needed = 1; + if (advanced_dacp_server_status_now != + -1) { // if advanced_dacp_server_status_now is actually known... + if (metadata_store.advanced_dacp_server_active != advanced_dacp_server_status_now) { + debug(2, "metadata_store.advanced_dacp_server_active set to %d.", dacp_server_status_now); + metadata_store.advanced_dacp_server_active = advanced_dacp_server_status_now; + update_needed = 1; + } } - } - metadata_hub_modify_epilog(update_needed); + metadata_hub_modify_epilog(update_needed); - // pthread_mutex_unlock(&dacp_server_information_lock); - // 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); + // pthread_mutex_unlock(&dacp_server_information_lock); + // 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 == 200) { - metadata_hub_modify_prolog(); - int diff = metadata_store.speaker_volume != the_volume; - if (diff) - metadata_store.speaker_volume = the_volume; - metadata_hub_modify_epilog(diff); - - ssize_t le; - char *response = NULL; - int32_t item_size; - char command[1024] = ""; - if (always_use_revision_number_1 != 0) // for forked-daapd - revision_number = 1; - snprintf(command, sizeof(command) - 1, "playstatusupdate?revision-number=%d", - revision_number); - // debug(1,"dacp_monitor_thread_code: command: \"%s\"",command); - result = dacp_send_command(command, &response, &le); - // debug(1,"Response to \"%s\" is %d.",command,result); - // remember: unless the revision_number you pass in is 1, - // response will be 200 only if there's something new to report. if (result == 200) { - // if (0) { - char *sp = response; - if (le >= 8) { - // here start looking for the contents of the status update - if (dacp_tlv_crawl(&sp, &item_size) == 'cmst') { // status - // here, we know that we are receiving playerstatusupdates, so set a flag - metadata_hub_modify_prolog(); - // debug(1, "playstatusupdate release track metadata"); - // metadata_hub_reset_track_metadata(); - // metadata_store.playerstatusupdates_are_received = 1; - sp -= item_size; // drop down into the array -- don't skip over it - le -= 8; - // char typestring[5]; - // we need to acquire the metadata data structure and possibly update it - while (le >= 8) { - uint32_t type = dacp_tlv_crawl(&sp, &item_size); - le -= item_size + 8; - char *t; - // char u; - // char *st; - int32_t r; - uint32_t ui; - // uint64_t v; - // int i; - - switch (type) { - case 'cmsr': // revision number - t = sp - item_size; - revision_number = ntohl(*(uint32_t *)(t)); - // debug(1,"New revision number received: %d", revision_number); - break; - case 'caps': // play status - t = sp - item_size; - r = *(unsigned char *)(t); - switch (r) { - case 2: - if (metadata_store.play_status != PS_STOPPED) { - metadata_store.play_status = PS_STOPPED; - debug(2, "Play status is \"stopped\"."); - } + metadata_hub_modify_prolog(); + int diff = metadata_store.speaker_volume != the_volume; + if (diff) + metadata_store.speaker_volume = the_volume; + metadata_hub_modify_epilog(diff); + + ssize_t le; + char *response = NULL; + int32_t item_size; + char command[1024] = ""; + if (always_use_revision_number_1 != 0) // for forked-daapd + revision_number = 1; + snprintf(command, sizeof(command) - 1, "playstatusupdate?revision-number=%d", + revision_number); + // debug(1,"dacp_monitor_thread_code: command: \"%s\"",command); + result = dacp_send_command(command, &response, &le); + // debug(1,"Response to \"%s\" is %d.",command,result); + // remember: unless the revision_number you pass in is 1, + // response will be 200 only if there's something new to report. + if (result == 200) { + // if (0) { + char *sp = response; + if (le >= 8) { + // here start looking for the contents of the status update + if (dacp_tlv_crawl(&sp, &item_size) == 'cmst') { // status + // here, we know that we are receiving playerstatusupdates, so set a flag + metadata_hub_modify_prolog(); + // debug(1, "playstatusupdate release track metadata"); + // metadata_hub_reset_track_metadata(); + // metadata_store.playerstatusupdates_are_received = 1; + sp -= item_size; // drop down into the array -- don't skip over it + le -= 8; + // char typestring[5]; + // we need to acquire the metadata data structure and possibly update it + while (le >= 8) { + uint32_t type = dacp_tlv_crawl(&sp, &item_size); + le -= item_size + 8; + char *t; + // char u; + // char *st; + int32_t r; + uint32_t ui; + // uint64_t v; + // int i; + + switch (type) { + case 'cmsr': // revision number + t = sp - item_size; + revision_number = ntohl(*(uint32_t *)(t)); + // debug(1,"New revision number received: %d", revision_number); break; - case 3: - if (metadata_store.play_status != PS_PAUSED) { - metadata_store.play_status = PS_PAUSED; - debug(2, "Play status is \"paused\"."); + case 'caps': // play status + t = sp - item_size; + r = *(unsigned char *)(t); + switch (r) { + case 2: + if (metadata_store.play_status != PS_STOPPED) { + metadata_store.play_status = PS_STOPPED; + debug(2, "Play status is \"stopped\"."); + } + break; + case 3: + if (metadata_store.play_status != PS_PAUSED) { + metadata_store.play_status = PS_PAUSED; + debug(2, "Play status is \"paused\"."); + } + break; + case 4: + if (metadata_store.play_status != PS_PLAYING) { + metadata_store.play_status = PS_PLAYING; + debug(2, "Play status changed to \"playing\"."); + } + break; + default: + debug(1, "Unrecognised play status %d received.", r); + break; } break; - case 4: - if (metadata_store.play_status != PS_PLAYING) { - metadata_store.play_status = PS_PLAYING; - debug(2, "Play status changed to \"playing\"."); + case 'cash': // shuffle status + t = sp - item_size; + r = *(unsigned char *)(t); + switch (r) { + case 0: + if (metadata_store.shuffle_status != SS_OFF) { + metadata_store.shuffle_status = SS_OFF; + debug(2, "Shuffle status is \"off\"."); + } + break; + case 1: + if (metadata_store.shuffle_status != SS_ON) { + metadata_store.shuffle_status = SS_ON; + debug(2, "Shuffle status is \"on\"."); + } + break; + default: + debug(1, "Unrecognised shuffle status %d received.", r); + break; } break; - default: - debug(1, "Unrecognised play status %d received.", r); + case 'carp': // repeat status + t = sp - item_size; + r = *(unsigned char *)(t); + switch (r) { + case 0: + if (metadata_store.repeat_status != RS_OFF) { + metadata_store.repeat_status = RS_OFF; + debug(2, "Repeat status is \"none\"."); + } + break; + case 1: + if (metadata_store.repeat_status != RS_ONE) { + metadata_store.repeat_status = RS_ONE; + debug(2, "Repeat status is \"one\"."); + } + break; + case 2: + if (metadata_store.repeat_status != RS_ALL) { + metadata_store.repeat_status = RS_ALL; + debug(2, "Repeat status is \"all\"."); + } + break; + default: + debug(1, "Unrecognised repeat status %d received.", r); + break; + } break; - } - break; - case 'cash': // shuffle status - t = sp - item_size; - r = *(unsigned char *)(t); - switch (r) { - case 0: - if (metadata_store.shuffle_status != SS_OFF) { - metadata_store.shuffle_status = SS_OFF; - debug(2, "Shuffle status is \"off\"."); + case 'cann': // track name + debug(2, "DACP Track Name seen"); + if (string_update_with_size(&metadata_store.track_name, + &metadata_store.track_name_changed, sp - item_size, + item_size)) { + debug(2, "DACP Track Name set to: \"%s\"", metadata_store.track_name); } break; - case 1: - if (metadata_store.shuffle_status != SS_ON) { - metadata_store.shuffle_status = SS_ON; - debug(2, "Shuffle status is \"on\"."); + case 'cana': // artist name + debug(2, "DACP Artist Name seen"); + if (string_update_with_size(&metadata_store.artist_name, + &metadata_store.artist_name_changed, sp - item_size, + item_size)) { + debug(2, "DACP Artist Name set to: \"%s\"", metadata_store.artist_name); } break; - default: - debug(1, "Unrecognised shuffle status %d received.", r); + case 'canl': // album name + debug(2, "DACP Album Name seen"); + if (string_update_with_size(&metadata_store.album_name, + &metadata_store.album_name_changed, sp - item_size, + item_size)) { + debug(2, "DACP Album Name set to: \"%s\"", metadata_store.album_name); + } break; - } - break; - case 'carp': // repeat status - t = sp - item_size; - r = *(unsigned char *)(t); - switch (r) { - case 0: - if (metadata_store.repeat_status != RS_OFF) { - metadata_store.repeat_status = RS_OFF; - debug(2, "Repeat status is \"none\"."); + case 'cang': // genre + debug(2, "DACP Genre seen"); + if (string_update_with_size(&metadata_store.genre, &metadata_store.genre_changed, + sp - item_size, item_size)) { + debug(2, "DACP Genre set to: \"%s\"", metadata_store.genre); } break; - case 1: - if (metadata_store.repeat_status != RS_ONE) { - metadata_store.repeat_status = RS_ONE; - debug(2, "Repeat status is \"one\"."); + case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware + // see reference above) + debug(2, "DACP Composite ID seen"); + if (memcmp(metadata_store.item_composite_id, sp - item_size, + sizeof(metadata_store.item_composite_id)) != 0) { + memcpy(metadata_store.item_composite_id, sp - item_size, + sizeof(metadata_store.item_composite_id)); + char st[33]; + char *pt = st; + int it; + for (it = 0; it < 16; it++) { + snprintf(pt, 3, "%02X", metadata_store.item_composite_id[it]); + pt += 2; + } + *pt = 0; + debug(2, "Item composite ID changed to 0x%s.", st); + metadata_store.item_composite_id_changed = 1; } break; - case 2: - if (metadata_store.repeat_status != RS_ALL) { - metadata_store.repeat_status = RS_ALL; - debug(2, "Repeat status is \"all\"."); + case 'astm': + t = sp - item_size; + ui = ntohl(*(uint32_t *)(t)); + debug(2, "DACP Song Time seen: \"%u\" of length %u.", ui, item_size); + if (ui != metadata_store.songtime_in_milliseconds) { + metadata_store.songtime_in_milliseconds = ui; + metadata_store.songtime_in_milliseconds_changed = 1; + debug(2, "DACP Song Time set to: \"%u\"", + metadata_store.songtime_in_milliseconds); } break; + + /* + case 'mstt': + case 'cant': + case 'cast': + case 'cmmk': + case 'caas': + case 'caar': + t = sp - item_size; + r = ntohl(*(uint32_t *)(t)); + printf(" %d", r); + printf(" (0x"); + t = sp - item_size; + for (i = 0; i < item_size; i++) { + printf("%02x", *t & 0xff); + t++; + } + printf(")"); + break; + case 'asai': + t = sp - item_size; + s = ntohl(*(uint32_t *)(t)); + s = s << 32; + t += 4; + v = (ntohl(*(uint32_t *)(t))) & 0xffffffff; + s += v; + printf(" %lu", s); + printf(" (0x"); + t = sp - item_size; + for (i = 0; i < item_size; i++) { + printf("%02x", *t & 0xff); + t++; + } + printf(")"); + break; + */ default: - debug(1, "Unrecognised repeat status %d received.", r); + /* + printf(" 0x"); + t = sp - item_size; + for (i = 0; i < item_size; i++) { + printf("%02x", *t & 0xff); + t++; + } + */ break; } - break; - case 'cann': // track name - debug(2, "DACP Track Name seen"); - if (string_update_with_size(&metadata_store.track_name, - &metadata_store.track_name_changed, sp - item_size, - item_size)) { - debug(2, "DACP Track Name set to: \"%s\"", metadata_store.track_name); - } - break; - case 'cana': // artist name - debug(2, "DACP Artist Name seen"); - if (string_update_with_size(&metadata_store.artist_name, - &metadata_store.artist_name_changed, sp - item_size, - item_size)) { - debug(2, "DACP Artist Name set to: \"%s\"", metadata_store.artist_name); - } - break; - case 'canl': // album name - debug(2, "DACP Album Name seen"); - if (string_update_with_size(&metadata_store.album_name, - &metadata_store.album_name_changed, sp - item_size, - item_size)) { - debug(2, "DACP Album Name set to: \"%s\"", metadata_store.album_name); - } - break; - case 'cang': // genre - debug(2, "DACP Genre seen"); - if (string_update_with_size(&metadata_store.genre, &metadata_store.genre_changed, - sp - item_size, item_size)) { - debug(2, "DACP Genre set to: \"%s\"", metadata_store.genre); - } - break; - case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware - // see reference above) - debug(2, "DACP Composite ID seen"); - if (memcmp(metadata_store.item_composite_id, sp - item_size, - sizeof(metadata_store.item_composite_id)) != 0) { - memcpy(metadata_store.item_composite_id, sp - item_size, - sizeof(metadata_store.item_composite_id)); - char st[33]; - char *pt = st; - int it; - for (it = 0; it < 16; it++) { - snprintf(pt, 3, "%02X", metadata_store.item_composite_id[it]); - pt += 2; - } - *pt = 0; - debug(2, "Item composite ID changed to 0x%s.", st); - metadata_store.item_composite_id_changed = 1; - } - break; - case 'astm': - t = sp - item_size; - ui = ntohl(*(uint32_t *)(t)); - debug(2, "DACP Song Time seen: \"%u\" of length %u.", ui, item_size); - if (ui != metadata_store.songtime_in_milliseconds) { - metadata_store.songtime_in_milliseconds = ui; - metadata_store.songtime_in_milliseconds_changed = 1; - debug(2, "DACP Song Time set to: \"%u\"", - metadata_store.songtime_in_milliseconds); - } - break; - - /* - case 'mstt': - case 'cant': - case 'cast': - case 'cmmk': - case 'caas': - case 'caar': - t = sp - item_size; - r = ntohl(*(uint32_t *)(t)); - printf(" %d", r); - printf(" (0x"); - t = sp - item_size; - for (i = 0; i < item_size; i++) { - printf("%02x", *t & 0xff); - t++; - } - printf(")"); - break; - case 'asai': - t = sp - item_size; - s = ntohl(*(uint32_t *)(t)); - s = s << 32; - t += 4; - v = (ntohl(*(uint32_t *)(t))) & 0xffffffff; - s += v; - printf(" %lu", s); - printf(" (0x"); - t = sp - item_size; - for (i = 0; i < item_size; i++) { - printf("%02x", *t & 0xff); - t++; - } - printf(")"); - break; - */ - default: - /* - printf(" 0x"); - t = sp - item_size; - for (i = 0; i < item_size; i++) { - printf("%02x", *t & 0xff); - t++; - } - */ - break; + // printf("\n"); } - // printf("\n"); - } - // finished possibly writing to the metadata hub - metadata_hub_modify_epilog( - 1); // should really see if this can be made responsive to changes + // finished possibly writing to the metadata hub + metadata_hub_modify_epilog( + 1); // should really see if this can be made responsive to changes + } else { + debug(1, "Status Update not found.\n"); + } } else { - debug(1, "Status Update not found.\n"); + debug(1, "Can't find any content in playerstatusupdate request"); } - } else { - debug(1, "Can't find any content in playerstatusupdate request"); - } - } /* else { - if (result != 403) - debug(1, "Unexpected response %d to playerstatusupdate request", result); - } */ + } /* else { + if (result != 403) + debug(1, "Unexpected response %d to playerstatusupdate request", result); + } */ + if (response) { + free(response); + response = NULL; + }; + }; + /* + strcpy(command,"nowplayingartwork?mw=320&mh=320"); + debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le)); if (response) { free(response); response = NULL; - }; - }; - /* - strcpy(command,"nowplayingartwork?mw=320&mh=320"); - debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le)); - if (response) { - free(response); - response = NULL; - } - strcpy(command,"getproperty?properties=dmcp.volume"); - debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le)); - if (response) { - free(response); - response = NULL; - } - strcpy(command,"setproperty?dmcp.volume=100.000000"); - debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le)); - if (response) { - free(response); - response = NULL; + } + strcpy(command,"getproperty?properties=dmcp.volume"); + debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le)); + if (response) { + free(response); + response = NULL; + } + strcpy(command,"setproperty?dmcp.volume=100.000000"); + debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le)); + if (response) { + free(response); + response = NULL; + } + */ + if (metadata_store.player_thread_active) + sleep(config.scan_interval_when_active); + else + sleep(config.scan_interval_when_inactive); } - */ - if (metadata_store.player_thread_active) - sleep(config.scan_interval_when_active); - else - sleep(config.scan_interval_when_inactive); } debug(1, "DACP monitor thread exiting -- should never happen."); pthread_exit(NULL); @@ -889,6 +920,22 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) { void dacp_monitor_start() { int rc; + +#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it. + rc = pthread_cond_init(&dacp_server_information_cv, &attr); + if (rc) + debug(1, "Error initialising the DACP Server Information Condition Variable"); + pthread_condattr_destroy(&attr); +#endif +#ifdef COMPILE_FOR_OSX + rc = pthread_cond_init(&dacp_server_information_cv, NULL); +#endif + + + pthread_mutexattr_t mta; rc = pthread_mutexattr_init(&mta); @@ -947,6 +994,8 @@ void dacp_monitor_stop() { pthread_mutex_destroy(&dacp_server_information_lock); debug(3, "DACP Conversation Lock Mutex Destroyed"); pthread_mutex_destroy(&dacp_conversation_lock); + pthread_cond_destroy(&dacp_server_information_cv); + debug(1, "DACP Server Information Condition Variable destroyed."); } } diff --git a/rtsp.c b/rtsp.c index dca0ecb5..4013acb9 100644 --- a/rtsp.c +++ b/rtsp.c @@ -2335,6 +2335,7 @@ static void *rtsp_conversation_thread_func(void *pconn) { pthread_condattr_init(&attr); pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it. rc = pthread_cond_init(&conn->flowcontrol, &attr); + pthread_condattr_destroy(&attr); #endif #ifdef COMPILE_FOR_OSX rc = pthread_cond_init(&conn->flowcontrol, NULL); diff --git a/shairport.c b/shairport.c index 881ecd97..8f80ebdb 100644 --- a/shairport.c +++ b/shairport.c @@ -405,6 +405,7 @@ int parse_options(int argc, char **argv) { config.resend_control_first_check_time = 0.10; // wait this many seconds before requesting the resending of a missing packet config.resend_control_check_interval_time = 0.25; // wait this many seconds before again requesting the resending of a missing packet config.resend_control_last_check_time = 0.10; // give up if the packet is still missing this close to when it's needed + config.missing_port_dacp_scan_interval_seconds = 2.0; // check at this interval if no DACP port number is known #ifdef CONFIG_METADATA_HUB config.cover_art_cache_dir = "/tmp/shairport-sync/.cache/coverart";