mirror of https://git.ffmpeg.org/ffmpeg.git
Send dummy requests over the TCP connection (WMS wants GET_PARAMETER,
Real wants OPTIONS) while the connection is idle, otherwise it will be aborted after a short period (usually a minute). See the thread "[PATCH] rtsp.c: keep-alive" on the mailinglist. Originally committed as revision 18525 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
888505df22
commit
30e79845b4
|
@ -682,7 +682,12 @@ void rtsp_parse_line(RTSPMessageHeader *reply, const char *buf)
|
||||||
/* NOTE: we do case independent match for broken servers */
|
/* NOTE: we do case independent match for broken servers */
|
||||||
p = buf;
|
p = buf;
|
||||||
if (av_stristart(p, "Session:", &p)) {
|
if (av_stristart(p, "Session:", &p)) {
|
||||||
|
int t;
|
||||||
get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p);
|
get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p);
|
||||||
|
if (av_stristart(p, ";timeout=", &p) &&
|
||||||
|
(t = strtol(p, NULL, 10)) > 0) {
|
||||||
|
reply->timeout = t;
|
||||||
|
}
|
||||||
} else if (av_stristart(p, "Content-Length:", &p)) {
|
} else if (av_stristart(p, "Content-Length:", &p)) {
|
||||||
reply->content_length = strtol(p, NULL, 10);
|
reply->content_length = strtol(p, NULL, 10);
|
||||||
} else if (av_stristart(p, "Transport:", &p)) {
|
} else if (av_stristart(p, "Transport:", &p)) {
|
||||||
|
@ -837,7 +842,7 @@ rtsp_read_reply (AVFormatContext *s, RTSPMessageHeader *reply,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtsp_send_cmd(AVFormatContext *s,
|
static void rtsp_send_cmd_async (AVFormatContext *s,
|
||||||
const char *cmd, RTSPMessageHeader *reply,
|
const char *cmd, RTSPMessageHeader *reply,
|
||||||
unsigned char **content_ptr)
|
unsigned char **content_ptr)
|
||||||
{
|
{
|
||||||
|
@ -857,6 +862,14 @@ static void rtsp_send_cmd(AVFormatContext *s,
|
||||||
printf("Sending:\n%s--\n", buf);
|
printf("Sending:\n%s--\n", buf);
|
||||||
#endif
|
#endif
|
||||||
url_write(rt->rtsp_hd, buf, strlen(buf));
|
url_write(rt->rtsp_hd, buf, strlen(buf));
|
||||||
|
rt->last_cmd_time = av_gettime();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtsp_send_cmd (AVFormatContext *s,
|
||||||
|
const char *cmd, RTSPMessageHeader *reply,
|
||||||
|
unsigned char **content_ptr)
|
||||||
|
{
|
||||||
|
rtsp_send_cmd_async(s, cmd, reply, content_ptr);
|
||||||
|
|
||||||
rtsp_read_reply(s, reply, content_ptr, 0);
|
rtsp_read_reply(s, reply, content_ptr, 0);
|
||||||
}
|
}
|
||||||
|
@ -943,6 +956,9 @@ make_setup_request (AVFormatContext *s, const char *host, int port,
|
||||||
else
|
else
|
||||||
trans_pref = "RTP/AVP";
|
trans_pref = "RTP/AVP";
|
||||||
|
|
||||||
|
/* default timeout: 1 minute */
|
||||||
|
rt->timeout = 60;
|
||||||
|
|
||||||
/* for each stream, make the setup request */
|
/* for each stream, make the setup request */
|
||||||
/* XXX: we assume the same server is used for the control of each
|
/* XXX: we assume the same server is used for the control of each
|
||||||
RTSP stream */
|
RTSP stream */
|
||||||
|
@ -1123,6 +1139,9 @@ make_setup_request (AVFormatContext *s, const char *host, int port,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reply->timeout > 0)
|
||||||
|
rt->timeout = reply->timeout;
|
||||||
|
|
||||||
if (rt->server_type == RTSP_SERVER_REAL)
|
if (rt->server_type == RTSP_SERVER_REAL)
|
||||||
rt->need_subscription = 1;
|
rt->need_subscription = 1;
|
||||||
|
|
||||||
|
@ -1403,12 +1422,12 @@ static int rtsp_read_packet(AVFormatContext *s,
|
||||||
RTSPStream *rtsp_st;
|
RTSPStream *rtsp_st;
|
||||||
int ret, len;
|
int ret, len;
|
||||||
uint8_t buf[10 * RTP_MAX_PACKET_LENGTH];
|
uint8_t buf[10 * RTP_MAX_PACKET_LENGTH];
|
||||||
|
RTSPMessageHeader reply1, *reply = &reply1;
|
||||||
|
char cmd[1024];
|
||||||
|
|
||||||
if (rt->server_type == RTSP_SERVER_REAL) {
|
if (rt->server_type == RTSP_SERVER_REAL) {
|
||||||
int i;
|
int i;
|
||||||
RTSPMessageHeader reply1, *reply = &reply1;
|
|
||||||
enum AVDiscard cache[MAX_STREAMS];
|
enum AVDiscard cache[MAX_STREAMS];
|
||||||
char cmd[1024];
|
|
||||||
|
|
||||||
for (i = 0; i < s->nb_streams; i++)
|
for (i = 0; i < s->nb_streams; i++)
|
||||||
cache[i] = s->streams[i]->discard;
|
cache[i] = s->streams[i]->discard;
|
||||||
|
@ -1508,6 +1527,22 @@ static int rtsp_read_packet(AVFormatContext *s,
|
||||||
/* more packets may follow, so we save the RTP context */
|
/* more packets may follow, so we save the RTP context */
|
||||||
rt->cur_transport_priv = rtsp_st->transport_priv;
|
rt->cur_transport_priv = rtsp_st->transport_priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* send dummy request to keep TCP connection alive */
|
||||||
|
if ((rt->server_type == RTSP_SERVER_WMS ||
|
||||||
|
rt->server_type == RTSP_SERVER_REAL) &&
|
||||||
|
(av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) {
|
||||||
|
if (rt->server_type == RTSP_SERVER_WMS) {
|
||||||
|
snprintf(cmd, sizeof(cmd) - 1,
|
||||||
|
"GET_PARAMETER %s RTSP/1.0\r\n",
|
||||||
|
s->filename);
|
||||||
|
rtsp_send_cmd_async(s, cmd, reply, NULL);
|
||||||
|
} else {
|
||||||
|
rtsp_send_cmd_async(s, "OPTIONS * RTSP/1.0\r\n",
|
||||||
|
reply, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,14 @@ typedef struct RTSPMessageHeader {
|
||||||
* (RealServer compatible)" or "RealServer Version v.e.r.sion (platform)",
|
* (RealServer compatible)" or "RealServer Version v.e.r.sion (platform)",
|
||||||
* where platform is the output of $uname -msr | sed 's/ /-/g'. */
|
* where platform is the output of $uname -msr | sed 's/ /-/g'. */
|
||||||
char server[64];
|
char server[64];
|
||||||
|
|
||||||
|
/** The "timeout" comes as part of the server response to the "SETUP"
|
||||||
|
* command, in the "Session: <xyz>[;timeout=<value>]" line. It is the
|
||||||
|
* time, in seconds, that the server will go without traffic over the
|
||||||
|
* RTSP/TCP connection before it closes the connection. To prevent
|
||||||
|
* this, sent dummy requests (e.g. OPTIONS) with intervals smaller
|
||||||
|
* than this value. */
|
||||||
|
int timeout;
|
||||||
} RTSPMessageHeader;
|
} RTSPMessageHeader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -192,6 +200,16 @@ typedef struct RTSPState {
|
||||||
* identifier that the client should re-transmit in each RTSP command */
|
* identifier that the client should re-transmit in each RTSP command */
|
||||||
char session_id[512];
|
char session_id[512];
|
||||||
|
|
||||||
|
/** copy of RTSPMessageHeader->timeout, i.e. the time (in seconds) that
|
||||||
|
* the server will go without traffic on the RTSP/TCP line before it
|
||||||
|
* closes the connection. */
|
||||||
|
int timeout;
|
||||||
|
|
||||||
|
/** timestamp of the last RTSP command that we sent to the RTSP server.
|
||||||
|
* This is used to calculate when to send dummy commands to keep the
|
||||||
|
* connection alive, in conjunction with \p timeout. */
|
||||||
|
int64_t last_cmd_time;
|
||||||
|
|
||||||
/** the negotiated data/packet transport protocol; e.g. RTP or RDT */
|
/** the negotiated data/packet transport protocol; e.g. RTP or RDT */
|
||||||
enum RTSPTransport transport;
|
enum RTSPTransport transport;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue