From 9c8fa20d7e60760f117c2123a51137db1ac91682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Tue, 16 Feb 2010 22:50:50 +0000 Subject: [PATCH] When using RTP-over-UDP, send dummy packets during stream setup, similar to what e.g. RealPlayer does. This allows proper port forwarding setup in NAT- based environments. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch by Martin Storsjö <$firstname at $firstname dot st>. Originally committed as revision 21856 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/rtpdec.c | 39 +++++++++++++++++++++++++++++++++++++++ libavformat/rtpdec.h | 13 +++++++++++++ libavformat/rtsp.c | 6 ++++++ 3 files changed, 58 insertions(+) diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index 80b576c28a..dfc5b0b482 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -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 diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h index 1a243f89c8..92d519684f 100644 --- a/libavformat/rtpdec.h +++ b/libavformat/rtpdec.h @@ -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 diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 8bc940dd92..f379b781b0 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -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: {