From: Mike Brady Date: Fri, 10 Jan 2020 08:31:13 +0000 (+0000) Subject: Remove timeout on reception of DACP responses to allow for long poll behaviour of... X-Git-Tag: 3.3.7d12~166 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=85b17cdaef3f5878c7afd793aa8be9001d6b1730;p=thirdparty%2Fshairport-sync.git Remove timeout on reception of DACP responses to allow for long poll behaviour of some players, e.g. Forked Daapd. Add some examples to the dbus client. --- diff --git a/dacp.c b/dacp.c index 7797f794..a47d1608 100644 --- a/dacp.c +++ b/dacp.c @@ -150,12 +150,12 @@ void http_cleanup(void *arg) { int dacp_send_command(const char *command, char **body, ssize_t *bodysize) { int result; - // debug(1,"dacp_send_command: command is: \"%s\".",command); - - if (dacp_server.port == 0) { - debug(1,"No DACP port specified yet"); - result = 490; // no port specified - } else { + // debug(1,"dacp_send_command: command is: \"%s\".",command); + + if (dacp_server.port == 0) { + debug(1, "No DACP port specified yet"); + result = 490; // no port specified + } else { // will malloc space for the body or set it to NULL -- the caller should free it. @@ -213,20 +213,27 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) { sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd == -1) { - // debug(1, "DACP socket could not be created -- error %d: \"%s\".",errno,strerror(errno)); + // debug(1, "DACP socket could not be created -- error %d: + // \"%s\".",errno,strerror(errno)); response.code = 497; // Can't establish a socket to the DACP server } else { pthread_cleanup_push(connect_cleanup, (void *)&sockfd); // debug(2, "dacp_send_command: open socket %d.",sockfd); + + // This is for limiting the time to be spent waiting for a response. + struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 500000; - if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1) - debug(1, "dacp_send_command: error %d setting receive timeout.", errno); + // Don't place a timeout on the receive side of these calls, as some clients may provide + // a "long poll" mechanism whereby a reply will not be sent until a change has occurred + // if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1) + // debug(1, "dacp_send_command: error %d setting receive timeout.", errno); if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof tv) == -1) debug(1, "dacp_send_command: error %d setting send timeout.", errno); + // connect! // debug(1, "DACP socket created."); if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) { @@ -240,7 +247,8 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) { snprintf(message, sizeof(message), "GET /ctrl-int/1/%s HTTP/1.1\r\nHost: %s:%u\r\nActive-Remote: %u\r\n\r\n", - command, dacp_server.ip_string, dacp_server.port, dacp_server.active_remote_id); + command, dacp_server.ip_string, dacp_server.port, + dacp_server.active_remote_id); // Send command debug(3, "dacp_send_command: \"%s\".", command); @@ -276,8 +284,12 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) { memset(buffer, 0, sizeof(buffer)); while (needmore && !looperror) { const char *data = buffer; - if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1) - debug(1, "dacp_send_command: error %d setting receive timeout.", errno); + + // Don't place a timeout on the receive, as some clients may provide + // a "long poll" mechanism whereby a reply will not be sent until a change has occurred + + // if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1) + // debug(1, "dacp_send_command: error %d setting receive timeout.", errno); ssize_t ndata = recv(sockfd, buffer, sizeof(buffer), 0); // debug(3, "Received %d bytes: \"%s\".", ndata, buffer); if (ndata <= 0) { @@ -289,10 +301,12 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) { struct linger so_linger; so_linger.l_onoff = 1; // "true" so_linger.l_linger = 0; - int err = setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger); + int err = + setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger); if (err) - debug(1, - "Could not set the dacp socket to abort due to a read error on closing."); + debug( + 1, + "Could not set the dacp socket to abort due to a read error on closing."); } free(response.body); @@ -487,7 +501,8 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) { metadata_store.dacp_server_active = 0; metadata_store.advanced_dacp_server_active = 0; debug(2, - "setting metadata_store.dacp_server_active and metadata_store.advanced_dacp_server_active to 0 with an update " + "setting metadata_store.dacp_server_active and " + "metadata_store.advanced_dacp_server_active to 0 with an update " "flag value of %d", ch); metadata_hub_modify_epilog(ch); @@ -499,9 +514,8 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) { // so dacp_server.scan_enable will be true at this point bad_result_count = 0; idle_scan_count = 0; - } - + result = dacp_get_volume(&the_volume); // just want the http code pthread_cleanup_pop(1); @@ -514,25 +528,27 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) { 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 - + // 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) { + + 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 + } 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; } @@ -545,14 +561,14 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) { 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... @@ -562,7 +578,8 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) { update_needed = 1; } } - if (advanced_dacp_server_status_now != -1) { // if advanced_dacp_server_status_now is actually known... + 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; @@ -571,286 +588,289 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) { } 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); + 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] = ""; + 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) { - 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] = ""; - 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," Serial Number: %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\"."); - } - 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; + // 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," Serial Number: %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\"."); } 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\"."); - } - 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; + case 3: + if (metadata_store.play_status != PS_PAUSED) { + metadata_store.play_status = PS_PAUSED; + debug(2, "Play status is \"paused\"."); } 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\"."); - } - 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; + case 4: + if (metadata_store.play_status != PS_PLAYING) { + metadata_store.play_status = PS_PLAYING; + debug(2, "Play status changed to \"playing\"."); } 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); - } + default: + debug(1, "Unrecognised play status %d received.", r); 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 '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 '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); + case 1: + if (metadata_store.shuffle_status != SS_ON) { + metadata_store.shuffle_status = SS_ON; + debug(2, "Shuffle status is \"on\"."); } 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); + default: + debug(1, "Unrecognised shuffle status %d received.", r); + 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\"."); } 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; + case 1: + if (metadata_store.repeat_status != RS_ONE) { + metadata_store.repeat_status = RS_ONE; + debug(2, "Repeat status is \"one\"."); } 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); + case 2: + if (metadata_store.repeat_status != RS_ALL) { + metadata_store.repeat_status = RS_ALL; + debug(2, "Repeat status is \"all\"."); } 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++; - } - */ + debug(1, "Unrecognised repeat status %d received.", r); break; } - // printf("\n"); + 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; } - - // 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"); + // 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 } else { - debug(1, "Can't find any content in playerstatusupdate request"); + debug(1, "Status Update not found.\n"); } - } /* 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,"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)); + } else { + debug(1, "Can't find any content in playerstatusupdate request"); + } + } /* else { + if (result != 403) + debug(1, "Unexpected response %d to playerstatusupdate request", result); + } */ 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); + }; + }; + /* + 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; + } + */ + 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); diff --git a/shairport-sync-dbus-test-client.c b/shairport-sync-dbus-test-client.c index 6b8f122c..11100234 100644 --- a/shairport-sync-dbus-test-client.c +++ b/shairport-sync-dbus-test-client.c @@ -65,8 +65,7 @@ void on_properties_changed(__attribute__((unused)) GDBusProxy *proxy, GVariant * } } -void notify_loudness_callback(ShairportSync *proxy, - __attribute__((unused)) gpointer user_data) { +void notify_loudness_callback(ShairportSync *proxy, __attribute__((unused)) gpointer user_data) { // printf("\"notify_loudness_callback\" called with a gpointer of // %lx.\n",(int64_t)user_data); gboolean ebl = shairport_sync_get_loudness(proxy); @@ -187,28 +186,44 @@ int main(int argc, char *argv[]) { g_signal_connect(proxy4, "notify::volume", G_CALLBACK(notify_volume_callback), "ShairportSync.AdvancedRemoteControl"); + + g_print("Starting test...\n"); + g_print("Using the RemoteControl interface, set airplay volume to -30, -20, -10, 0 and -15 for two seconds each...\n"); + shairport_sync_remote_control_call_set_airplay_volume(SHAIRPORT_SYNC_REMOTE_CONTROL(proxy3), -30, NULL, NULL, 0); + sleep(2); + shairport_sync_remote_control_call_set_airplay_volume(SHAIRPORT_SYNC_REMOTE_CONTROL(proxy3), -20, NULL, NULL, 0); + sleep(2); + shairport_sync_remote_control_call_set_airplay_volume(SHAIRPORT_SYNC_REMOTE_CONTROL(proxy3), -10, NULL, NULL, 0); + sleep(2); + shairport_sync_remote_control_call_set_airplay_volume(SHAIRPORT_SYNC_REMOTE_CONTROL(proxy3), 0, NULL, NULL, 0); + sleep(2); + shairport_sync_remote_control_call_set_airplay_volume(SHAIRPORT_SYNC_REMOTE_CONTROL(proxy3), -15, NULL, NULL, 0); + sleep(2); + + g_print("Using the AdvancedRemoteControl interface, set airplay volume to 20%%, 100%%, 40%% and 60%% for two seconds each...\n"); shairport_sync_advanced_remote_control_call_set_volume( SHAIRPORT_SYNC_ADVANCED_REMOTE_CONTROL(proxy4), 20, NULL, NULL, 0); - sleep(5); + sleep(2); shairport_sync_advanced_remote_control_call_set_volume( SHAIRPORT_SYNC_ADVANCED_REMOTE_CONTROL(proxy4), 100, NULL, NULL, 0); - sleep(5); + sleep(2); shairport_sync_advanced_remote_control_call_set_volume( SHAIRPORT_SYNC_ADVANCED_REMOTE_CONTROL(proxy4), 40, NULL, NULL, 0); - sleep(5); + sleep(2); shairport_sync_advanced_remote_control_call_set_volume( SHAIRPORT_SYNC_ADVANCED_REMOTE_CONTROL(proxy4), 60, NULL, NULL, 0); - - sleep(5); - g_print("Volume up for five seconds...\n"); - shairport_sync_remote_control_call_volume_up(SHAIRPORT_SYNC_REMOTE_CONTROL(proxy3), NULL, NULL, NULL); + sleep(2); + g_print("Using the RemoteControl interface, increase volume for five seconds...\n"); + shairport_sync_remote_control_call_volume_up(SHAIRPORT_SYNC_REMOTE_CONTROL(proxy3), NULL, NULL, + NULL); sleep(5); - g_print("Volume down\n"); - shairport_sync_remote_control_call_volume_down(SHAIRPORT_SYNC_REMOTE_CONTROL(proxy3), NULL, NULL, NULL); - + g_print("Using the RemoteControl interface, decrease volume...\n"); + shairport_sync_remote_control_call_volume_down(SHAIRPORT_SYNC_REMOTE_CONTROL(proxy3), NULL, NULL, + NULL); + /* // sleep(1); shairport_sync_set_loudness_filter_active(SHAIRPORT_SYNC(proxy), TRUE);