When using RTP-over-UDP, send dummy packets during stream setup, similar to
authorMartin Storsjö <martin@martin.st>
Tue, 16 Feb 2010 22:50:50 +0000 (22:50 +0000)
committerRonald S. Bultje <rsbultje@gmail.com>
Tue, 16 Feb 2010 22:50:50 +0000 (22:50 +0000)
what e.g. RealPlayer does. This allows proper port forwarding setup in NAT-
based environments.

Patch by Martin Storsjö <$firstname at $firstname dot st>.

Originally committed as revision 21856 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/rtpdec.c
libavformat/rtpdec.h
libavformat/rtsp.c

index 80b576c28a2c0fd920847486388c176c2af96f06..dfc5b0b482844cbf947fc376f64c9a76490cf34f 100644 (file)
@@ -273,6 +273,45 @@ int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count)
     return 0;
 }
 
+void rtp_send_punch_packets(URLContext* rtp_handle)
+{
+    ByteIOContext *pb;
+    uint8_t *buf;
+    int len;
+
+    /* Send a small RTP packet */
+    if (url_open_dyn_buf(&pb) < 0)
+        return;
+
+    put_byte(pb, (RTP_VERSION << 6));
+    put_byte(pb, 0); /* Payload type */
+    put_be16(pb, 0); /* Seq */
+    put_be32(pb, 0); /* Timestamp */
+    put_be32(pb, 0); /* SSRC */
+
+    put_flush_packet(pb);
+    len = url_close_dyn_buf(pb, &buf);
+    if ((len > 0) && buf)
+        url_write(rtp_handle, buf, len);
+    av_free(buf);
+
+    /* Send a minimal RTCP RR */
+    if (url_open_dyn_buf(&pb) < 0)
+        return;
+
+    put_byte(pb, (RTP_VERSION << 6));
+    put_byte(pb, 201); /* receiver report */
+    put_be16(pb, 1); /* length in words - 1 */
+    put_be32(pb, 0); /* our own SSRC */
+
+    put_flush_packet(pb);
+    len = url_close_dyn_buf(pb, &buf);
+    if ((len > 0) && buf)
+        url_write(rtp_handle, buf, len);
+    av_free(buf);
+}
+
+
 /**
  * open a new RTP parse context for stream 'st'. 'st' can be NULL for
  * MPEG2TS streams to indicate that they should be demuxed inside the
index 1a243f89c853147f44381e34f78390fd7aae8c84..92d519684fd35f3ed61adedbb9f1556cbd5cbbb1 100644 (file)
@@ -73,6 +73,19 @@ int rtp_set_remote_url(URLContext *h, const char *uri);
 void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd);
 #endif
 
+/**
+ * Send a dummy packet on both port pairs to set up the connection
+ * state in potential NAT routers, so that we're able to receive
+ * packets.
+ *
+ * Note, this only works if the NAT router doesn't remap ports. This
+ * isn't a standardized procedure, but it works in many cases in practice.
+ *
+ * The same routine is used with RDT too, even if RDT doesn't use normal
+ * RTP packets otherwise.
+ */
+void rtp_send_punch_packets(URLContext* rtp_handle);
+
 /**
  * some rtp servers assume client is dead if they don't hear from them...
  * so we send a Receiver Report to the provided ByteIO context
index 8bc940dd926a41b93d775095c125fcd4968bcce5..f379b781b0db8a0264b1025aa88a063650377e13 100644 (file)
@@ -1146,6 +1146,12 @@ static int make_setup_request(AVFormatContext *s, const char *host, int port,
                 err = AVERROR_INVALIDDATA;
                 goto fail;
             }
+            /* Try to initialize the connection state in a
+             * potential NAT router by sending dummy packets.
+             * RTP/RTCP dummy packets are used for RDT, too.
+             */
+            if (!(rt->server_type == RTSP_SERVER_WMS && i > 1))
+                rtp_send_punch_packets(rtsp_st->rtp_handle);
             break;
         }
         case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: {