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.

This commit is contained in:
Mike Brady
2020-01-10 08:31:13 +00:00
parent 1f75fe4e7a
commit 85b17cdaef
2 changed files with 341 additions and 306 deletions
+314 -294
View File
@@ -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);
// 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;
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;
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);
}
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++;
}
*/
debug(1, "Unrecognised play status %d received.", r);
break;
}
// printf("\n");
}
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;
}
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;
}
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;
// 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");
/*
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");
}
// 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;
};
} 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;
};
/*
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);
};
/*
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);
+27 -12
View File
@@ -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);