Tidy up dacp scanner -- stop scanning when audio source goes offline.
This commit is contained in:
@@ -45,7 +45,8 @@
|
||||
#include "tinyhttp/http.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t port;
|
||||
int scan_enable; // set to 1 if if sacanning should be considered
|
||||
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
|
||||
@@ -268,7 +269,10 @@ void set_dacp_server_information(rtsp_conn_info *conn) { // tell the DACP conver
|
||||
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
|
||||
dacp_server.scan_enable=0;
|
||||
pthread_cond_signal(&dacp_server_information_cv);
|
||||
pthread_mutex_unlock(&dacp_server_information_lock);
|
||||
}
|
||||
@@ -280,285 +284,289 @@ void *dacp_monitor_thread_code(void *na) {
|
||||
// wait until we get a valid port number to begin monitoring it
|
||||
int32_t revision_number = 1;
|
||||
while (1) {
|
||||
int result;
|
||||
pthread_mutex_lock(&dacp_server_information_lock);
|
||||
while (dacp_server.port == 0) {
|
||||
while (dacp_server.scan_enable == 0) {
|
||||
debug(1, "Wait for a valid DACP port");
|
||||
pthread_cond_wait(&dacp_server_information_cv, &dacp_server_information_lock);
|
||||
}
|
||||
scan_index++;
|
||||
result = dacp_get_volume(NULL); // just want the http code
|
||||
if ((result==496) || (result==403)|| (result==501)) {
|
||||
debug(1,"Stopping scan because the response to \"dacp_get_volume(NULL)\" is %d.",result);
|
||||
dacp_server.scan_enable = 0;
|
||||
}
|
||||
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);
|
||||
scan_index++;
|
||||
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,"Command: \"%s\"",command);
|
||||
int result = dacp_send_command(command, &response, &le);
|
||||
if (result == 200) {
|
||||
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();
|
||||
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);
|
||||
if (result==200) {
|
||||
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,"Command: \"%s\"",command);
|
||||
result = dacp_send_command(command, &response, &le);
|
||||
// debug(1,"Response to \"%s\" is %d.",command,result);
|
||||
if (result == 200) {
|
||||
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();
|
||||
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;
|
||||
uint64_t s, v;
|
||||
int i;
|
||||
|
||||
//*(uint32_t *)typestring = htonl(type);
|
||||
// typestring[4] = 0;
|
||||
// printf("\"%s\" %4d", typestring, item_size);
|
||||
|
||||
le -= item_size + 8;
|
||||
char *t;
|
||||
char u;
|
||||
char *st;
|
||||
int32_t r;
|
||||
uint64_t s, 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;
|
||||
metadata_store.play_status_changed = 1;
|
||||
debug(1, "Play status set to \"stopped\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (metadata_store.play_status != PS_PAUSED) {
|
||||
metadata_store.play_status = PS_PAUSED;
|
||||
metadata_store.play_status_changed = 1;
|
||||
debug(1, "Play status set to \"paused\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (metadata_store.play_status != PS_PLAYING) {
|
||||
metadata_store.play_status = PS_PLAYING;
|
||||
metadata_store.play_status_changed = 1;
|
||||
debug(1, "Play status set to \"playing\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug(1, "Unrecognised play status %d received.", r);
|
||||
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;
|
||||
metadata_store.shuffle_status_changed = 1;
|
||||
debug(1, "Shuffle status set to \"off\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (metadata_store.shuffle_status != SS_ON) {
|
||||
metadata_store.shuffle_status = SS_ON;
|
||||
metadata_store.shuffle_status_changed = 1;
|
||||
debug(1, "Shuffle status set to \"on\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
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_NONE) {
|
||||
metadata_store.repeat_status = RS_NONE;
|
||||
metadata_store.repeat_status_changed = 1;
|
||||
debug(1, "Repeat status set to \"none\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (metadata_store.repeat_status != RS_SINGLE) {
|
||||
metadata_store.repeat_status = RS_SINGLE;
|
||||
metadata_store.repeat_status_changed = 1;
|
||||
debug(1, "Repeat status set to \"single\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (metadata_store.repeat_status != RS_ALL) {
|
||||
metadata_store.repeat_status = RS_ALL;
|
||||
metadata_store.repeat_status_changed = 1;
|
||||
debug(1, "Repeat status set to \"all\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug(1, "Unrecognised repeat status %d received.", r);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'cann': // track name
|
||||
t = sp - item_size;
|
||||
if ((metadata_store.track_name == NULL) ||
|
||||
(strncmp(metadata_store.track_name, t, item_size) != 0)) {
|
||||
if (metadata_store.track_name)
|
||||
free(metadata_store.track_name);
|
||||
metadata_store.track_name = strndup(t, item_size);
|
||||
debug(1, "Track name set to: \"%s\"", metadata_store.track_name);
|
||||
metadata_store.track_name_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'cana': // artist name
|
||||
t = sp - item_size;
|
||||
if ((metadata_store.artist_name == NULL) ||
|
||||
(strncmp(metadata_store.artist_name, t, item_size) != 0)) {
|
||||
if (metadata_store.artist_name)
|
||||
free(metadata_store.artist_name);
|
||||
metadata_store.artist_name = strndup(t, item_size);
|
||||
debug(1, "Artist name set to: \"%s\"", metadata_store.artist_name);
|
||||
metadata_store.artist_name_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'canl': // album name
|
||||
t = sp - item_size;
|
||||
if ((metadata_store.album_name == NULL) ||
|
||||
(strncmp(metadata_store.album_name, t, item_size) != 0)) {
|
||||
if (metadata_store.album_name)
|
||||
free(metadata_store.album_name);
|
||||
metadata_store.album_name = strndup(t, item_size);
|
||||
debug(1, "Album name set to: \"%s\"", metadata_store.album_name);
|
||||
metadata_store.album_name_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'cang': // genre
|
||||
t = sp - item_size;
|
||||
if ((metadata_store.genre == NULL) ||
|
||||
(strncmp(metadata_store.genre, t, item_size) != 0)) {
|
||||
if (metadata_store.genre)
|
||||
free(metadata_store.genre);
|
||||
metadata_store.genre = strndup(t, item_size);
|
||||
debug(1, "Genre set to: \"%s\"", metadata_store.genre);
|
||||
metadata_store.genre_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware --
|
||||
// see reference above)
|
||||
t = sp - item_size;
|
||||
if (memcmp(metadata_store.item_composite_id, t,
|
||||
sizeof(metadata_store.item_composite_id)) != 0) {
|
||||
memcpy(metadata_store.item_composite_id, t,
|
||||
sizeof(metadata_store.item_composite_id));
|
||||
|
||||
char st[33];
|
||||
char *pt = st;
|
||||
int it;
|
||||
for (it = 0; it < 16; it++) {
|
||||
sprintf(pt, "%02X", metadata_store.item_composite_id[it]);
|
||||
pt += 2;
|
||||
}
|
||||
*pt = 0;
|
||||
debug(1, "Item composite ID set to 0x%s.", st);
|
||||
metadata_store.item_id_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'astm':
|
||||
t = sp - item_size;
|
||||
r = ntohl(*(uint32_t *)(t));
|
||||
metadata_store.songtime_in_milliseconds = ntohl(*(uint32_t *)(t));
|
||||
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");
|
||||
switch (type) {
|
||||
case 'cmsr': // revision number
|
||||
t = sp - item_size;
|
||||
for (i = 0; i < item_size; i++) {
|
||||
printf("%02x", *t & 0xff);
|
||||
t++;
|
||||
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;
|
||||
metadata_store.play_status_changed = 1;
|
||||
debug(1, "Play status changed to \"stopped\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (metadata_store.play_status != PS_PAUSED) {
|
||||
metadata_store.play_status = PS_PAUSED;
|
||||
metadata_store.play_status_changed = 1;
|
||||
debug(1, "Play status changed to \"paused\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (metadata_store.play_status != PS_PLAYING) {
|
||||
metadata_store.play_status = PS_PLAYING;
|
||||
metadata_store.play_status_changed = 1;
|
||||
debug(1, "Play status changed to \"playing\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug(1, "Unrecognised play status %d received.", r);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
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;
|
||||
metadata_store.shuffle_status_changed = 1;
|
||||
debug(1, "Shuffle status changed to \"off\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (metadata_store.shuffle_status != SS_ON) {
|
||||
metadata_store.shuffle_status = SS_ON;
|
||||
metadata_store.shuffle_status_changed = 1;
|
||||
debug(1, "Shuffle status changed to \"on\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
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_NONE) {
|
||||
metadata_store.repeat_status = RS_NONE;
|
||||
metadata_store.repeat_status_changed = 1;
|
||||
debug(1, "Repeat status changed to \"none\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (metadata_store.repeat_status != RS_SINGLE) {
|
||||
metadata_store.repeat_status = RS_SINGLE;
|
||||
metadata_store.repeat_status_changed = 1;
|
||||
debug(1, "Repeat status changed to \"single\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (metadata_store.repeat_status != RS_ALL) {
|
||||
metadata_store.repeat_status = RS_ALL;
|
||||
metadata_store.repeat_status_changed = 1;
|
||||
debug(1, "Repeat status changed to \"all\".");
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug(1, "Unrecognised repeat status %d received.", r);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'cann': // track name
|
||||
t = sp - item_size;
|
||||
if ((metadata_store.track_name == NULL) ||
|
||||
(strncmp(metadata_store.track_name, t, item_size) != 0)) {
|
||||
if (metadata_store.track_name)
|
||||
free(metadata_store.track_name);
|
||||
metadata_store.track_name = strndup(t, item_size);
|
||||
debug(1, "Track name changed to: \"%s\"", metadata_store.track_name);
|
||||
metadata_store.track_name_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'cana': // artist name
|
||||
t = sp - item_size;
|
||||
if ((metadata_store.artist_name == NULL) ||
|
||||
(strncmp(metadata_store.artist_name, t, item_size) != 0)) {
|
||||
if (metadata_store.artist_name)
|
||||
free(metadata_store.artist_name);
|
||||
metadata_store.artist_name = strndup(t, item_size);
|
||||
debug(1, "Artist name changed to: \"%s\"", metadata_store.artist_name);
|
||||
metadata_store.artist_name_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'canl': // album name
|
||||
t = sp - item_size;
|
||||
if ((metadata_store.album_name == NULL) ||
|
||||
(strncmp(metadata_store.album_name, t, item_size) != 0)) {
|
||||
if (metadata_store.album_name)
|
||||
free(metadata_store.album_name);
|
||||
metadata_store.album_name = strndup(t, item_size);
|
||||
debug(1, "Album name changed to: \"%s\"", metadata_store.album_name);
|
||||
metadata_store.album_name_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'cang': // genre
|
||||
t = sp - item_size;
|
||||
if ((metadata_store.genre == NULL) ||
|
||||
(strncmp(metadata_store.genre, t, item_size) != 0)) {
|
||||
if (metadata_store.genre)
|
||||
free(metadata_store.genre);
|
||||
metadata_store.genre = strndup(t, item_size);
|
||||
debug(1, "Genre changed to: \"%s\"", metadata_store.genre);
|
||||
metadata_store.genre_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware --
|
||||
// see reference above)
|
||||
t = sp - item_size;
|
||||
if (memcmp(metadata_store.item_composite_id, t,
|
||||
sizeof(metadata_store.item_composite_id)) != 0) {
|
||||
memcpy(metadata_store.item_composite_id, t,
|
||||
sizeof(metadata_store.item_composite_id));
|
||||
|
||||
// finished possibly writing to the metadata hub
|
||||
metadata_hub_modify_epilog();
|
||||
char st[33];
|
||||
char *pt = st;
|
||||
int it;
|
||||
for (it = 0; it < 16; it++) {
|
||||
sprintf(pt, "%02X", metadata_store.item_composite_id[it]);
|
||||
pt += 2;
|
||||
}
|
||||
*pt = 0;
|
||||
// debug(1, "Item composite ID set to 0x%s.", st);
|
||||
metadata_store.item_id_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
}
|
||||
break;
|
||||
case 'astm':
|
||||
t = sp - item_size;
|
||||
r = ntohl(*(uint32_t *)(t));
|
||||
metadata_store.songtime_in_milliseconds = ntohl(*(uint32_t *)(t));
|
||||
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");
|
||||
}
|
||||
|
||||
// finished possibly writing to the metadata hub
|
||||
metadata_hub_modify_epilog(1);
|
||||
} else {
|
||||
debug(1,"Status Update not found.\n");
|
||||
}
|
||||
} else {
|
||||
printf("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);
|
||||
}
|
||||
if (response) {
|
||||
free(response);
|
||||
response = NULL;
|
||||
} /* 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");
|
||||
@@ -603,7 +611,7 @@ uint32_t dacp_tlv_crawl(char **p, int32_t *length) {
|
||||
return type;
|
||||
}
|
||||
|
||||
int32_t dacp_get_client_volume(void) {
|
||||
int dacp_get_client_volume(int32_t *result) {
|
||||
char *server_reply = NULL;
|
||||
int32_t overall_volume = -1;
|
||||
ssize_t reply_size;
|
||||
@@ -632,16 +640,18 @@ int32_t dacp_get_client_volume(void) {
|
||||
}
|
||||
// debug(1, "Overall Volume is %d.", overall_volume);
|
||||
free(server_reply);
|
||||
} else {
|
||||
} /* else {
|
||||
debug(1, "Unexpected response %d to dacp volume control request", response);
|
||||
}
|
||||
return overall_volume;
|
||||
} */
|
||||
if (result)
|
||||
*result=overall_volume;
|
||||
return response;
|
||||
}
|
||||
|
||||
int dacp_set_include_speaker_volume(int64_t machine_number, int32_t vo) {
|
||||
char message[1000];
|
||||
memset(message, 0, sizeof(message));
|
||||
sprintf(message, "setproperty?include-speaker-id=%lld&dmcp.volume=%d", machine_number, vo);
|
||||
sprintf(message, "setproperty?include-speaker-id=%ld&dmcp.volume=%d", machine_number, vo);
|
||||
// debug(1,"sending \"%s\"",message);
|
||||
return send_simple_dacp_command(message);
|
||||
// should return 204
|
||||
@@ -650,16 +660,17 @@ int dacp_set_include_speaker_volume(int64_t machine_number, int32_t vo) {
|
||||
int dacp_set_speaker_volume(int64_t machine_number, int32_t vo) {
|
||||
char message[1000];
|
||||
memset(message, 0, sizeof(message));
|
||||
sprintf(message, "setproperty?speaker-id=%lld&dmcp.volume=%d", machine_number, vo);
|
||||
sprintf(message, "setproperty?speaker-id=%ld&dmcp.volume=%d", machine_number, vo);
|
||||
// debug(1,"sending \"%s\"",message);
|
||||
return send_simple_dacp_command(message);
|
||||
// should return 204
|
||||
}
|
||||
|
||||
int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array) {
|
||||
int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array, int *actual_speaker_count) {
|
||||
char typestring[5];
|
||||
char *server_reply = NULL;
|
||||
int speaker_index = -1; // will be incremented before use
|
||||
int reply = -1; // will bve fixed if there is no problem
|
||||
int speaker_count = -1; // will be fixed if there is no problem
|
||||
ssize_t le;
|
||||
|
||||
int response = dacp_send_command("getspeakers", &server_reply, &le);
|
||||
@@ -679,7 +690,7 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
|
||||
le -= 8;
|
||||
speaker_index++;
|
||||
if (speaker_index == max_size_of_array)
|
||||
return -1; // too many speakers
|
||||
return 413;// Payload Too Large -- too many speakers
|
||||
speaker_info[speaker_index].active = 0;
|
||||
speaker_info[speaker_index].speaker_number = 0;
|
||||
speaker_info[speaker_index].volume = 0;
|
||||
@@ -696,19 +707,11 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
|
||||
speaker_info[speaker_index].name = strndup(t, item_size);
|
||||
// debug(1," \"%s\"",speaker_info[speaker_index].name);
|
||||
break;
|
||||
/*
|
||||
case 'cads':
|
||||
t = sp-item_size;
|
||||
r = ntohl(*(uint32_t*)(t));
|
||||
//debug(1,"CADS: \"%d\".",r);
|
||||
break;
|
||||
*/
|
||||
case 'cmvo':
|
||||
t = sp - item_size;
|
||||
r = ntohl(*(uint32_t *)(t));
|
||||
speaker_info[speaker_index].volume = r;
|
||||
// debug(1,"The individual volume of speaker \"%s\" is
|
||||
// \"%d\".",speaker_info[speaker_index].name,r);
|
||||
// debug(1,"The individual volume of speaker \"%s\" is \"%d\".",speaker_info[speaker_index].name,r);
|
||||
break;
|
||||
case 'msma':
|
||||
t = sp - item_size;
|
||||
@@ -728,9 +731,16 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
|
||||
case 'caip':
|
||||
case 'cavd':
|
||||
case 'caiv':
|
||||
case 'cads':
|
||||
|
||||
*(uint32_t *)typestring = htonl(type);
|
||||
typestring[4] = 0;
|
||||
|
||||
|
||||
|
||||
t = sp-item_size;
|
||||
u = *t;
|
||||
//debug(1,"Value: \"%d\".",u);
|
||||
debug(1,"Type: '%s' Value: \"%d\".",typestring,u);
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
@@ -739,7 +749,7 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
|
||||
}
|
||||
}
|
||||
// debug(1,"Total of %d speakers found. Here are the active ones:",speaker_index+1);
|
||||
reply = speaker_index + 1; // number of speaker entries in the array
|
||||
speaker_count = speaker_index + 1; // number of speaker entries in the array
|
||||
} else {
|
||||
debug(1, "Speaker array not found.");
|
||||
}
|
||||
@@ -761,10 +771,12 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
|
||||
} else {
|
||||
debug(1, "Unexpected response %d to dacp speakers request", response);
|
||||
}
|
||||
return reply;
|
||||
if (actual_speaker_count)
|
||||
*actual_speaker_count = speaker_count;
|
||||
return response;
|
||||
}
|
||||
|
||||
void dacp_get_volume(void) {
|
||||
int dacp_get_volume(int32_t *the_actual_volume) {
|
||||
// get the speaker volume information from the DACP source and store it in the metadata_hub
|
||||
// A volume command has been sent from the client
|
||||
// let's get the master volume from the DACP remote control
|
||||
@@ -772,32 +784,51 @@ void dacp_get_volume(void) {
|
||||
// we need the overall volume and the speakers information to get this device's relative volume to
|
||||
// calculate the real volume
|
||||
|
||||
int32_t overall_volume = dacp_get_client_volume();
|
||||
int32_t overall_volume = 0;
|
||||
int32_t actual_volume = 0;
|
||||
int http_response = dacp_get_client_volume(&overall_volume);
|
||||
// debug(1, "DACP Volume: %d.", overall_volume);
|
||||
int speaker_count = dacp_get_speaker_list((dacp_spkr_stuff *)&speaker_info, 50);
|
||||
// debug(1,"DACP Speaker Count: %d.",speaker_count);
|
||||
if (http_response==200) {
|
||||
int speaker_count = 0;
|
||||
http_response = dacp_get_speaker_list((dacp_spkr_stuff *)&speaker_info, 50,&speaker_count);
|
||||
// debug(1,"DACP Speaker Count: %d.",speaker_count);
|
||||
if (http_response==200) {
|
||||
// get our machine number
|
||||
uint16_t *hn = (uint16_t *)config.hw_addr;
|
||||
uint32_t *ln = (uint32_t *)(config.hw_addr + 2);
|
||||
uint64_t t1 = ntohs(*hn);
|
||||
uint64_t t2 = ntohl(*ln);
|
||||
int64_t machine_number = (t1 << 32) + t2; // this form is useful
|
||||
|
||||
// get our machine number
|
||||
uint16_t *hn = (uint16_t *)config.hw_addr;
|
||||
uint32_t *ln = (uint32_t *)(config.hw_addr + 2);
|
||||
uint64_t t1 = ntohs(*hn);
|
||||
uint64_t t2 = ntohl(*ln);
|
||||
int64_t machine_number = (t1 << 32) + t2; // this form is useful
|
||||
|
||||
// Let's find our own speaker in the array and pick up its relative volume
|
||||
int i;
|
||||
int32_t relative_volume = 0;
|
||||
for (i = 0; i < speaker_count; i++) {
|
||||
if (speaker_info[i].speaker_number == machine_number) {
|
||||
// debug(1,"Our speaker number found: %ld.",machine_number);
|
||||
relative_volume = speaker_info[i].volume;
|
||||
// Let's find our own speaker in the array and pick up its relative volume
|
||||
int i;
|
||||
int32_t relative_volume = 0;
|
||||
for (i = 0; i < speaker_count; i++) {
|
||||
if (speaker_info[i].speaker_number == machine_number) {
|
||||
// debug(1,"Our speaker number found: %ld.",machine_number);
|
||||
relative_volume = speaker_info[i].volume;
|
||||
/*
|
||||
if (speaker_info[i].active)
|
||||
debug(1,"Our speaker is active.");
|
||||
else
|
||||
debug(1,"Our speaker is inactive.");
|
||||
*/
|
||||
}
|
||||
}
|
||||
actual_volume = (overall_volume * relative_volume + 50) / 100;
|
||||
// debug(1,"Overall volume: %d, relative volume: %d%, actual volume:
|
||||
// %d.",overall_volume,relative_volume,actual_volume);
|
||||
// debug(1,"Our actual speaker volume is %d.",actual_volume);
|
||||
//metadata_hub_modify_prolog();
|
||||
//metadata_store.speaker_volume = actual_volume;
|
||||
//metadata_hub_modify_epilog(1);
|
||||
} else {
|
||||
debug(1,"Unexpected return code %d from dacp_get_speaker_list.",http_response);
|
||||
}
|
||||
}
|
||||
int32_t actual_volume = (overall_volume * relative_volume + 50) / 100;
|
||||
// debug(1,"Overall volume: %d, relative volume: %d%, actual volume:
|
||||
// %d.",overall_volume,relative_volume,actual_volume);
|
||||
// debug(1,"Our actual speaker volume is %d.",actual_volume);
|
||||
metadata_hub_modify_prolog();
|
||||
metadata_store.speaker_volume = actual_volume;
|
||||
metadata_hub_modify_epilog();
|
||||
} /* else {
|
||||
debug(1,"Unexpected return code %d from dacp_get_client_volume.",http_response);
|
||||
} */
|
||||
if (the_actual_volume)
|
||||
*the_actual_volume = actual_volume;
|
||||
return http_response;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
|
||||
#include "player.h"
|
||||
|
||||
static pthread_mutex_t dacp_server_information_lock;
|
||||
static pthread_cond_t dacp_server_information_cv;
|
||||
|
||||
typedef struct dacp_speaker_stuff {
|
||||
int64_t speaker_number;
|
||||
int active;
|
||||
@@ -24,11 +21,11 @@ uint32_t dacp_tlv_crawl(
|
||||
|
||||
int dacp_set_speaker_volume(int64_t machine_number, int32_t vo);
|
||||
|
||||
int dacp_get_speaker_list(dacp_spkr_stuff *speaker_array, int max_size_of_array);
|
||||
int dacp_get_speaker_list(dacp_spkr_stuff *speaker_array, int max_size_of_array, int *actual_speaker_count);
|
||||
void set_dacp_server_information(rtsp_conn_info *conn); // tell the DACP conversation thread that
|
||||
// the dacp server information has been set
|
||||
// or changed
|
||||
int send_simple_dacp_command(const char *command);
|
||||
|
||||
void dacp_get_volume(void); // get the speaker volume information from the DACP source and store it
|
||||
int dacp_get_volume(int32_t *the_actual_volume); // get the speaker volume information from the DACP source and store it
|
||||
// in the metadata_hub
|
||||
|
||||
+2
-2
@@ -122,7 +122,7 @@ static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, Avah
|
||||
avahi_threaded_poll_quit(tpoll);
|
||||
break;
|
||||
case AVAHI_BROWSER_NEW:
|
||||
debug(3, "(Browser) NEW: service '%s' of type '%s' in domain '%s'.", name, type, domain);
|
||||
debug(1, "(Browser) NEW: service '%s' of type '%s' in domain '%s'.", name, type, domain);
|
||||
/* We ignore the returned resolver object. In the callback
|
||||
function we free it. If the server is terminated before
|
||||
the callback function is called the server will free
|
||||
@@ -133,7 +133,7 @@ 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);
|
||||
char *dacpid = strstr(name, "iTunes_Ctrl_");
|
||||
if (dacpid) {
|
||||
dacpid += strlen("iTunes_Ctrl_");
|
||||
|
||||
+17
-16
@@ -78,28 +78,29 @@ void add_metadata_watcher(metadata_watcher fn, void *userdata) {
|
||||
|
||||
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");
|
||||
// debug(1, "locking metadata hub for writing");
|
||||
pthread_rwlock_wrlock(&metadata_hub_re_lock);
|
||||
}
|
||||
|
||||
void run_metadata_watchers(void) {
|
||||
int i;
|
||||
debug(1, "locking metadata hub for reading");
|
||||
// debug(1, "locking metadata hub for reading");
|
||||
pthread_rwlock_rdlock(&metadata_hub_re_lock);
|
||||
for (i = 0; i < number_of_watchers; i++) {
|
||||
if (metadata_store.watchers[i]) {
|
||||
metadata_store.watchers[i](&metadata_store, metadata_store.watchers_data[i]);
|
||||
}
|
||||
}
|
||||
debug(1, "unlocking metadata hub for reading");
|
||||
// debug(1, "unlocking metadata hub for reading");
|
||||
pthread_rwlock_unlock(&metadata_hub_re_lock);
|
||||
}
|
||||
|
||||
void metadata_hub_modify_epilog(void) {
|
||||
void metadata_hub_modify_epilog(int modified) {
|
||||
// always run this after changing an entry or a sequence of entries in the metadata_hub
|
||||
debug(1, "unlocking metadata hub for writing");
|
||||
// debug(1, "unlocking metadata hub for writing");
|
||||
pthread_rwlock_unlock(&metadata_hub_re_lock);
|
||||
run_metadata_watchers();
|
||||
if (modified)
|
||||
run_metadata_watchers();
|
||||
}
|
||||
|
||||
char *metadata_write_image_file(const char *buf, int len) {
|
||||
@@ -359,21 +360,21 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
|
||||
break;
|
||||
|
||||
case 'mdst':
|
||||
debug(1, "MH Metadata stream processing start.");
|
||||
// debug(1, "MH Metadata stream processing start.");
|
||||
metadata_hub_modify_prolog();
|
||||
break;
|
||||
case 'mden':
|
||||
metadata_hub_modify_epilog();
|
||||
debug(1, "MH Metadata stream processing end.");
|
||||
metadata_hub_modify_epilog(1);
|
||||
// debug(1, "MH Metadata stream processing end.");
|
||||
break;
|
||||
case 'PICT':
|
||||
if (length > 16) {
|
||||
metadata_hub_modify_prolog();
|
||||
debug(1, "MH Picture received, length %u bytes.", length);
|
||||
// debug(1, "MH Picture received, length %u bytes.", length);
|
||||
if (metadata_store.cover_art_pathname)
|
||||
free(metadata_store.cover_art_pathname);
|
||||
metadata_store.cover_art_pathname = metadata_write_image_file(data, length);
|
||||
metadata_hub_modify_epilog();
|
||||
metadata_hub_modify_epilog(1);
|
||||
}
|
||||
break;
|
||||
case 'clip':
|
||||
@@ -383,10 +384,10 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
|
||||
if (metadata_store.client_ip)
|
||||
free(metadata_store.client_ip);
|
||||
metadata_store.client_ip = strndup(data, length);
|
||||
debug(1, "MH Client IP set to: \"%s\"", metadata_store.client_ip);
|
||||
// debug(1, "MH Client IP set to: \"%s\"", metadata_store.client_ip);
|
||||
metadata_store.client_ip_changed = 1;
|
||||
metadata_store.changed = 1;
|
||||
metadata_hub_modify_epilog();
|
||||
metadata_hub_modify_epilog(1);
|
||||
}
|
||||
break;
|
||||
case 'svip':
|
||||
@@ -396,8 +397,8 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
|
||||
if (metadata_store.server_ip)
|
||||
free(metadata_store.server_ip);
|
||||
metadata_store.server_ip = strndup(data, length);
|
||||
debug(1, "MH Server IP set to: \"%s\"", metadata_store.server_ip);
|
||||
metadata_hub_modify_epilog();
|
||||
// debug(1, "MH Server IP set to: \"%s\"", metadata_store.server_ip);
|
||||
metadata_hub_modify_epilog(1);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
@@ -412,7 +413,7 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
|
||||
payload = strndup(data, length);
|
||||
else
|
||||
payload = NULL;
|
||||
debug(1, "MH \"%s\" \"%s\" (%d bytes): \"%s\".", typestring, codestring, length, payload);
|
||||
// debug(1, "MH \"%s\" \"%s\" (%d bytes): \"%s\".", typestring, codestring, length, payload);
|
||||
if (payload)
|
||||
free(payload);
|
||||
}
|
||||
|
||||
+1
-1
@@ -102,4 +102,4 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
|
||||
// these functions lock and unlock the read-write mutex on the metadata hub and run the watchers
|
||||
// afterwards
|
||||
void metadata_hub_modify_prolog(void);
|
||||
void metadata_hub_modify_epilog(void);
|
||||
void metadata_hub_modify_epilog(int modified); //set to true if modifications occured, 0 otherwise
|
||||
|
||||
+68
-53
@@ -15,7 +15,7 @@
|
||||
#include "mpris-service.h"
|
||||
|
||||
void mpris_metadata_watcher(struct metadata_bundle *argc, void *userdata) {
|
||||
debug(1, "MPRIS metadata watcher called");
|
||||
// debug(1, "MPRIS metadata watcher called");
|
||||
char response[100];
|
||||
switch (argc->repeat_status) {
|
||||
case RS_NONE:
|
||||
@@ -33,74 +33,89 @@ void mpris_metadata_watcher(struct metadata_bundle *argc, void *userdata) {
|
||||
media_player2_player_set_loop_status(mprisPlayerPlayerSkeleton, response);
|
||||
|
||||
GVariantBuilder *dict_builder, *aa;
|
||||
GVariant *trackname, *albumname, *trackid, *tracklength, *artUrl;
|
||||
|
||||
/* Build the metadata array */
|
||||
// debug(1,"Build metadata");
|
||||
dict_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
|
||||
|
||||
// Make up the artwork URI if we have one
|
||||
if (argc->cover_art_pathname) {
|
||||
char artURIstring[1024];
|
||||
sprintf(artURIstring, "file://%s", argc->cover_art_pathname);
|
||||
// sprintf(artURIstring,"");
|
||||
// debug(1,"artURI String: \"%s\".",artURIstring);
|
||||
GVariant *artUrl = g_variant_new("s", artURIstring);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "mpris:artUrl", artUrl);
|
||||
}
|
||||
|
||||
// Add the TrackID if we have one
|
||||
// Build the Track ID from the 16-byte item_composite_id in hex prefixed by
|
||||
// /org/gnome/ShairportSync
|
||||
|
||||
char st[33];
|
||||
char *pt = st;
|
||||
int it;
|
||||
int non_zero = 0;
|
||||
for (it = 0; it < 16; it++) {
|
||||
if (argc->item_composite_id[it])
|
||||
non_zero = 1;
|
||||
sprintf(pt, "%02X", argc->item_composite_id[it]);
|
||||
pt += 2;
|
||||
}
|
||||
*pt = 0;
|
||||
// debug(1, "Item composite ID set to 0x%s.", st);
|
||||
|
||||
char artURIstring[1024];
|
||||
char trackidstring[1024];
|
||||
sprintf(trackidstring, "/org/gnome/ShairportSync/%s", st);
|
||||
|
||||
trackid = g_variant_new("o", trackidstring);
|
||||
|
||||
// Make up the track name and album name
|
||||
trackname = g_variant_new("s", argc->track_name);
|
||||
albumname = g_variant_new("s", argc->album_name);
|
||||
|
||||
// Make up the track length in microseconds as an int64
|
||||
|
||||
uint64_t track_length_in_microseconds = argc->songtime_in_milliseconds;
|
||||
|
||||
track_length_in_microseconds *= 1000; // to microseconds in 64-bit precision
|
||||
|
||||
// Make up the track name and album name
|
||||
tracklength = g_variant_new("x", track_length_in_microseconds);
|
||||
|
||||
/* Build the artists array */
|
||||
// debug(1,"Build artists");
|
||||
aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
|
||||
g_variant_builder_add(aa, "s", argc->artist_name);
|
||||
GVariant *artists = g_variant_builder_end(aa);
|
||||
g_variant_builder_unref(aa);
|
||||
|
||||
/* Build the genre array */
|
||||
// debug(1,"Build genre");
|
||||
aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
|
||||
g_variant_builder_add(aa, "s", argc->genre);
|
||||
GVariant *genres = g_variant_builder_end(aa);
|
||||
g_variant_builder_unref(aa);
|
||||
|
||||
/* Build the metadata array */
|
||||
// debug(1,"Build metadata");
|
||||
dict_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
|
||||
// Make up the artwork URI if we have one
|
||||
if (argc->cover_art_pathname) {
|
||||
sprintf(artURIstring, "file://%s", argc->cover_art_pathname);
|
||||
// sprintf(artURIstring,"");
|
||||
artUrl = g_variant_new("s", artURIstring);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "mpris:artUrl", artUrl);
|
||||
if (non_zero) {
|
||||
// debug(1, "Item composite ID set to 0x%s.", st);
|
||||
char trackidstring[1024];
|
||||
sprintf(trackidstring, "/org/gnome/ShairportSync/%s", st);
|
||||
GVariant* trackid = g_variant_new("o", trackidstring);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "mpris:trackid", trackid);
|
||||
}
|
||||
|
||||
// Add the track length if it's non-zero
|
||||
if (argc->songtime_in_milliseconds) {
|
||||
uint64_t track_length_in_microseconds = argc->songtime_in_milliseconds;
|
||||
track_length_in_microseconds *= 1000; // to microseconds in 64-bit precision
|
||||
// Make up the track name and album name
|
||||
GVariant *tracklength = g_variant_new("x", track_length_in_microseconds);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "mpris:length", tracklength);
|
||||
}
|
||||
g_variant_builder_add(dict_builder, "{sv}", "mpris:trackid", trackid);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "mpris:length", tracklength);
|
||||
|
||||
g_variant_builder_add(dict_builder, "{sv}", "xesam:title", trackname);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "xesam:album", albumname);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "xesam:artist", artists);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "xesam:genre", genres);
|
||||
// Add the track name if there is one
|
||||
if (argc->track_name) {
|
||||
GVariant *trackname = g_variant_new("s", argc->track_name);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "xesam:title", trackname);
|
||||
}
|
||||
|
||||
// Add the album name if there is one
|
||||
if (argc->album_name) {
|
||||
GVariant *albumname = g_variant_new("s", argc->album_name);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "xesam:album", albumname);
|
||||
}
|
||||
|
||||
// Add the artists if there are any (actually there will be at most one, but put it in an array)
|
||||
if (argc->artist_name) {
|
||||
/* Build the artists array */
|
||||
// debug(1,"Build artist array");
|
||||
aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
|
||||
g_variant_builder_add(aa, "s", argc->artist_name);
|
||||
GVariant *artists = g_variant_builder_end(aa);
|
||||
g_variant_builder_unref(aa);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "xesam:artist", artists);
|
||||
}
|
||||
|
||||
// Add the genres if there are any (actually there will be at most one, but put it in an array)
|
||||
if (argc->genre) {
|
||||
// debug(1,"Build genre");
|
||||
aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
|
||||
g_variant_builder_add(aa, "s", argc->genre);
|
||||
GVariant *genres = g_variant_builder_end(aa);
|
||||
g_variant_builder_unref(aa);
|
||||
g_variant_builder_add(dict_builder, "{sv}", "xesam:genre", genres);
|
||||
}
|
||||
|
||||
GVariant *dict = g_variant_builder_end(dict_builder);
|
||||
g_variant_builder_unref(dict_builder);
|
||||
|
||||
// debug(1,"Set metadata");
|
||||
media_player2_player_set_metadata(mprisPlayerPlayerSkeleton, dict);
|
||||
}
|
||||
|
||||
|
||||
@@ -826,7 +826,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
#ifdef HAVE_METADATA_HUB
|
||||
metadata_hub_modify_prolog();
|
||||
metadata_store.player_state = PS_PLAYING;
|
||||
metadata_hub_modify_epilog();
|
||||
metadata_hub_modify_epilog(1);
|
||||
#endif
|
||||
if (reference_timestamp) { // if we have a reference time
|
||||
// debug(1,"First frame seen with timestamp...");
|
||||
@@ -2501,7 +2501,17 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
|
||||
void player_volume(double airplay_volume, rtsp_conn_info *conn) {
|
||||
command_set_volume(airplay_volume);
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
dacp_get_volume();
|
||||
int32_t actual_volume;
|
||||
if (dacp_get_volume(&actual_volume)==200) {
|
||||
metadata_hub_modify_prolog();
|
||||
if (metadata_store.speaker_volume == actual_volume)
|
||||
metadata_hub_modify_epilog(0); // no change
|
||||
else {
|
||||
metadata_store.speaker_volume = actual_volume;
|
||||
metadata_hub_modify_epilog(1); // change
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
player_volume_without_notification(airplay_volume, conn);
|
||||
@@ -2523,7 +2533,7 @@ void player_flush(int64_t timestamp, rtsp_conn_info *conn) {
|
||||
#ifdef HAVE_METADATA_HUB
|
||||
metadata_hub_modify_prolog();
|
||||
metadata_store.player_state = PS_PAUSED;
|
||||
metadata_hub_modify_epilog();
|
||||
metadata_hub_modify_epilog(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2553,7 +2563,7 @@ int player_play(rtsp_conn_info *conn) {
|
||||
#ifdef HAVE_METADATA_HUB
|
||||
metadata_hub_modify_prolog();
|
||||
metadata_store.player_state = PS_PLAYING;
|
||||
metadata_hub_modify_epilog();
|
||||
metadata_hub_modify_epilog(1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -2573,7 +2583,7 @@ void player_stop(rtsp_conn_info *conn) {
|
||||
#ifdef HAVE_METADATA_HUB
|
||||
metadata_hub_modify_prolog();
|
||||
metadata_store.player_state = PS_STOPPED;
|
||||
metadata_hub_modify_epilog();
|
||||
metadata_hub_modify_epilog(1);
|
||||
#endif
|
||||
} else {
|
||||
debug(3, "player thread of RTSP conversation %d is already deleted.", conn->connection_number);
|
||||
|
||||
Reference in New Issue
Block a user