[FFmpeg-devel] [PATCH] rtsp.c: keep-alive

Ronald S. Bultje rsbultje
Fri Mar 6 17:59:29 CET 2009


Hi,

attached patch adds dummy requests to the RTSP demuxer to keep TCP
connections (and UDP connections created through it) alive while
streaming data. Without this, some servers will auto-timeout after a
specified amount of time, assuming the client died (or so). Tested
with Real servers, they timeout without this patch (my example stream
after 80 seconds), and work fine for at least 10 minutes after this
patch. I'll test WMS servers after that stuff is committed to SVN.

Ronald

PS the file extension is .txt because otherwise GMail thinks it's a
binary (hi Luca!)...
-------------- next part --------------
Index: ffmpeg-svn/libavformat/rtsp.c
===================================================================
--- ffmpeg-svn.orig/libavformat/rtsp.c	2009-03-05 22:24:37.000000000 -0500
+++ ffmpeg-svn/libavformat/rtsp.c	2009-03-06 11:54:48.000000000 -0500
@@ -686,7 +686,12 @@
     /* NOTE: we do case independent match for broken servers */
     p = buf;
     if (av_stristart(p, "Session:", &p)) {
+        int t;
         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)) {
         reply->content_length = strtol(p, NULL, 10);
     } else if (av_stristart(p, "Transport:", &p)) {
@@ -855,7 +857,7 @@
     return 0;
 }
 
-static void rtsp_send_cmd(AVFormatContext *s,
+static void rtsp_send_cmd_async (AVFormatContext *s,
                           const char *cmd, RTSPMessageHeader *reply,
                           unsigned char **content_ptr)
 {
@@ -875,6 +877,14 @@
     printf("Sending:\n%s--\n", buf);
 #endif
     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);
 }
@@ -952,6 +962,9 @@
     else
         trans_pref = "RTP/AVP";
 
+    /* default timeout: 1 minute */
+    rt->timeout = 60;
+
     /* for each stream, make the setup request */
     /* XXX: we assume the same server is used for the control of each
        RTSP stream */
@@ -1137,6 +1151,9 @@
             goto fail;
     }
 
+    if (reply->timeout > 0)
+        rt->timeout = reply->timeout;
+
     if (rt->server_type == RTSP_SERVER_REAL)
         rt->need_subscription = 1;
 
@@ -1419,10 +1436,10 @@
     RTSPStream *rtsp_st;
     int ret, len;
     uint8_t buf[10 * RTP_MAX_PACKET_LENGTH];
+    RTSPMessageHeader reply1, *reply = &reply1;
 
     if (rt->server_type == RTSP_SERVER_REAL) {
         int i;
-        RTSPMessageHeader reply1, *reply = &reply1;
         enum AVDiscard cache[MAX_STREAMS];
         char cmd[1024];
 
@@ -1526,6 +1543,12 @@
         /* more packets may follow, so we save the RTP context */
         rt->cur_transport_priv = rtsp_st->transport_priv;
     }
+
+    /* send dummy request to keep TCP connection alive */
+    if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) {
+        rtsp_send_cmd_async(s, "OPTIONS * RTSP/1.0\r\n", reply, NULL);
+    }
+
     return 0;
 }
 
Index: ffmpeg-svn/libavformat/rtsp.h
===================================================================
--- ffmpeg-svn.orig/libavformat/rtsp.h	2009-03-06 09:58:50.000000000 -0500
+++ ffmpeg-svn/libavformat/rtsp.h	2009-03-06 10:12:41.000000000 -0500
@@ -137,6 +137,14 @@
      * http://tools.ietf.org/html/draft-stiemerling-rtsp-announce-00
      * for a complete list of supported values. */
     int notice;
+
+    /** 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;
 
 /**
@@ -195,6 +203,16 @@
      * identifier that the client should re-transmit in each RTSP command */
     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 */
     enum RTSPTransport transport;
 



More information about the ffmpeg-devel mailing list