summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2008-06-14 16:52:04 +0000
committerBenny Prijono <bennylp@teluu.com>2008-06-14 16:52:04 +0000
commite90196a46553e346d1dafeab1b1239b6f40ccd70 (patch)
tree3b33c83286b54c44aa759f3829229987bf464c77 /pjmedia
parent5a7fe8a7f6e92869075baea0384059cc46816cde (diff)
Implement ticket #546 and revisit ticket #439:
- ticket #546 implements RTCP SDES and CNAME - re-enable periodic RTP TX which was disabled by #439 - fixed bug in RTCP TX interval - changed PJMEDIA_CODEC_MAX_SILENCE_PERIOD value from ts to msec git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2020 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/include/pjmedia/config.h6
-rw-r--r--pjmedia/src/pjmedia-codec/g722.c2
-rw-r--r--pjmedia/src/pjmedia-codec/gsm.c2
-rw-r--r--pjmedia/src/pjmedia-codec/ilbc.c2
-rw-r--r--pjmedia/src/pjmedia/g711.c2
-rw-r--r--pjmedia/src/pjmedia/stream.c176
6 files changed, 177 insertions, 13 deletions
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h
index 5eebe4cb..340d4584 100644
--- a/pjmedia/include/pjmedia/config.h
+++ b/pjmedia/include/pjmedia/config.h
@@ -394,7 +394,7 @@
/**
- * Specify the maximum duration of silence period in the codec.
+ * Specify the maximum duration of silence period in the codec, in msec.
* This is useful for example to keep NAT binding open in the firewall
* and to prevent server from disconnecting the call because no
* RTP packet is received.
@@ -405,11 +405,11 @@
*
* Use (-1) to disable this feature.
*
- * Default: 8000 (one second on 8KHz).
+ * Default: 500 ms
*
*/
#ifndef PJMEDIA_CODEC_MAX_SILENCE_PERIOD
-# define PJMEDIA_CODEC_MAX_SILENCE_PERIOD 8000
+# define PJMEDIA_CODEC_MAX_SILENCE_PERIOD 500
#endif
diff --git a/pjmedia/src/pjmedia-codec/g722.c b/pjmedia/src/pjmedia-codec/g722.c
index cc1afa1f..38eceaca 100644
--- a/pjmedia/src/pjmedia-codec/g722.c
+++ b/pjmedia/src/pjmedia-codec/g722.c
@@ -552,7 +552,7 @@ static pj_status_t g722_codec_encode(pjmedia_codec *codec,
NULL);
if (is_silence &&
PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
- silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD)
+ silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*16000/1000)
{
output->type = PJMEDIA_FRAME_TYPE_NONE;
output->buf = NULL;
diff --git a/pjmedia/src/pjmedia-codec/gsm.c b/pjmedia/src/pjmedia-codec/gsm.c
index 7bb4d729..b4c98db8 100644
--- a/pjmedia/src/pjmedia-codec/gsm.c
+++ b/pjmedia/src/pjmedia-codec/gsm.c
@@ -542,7 +542,7 @@ static pj_status_t gsm_codec_encode( pjmedia_codec *codec,
NULL);
if (is_silence &&
PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
- silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD)
+ silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000)
{
output->type = PJMEDIA_FRAME_TYPE_NONE;
output->buf = NULL;
diff --git a/pjmedia/src/pjmedia-codec/ilbc.c b/pjmedia/src/pjmedia-codec/ilbc.c
index e14647ec..92b78310 100644
--- a/pjmedia/src/pjmedia-codec/ilbc.c
+++ b/pjmedia/src/pjmedia-codec/ilbc.c
@@ -539,7 +539,7 @@ static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
NULL);
if (is_silence &&
PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
- silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD)
+ silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000)
{
output->type = PJMEDIA_FRAME_TYPE_NONE;
output->buf = NULL;
diff --git a/pjmedia/src/pjmedia/g711.c b/pjmedia/src/pjmedia/g711.c
index b5ce69a8..e200b689 100644
--- a/pjmedia/src/pjmedia/g711.c
+++ b/pjmedia/src/pjmedia/g711.c
@@ -502,7 +502,7 @@ static pj_status_t g711_encode(pjmedia_codec *codec,
(input->size >> 1), NULL);
if (is_silence &&
PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
- silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD)
+ silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000)
{
output->type = PJMEDIA_FRAME_TYPE_NONE;
output->buf = NULL;
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index 28702f45..3e4be105 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -83,6 +83,7 @@ struct pjmedia_stream
pjmedia_dir dir; /**< Stream direction. */
void *user_data; /**< User data. */
+ pj_str_t cname; /**< SDES CNAME */
pjmedia_transport *transport; /**< Stream transport. */
@@ -115,6 +116,7 @@ struct pjmedia_stream
pj_uint32_t rtcp_last_tx; /**< RTCP tx time in timestamp */
pj_uint32_t rtcp_interval; /**< Interval, in timestamp. */
+ pj_bool_t initial_rr; /**< Initial RTCP RR sent */
/* RFC 2833 DTMF transmission queue: */
int tx_event_pt; /**< Outgoing pt for dtmf. */
@@ -176,6 +178,9 @@ static const char digitmap[16] = { '0', '1', '2', '3',
'8', '9', '*', '#',
'A', 'B', 'C', 'D'};
+/* Zero audio frame samples */
+static pj_int16_t zero_frame[30 * 16000 / 1000];
+
/*
* Print error.
*/
@@ -534,6 +539,68 @@ static void check_tx_rtcp(pjmedia_stream *stream, pj_uint32_t timestamp)
#endif
}
+/* Build RTCP SDES packet */
+static unsigned create_rtcp_sdes(pjmedia_stream *stream, pj_uint8_t *pkt,
+ unsigned max_len)
+{
+ pjmedia_rtcp_common hdr;
+ pj_uint8_t *p = pkt;
+
+ /* SDES header */
+ hdr.version = 2;
+ hdr.p = 0;
+ hdr.count = 1;
+ hdr.pt = 202;
+ hdr.length = 2 + (4+stream->cname.slen+3)/4 - 1;
+ if (max_len < (hdr.length << 2)) {
+ pj_assert(!"Not enough buffer for SDES packet");
+ return 0;
+ }
+ hdr.length = pj_htons((pj_uint16_t)hdr.length);
+ hdr.ssrc = stream->enc->rtp.out_hdr.ssrc;
+ pj_memcpy(p, &hdr, sizeof(hdr));
+ p += sizeof(hdr);
+
+ /* CNAME item */
+ *p++ = 1;
+ *p++ = (pj_uint8_t)stream->cname.slen;
+ pj_memcpy(p, stream->cname.ptr, stream->cname.slen);
+ p += stream->cname.slen;
+
+ /* END */
+ *p++ = '\0';
+ *p++ = '\0';
+
+ /* Pad to 32bit */
+ while ((p-pkt) % 4)
+ *p++ = '\0';
+
+ return (p - pkt);
+}
+
+/* Build RTCP BYE packet */
+static unsigned create_rtcp_bye(pjmedia_stream *stream, pj_uint8_t *pkt,
+ unsigned max_len)
+{
+ pjmedia_rtcp_common hdr;
+
+ /* BYE header */
+ hdr.version = 2;
+ hdr.p = 0;
+ hdr.count = 1;
+ hdr.pt = 203;
+ hdr.length = 1;
+ if (max_len < (hdr.length << 2)) {
+ pj_assert(!"Not enough buffer for SDES packet");
+ return 0;
+ }
+ hdr.length = pj_htons((pj_uint16_t)hdr.length);
+ hdr.ssrc = stream->enc->rtp.out_hdr.ssrc;
+ pj_memcpy(pkt, &hdr, sizeof(hdr));
+
+ return sizeof(hdr);
+}
+
/**
* Rebuffer the frame when encoder and decoder has different ptime
@@ -673,9 +740,53 @@ static pj_status_t put_frame_imp( pjmedia_port *port,
inc_timestamp = PJMEDIA_DTMF_DURATION - rtp_ts_len;
}
- /* No need to encode if this is a zero frame.
- * See http://www.pjsip.org/trac/ticket/439
- */
+
+ /*
+ * Special treatment for FRAME_TYPE_AUDIO but with frame->buf==NULL.
+ * This happens when stream input is disconnected from the bridge.
+ * In this case we periodically transmit RTP frame to keep NAT binding
+ * open, by giving zero PCM frame to the codec.
+ *
+ * This was originally done in http://trac.pjsip.org/repos/ticket/56,
+ * but then disabled in http://trac.pjsip.org/repos/ticket/439, but
+ * now it's enabled again.
+ */
+ } else if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO &&
+ frame->buf == NULL &&
+ (stream->dir & PJMEDIA_DIR_ENCODING) &&
+ stream->codec_param.info.frm_ptime *
+ stream->codec_param.info.clock_rate/1000 <
+ PJ_ARRAY_SIZE(zero_frame))
+ {
+ pjmedia_frame silence_frame;
+
+ pj_bzero(&silence_frame, sizeof(silence_frame));
+ silence_frame.buf = zero_frame;
+ silence_frame.size = stream->codec_param.info.frm_ptime * 2 *
+ stream->codec_param.info.clock_rate / 1000;
+ silence_frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+ silence_frame.timestamp.u32.lo = pj_ntohl(stream->enc->rtp.out_hdr.ts);
+
+ /* Encode! */
+ status = stream->codec->op->encode( stream->codec, &silence_frame,
+ channel->out_pkt_size -
+ sizeof(pjmedia_rtp_hdr),
+ &frame_out);
+ if (status != PJ_SUCCESS) {
+ LOGERR_((stream->port.info.name.ptr,
+ "Codec encode() error", status));
+ return status;
+ }
+
+ /* Encapsulate. */
+ status = pjmedia_rtp_encode_rtp( &channel->rtp,
+ channel->pt, 0,
+ frame_out.size, rtp_ts_len,
+ (const void**)&rtphdr,
+ &rtphdrlen);
+
+
+ /* Encode audio frame */
} else if (frame->type != PJMEDIA_FRAME_TYPE_NONE &&
frame->buf != NULL)
{
@@ -696,6 +807,7 @@ static pj_status_t put_frame_imp( pjmedia_port *port,
frame_out.size, rtp_ts_len,
(const void**)&rtphdr,
&rtphdrlen);
+
} else {
/* Just update RTP session's timestamp. */
@@ -1204,6 +1316,31 @@ on_return:
pjmedia_rtcp_rx_rtp2(&stream->rtcp, pj_ntohs(hdr->seq),
pj_ntohl(hdr->ts), payloadlen, pkt_discarded);
+
+ /* Send RTCP RR and SDES after we receive some RTP packets */
+ if (stream->rtcp.received >= 10 && !stream->initial_rr) {
+ void *sr_rr_pkt;
+ pj_uint8_t *pkt;
+ int len;
+
+ /* Build RR or SR */
+ pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len);
+ pkt = (pj_uint8_t*) stream->enc->out_pkt;
+ pj_memcpy(pkt, sr_rr_pkt, len);
+ pkt += len;
+
+ /* Append SDES */
+ len = create_rtcp_sdes(stream, (pj_uint8_t*)pkt,
+ stream->enc->out_pkt_size - len);
+ if (len > 0) {
+ pkt += len;
+ len = ((pj_uint8_t*)pkt) - ((pj_uint8_t*)stream->enc->out_pkt);
+ pjmedia_transport_send_rtcp(stream->transport,
+ stream->enc->out_pkt, len);
+ }
+
+ stream->initial_rr = PJ_TRUE;
+ }
}
@@ -1301,7 +1438,8 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
enum { M = 32 };
pjmedia_stream *stream;
pj_str_t name;
- unsigned jb_init, jb_max, jb_min_pre, jb_max_pre;
+ unsigned jb_init, jb_max, jb_min_pre, jb_max_pre, len;
+ char *p;
pj_status_t status;
PJ_ASSERT_RETURN(pool && info && p_stream, PJ_EINVAL);
@@ -1339,13 +1477,23 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
stream->codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
stream->dir = info->dir;
stream->user_data = user_data;
- stream->rtcp_interval = (PJMEDIA_RTCP_INTERVAL + (pj_rand() % 8000)) *
+ stream->rtcp_interval = (PJMEDIA_RTCP_INTERVAL-500 + (pj_rand()%1000)) *
info->fmt.clock_rate / 1000;
stream->tx_event_pt = info->tx_event_pt ? info->tx_event_pt : -1;
stream->rx_event_pt = info->rx_event_pt ? info->rx_event_pt : -1;
stream->last_dtmf = -1;
+ /* Build random RTCP CNAME. CNAME has user@host format */
+ stream->cname.ptr = p = (char*) pj_pool_alloc(pool, 20);
+ pj_create_random_string(p, 5);
+ p += 5;
+ *p++ = '@'; *p++ = 'p'; *p++ = 'j';
+ pj_create_random_string(p, 6);
+ p += 6;
+ *p++ = '.'; *p++ = 'o'; *p++ = 'r'; *p++ = 'g';
+ stream->cname.slen = p - stream->cname.ptr;
+
/* Create mutex to protect jitter buffer: */
@@ -1609,6 +1757,14 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
}
#endif
+ /* Send RTCP SDES */
+ len = create_rtcp_sdes(stream, stream->enc->out_pkt,
+ stream->enc->out_pkt_size);
+ if (len != 0) {
+ pjmedia_transport_send_rtcp(stream->transport,
+ stream->enc->out_pkt, len);
+ }
+
/* Success! */
*p_stream = stream;
@@ -1628,7 +1784,7 @@ err_cleanup:
*/
PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream )
{
-
+ unsigned len;
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
@@ -1669,6 +1825,14 @@ PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream )
}
#endif
+ /* Send RTCP BYE */
+ len = create_rtcp_bye(stream, stream->enc->out_pkt,
+ stream->enc->out_pkt_size);
+ if (len != 0) {
+ pjmedia_transport_send_rtcp(stream->transport,
+ stream->enc->out_pkt, len);
+ }
+
/* Detach from transport
* MUST NOT hold stream mutex while detaching from transport, as
* it may cause deadlock. See ticket #460 for the details.