mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-24 13:13:17 -05:00
[raop] Only send exact types of metadata requested by device
Airport Express announces md=2, meaning only progress metadata, so we shouldn't send artwork and text metadata to it.
This commit is contained in:
parent
4491928466
commit
07972c28f7
@ -96,6 +96,9 @@
|
|||||||
|
|
||||||
#define RAOP_MD_DELAY_STARTUP 15360
|
#define RAOP_MD_DELAY_STARTUP 15360
|
||||||
#define RAOP_MD_DELAY_SWITCH (RAOP_MD_DELAY_STARTUP * 2)
|
#define RAOP_MD_DELAY_SWITCH (RAOP_MD_DELAY_STARTUP * 2)
|
||||||
|
#define RAOP_MD_WANTS_TEXT (1 << 0)
|
||||||
|
#define RAOP_MD_WANTS_ARTWORK (1 << 1)
|
||||||
|
#define RAOP_MD_WANTS_PROGRESS (1 << 2)
|
||||||
|
|
||||||
// This is an arbitrary value which just needs to be kept in sync with the config
|
// This is an arbitrary value which just needs to be kept in sync with the config
|
||||||
#define RAOP_CONFIG_MAX_VOLUME 11
|
#define RAOP_CONFIG_MAX_VOLUME 11
|
||||||
@ -152,8 +155,8 @@ struct raop_extra
|
|||||||
{
|
{
|
||||||
enum raop_devtype devtype;
|
enum raop_devtype devtype;
|
||||||
|
|
||||||
|
uint16_t wanted_metadata;
|
||||||
bool encrypt;
|
bool encrypt;
|
||||||
bool wants_metadata;
|
|
||||||
bool supports_auth_setup;
|
bool supports_auth_setup;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -189,10 +192,11 @@ struct raop_session
|
|||||||
struct evrtsp_connection *ctrl;
|
struct evrtsp_connection *ctrl;
|
||||||
|
|
||||||
enum raop_state state;
|
enum raop_state state;
|
||||||
|
|
||||||
|
uint16_t wanted_metadata;
|
||||||
bool req_has_auth;
|
bool req_has_auth;
|
||||||
bool encrypt;
|
bool encrypt;
|
||||||
bool auth_quirk_itunes;
|
bool auth_quirk_itunes;
|
||||||
bool wants_metadata;
|
|
||||||
bool supports_post;
|
bool supports_post;
|
||||||
bool supports_auth_setup;
|
bool supports_auth_setup;
|
||||||
|
|
||||||
@ -252,9 +256,6 @@ struct raop_service
|
|||||||
|
|
||||||
typedef void (*evrtsp_req_cb)(struct evrtsp_request *req, void *arg);
|
typedef void (*evrtsp_req_cb)(struct evrtsp_request *req, void *arg);
|
||||||
|
|
||||||
/* Truncate RTP time to lower 32bits for RAOP */
|
|
||||||
#define RAOP_RTPTIME(x) ((uint32_t)((x) & (uint64_t)0xffffffff))
|
|
||||||
|
|
||||||
/* NTP timestamp definitions */
|
/* NTP timestamp definitions */
|
||||||
#define FRAC 4294967296. /* 2^32 as a double */
|
#define FRAC 4294967296. /* 2^32 as a double */
|
||||||
#define NTP_EPOCH_DELTA 0x83aa7e80 /* 2208988800 - that's 1970 - 1900 in seconds */
|
#define NTP_EPOCH_DELTA 0x83aa7e80 /* 2208988800 - that's 1970 - 1900 in seconds */
|
||||||
@ -2026,7 +2027,7 @@ session_make(struct output_device *rd, int family, int callback_id, bool only_pr
|
|||||||
rs->password = rd->password;
|
rs->password = rd->password;
|
||||||
|
|
||||||
rs->supports_auth_setup = re->supports_auth_setup;
|
rs->supports_auth_setup = re->supports_auth_setup;
|
||||||
rs->wants_metadata = re->wants_metadata;
|
rs->wanted_metadata = re->wanted_metadata;
|
||||||
|
|
||||||
switch (re->devtype)
|
switch (re->devtype)
|
||||||
{
|
{
|
||||||
@ -2339,7 +2340,6 @@ raop_metadata_send_artwork(struct raop_session *rs, struct evbuffer *evbuf, stru
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
DPRINTF(E_LOG, L_RAOP, "Unsupported artwork format %d\n", rmd->artwork_fmt);
|
DPRINTF(E_LOG, L_RAOP, "Unsupported artwork format %d\n", rmd->artwork_fmt);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2350,7 +2350,6 @@ raop_metadata_send_artwork(struct raop_session *rs, struct evbuffer *evbuf, stru
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_RAOP, "Could not copy artwork for sending\n");
|
DPRINTF(E_LOG, L_RAOP, "Could not copy artwork for sending\n");
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2362,7 +2361,7 @@ raop_metadata_send_artwork(struct raop_session *rs, struct evbuffer *evbuf, stru
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
raop_metadata_send_metadata(struct raop_session *rs, struct evbuffer *evbuf, struct raop_metadata *rmd, char *rtptime)
|
raop_metadata_send_text(struct raop_session *rs, struct evbuffer *evbuf, struct raop_metadata *rmd, char *rtptime)
|
||||||
{
|
{
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -2375,11 +2374,10 @@ raop_metadata_send_metadata(struct raop_session *rs, struct evbuffer *evbuf, str
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_RAOP, "Could not copy metadata for sending\n");
|
DPRINTF(E_LOG, L_RAOP, "Could not copy metadata for sending\n");
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = raop_send_req_set_parameter(rs, evbuf, "application/x-dmap-tagged", rtptime, raop_cb_metadata, "send_metadata");
|
ret = raop_send_req_set_parameter(rs, evbuf, "application/x-dmap-tagged", rtptime, raop_cb_metadata, "send_text");
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
DPRINTF(E_LOG, L_RAOP, "Could not send SET_PARAMETER metadata request to '%s'\n", rs->devname);
|
DPRINTF(E_LOG, L_RAOP, "Could not send SET_PARAMETER metadata request to '%s'\n", rs->devname);
|
||||||
|
|
||||||
@ -2400,56 +2398,48 @@ raop_metadata_send_generic(struct raop_session *rs, struct output_metadata *meta
|
|||||||
|
|
||||||
raop_metadata_rtptimes_get(&start, &display, &pos, &end, rs->master_session, metadata);
|
raop_metadata_rtptimes_get(&start, &display, &pos, &end, rs->master_session, metadata);
|
||||||
|
|
||||||
CHECK_NULL(L_RAOP, evbuf = evbuffer_new());
|
|
||||||
|
|
||||||
ret = raop_metadata_send_progress(rs, evbuf, rmd, display, pos, end);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_RAOP, "Could not send progress to '%s'\n", rs->devname);
|
|
||||||
ret = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (only_progress)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = snprintf(rtptime, sizeof(rtptime), "rtptime=%u", start);
|
ret = snprintf(rtptime, sizeof(rtptime), "rtptime=%u", start);
|
||||||
if ((ret < 0) || (ret >= sizeof(rtptime)))
|
if ((ret < 0) || (ret >= sizeof(rtptime)))
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_RAOP, "RTP-Info too big for buffer while sending metadata\n");
|
DPRINTF(E_LOG, L_RAOP, "RTP-Info too big for buffer while sending metadata\n");
|
||||||
ret = -1;
|
return -1;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = raop_metadata_send_metadata(rs, evbuf, rmd, rtptime);
|
CHECK_NULL(L_RAOP, evbuf = evbuffer_new());
|
||||||
if (ret < 0)
|
|
||||||
|
if (rs->wanted_metadata & RAOP_MD_WANTS_PROGRESS)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_RAOP, "Could not send metadata to '%s'\n", rs->devname);
|
ret = raop_metadata_send_progress(rs, evbuf, rmd, display, pos, end);
|
||||||
ret = -1;
|
if (ret < 0)
|
||||||
goto out;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rmd->artwork)
|
if (!only_progress && (rs->wanted_metadata & RAOP_MD_WANTS_TEXT))
|
||||||
|
{
|
||||||
|
ret = raop_metadata_send_text(rs, evbuf, rmd, rtptime);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!only_progress && (rs->wanted_metadata & RAOP_MD_WANTS_ARTWORK) && rmd->artwork)
|
||||||
{
|
{
|
||||||
ret = raop_metadata_send_artwork(rs, evbuf, rmd, rtptime);
|
ret = raop_metadata_send_artwork(rs, evbuf, rmd, rtptime);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
goto error;
|
||||||
DPRINTF(E_LOG, L_RAOP, "Could not send artwork to '%s'\n", rs->devname);
|
|
||||||
ret = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
evbuffer_free(evbuf);
|
evbuffer_free(evbuf);
|
||||||
|
return 0;
|
||||||
|
|
||||||
return ret;
|
error:
|
||||||
|
evbuffer_free(evbuf);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
raop_metadata_startup_send(struct raop_session *rs)
|
raop_metadata_startup_send(struct raop_session *rs)
|
||||||
{
|
{
|
||||||
if (!rs->wants_metadata || !raop_cur_metadata)
|
if (!rs->wanted_metadata || !raop_cur_metadata)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
raop_cur_metadata->startup = true;
|
raop_cur_metadata->startup = true;
|
||||||
@ -2460,7 +2450,7 @@ raop_metadata_startup_send(struct raop_session *rs)
|
|||||||
static int
|
static int
|
||||||
raop_metadata_keep_alive_send(struct raop_session *rs)
|
raop_metadata_keep_alive_send(struct raop_session *rs)
|
||||||
{
|
{
|
||||||
if (!rs->wants_metadata || !raop_cur_metadata)
|
if (!rs->wanted_metadata || !raop_cur_metadata)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
raop_cur_metadata->startup = false;
|
raop_cur_metadata->startup = false;
|
||||||
@ -2479,7 +2469,7 @@ raop_metadata_send(struct output_metadata *metadata)
|
|||||||
{
|
{
|
||||||
next = rs->next;
|
next = rs->next;
|
||||||
|
|
||||||
if (!(rs->state & RAOP_STATE_F_CONNECTED) || !rs->wants_metadata)
|
if (!(rs->state & RAOP_STATE_F_CONNECTED) || !rs->wanted_metadata)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = raop_metadata_send_generic(rs, metadata, false);
|
ret = raop_metadata_send_generic(rs, metadata, false);
|
||||||
@ -4427,7 +4417,7 @@ raop_device_cb(const char *name, const char *type, const char *domain, const cha
|
|||||||
const char *p;
|
const char *p;
|
||||||
char *at_name;
|
char *at_name;
|
||||||
char *password;
|
char *password;
|
||||||
char *et;
|
char *s;
|
||||||
char *token;
|
char *token;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
@ -4600,22 +4590,32 @@ raop_device_cb(const char *name, const char *type, const char *domain, const cha
|
|||||||
p = keyval_get(txt, "ek");
|
p = keyval_get(txt, "ek");
|
||||||
if (p && (*p == '1'))
|
if (p && (*p == '1'))
|
||||||
re->encrypt = 1;
|
re->encrypt = 1;
|
||||||
else
|
|
||||||
re->encrypt = 0;
|
|
||||||
|
|
||||||
// Metadata support
|
// Metadata support
|
||||||
// We don't use the values, but they should mean: 0 = text, 1 = artwork, 2 = progress
|
|
||||||
p = keyval_get(txt, "md");
|
p = keyval_get(txt, "md");
|
||||||
if (p && (*p != '\0'))
|
if (p)
|
||||||
re->wants_metadata = 1;
|
{
|
||||||
else
|
CHECK_NULL(L_RAOP, s = strdup(p));
|
||||||
re->wants_metadata = 0;
|
token = strtok_r(s, ",", &ptr);
|
||||||
|
while (token)
|
||||||
|
{
|
||||||
|
if (strcmp(token, "0") == 0)
|
||||||
|
re->wanted_metadata |= RAOP_MD_WANTS_TEXT;
|
||||||
|
else if (strcmp(token, "1") == 0)
|
||||||
|
re->wanted_metadata |= RAOP_MD_WANTS_ARTWORK;
|
||||||
|
else if (strcmp(token, "2") == 0)
|
||||||
|
re->wanted_metadata |= RAOP_MD_WANTS_PROGRESS;
|
||||||
|
|
||||||
|
token = strtok_r(NULL, ",", &ptr);
|
||||||
|
}
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
p = keyval_get(txt, "et");
|
p = keyval_get(txt, "et");
|
||||||
if (p)
|
if (p)
|
||||||
{
|
{
|
||||||
CHECK_NULL(L_RAOP, et = strdup(p));
|
CHECK_NULL(L_RAOP, s = strdup(p));
|
||||||
token = strtok_r(et, ",", &ptr);
|
token = strtok_r(s, ",", &ptr);
|
||||||
while (token)
|
while (token)
|
||||||
{
|
{
|
||||||
// Value of 4 seems to indicate support (!= requirement) for auth-setup
|
// Value of 4 seems to indicate support (!= requirement) for auth-setup
|
||||||
@ -4624,7 +4624,7 @@ raop_device_cb(const char *name, const char *type, const char *domain, const cha
|
|||||||
|
|
||||||
token = strtok_r(NULL, ",", &ptr);
|
token = strtok_r(NULL, ",", &ptr);
|
||||||
}
|
}
|
||||||
free(et);
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (family)
|
switch (family)
|
||||||
@ -4633,14 +4633,14 @@ raop_device_cb(const char *name, const char *type, const char *domain, const cha
|
|||||||
rd->v4_address = strdup(address);
|
rd->v4_address = strdup(address);
|
||||||
rd->v4_port = port;
|
rd->v4_port = port;
|
||||||
DPRINTF(E_INFO, L_RAOP, "Adding AirPlay device '%s': password: %u, verification: %u, encrypt: %u, authsetup: %u, metadata: %u, type %s, address %s:%d\n",
|
DPRINTF(E_INFO, L_RAOP, "Adding AirPlay device '%s': password: %u, verification: %u, encrypt: %u, authsetup: %u, metadata: %u, type %s, address %s:%d\n",
|
||||||
at_name, rd->has_password, rd->requires_auth, re->encrypt, re->supports_auth_setup, re->wants_metadata, raop_devtype[re->devtype], address, port);
|
at_name, rd->has_password, rd->requires_auth, re->encrypt, re->supports_auth_setup, re->wanted_metadata, raop_devtype[re->devtype], address, port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
rd->v6_address = strdup(address);
|
rd->v6_address = strdup(address);
|
||||||
rd->v6_port = port;
|
rd->v6_port = port;
|
||||||
DPRINTF(E_INFO, L_RAOP, "Adding AirPlay device '%s': password: %u, verification: %u, encrypt: %u, authsetup: %u, metadata: %u, type %s, address [%s]:%d\n",
|
DPRINTF(E_INFO, L_RAOP, "Adding AirPlay device '%s': password: %u, verification: %u, encrypt: %u, authsetup: %u, metadata: %u, type %s, address [%s]:%d\n",
|
||||||
at_name, rd->has_password, rd->requires_auth, re->encrypt, re->supports_auth_setup, re->wants_metadata, raop_devtype[re->devtype], address, port);
|
at_name, rd->has_password, rd->requires_auth, re->encrypt, re->supports_auth_setup, re->wanted_metadata, raop_devtype[re->devtype], address, port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user