diff options
author | Nanang Izzuddin <nanang@teluu.com> | 2009-06-12 17:37:13 +0000 |
---|---|---|
committer | Nanang Izzuddin <nanang@teluu.com> | 2009-06-12 17:37:13 +0000 |
commit | cd141ad3cd391ee66090e89d04d7c466472fdb7f (patch) | |
tree | a0fe7112f55ad149adf11c67202969c33071d959 /pjmedia | |
parent | 68caf8c9c8cba8263e1ac0001e361c2fd5f21edf (diff) |
Ticket #883: Added user defined NAT hole-punching and keep-alive mechanism to media stream.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2759 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r-- | pjmedia/include/pjmedia/config.h | 62 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/stream.c | 77 |
2 files changed, 139 insertions, 0 deletions
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h index 9a3eea9b..7cf3652a 100644 --- a/pjmedia/include/pjmedia/config.h +++ b/pjmedia/include/pjmedia/config.h @@ -696,6 +696,68 @@ #endif +/** + * Value to be specified in PJMEDIA_STREAM_ENABLE_KA setting. + * This indicates that an empty RTP packet should be used as + * the keep-alive packet. + */ +#define PJMEDIA_STREAM_KA_EMPTY_RTP 1 + +/** + * Value to be specified in PJMEDIA_STREAM_ENABLE_KA setting. + * This indicates that a user defined packet should be used + * as the keep-alive packet. The content of the user-defined + * packet is specified by PJMEDIA_STREAM_KA_USER_PKT. Default + * content is a CR-LF packet. + */ +#define PJMEDIA_STREAM_KA_USER 2 + +/** + * The content of the user defined keep-alive packet. The format + * of the packet is initializer to pj_str_t structure. Note that + * the content may contain NULL character. + */ +#ifndef PJMEDIA_STREAM_KA_USER_PKT +# define PJMEDIA_STREAM_KA_USER_PKT { "\r\n", 2 } +#endif + +/** + * Specify another type of keep-alive and NAT hole punching + * mechanism (the other type is PJMEDIA_STREAM_VAD_SUSPEND_MSEC + * and PJMEDIA_CODEC_MAX_SILENCE_PERIOD) to be used by stream. + * When this feature is enabled, the stream will initially + * transmit one packet to punch a hole in NAT, and periodically + * transmit keep-alive packets. + * + * When this alternative keep-alive mechanism is used, application + * may disable the other keep-alive mechanisms, i.e: by setting + * PJMEDIA_STREAM_VAD_SUSPEND_MSEC to zero and + * PJMEDIA_CODEC_MAX_SILENCE_PERIOD to -1. + * + * The value of this macro specifies the type of packet used + * for the keep-alive mechanism. Valid values are + * PJMEDIA_STREAM_KA_EMPTY_RTP and PJMEDIA_STREAM_KA_USER. + * + * The duration of the keep-alive interval further can be set + * with PJMEDIA_STREAM_KA_INTERVAL setting. + * + * Default: 0 (disabled) + */ +#ifndef PJMEDIA_STREAM_ENABLE_KA +# define PJMEDIA_STREAM_ENABLE_KA 0 +#endif + + +/** + * Specify the keep-alive interval of PJMEDIA_STREAM_ENABLE_KA + * mechanism, in seconds. + * + * Default: 5 seconds + */ +#ifndef PJMEDIA_STREAM_KA_INTERVAL +# define PJMEDIA_STREAM_KA_INTERVAL 5 +#endif + /** * @} diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c index a52d56ac..9b6d245a 100644 --- a/pjmedia/src/pjmedia/stream.c +++ b/pjmedia/src/pjmedia/stream.c @@ -168,6 +168,11 @@ struct pjmedia_stream unsigned rtcp_xr_dest_len; /**< Length of RTCP XR dest address */ #endif + +#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 + pj_timestamp last_frm_ts_sent; /**< Timestamp of last sending + packet */ +#endif }; @@ -192,6 +197,49 @@ static void stream_perror(const char *sender, const char *title, PJ_LOG(4,(sender, "%s: %s [err:%d]", title, errmsg, status)); } +/* + * Send keep-alive packet. + */ +static void send_keep_alive_packet(pjmedia_stream *stream) +{ +#if defined(PJMEDIA_STREAM_ENABLE_KA) && \ + PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_EMPTY_RTP + + /* Keep-alive packet is empty RTP */ + pj_status_t status; + int pkt_len; + + + status = pjmedia_rtp_encode_rtp( &stream->enc->rtp, + stream->enc->pt, 1, + 1, + 0, + (const void**)stream->enc->out_pkt, + &pkt_len); + pj_assert(status == PJ_SUCCESS); + pjmedia_transport_send_rtp(stream->transport, stream->enc->out_pkt, + pkt_len); + TRC_((stream->port.info.name.ptr, "Keep-alive sent (empty RTP)")); + +#elif defined(PJMEDIA_STREAM_ENABLE_KA) && \ + PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_USER + + /* Keep-alive packet is defined in PJMEDIA_STREAM_KA_USER_PKT */ + int pkt_len; + const pj_str_t str_ka = PJMEDIA_STREAM_KA_USER_PKT; + + pj_memcpy(stream->enc->out_pkt, str_ka.ptr, str_ka.slen); + pkt_len = str_ka.slen; + pjmedia_transport_send_rtp(stream->transport, stream->enc->out_pkt, + pkt_len); + TRC_((stream->port.info.name.ptr, "Keep-alive sent")); + +#else + + PJ_UNUSED_ARG(stream); + +#endif +} /* * play_callback() @@ -787,6 +835,25 @@ static pj_status_t put_frame_imp( pjmedia_port *port, int rtphdrlen; int inc_timestamp = 0; + +#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0 + /* If the interval since last sending packet is greater than + * PJMEDIA_STREAM_KA_INTERVAL, send keep-alive packet. + */ + { + pj_uint32_t dtx_duration; + + dtx_duration = pj_timestamp_diff32(&stream->last_frm_ts_sent, + &frame->timestamp); + if (dtx_duration > + PJMEDIA_STREAM_KA_INTERVAL * stream->port.info.clock_rate) + { + send_keep_alive_packet(stream); + stream->last_frm_ts_sent = frame->timestamp; + } + } +#endif + /* Don't do anything if stream is paused */ if (channel->paused) { stream->enc_buf_pos = stream->enc_buf_count = 0; @@ -990,6 +1057,11 @@ static pj_status_t put_frame_imp( pjmedia_port *port, stream->rtcp.stat.rtp_tx_last_ts = pj_ntohl(stream->enc->rtp.out_hdr.ts); stream->rtcp.stat.rtp_tx_last_seq = pj_ntohs(stream->enc->rtp.out_hdr.seq); +#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 + /* Update timestamp of last sending packet. */ + stream->last_frm_ts_sent = frame->timestamp; +#endif + return PJ_SUCCESS; } @@ -1910,6 +1982,11 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt, stream->enc->out_pkt, len); } +#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 + /* NAT hole punching by sending KA packet via RTP transport. */ + send_keep_alive_packet(stream); +#endif + /* Success! */ *p_stream = stream; |