Commit f1b4abc8 authored by rbultje's avatar rbultje

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.

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



git-svn-id: file:///var/local/repositories/ffmpeg/trunk@21856 9553f0bf-9b14-0410-a0b8-cfaf0461ba5b
parent ef737235
...@@ -273,6 +273,45 @@ int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count) ...@@ -273,6 +273,45 @@ int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count)
return 0; 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 * 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 * MPEG2TS streams to indicate that they should be demuxed inside the
......
...@@ -73,6 +73,19 @@ int rtp_set_remote_url(URLContext *h, const char *uri); ...@@ -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); void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd);
#endif #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... * 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 * so we send a Receiver Report to the provided ByteIO context
......
...@@ -1146,6 +1146,12 @@ static int make_setup_request(AVFormatContext *s, const char *host, int port, ...@@ -1146,6 +1146,12 @@ static int make_setup_request(AVFormatContext *s, const char *host, int port,
err = AVERROR_INVALIDDATA; err = AVERROR_INVALIDDATA;
goto fail; 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; break;
} }
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: { case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment