summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2009-06-12 17:37:13 +0000
committerNanang Izzuddin <nanang@teluu.com>2009-06-12 17:37:13 +0000
commitcd141ad3cd391ee66090e89d04d7c466472fdb7f (patch)
treea0fe7112f55ad149adf11c67202969c33071d959 /pjmedia
parent68caf8c9c8cba8263e1ac0001e361c2fd5f21edf (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.h62
-rw-r--r--pjmedia/src/pjmedia/stream.c77
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;