[raop] Temporary fix for issue #293

This commit is contained in:
ejurgensen 2016-10-09 00:42:48 +02:00
parent 9a997551a2
commit 94e133e8dc
1 changed files with 79 additions and 9 deletions

View File

@ -114,6 +114,7 @@ enum raop_devtype {
RAOP_DEV_APEX2_80211N,
RAOP_DEV_APEX3_80211N,
RAOP_DEV_APPLETV,
RAOP_DEV_APPLETV4,
RAOP_DEV_OTHER,
};
@ -161,6 +162,7 @@ struct raop_session
unsigned encrypt:1;
unsigned auth_quirk_itunes:1;
unsigned wants_metadata:1;
unsigned keep_alive:1;
struct event *deferredev;
@ -263,6 +265,7 @@ static const char *raop_devtype[] =
"AirPort Express 2 - 802.11n",
"AirPort Express 3 - 802.11n",
"AppleTV",
"AppleTV4",
"Other",
};
@ -303,6 +306,10 @@ static struct raop_metadata *metadata_tail;
/* FLUSH timer */
static struct event *flush_timer;
/* Keep-alive timer - hack for ATV's with tvOS 10 */
static struct event *keep_alive_timer;
static struct timeval keep_alive_tv = { 60, 0 };
/* Sessions */
static struct raop_session *sessions;
@ -1905,26 +1912,37 @@ raop_session_make(struct output_device *rd, int family, output_status_cb cb)
case RAOP_DEV_APEX1_80211G:
rs->encrypt = 1;
rs->auth_quirk_itunes = 1;
rs->keep_alive = 0;
break;
case RAOP_DEV_APEX2_80211N:
rs->encrypt = 1;
rs->auth_quirk_itunes = 0;
rs->keep_alive = 0;
break;
case RAOP_DEV_APEX3_80211N:
rs->encrypt = 0;
rs->auth_quirk_itunes = 0;
rs->keep_alive = 0;
break;
case RAOP_DEV_APPLETV:
rs->encrypt = 0;
rs->auth_quirk_itunes = 0;
rs->keep_alive = 0;
break;
case RAOP_DEV_APPLETV4:
rs->encrypt = 0;
rs->auth_quirk_itunes = 0;
rs->keep_alive = 1;
break;
case RAOP_DEV_OTHER:
rs->encrypt = re->encrypt;
rs->auth_quirk_itunes = 0;
rs->keep_alive = 0;
break;
}
@ -2335,8 +2353,6 @@ raop_volume_convert(int volume, char *name)
max_volume = RAOP_CONFIG_MAX_VOLUME;
}
DPRINTF(E_DBG, L_RAOP, "Setting max_volume for device %s to %d\n", name, max_volume);
/* RAOP volume
* -144.0 is off
* 0 - 100 maps to -30.0 - 0
@ -2488,6 +2504,31 @@ raop_cb_flush(struct evrtsp_request *req, void *arg)
raop_session_failure(rs);
}
static void
raop_cb_keep_alive(struct evrtsp_request *req, void *arg)
{
struct raop_session *rs = arg;
rs->reqs_in_flight--;
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);
goto error;
}
if (!rs->reqs_in_flight)
evrtsp_connection_set_closecb(rs->ctrl, raop_rtsp_close_cb, rs);
return;
error:
raop_session_failure(rs);
}
// Forward
static void
raop_device_stop(struct output_session *session);
@ -2508,6 +2549,25 @@ raop_flush_timer_cb(int fd, short what, void *arg)
}
}
static void
raop_keep_alive_timer_cb(int fd, short what, void *arg)
{
struct raop_session *rs;
for (rs = sessions; rs; rs = rs->next)
{
if (!rs->keep_alive)
continue;
if (!(rs->state & RAOP_STATE_F_CONNECTED))
continue;
raop_set_volume_internal(rs, rs->volume, raop_cb_keep_alive);
}
evtimer_add(keep_alive_timer, &keep_alive_tv);
}
static int
raop_flush(output_status_cb cb, uint64_t rtptime)
{
@ -3900,6 +3960,8 @@ raop_cb_probe_options(struct evrtsp_request *req, void *arg)
["sf=0x4" "am=AppleTV2,1" "vs=105.5" "md=0,1,2" "tp=TCP,UDP" "vn=65537" "pw=false" "ss=16" "sr=44100" "da=true" "sv=false" "et=0,3" "cn=0,1" "ch=2" "txtvers=1"]
* Apple TV 3:
["vv=2" "vs=200.54" "vn=65537" "tp=UDP" "sf=0x44" "pk=8...f" "am=AppleTV3,1" "md=0,1,2" "ft=0x5A7FFFF7,0xE" "et=0,3,5" "da=true" "cn=0,1,2,3"]
* Apple TV 4:
["vv=2" "vs=301.44.3" "vn=65537" "tp=UDP" "pk=9...f" "am=AppleTV5,3" "md=0,1,2" "sf=0x44" "ft=0x5A7FFFF7,0x4DE" "et=0,3,5" "da=true" "cn=0,1,2,3"]
* Sony STR-DN1040:
["fv=s9327.1090.0" "am=STR-DN1040" "vs=141.9" "vn=65537" "tp=UDP" "ss=16" "sr=44100" "sv=false" "pw=false" "md=0,2" "ft=0x44F0A00" "et=0,4" "da=true" "cn=0,1" "ch=2" "txtvers=1"]
* AirFoil:
@ -4050,6 +4112,8 @@ raop_device_cb(const char *name, const char *type, const char *domain, const cha
re->devtype = RAOP_DEV_APEX2_80211N; // Second generation
else if (strncmp(p, "AirPort", strlen("AirPort")) == 0)
re->devtype = RAOP_DEV_APEX3_80211N; // Third generation and newer
else if (strncmp(p, "AppleTV5,3", strlen("AppleTV5,3")) == 0)
re->devtype = RAOP_DEV_APPLETV4; // Stream to ATV with tvOS 10 needs to be kept alive
else if (strncmp(p, "AppleTV", strlen("AppleTV")) == 0)
re->devtype = RAOP_DEV_APPLETV;
else if (*p == '\0')
@ -4069,8 +4133,8 @@ raop_device_cb(const char *name, const char *type, const char *domain, const cha
else
re->wants_metadata = 0;
DPRINTF(E_INFO, L_RAOP, "Adding AirPlay device %s: password: %u, encrypt: %u, metadata: %u, type %s\n",
name, rd->has_password, re->encrypt, re->wants_metadata, raop_devtype[re->devtype]);
DPRINTF(E_INFO, L_RAOP, "Adding AirPlay device %s: password: %u, encrypt: %u, metadata: %u, type %s, address [%s]:%d\n",
name, rd->has_password, re->encrypt, re->wants_metadata, raop_devtype[re->devtype], address, port);
rd->advertised = 1;
@ -4206,6 +4270,7 @@ raop_playback_start(uint64_t next_pkt, struct timespec *ts)
struct raop_session *rs;
event_del(flush_timer);
evtimer_add(keep_alive_timer, &keep_alive_tv);
sync_counter = 0;
@ -4225,6 +4290,8 @@ raop_playback_stop(void)
struct raop_session *rs;
int ret;
evtimer_del(keep_alive_timer);
for (rs = sessions; rs; rs = rs->next)
{
ret = raop_send_req_teardown(rs, raop_cb_shutdown_teardown);
@ -4331,9 +4398,10 @@ raop_init(void)
*ptr = '\0';
flush_timer = evtimer_new(evbase_player, raop_flush_timer_cb, NULL);
if (!flush_timer)
keep_alive_timer = evtimer_new(evbase_player, raop_keep_alive_timer_cb, NULL);
if (!flush_timer || !keep_alive_timer)
{
DPRINTF(E_LOG, L_RAOP, "Out of memory for flush timer\n");
DPRINTF(E_LOG, L_RAOP, "Out of memory for flush timer or keep alive timer\n");
goto out_free_b64_iv;
}
@ -4345,13 +4413,13 @@ raop_init(void)
{
DPRINTF(E_LOG, L_RAOP, "AirPlay time synchronization failed to start\n");
goto out_free_flush_timer;
goto out_free_timers;
}
ret = raop_v2_control_start(v6enabled);
if (ret < 0)
{
DPRINTF(E_LOG, L_RAOP, "AirPlay playback synchronization failed to start\n");
DPRINTF(E_LOG, L_RAOP, "AirPlay playback control failed to start\n");
goto out_stop_timing;
}
@ -4379,8 +4447,9 @@ raop_init(void)
raop_v2_control_stop();
out_stop_timing:
raop_v2_timing_stop();
out_free_flush_timer:
out_free_timers:
event_free(flush_timer);
event_free(keep_alive_timer);
out_free_b64_iv:
free(raop_aes_iv_b64);
out_free_b64_key:
@ -4407,6 +4476,7 @@ raop_deinit(void)
raop_v2_timing_stop();
event_free(flush_timer);
event_free(keep_alive_timer);
gcry_cipher_close(raop_aes_ctx);