[raop] Use GET_PARAMETER of volume to keep connection alive and get speaker volume

This commit is contained in:
ejurgensen 2018-04-11 22:29:07 +02:00
parent fe05f80822
commit d9a67b6dce

View File

@ -327,7 +327,7 @@ static struct event *flush_timer;
/* Keep-alive timer - hack for ATV's with tvOS 10 */ /* Keep-alive timer - hack for ATV's with tvOS 10 */
static struct event *keep_alive_timer; static struct event *keep_alive_timer;
static struct timeval keep_alive_tv = { 60, 0 }; static struct timeval keep_alive_tv = { 30, 0 };
/* Sessions */ /* Sessions */
static struct raop_session *sessions; static struct raop_session *sessions;
@ -1443,6 +1443,56 @@ raop_send_req_set_parameter(struct raop_session *rs, struct evbuffer *evbuf, cha
return 0; return 0;
} }
static int
raop_send_req_get_parameter(struct raop_session *rs, struct evbuffer *evbuf, char *ctype, char *rtpinfo, evrtsp_req_cb cb)
{
struct evrtsp_request *req;
int ret;
req = evrtsp_request_new(cb, rs);
if (!req)
{
DPRINTF(E_LOG, L_RAOP, "Could not create RTSP request for GET_PARAMETER\n");
return -1;
}
ret = evbuffer_add_buffer(req->output_buffer, evbuf);
if (ret < 0)
{
DPRINTF(E_LOG, L_RAOP, "Out of memory for GET_PARAMETER payload\n");
evrtsp_request_free(req);
return -1;
}
ret = raop_add_headers(rs, req, EVRTSP_REQ_GET_PARAMETER);
if (ret < 0)
{
evrtsp_request_free(req);
return -1;
}
evrtsp_add_header(req->output_headers, "Content-Type", ctype);
if (rtpinfo)
evrtsp_add_header(req->output_headers, "RTP-Info", rtpinfo);
ret = evrtsp_make_request(rs->ctrl, req, EVRTSP_REQ_GET_PARAMETER, rs->session_url);
if (ret < 0)
{
DPRINTF(E_LOG, L_RAOP, "Could not make GET_PARAMETER request\n");
return -1;
}
rs->reqs_in_flight++;
evrtsp_connection_set_closecb(rs->ctrl, NULL, NULL);
return 0;
}
static int static int
raop_send_req_record(struct raop_session *rs, evrtsp_req_cb cb) raop_send_req_record(struct raop_session *rs, evrtsp_req_cb cb)
{ {
@ -2376,8 +2426,25 @@ raop_metadata_send(void *metadata, uint64_t rtptime, uint64_t offset, int startu
} }
/* Volume handling */ /* Volume handling */
static int
raop_volume_to_pct(float raop_volume)
{
int volume;
/* RAOP volume
* -144.0 is off
* -30.0 - 0 maps to 0 - 100
*/
if (raop_volume > -30.0 && raop_volume <= 0.0)
volume = (int)(100.0 * raop_volume / 30.0 + 100.0);
else
volume = 0;
return volume;
}
static float static float
raop_volume_convert(int volume, char *name) raop_volume_from_pct(int volume, char *name)
{ {
float raop_volume; float raop_volume;
cfg_t *airplay; cfg_t *airplay;
@ -2391,7 +2458,7 @@ raop_volume_convert(int volume, char *name)
if ((max_volume < 1) || (max_volume > RAOP_CONFIG_MAX_VOLUME)) if ((max_volume < 1) || (max_volume > RAOP_CONFIG_MAX_VOLUME))
{ {
DPRINTF(E_LOG, L_RAOP, "Config has bad max_volume (%d) for device %s, using default instead\n", max_volume, name); DPRINTF(E_LOG, L_RAOP, "Config has bad max_volume (%d) for device '%s', using default instead\n", max_volume, name);
max_volume = RAOP_CONFIG_MAX_VOLUME; max_volume = RAOP_CONFIG_MAX_VOLUME;
} }
@ -2423,7 +2490,7 @@ raop_set_volume_internal(struct raop_session *rs, int volume, evrtsp_req_cb cb)
return -1; return -1;
} }
raop_volume = raop_volume_convert(volume, rs->devname); raop_volume = raop_volume_from_pct(volume, rs->devname);
/* Don't let locales get in the way here */ /* Don't let locales get in the way here */
/* We use -%d and -(int)raop_volume so -0.3 won't become 0.3 */ /* We use -%d and -(int)raop_volume so -0.3 won't become 0.3 */
@ -2447,6 +2514,36 @@ raop_set_volume_internal(struct raop_session *rs, int volume, evrtsp_req_cb cb)
return ret; return ret;
} }
static int
raop_get_volume_internal(struct raop_session *rs, evrtsp_req_cb cb)
{
struct evbuffer *evbuf;
int ret;
evbuf = evbuffer_new();
if (!evbuf)
{
DPRINTF(E_LOG, L_RAOP, "Could not allocate evbuffer for volume payload\n");
return -1;
}
ret = evbuffer_add_printf(evbuf, "volume\n");
if (ret < 0)
{
DPRINTF(E_LOG, L_RAOP, "Out of memory for GET_PARAMETER payload (volume)\n");
evbuffer_free(evbuf);
return -1;
}
ret = raop_send_req_get_parameter(rs, evbuf, "text/parameters", NULL, cb);
if (ret < 0)
DPRINTF(E_LOG, L_RAOP, "Could not send GET_PARAMETER request for volume\n");
evbuffer_free(evbuf);
return ret;
}
static void static void
raop_cb_set_volume(struct evrtsp_request *req, void *arg) raop_cb_set_volume(struct evrtsp_request *req, void *arg)
{ {
@ -2549,25 +2646,45 @@ static void
raop_cb_keep_alive(struct evrtsp_request *req, void *arg) raop_cb_keep_alive(struct evrtsp_request *req, void *arg)
{ {
struct raop_session *rs = arg; struct raop_session *rs = arg;
char *body;
float raop_volume;
rs->reqs_in_flight--; rs->reqs_in_flight--;
if (!req) if (!req)
goto error;
if (req->response_code != RTSP_OK)
{ {
DPRINTF(E_LOG, L_RAOP, "SET_PARAMETER request failed for keep alive: %d %s\n", req->response_code, req->response_code_line); DPRINTF(E_LOG, L_RAOP, "No reply from '%s' to our keep alive request, hanging up\n", rs->devname);
goto error; raop_session_failure(rs);
return;
} }
if (!rs->reqs_in_flight) if (!rs->reqs_in_flight)
evrtsp_connection_set_closecb(rs->ctrl, raop_rtsp_close_cb, rs); evrtsp_connection_set_closecb(rs->ctrl, raop_rtsp_close_cb, rs);
if (req->response_code != RTSP_OK)
{
DPRINTF(E_LOG, L_RAOP, "Keep alive GET_PARAMETER request to '%s' failed: %d %s\n", rs->devname, req->response_code, req->response_code_line);
return; return;
}
error: evbuffer_add(req->input_buffer, "", 1); // NULL-terminate
raop_session_failure(rs);
body = (char *)evbuffer_pullup(req->input_buffer, -1);
if (!body || strncmp(body, "volume: ", strlen("volume: ")) != 0)
{
DPRINTF(E_LOG, L_RAOP, "Invalid response from '%s' to keep alive request: '%s'\n", rs->devname, body);
return;
}
raop_volume = atof(strchr(body, ':') + 2);
rs->volume = raop_volume_to_pct(raop_volume);
DPRINTF(E_DBG, L_RAOP, "GET_PARAMETER request to '%s' returned volume %f (%d)\n", rs->devname, raop_volume, rs->volume);
evtimer_add(keep_alive_timer, &keep_alive_tv);
return;
} }
static void static void
@ -2632,16 +2749,14 @@ raop_keep_alive_timer_cb(int fd, short what, void *arg)
for (rs = sessions; rs; rs = rs->next) for (rs = sessions; rs; rs = rs->next)
{ {
if (!rs->keep_alive) // if (!rs->keep_alive)
continue; // continue;
if (!(rs->state & RAOP_STATE_F_CONNECTED)) if (!(rs->state & RAOP_STATE_F_CONNECTED))
continue; continue;
raop_set_volume_internal(rs, rs->volume, raop_cb_keep_alive); raop_get_volume_internal(rs, raop_cb_keep_alive);
} }
evtimer_add(keep_alive_timer, &keep_alive_tv);
} }
static int static int