summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2012-03-30 07:10:13 +0000
committerBenny Prijono <bennylp@teluu.com>2012-03-30 07:10:13 +0000
commit6b4964727bffb379aca9601e1cf69051ccbf600c (patch)
tree1d9739ea8b3b5e0421f1d99b39e798b1514fb644 /pjmedia
parent85ac546acb235df62169c4ad317da74a62e56a88 (diff)
Re #1474: Merged all changes from 1.12 - HEAD (from the 1.x branch)
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3999 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/include/pjmedia/config.h28
-rw-r--r--pjmedia/include/pjmedia/endpoint.h23
-rw-r--r--pjmedia/include/pjmedia/rtcp.h121
-rw-r--r--pjmedia/include/pjmedia/rtcp_xr.h14
-rw-r--r--pjmedia/include/pjmedia/transport_srtp.h6
-rw-r--r--pjmedia/src/pjmedia/conf_switch.c24
-rw-r--r--pjmedia/src/pjmedia/endpoint.c46
-rw-r--r--pjmedia/src/pjmedia/rtcp.c293
-rw-r--r--pjmedia/src/pjmedia/sound_port.c1
-rw-r--r--pjmedia/src/pjmedia/stream.c385
-rw-r--r--pjmedia/src/pjmedia/transport_ice.c9
-rw-r--r--pjmedia/src/pjmedia/transport_srtp.c45
12 files changed, 696 insertions, 299 deletions
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h
index e8e7f807..76b8fc84 100644
--- a/pjmedia/include/pjmedia/config.h
+++ b/pjmedia/include/pjmedia/config.h
@@ -453,6 +453,19 @@
# define PJMEDIA_RTCP_STAT_HAS_RAW_JITTER 0
#endif
+/**
+ * Specify the factor with wich RTCP RTT statistics should be normalized
+ * if exceptionally high. For e.g. mobile networks with potentially large
+ * fluctuations, this might be unwanted.
+ *
+ * Use (0) to disable this feature.
+ *
+ * Default: 3.
+ */
+#ifndef PJMEDIA_RTCP_NORMALIZE_FACTOR
+# define PJMEDIA_RTCP_NORMALIZE_FACTOR 3
+#endif
+
/**
* Specify whether RTCP statistics includes IP Delay Variation statistics.
@@ -476,7 +489,7 @@
* if it is enabled on run-time on per stream basis. See
* PJMEDIA_STREAM_ENABLE_XR setting for more info.
*
- * Default: 1 (yes).
+ * Default: 0 (no).
*/
#ifndef PJMEDIA_HAS_RTCP_XR
# define PJMEDIA_HAS_RTCP_XR 0
@@ -494,6 +507,19 @@
# define PJMEDIA_STREAM_ENABLE_XR 0
#endif
+
+/**
+ * Specify the buffer length for storing any received RTCP SDES text
+ * in a stream session. Usually RTCP contains only the mandatory SDES
+ * field, i.e: CNAME.
+ *
+ * Default: 64 bytes.
+ */
+#ifndef PJMEDIA_RTCP_RX_SDES_BUF_LEN
+# define PJMEDIA_RTCP_RX_SDES_BUF_LEN 64
+#endif
+
+
/**
* Specify how long (in miliseconds) the stream should suspend the
* silence detector/voice activity detector (VAD) during the initial
diff --git a/pjmedia/include/pjmedia/endpoint.h b/pjmedia/include/pjmedia/endpoint.h
index 9956b95f..0e5debb8 100644
--- a/pjmedia/include/pjmedia/endpoint.h
+++ b/pjmedia/include/pjmedia/endpoint.h
@@ -61,6 +61,12 @@ typedef enum pjmedia_endpt_flag
/**
+ * Type of callback to register to pjmedia_endpt_atexit().
+ */
+typedef void (*pjmedia_endpt_exit_callback)(pjmedia_endpt *endpt);
+
+
+/**
* Create an instance of media endpoint.
*
* @param pf Pool factory, which will be used by the media endpoint
@@ -260,6 +266,23 @@ PJ_DECL(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
PJ_DECL(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt);
+/**
+ * Register cleanup function to be called by media endpoint when
+ * #pjmedia_endpt_destroy() is called. Note that application should not
+ * use or access any endpoint resource (such as pool, ioqueue) from within
+ * the callback as such resource may have been released when the callback
+ * function is invoked.
+ *
+ * @param endpt The media endpoint.
+ * @param func The function to be registered.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_endpt_atexit(pjmedia_endpt *endpt,
+ pjmedia_endpt_exit_callback func);
+
+
+
PJ_END_DECL
diff --git a/pjmedia/include/pjmedia/rtcp.h b/pjmedia/include/pjmedia/rtcp.h
index 259d3483..9fc53657 100644
--- a/pjmedia/include/pjmedia/rtcp.h
+++ b/pjmedia/include/pjmedia/rtcp.h
@@ -54,29 +54,26 @@ PJ_BEGIN_DECL
* #pjmedia_stream_get_stat() function.
*/
+
#pragma pack(1)
/**
* RTCP sender report.
*/
-struct pjmedia_rtcp_sr
+typedef struct pjmedia_rtcp_sr
{
pj_uint32_t ntp_sec; /**< NTP time, seconds part. */
pj_uint32_t ntp_frac; /**< NTP time, fractions part. */
pj_uint32_t rtp_ts; /**< RTP timestamp. */
pj_uint32_t sender_pcount; /**< Sender packet cound. */
pj_uint32_t sender_bcount; /**< Sender octet/bytes count. */
-};
+} pjmedia_rtcp_sr;
-/**
- * @see pjmedia_rtcp_sr
- */
-typedef struct pjmedia_rtcp_sr pjmedia_rtcp_sr;
/**
* RTCP receiver report.
*/
-struct pjmedia_rtcp_rr
+typedef struct pjmedia_rtcp_rr
{
pj_uint32_t ssrc; /**< SSRC identification. */
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
@@ -94,18 +91,13 @@ struct pjmedia_rtcp_rr
pj_uint32_t jitter; /**< Jitter. */
pj_uint32_t lsr; /**< Last SR. */
pj_uint32_t dlsr; /**< Delay since last SR. */
-};
-
-/**
- * @see pjmedia_rtcp_rr
- */
-typedef struct pjmedia_rtcp_rr pjmedia_rtcp_rr;
+} pjmedia_rtcp_rr;
/**
* RTCP common header.
*/
-struct pjmedia_rtcp_common
+typedef struct pjmedia_rtcp_common
{
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
unsigned version:2; /**< packet type */
@@ -120,12 +112,8 @@ struct pjmedia_rtcp_common
#endif
unsigned length:16; /**< packet length */
pj_uint32_t ssrc; /**< SSRC identification */
-};
+} pjmedia_rtcp_common;
-/**
- * @see pjmedia_rtcp_common
- */
-typedef struct pjmedia_rtcp_common pjmedia_rtcp_common;
/**
* This structure declares default RTCP packet (SR) that is sent by pjmedia.
@@ -153,25 +141,34 @@ typedef struct pjmedia_rtcp_rr_pkt
/**
- * NTP time representation.
+ * RTCP SDES structure.
*/
-struct pjmedia_rtcp_ntp_rec
+typedef struct pjmedia_rtcp_sdes
{
- pj_uint32_t hi; /**< High order 32-bit part. */
- pj_uint32_t lo; /**< Lo order 32-bit part. */
-};
+ pj_str_t cname; /**< RTCP SDES type CNAME. */
+ pj_str_t name; /**< RTCP SDES type NAME. */
+ pj_str_t email; /**< RTCP SDES type EMAIL. */
+ pj_str_t phone; /**< RTCP SDES type PHONE. */
+ pj_str_t loc; /**< RTCP SDES type LOC. */
+ pj_str_t tool; /**< RTCP SDES type TOOL. */
+ pj_str_t note; /**< RTCP SDES type NOTE. */
+} pjmedia_rtcp_sdes;
+
/**
- * @see pjmedia_rtcp_ntp_rec
+ * NTP time representation.
*/
-typedef struct pjmedia_rtcp_ntp_rec pjmedia_rtcp_ntp_rec;
-
+typedef struct pjmedia_rtcp_ntp_rec
+{
+ pj_uint32_t hi; /**< High order 32-bit part. */
+ pj_uint32_t lo; /**< Lo order 32-bit part. */
+} pjmedia_rtcp_ntp_rec;
/**
* Unidirectional RTP stream statistics.
*/
-struct pjmedia_rtcp_stream_stat
+typedef struct pjmedia_rtcp_stream_stat
{
pj_time_val update; /**< Time of last update. */
unsigned update_cnt; /**< Number of updates (to calculate avg) */
@@ -190,20 +187,14 @@ struct pjmedia_rtcp_stream_stat
} loss_type; /**< Types of loss detected. */
pj_math_stat jitter; /**< Jitter statistics (in usec) */
-};
-
-
-/**
- * @see pjmedia_rtcp_stream_stat
- */
-typedef struct pjmedia_rtcp_stream_stat pjmedia_rtcp_stream_stat;
+} pjmedia_rtcp_stream_stat;
/**
* Bidirectional RTP stream statistics.
*/
-struct pjmedia_rtcp_stat
+typedef struct pjmedia_rtcp_stat
{
pj_time_val start; /**< Time when session was created */
@@ -226,20 +217,19 @@ struct pjmedia_rtcp_stat
receiving direction
(in usec). */
#endif
-};
+ pjmedia_rtcp_sdes peer_sdes; /**< Peer SDES. */
+ char peer_sdes_buf_[PJMEDIA_RTCP_RX_SDES_BUF_LEN];
+ /**< Peer SDES buffer. */
-/**
- * @see pjmedia_rtcp_stat
- */
-typedef struct pjmedia_rtcp_stat pjmedia_rtcp_stat;
+} pjmedia_rtcp_stat;
/**
* RTCP session is used to monitor the RTP session of one endpoint. There
* should only be one RTCP session for a bidirectional RTP streams.
*/
-struct pjmedia_rtcp_session
+typedef struct pjmedia_rtcp_session
{
char *name; /**< Name identification. */
pjmedia_rtcp_sr_pkt rtcp_sr_pkt;/**< Cached RTCP SR packet. */
@@ -278,12 +268,7 @@ struct pjmedia_rtcp_session
*/
pjmedia_rtcp_xr_session xr_session;
#endif
-};
-
-/**
- * @see pjmedia_rtcp_session
- */
-typedef struct pjmedia_rtcp_session pjmedia_rtcp_session;
+} pjmedia_rtcp_session;
/**
@@ -439,6 +424,46 @@ PJ_DECL(void) pjmedia_rtcp_build_rtcp( pjmedia_rtcp_session *session,
/**
+ * Build an RTCP SDES (source description) packet. This packet can be
+ * appended to other RTCP packets, e.g: RTCP RR/SR, to compose a compound
+ * RTCP packet.
+ *
+ * @param session The RTCP session.
+ * @param buf The buffer to receive RTCP SDES packet.
+ * @param length On input, it will contain the buffer length.
+ * On output, it will contain the generated RTCP SDES
+ * packet length.
+ * @param sdes The source description, see #pjmedia_rtcp_sdes.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_rtcp_build_rtcp_sdes(
+ pjmedia_rtcp_session *session,
+ void *buf,
+ pj_size_t *length,
+ const pjmedia_rtcp_sdes *sdes);
+
+/**
+ * Build an RTCP BYE packet. This packet can be appended to other RTCP
+ * packets, e.g: RTCP RR/SR, to compose a compound RTCP packet.
+ *
+ * @param session The RTCP session.
+ * @param buf The buffer to receive RTCP BYE packet.
+ * @param length On input, it will contain the buffer length.
+ * On output, it will contain the generated RTCP BYE
+ * packet length.
+ * @param reason Optional, the BYE reason.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_rtcp_build_rtcp_bye(
+ pjmedia_rtcp_session *session,
+ void *buf,
+ pj_size_t *length,
+ const pj_str_t *reason);
+
+
+/**
* Call this function if RTCP XR needs to be enabled/disabled in the
* RTCP session.
*
diff --git a/pjmedia/include/pjmedia/rtcp_xr.h b/pjmedia/include/pjmedia/rtcp_xr.h
index e44bf1b1..fb204852 100644
--- a/pjmedia/include/pjmedia/rtcp_xr.h
+++ b/pjmedia/include/pjmedia/rtcp_xr.h
@@ -200,6 +200,17 @@ typedef struct pjmedia_rtcp_xr_rb_voip_mtc
jitter buffer */
} pjmedia_rtcp_xr_rb_voip_mtc;
+
+/**
+ * Constant of RTCP-XR content size.
+ */
+#define PJMEDIA_RTCP_XR_BUF_SIZE \
+ sizeof(pjmedia_rtcp_xr_rb_rr_time) + \
+ sizeof(pjmedia_rtcp_xr_rb_dlrr) + \
+ sizeof(pjmedia_rtcp_xr_rb_stats) + \
+ sizeof(pjmedia_rtcp_xr_rb_voip_mtc)
+
+
/**
* This structure declares RTCP XR (Extended Report) packet.
*/
@@ -221,7 +232,8 @@ typedef struct pjmedia_rtcp_xr_pkt
pj_uint32_t ssrc; /**< SSRC identification */
} common;
- pj_int8_t buf[PJMEDIA_MAX_MTU];/**< Content buffer */
+ pj_int8_t buf[PJMEDIA_RTCP_XR_BUF_SIZE];
+ /**< Content buffer */
} pjmedia_rtcp_xr_pkt;
#pragma pack()
diff --git a/pjmedia/include/pjmedia/transport_srtp.h b/pjmedia/include/pjmedia/transport_srtp.h
index 3a4820e8..910ec1d0 100644
--- a/pjmedia/include/pjmedia/transport_srtp.h
+++ b/pjmedia/include/pjmedia/transport_srtp.h
@@ -200,8 +200,12 @@ typedef struct pjmedia_srtp_info
* will also invoke this function. This function will also register SRTP
* library deinitialization to #pj_atexit(), so the deinitialization
* of SRTP library will be performed automatically by PJLIB destructor.
+ *
+ * @param endpt The media endpoint instance.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(void);
+PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt);
/**
diff --git a/pjmedia/src/pjmedia/conf_switch.c b/pjmedia/src/pjmedia/conf_switch.c
index 1e13e738..269405da 100644
--- a/pjmedia/src/pjmedia/conf_switch.c
+++ b/pjmedia/src/pjmedia/conf_switch.c
@@ -1086,11 +1086,14 @@ static pj_status_t write_frame(struct conf_port *cport_dst,
while (f_start < f_end) {
unsigned nsamples_to_copy, nsamples_req;
- /* Copy frame to listener's TX buffer. */
+ /* Copy frame to listener's TX buffer.
+ * Note that if the destination is port 0, just copy the whole
+ * available samples.
+ */
nsamples_to_copy = f_end - f_start;
nsamples_req = cport_dst->samples_per_frame -
(frm_dst->size>>1);
- if (nsamples_to_copy > nsamples_req)
+ if (cport_dst->slot && nsamples_to_copy > nsamples_req)
nsamples_to_copy = nsamples_req;
/* Adjust TX level. */
@@ -1123,16 +1126,19 @@ static pj_status_t write_frame(struct conf_port *cport_dst,
/* Check if it's time to deliver the TX buffer to listener,
* i.e: samples count in TX buffer equal to listener's
- * samples per frame.
+ * samples per frame. Note that for destination port 0 this
+ * function will just populate all samples in the TX buffer.
*/
- if ((frm_dst->size >> 1) == cport_dst->samples_per_frame)
+ if (cport_dst->slot == 0) {
+ /* Update TX timestamp. */
+ pj_add_timestamp32(&cport_dst->ts_tx, nsamples_to_copy);
+ } else if ((frm_dst->size >> 1) ==
+ cport_dst->samples_per_frame)
{
- if (cport_dst->slot) {
- pjmedia_port_put_frame(cport_dst->port, frm_dst);
+ pjmedia_port_put_frame(cport_dst->port, frm_dst);
- /* Reset TX buffer. */
- frm_dst->size = 0;
- }
+ /* Reset TX buffer. */
+ frm_dst->size = 0;
/* Update TX timestamp. */
pj_add_timestamp32(&cport_dst->ts_tx,
diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c
index b9ebe69a..4f592b6d 100644
--- a/pjmedia/src/pjmedia/endpoint.c
+++ b/pjmedia/src/pjmedia/endpoint.c
@@ -24,6 +24,7 @@
#include <pjmedia-audiodev/audiodev.h>
#include <pj/assert.h>
#include <pj/ioqueue.h>
+#include <pj/lock.h>
#include <pj/log.h>
#include <pj/os.h>
#include <pj/pool.h>
@@ -57,6 +58,14 @@ static int PJ_THREAD_FUNC worker_proc(void*);
#define MAX_THREADS 16
+/* List of media endpoint exit callback. */
+typedef struct exit_cb
+{
+ PJ_DECL_LIST_MEMBER (struct exit_cb);
+ pjmedia_endpt_exit_callback func;
+} exit_cb;
+
+
/** Concrete declaration of media endpoint. */
struct pjmedia_endpt
{
@@ -86,6 +95,9 @@ struct pjmedia_endpt
/** Is telephone-event enable */
pj_bool_t has_telephone_event;
+
+ /** List of exit callback. */
+ exit_cb exit_cb_list;
};
/**
@@ -129,6 +141,9 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf,
if (status != PJ_SUCCESS)
goto on_error;
+ /* Initialize exit callback list. */
+ pj_list_init(&endpt->exit_cb_list);
+
/* Create ioqueue if none is specified. */
if (endpt->ioqueue == NULL) {
@@ -189,6 +204,7 @@ PJ_DEF(pjmedia_codec_mgr*) pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt)
*/
PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
{
+ exit_cb *ecb;
unsigned i;
PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
@@ -214,6 +230,14 @@ PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
pjmedia_aud_subsys_shutdown();
+
+ /* Call all registered exit callbacks */
+ ecb = endpt->exit_cb_list.next;
+ while (ecb != &endpt->exit_cb_list) {
+ (*ecb->func)(endpt);
+ ecb = ecb->next;
+ }
+
pj_pool_release (endpt->pool);
return PJ_SUCCESS;
@@ -434,7 +458,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt,
rtpmap.param.slen = 1;
} else {
- rtpmap.param.ptr = NULL;
+ rtpmap.param.ptr = "";
rtpmap.param.slen = 0;
}
@@ -896,3 +920,23 @@ PJ_DEF(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt)
return PJ_SUCCESS;
}
+
+PJ_DEF(pj_status_t) pjmedia_endpt_atexit( pjmedia_endpt *endpt,
+ pjmedia_endpt_exit_callback func)
+{
+ exit_cb *new_cb;
+
+ PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
+
+ if (endpt->quit_flag)
+ return PJ_EINVALIDOP;
+
+ new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
+ new_cb->func = func;
+
+ pj_enter_critical_section();
+ pj_list_push_back(&endpt->exit_cb_list, new_cb);
+ pj_leave_critical_section();
+
+ return PJ_SUCCESS;
+}
diff --git a/pjmedia/src/pjmedia/rtcp.c b/pjmedia/src/pjmedia/rtcp.c
index cb048302..52274155 100644
--- a/pjmedia/src/pjmedia/rtcp.c
+++ b/pjmedia/src/pjmedia/rtcp.c
@@ -29,8 +29,21 @@
#define RTCP_SR 200
#define RTCP_RR 201
+#define RTCP_SDES 202
+#define RTCP_BYE 203
#define RTCP_XR 207
+enum {
+ RTCP_SDES_NULL = 0,
+ RTCP_SDES_CNAME = 1,
+ RTCP_SDES_NAME = 2,
+ RTCP_SDES_EMAIL = 3,
+ RTCP_SDES_PHONE = 4,
+ RTCP_SDES_LOC = 5,
+ RTCP_SDES_TOOL = 6,
+ RTCP_SDES_NOTE = 7
+};
+
#if PJ_HAS_HIGH_RES_TIMER==0
# error "High resolution timer needs to be enabled"
#endif
@@ -473,9 +486,9 @@ PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *sess,
}
-PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
- const void *pkt,
- pj_size_t size)
+static void parse_rtcp_report( pjmedia_rtcp_session *sess,
+ const void *pkt,
+ pj_size_t size)
{
pjmedia_rtcp_common *common = (pjmedia_rtcp_common*) pkt;
const pjmedia_rtcp_rr *rr = NULL;
@@ -615,19 +628,21 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
goto end_rtt_calc;
}
- /* "Normalize" rtt value that is exceptionally high.
- * For such values, "normalize" the rtt to be three times
- * the average value.
+#if defined(PJMEDIA_RTCP_NORMALIZE_FACTOR) && PJMEDIA_RTCP_NORMALIZE_FACTOR!=0
+ /* "Normalize" rtt value that is exceptionally high. For such
+ * values, "normalize" the rtt to be PJMEDIA_RTCP_NORMALIZE_FACTOR
+ * times the average value.
*/
- if (rtt > ((unsigned)sess->stat.rtt.mean*3) && sess->stat.rtt.n!=0)
+ if (rtt > ((unsigned)sess->stat.rtt.mean *
+ PJMEDIA_RTCP_NORMALIZE_FACTOR) && sess->stat.rtt.n!=0)
{
unsigned orig_rtt = rtt;
- rtt = sess->stat.rtt.mean*3;
- PJ_LOG(5,(sess->name,
+ rtt = sess->stat.rtt.mean * PJMEDIA_RTCP_NORMALIZE_FACTOR;
+ PJ_LOG(5,(sess->name,
"RTT value %d usec is normalized to %d usec",
orig_rtt, rtt));
}
-
+#endif
TRACE_((sess->name, "RTCP RTT is set to %d usec", rtt));
/* Update RTT stat */
@@ -650,6 +665,142 @@ end_rtt_calc:
}
+static void parse_rtcp_sdes(pjmedia_rtcp_session *sess,
+ const void *pkt,
+ pj_size_t size)
+{
+ pjmedia_rtcp_sdes *sdes = &sess->stat.peer_sdes;
+ char *p, *p_end;
+ char *b, *b_end;
+
+ p = (char*)pkt + 8;
+ p_end = (char*)pkt + size;
+
+ pj_bzero(sdes, sizeof(*sdes));
+ b = sess->stat.peer_sdes_buf_;
+ b_end = b + sizeof(sess->stat.peer_sdes_buf_);
+
+ while (p < p_end) {
+ pj_uint8_t sdes_type, sdes_len;
+ pj_str_t sdes_value = {NULL, 0};
+
+ sdes_type = *p++;
+
+ /* Check for end of SDES item list */
+ if (sdes_type == RTCP_SDES_NULL || p == p_end)
+ break;
+
+ sdes_len = *p++;
+
+ /* Check for corrupted SDES packet */
+ if (p + sdes_len > p_end)
+ break;
+
+ /* Get SDES item */
+ if (b + sdes_len < b_end) {
+ pj_memcpy(b, p, sdes_len);
+ sdes_value.ptr = b;
+ sdes_value.slen = sdes_len;
+ b += sdes_len;
+ } else {
+ /* Insufficient SDES buffer */
+ PJ_LOG(5, (sess->name,
+ "Unsufficient buffer to save RTCP SDES type %d:%.*s",
+ sdes_type, sdes_len, p));
+ p += sdes_len;
+ continue;
+ }
+
+ switch (sdes_type) {
+ case RTCP_SDES_CNAME:
+ sdes->cname = sdes_value;
+ break;
+ case RTCP_SDES_NAME:
+ sdes->name = sdes_value;
+ break;
+ case RTCP_SDES_EMAIL:
+ sdes->email = sdes_value;
+ break;
+ case RTCP_SDES_PHONE:
+ sdes->phone = sdes_value;
+ break;
+ case RTCP_SDES_LOC:
+ sdes->loc = sdes_value;
+ break;
+ case RTCP_SDES_TOOL:
+ sdes->tool = sdes_value;
+ break;
+ case RTCP_SDES_NOTE:
+ sdes->note = sdes_value;
+ break;
+ default:
+ TRACE_((sess->name, "Received unknown RTCP SDES type %d:%.*s",
+ sdes_type, sdes_value.slen, sdes_value.ptr));
+ break;
+ }
+
+ p += sdes_len;
+ }
+}
+
+
+static void parse_rtcp_bye(pjmedia_rtcp_session *sess,
+ const void *pkt,
+ pj_size_t size)
+{
+ pj_str_t reason = {"-", 1};
+
+ /* Check and get BYE reason */
+ if (size > 8) {
+ reason.slen = *((pj_uint8_t*)pkt+8);
+ pj_memcpy(sess->stat.peer_sdes_buf_, ((pj_uint8_t*)pkt+9),
+ reason.slen);
+ reason.ptr = sess->stat.peer_sdes_buf_;
+ }
+
+ /* Just print RTCP BYE log */
+ PJ_LOG(5, (sess->name, "Received RTCP BYE, reason: %.*s",
+ reason.slen, reason.ptr));
+}
+
+
+PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
+ const void *pkt,
+ pj_size_t size)
+{
+ pj_uint8_t *p, *p_end;
+
+ p = (pj_uint8_t*)pkt;
+ p_end = p + size;
+ while (p < p_end) {
+ pjmedia_rtcp_common *common = (pjmedia_rtcp_common*)p;
+ unsigned len;
+
+ len = (pj_ntohs((pj_uint16_t)common->length)+1) * 4;
+ switch(common->pt) {
+ case RTCP_SR:
+ case RTCP_RR:
+ case RTCP_XR:
+ parse_rtcp_report(sess, p, len);
+ break;
+ case RTCP_SDES:
+ parse_rtcp_sdes(sess, p, len);
+ break;
+ case RTCP_BYE:
+ parse_rtcp_bye(sess, p, len);
+ break;
+ default:
+ /* Ignore unknown RTCP */
+ TRACE_((sess->name, "Received unknown RTCP packet type=%d",
+ common->pt));
+ break;
+ }
+
+ p += len;
+ }
+}
+
+
PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess,
void **ret_p_pkt, int *len)
{
@@ -802,6 +953,128 @@ PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess,
sess->stat.rx.update_cnt++;
}
+
+PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_sdes(
+ pjmedia_rtcp_session *session,
+ void *buf,
+ pj_size_t *length,
+ const pjmedia_rtcp_sdes *sdes)
+{
+ pjmedia_rtcp_common *hdr;
+ pj_uint8_t *p;
+ unsigned len;
+
+ PJ_ASSERT_RETURN(session && buf && length && sdes, PJ_EINVAL);
+
+ /* Verify SDES item length */
+ if (sdes->cname.slen > 255 || sdes->name.slen > 255 ||
+ sdes->email.slen > 255 || sdes->phone.slen > 255 ||
+ sdes->loc.slen > 255 || sdes->tool.slen > 255 ||
+ sdes->note.slen > 255)
+ {
+ return PJ_EINVAL;
+ }
+
+ /* Verify buffer length */
+ len = sizeof(*hdr);
+ if (sdes->cname.slen) len += sdes->cname.slen + 2;
+ if (sdes->name.slen) len += sdes->name.slen + 2;
+ if (sdes->email.slen) len += sdes->email.slen + 2;
+ if (sdes->phone.slen) len += sdes->phone.slen + 2;
+ if (sdes->loc.slen) len += sdes->loc.slen + 2;
+ if (sdes->tool.slen) len += sdes->tool.slen + 2;
+ if (sdes->note.slen) len += sdes->note.slen + 2;
+ len++; /* null termination */
+ len = ((len+3)/4) * 4;
+ if (len > *length)
+ return PJ_ETOOSMALL;
+
+ /* Build RTCP SDES header */
+ hdr = (pjmedia_rtcp_common*)buf;
+ pj_memcpy(hdr, &session->rtcp_sr_pkt.common, sizeof(*hdr));
+ hdr->pt = RTCP_SDES;
+ hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
+
+ /* Build RTCP SDES items */
+ p = (pj_uint8_t*)hdr + sizeof(*hdr);
+#define BUILD_SDES_ITEM(SDES_NAME, SDES_TYPE) \
+ if (sdes->SDES_NAME.slen) { \
+ *p++ = SDES_TYPE; \
+ *p++ = (pj_uint8_t)sdes->SDES_NAME.slen; \
+ pj_memcpy(p, sdes->SDES_NAME.ptr, sdes->SDES_NAME.slen); \
+ p += sdes->SDES_NAME.slen; \
+ }
+ BUILD_SDES_ITEM(cname, RTCP_SDES_CNAME);
+ BUILD_SDES_ITEM(name, RTCP_SDES_NAME);
+ BUILD_SDES_ITEM(email, RTCP_SDES_EMAIL);
+ BUILD_SDES_ITEM(phone, RTCP_SDES_PHONE);
+ BUILD_SDES_ITEM(loc, RTCP_SDES_LOC);
+ BUILD_SDES_ITEM(tool, RTCP_SDES_TOOL);
+ BUILD_SDES_ITEM(note, RTCP_SDES_NOTE);
+#undef BUILD_SDES_ITEM
+
+ /* Null termination */
+ *p++ = 0;
+
+ /* Pad to 32bit */
+ while ((p-(pj_uint8_t*)buf) % 4)
+ *p++ = 0;
+
+ /* Finally */
+ pj_assert((int)len == p-(pj_uint8_t*)buf);
+ *length = len;
+
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_bye(pjmedia_rtcp_session *session,
+ void *buf,
+ pj_size_t *length,
+ const pj_str_t *reason)
+{
+ pjmedia_rtcp_common *hdr;
+ pj_uint8_t *p;
+ unsigned len;
+
+ PJ_ASSERT_RETURN(session && buf && length, PJ_EINVAL);
+
+ /* Verify BYE reason length */
+ if (reason && reason->slen > 255)
+ return PJ_EINVAL;
+
+ /* Verify buffer length */
+ len = sizeof(*hdr);
+ if (reason && reason->slen) len += reason->slen + 1;
+ len = ((len+3)/4) * 4;
+ if (len > *length)
+ return PJ_ETOOSMALL;
+
+ /* Build RTCP BYE header */
+ hdr = (pjmedia_rtcp_common*)buf;
+ pj_memcpy(hdr, &session->rtcp_sr_pkt.common, sizeof(*hdr));
+ hdr->pt = RTCP_BYE;
+ hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
+
+ /* Write RTCP BYE reason */
+ p = (pj_uint8_t*)hdr + sizeof(*hdr);
+ if (reason && reason->slen) {
+ *p++ = (pj_uint8_t)reason->slen;
+ pj_memcpy(p, reason->ptr, reason->slen);
+ p += reason->slen;
+ }
+
+ /* Pad to 32bit */
+ while ((p-(pj_uint8_t*)buf) % 4)
+ *p++ = 0;
+
+ pj_assert((int)len == p-(pj_uint8_t*)buf);
+ *length = len;
+
+ return PJ_SUCCESS;
+}
+
+
PJ_DEF(pj_status_t) pjmedia_rtcp_enable_xr( pjmedia_rtcp_session *sess,
pj_bool_t enable)
{
diff --git a/pjmedia/src/pjmedia/sound_port.c b/pjmedia/src/pjmedia/sound_port.c
index e377a1ed..d99d3049 100644
--- a/pjmedia/src/pjmedia/sound_port.c
+++ b/pjmedia/src/pjmedia/sound_port.c
@@ -441,7 +441,6 @@ PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool,
snd_port->dir = prm->base.dir;
snd_port->rec_id = prm->base.rec_id;
snd_port->play_id = prm->base.play_id;
- snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
snd_port->clock_rate = prm->base.clock_rate;
snd_port->channel_count = prm->base.channel_count;
snd_port->samples_per_frame = prm->base.samples_per_frame;
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index b5354cd1..983f0445 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -155,6 +155,9 @@ struct pjmedia_stream
pj_uint32_t rtcp_interval; /**< Interval, in timestamp. */
pj_bool_t initial_rr; /**< Initial RTCP RR sent */
pj_bool_t rtcp_sdes_bye_disabled;/**< Send RTCP SDES/BYE?*/
+ void *out_rtcp_pkt; /**< Outgoing RTCP packet. */
+ unsigned out_rtcp_pkt_size;
+ /**< Outgoing RTCP packet size. */
/* RFC 2833 DTMF transmission queue: */
int tx_event_pt; /**< Outgoing pt for dtmf. */
@@ -245,6 +248,12 @@ static void stream_perror(const char *sender, const char *title,
}
+static pj_status_t send_rtcp(pjmedia_stream *stream,
+ pj_bool_t with_sdes,
+ pj_bool_t with_bye,
+ pj_bool_t with_xr);
+
+
#if TRACE_JB
PJ_INLINE(int) trace_jb_print_timestamp(char **buf, pj_ssize_t len)
@@ -425,8 +434,7 @@ static void send_keep_alive_packet(pjmedia_stream *stream)
pkt_len);
/* Send RTCP */
- pjmedia_rtcp_build_rtcp(&stream->rtcp, &pkt, &pkt_len);
- pjmedia_transport_send_rtcp(stream->transport, pkt, pkt_len);
+ send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE);
#elif PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_USER
@@ -913,146 +921,159 @@ static void create_dtmf_payload(pjmedia_stream *stream,
}
-/**
- * check_tx_rtcp()
- *
- * This function is can be called by either put_frame() or get_frame(),
- * to transmit periodic RTCP SR/RR report.
- */
-static void check_tx_rtcp(pjmedia_stream *stream, pj_uint32_t timestamp)
+static pj_status_t send_rtcp(pjmedia_stream *stream,
+ pj_bool_t with_sdes,
+ pj_bool_t with_bye,
+ pj_bool_t with_xr)
{
- /* Note that timestamp may represent local or remote timestamp,
- * depending on whether this function is called from put_frame()
- * or get_frame().
- */
-
+ void *sr_rr_pkt;
+ pj_uint8_t *pkt;
+ int len, max_len;
+ pj_status_t status;
- if (stream->rtcp_last_tx == 0) {
-
- stream->rtcp_last_tx = timestamp;
+ /* Build RTCP RR/SR packet */
+ pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len);
- } else if (timestamp - stream->rtcp_last_tx >= stream->rtcp_interval) {
-
- void *rtcp_pkt;
- int len;
+#if !defined(PJMEDIA_HAS_RTCP_XR) || (PJMEDIA_HAS_RTCP_XR == 0)
+ with_xr = PJ_FALSE;
+#endif
- pjmedia_rtcp_build_rtcp(&stream->rtcp, &rtcp_pkt, &len);
+ if (with_sdes || with_bye || with_xr) {
+ pkt = (pj_uint8_t*) stream->out_rtcp_pkt;
+ pj_memcpy(pkt, sr_rr_pkt, len);
+ max_len = stream->out_rtcp_pkt_size;
+ } else {
+ pkt = sr_rr_pkt;
+ max_len = len;
+ }
- pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len);
+ /* Build RTCP SDES packet */
+ if (with_sdes) {
+ pjmedia_rtcp_sdes sdes;
+ pj_size_t sdes_len;
- stream->rtcp_last_tx = timestamp;
+ pj_bzero(&sdes, sizeof(sdes));
+ sdes.cname = stream->cname;
+ sdes_len = max_len - len;
+ status = pjmedia_rtcp_build_rtcp_sdes(&stream->rtcp, pkt+len,
+ &sdes_len, &sdes);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(stream->port.info.name.ptr, status,
+ "Error generating RTCP SDES"));
+ } else {
+ len += sdes_len;
+ }
}
+ /* Build RTCP XR packet */
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
- if (stream->rtcp.xr_enabled) {
-
- if (stream->rtcp_xr_last_tx == 0) {
-
- stream->rtcp_xr_last_tx = timestamp;
-
- } else if (timestamp - stream->rtcp_xr_last_tx >=
- stream->rtcp_xr_interval)
- {
- int i;
- pjmedia_jb_state jb_state;
- void *rtcp_pkt;
- int len;
+ if (with_xr) {
+ int i;
+ pjmedia_jb_state jb_state;
+ void *xr_pkt;
+ int xr_len;
- /* Update RTCP XR with current JB states */
- pjmedia_jbuf_get_state(stream->jb, &jb_state);
+ /* Update RTCP XR with current JB states */
+ pjmedia_jbuf_get_state(stream->jb, &jb_state);
- i = jb_state.avg_delay;
- pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
- PJMEDIA_RTCP_XR_INFO_JB_NOM,
- i);
+ i = jb_state.avg_delay;
+ status = pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
+ PJMEDIA_RTCP_XR_INFO_JB_NOM, i);
+ pj_assert(status == PJ_SUCCESS);
- i = jb_state.max_delay;
- pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
- PJMEDIA_RTCP_XR_INFO_JB_MAX,
- i);
+ i = jb_state.max_delay;
+ status = pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
+ PJMEDIA_RTCP_XR_INFO_JB_MAX, i);
+ pj_assert(status == PJ_SUCCESS);
- /* Build RTCP XR packet */
- pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0,
- &rtcp_pkt, &len);
+ pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0,
+ &xr_pkt, &xr_len);
- /* Send the RTCP XR to remote address */
- pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len);
+ if (xr_len + len <= max_len) {
+ pj_memcpy(pkt+len, xr_pkt, xr_len);
+ len += xr_len;
/* Send the RTCP XR to third-party destination if specified */
if (stream->rtcp_xr_dest_len) {
pjmedia_transport_send_rtcp2(stream->transport,
&stream->rtcp_xr_dest,
stream->rtcp_xr_dest_len,
- rtcp_pkt, len);
+ xr_pkt, xr_len);
}
- /* Update last tx RTCP XR */
- stream->rtcp_xr_last_tx = timestamp;
+ } else {
+ PJ_PERROR(4,(stream->port.info.name.ptr, PJ_ETOOBIG,
+ "Error generating RTCP-XR"));
}
}
#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 */
+ if (with_bye) {
+ pj_size_t bye_len;
+
+ bye_len = max_len - len;
+ status = pjmedia_rtcp_build_rtcp_bye(&stream->rtcp, pkt+len,
+ &bye_len, NULL);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(stream->port.info.name.ptr, status,
+ "Error generating RTCP BYE"));
+ } else {
+ len += bye_len;
+ }
+ }
+
+ /* Send! */
+ status = pjmedia_transport_send_rtcp(stream->transport, pkt, len);
+
+ return status;
}
-/* Build RTCP BYE packet */
-static unsigned create_rtcp_bye(pjmedia_stream *stream, pj_uint8_t *pkt,
- unsigned max_len)
+/**
+ * check_tx_rtcp()
+ *
+ * This function is can be called by either put_frame() or get_frame(),
+ * to transmit periodic RTCP SR/RR report.
+ */
+static void check_tx_rtcp(pjmedia_stream *stream, pj_uint32_t timestamp)
{
- 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);
+ /* Note that timestamp may represent local or remote timestamp,
+ * depending on whether this function is called from put_frame()
+ * or get_frame().
+ */
+
+ if (stream->rtcp_last_tx == 0) {
+
+ stream->rtcp_last_tx = timestamp;
+
+ } else if (timestamp - stream->rtcp_last_tx >= stream->rtcp_interval) {
+ pj_bool_t with_xr = PJ_FALSE;
+ pj_status_t status;
+
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+ if (stream->rtcp.xr_enabled) {
+ if (stream->rtcp_xr_last_tx == 0) {
+ stream->rtcp_xr_last_tx = timestamp;
+ } else if (timestamp - stream->rtcp_xr_last_tx >=
+ stream->rtcp_xr_interval)
+ {
+ with_xr = PJ_TRUE;
+
+ /* Update last tx RTCP XR */
+ stream->rtcp_xr_last_tx = timestamp;
+ }
+ }
+#endif
+
+ status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled, PJ_FALSE,
+ with_xr);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(stream->port.info.name.ptr, status,
+ "Error sending RTCP"));
+ }
+
+ stream->rtcp_last_tx = timestamp;
+ }
}
@@ -1348,8 +1369,13 @@ static pj_status_t put_frame_imp( pjmedia_port *port,
stream->is_streaming = PJ_TRUE;
/* Send the RTP packet to the transport. */
- pjmedia_transport_send_rtp(stream->transport, channel->out_pkt,
- frame_out.size + sizeof(pjmedia_rtp_hdr));
+ status = pjmedia_transport_send_rtp(stream->transport, channel->out_pkt,
+ frame_out.size +
+ sizeof(pjmedia_rtp_hdr));
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(stream->port.info.name.ptr, status,
+ "Error sending RTP"));
+ }
/* Update stat */
pjmedia_rtcp_tx_rtp(&stream->rtcp, frame_out.size);
@@ -1819,32 +1845,14 @@ on_return:
/* 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);
-
- if (!stream->rtcp_sdes_bye_disabled) {
- 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);
- }
- } else {
- pjmedia_transport_send_rtcp(stream->transport, sr_rr_pkt, len);
- }
-
- stream->initial_rr = PJ_TRUE;
+ status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled,
+ PJ_FALSE, PJ_FALSE);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(stream->port.info.name.ptr, status,
+ "Error sending initial RTCP RR"));
+ } else {
+ stream->initial_rr = PJ_TRUE;
+ }
}
}
@@ -1882,7 +1890,6 @@ static pj_status_t create_channel( pj_pool_t *pool,
{
pjmedia_channel *channel;
pj_status_t status;
- unsigned min_out_pkt_size;
/* Allocate memory for channel descriptor */
@@ -1914,15 +1921,6 @@ static pj_status_t create_channel( pj_pool_t *pool,
return PJ_ENOTSUP;
}
- /* It should big enough to hold (minimally) RTCP SR with an SDES. */
- min_out_pkt_size = sizeof(pjmedia_rtcp_sr_pkt) +
- sizeof(pjmedia_rtcp_common) +
- (4 + stream->cname.slen) +
- 32;
-
- if (channel->out_pkt_size < min_out_pkt_size)
- channel->out_pkt_size = min_out_pkt_size;
-
channel->out_pkt = pj_pool_alloc(pool, channel->out_pkt_size);
PJ_ASSERT_RETURN(channel->out_pkt != NULL, PJ_ENOMEM);
@@ -2265,7 +2263,30 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
#endif
pjmedia_rtcp_init2(&stream->rtcp, &rtcp_setting);
+
+ if (info->rtp_seq_ts_set) {
+ stream->rtcp.stat.rtp_tx_last_seq = info->rtp_seq;
+ stream->rtcp.stat.rtp_tx_last_ts = info->rtp_ts;
+ }
+ }
+
+ /* Allocate outgoing RTCP buffer, should be enough to hold SR/RR, SDES,
+ * BYE, and XR.
+ */
+ stream->out_rtcp_pkt_size = sizeof(pjmedia_rtcp_sr_pkt) +
+ sizeof(pjmedia_rtcp_common) +
+ (4 + stream->cname.slen) +
+ 32;
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+ if (info->rtcp_xr_enabled) {
+ stream->out_rtcp_pkt_size += sizeof(pjmedia_rtcp_xr_pkt);
}
+#endif
+
+ if (stream->out_rtcp_pkt_size > PJMEDIA_MAX_MTU)
+ stream->out_rtcp_pkt_size = PJMEDIA_MAX_MTU;
+
+ stream->out_rtcp_pkt = pj_pool_alloc(pool, stream->out_rtcp_pkt_size);
/* Only attach transport when stream is ready. */
status = pjmedia_transport_attach(tp, stream, &info->rem_addr,
@@ -2391,47 +2412,9 @@ PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream )
{
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
- /* Send RTCP XR on stream destroy */
- if (stream->rtcp.xr_enabled) {
- int i;
- pjmedia_jb_state jb_state;
- void *rtcp_pkt;
- int len;
-
- /* Update RTCP XR with current JB states */
- pjmedia_jbuf_get_state(stream->jb, &jb_state);
-
- i = jb_state.avg_delay;
- pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
- PJMEDIA_RTCP_XR_INFO_JB_NOM,
- i);
-
- i = jb_state.max_delay;
- pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
- PJMEDIA_RTCP_XR_INFO_JB_MAX,
- i);
-
- /* Build RTCP XR packet */
- pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0,
- &rtcp_pkt, &len);
-
- /* Send the RTCP XR to remote address */
- pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len);
-
- /* Send the RTCP XR to third-party destination if specified */
- if (stream->rtcp_xr_dest_len) {
- pjmedia_transport_send_rtcp2(stream->transport,
- &stream->rtcp_xr_dest,
- stream->rtcp_xr_dest_len,
- rtcp_pkt, len);
- }
- }
-#endif
-
- /* Send RTCP BYE */
+ /* Send RTCP BYE (also SDES & XR) */
if (!stream->rtcp_sdes_bye_disabled) {
- pjmedia_stream_send_rtcp_bye(stream);
+ send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_TRUE);
}
/* Detach from transport
@@ -2799,18 +2782,9 @@ PJ_DEF(pj_status_t) pjmedia_stream_set_dtmf_callback(pjmedia_stream *stream,
PJ_DEF(pj_status_t)
pjmedia_stream_send_rtcp_sdes( pjmedia_stream *stream )
{
- unsigned len;
-
PJ_ASSERT_RETURN(stream, PJ_EINVAL);
- len = create_rtcp_sdes(stream, (pj_uint8_t*)stream->enc->out_pkt,
- stream->enc->out_pkt_size);
- if (len != 0) {
- return pjmedia_transport_send_rtcp(stream->transport,
- stream->enc->out_pkt, len);
- }
-
- return PJ_SUCCESS;
+ return send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE);
}
/*
@@ -2822,14 +2796,7 @@ pjmedia_stream_send_rtcp_bye( pjmedia_stream *stream )
PJ_ASSERT_RETURN(stream, PJ_EINVAL);
if (stream->enc && stream->transport) {
- unsigned len;
-
- len = create_rtcp_bye(stream, (pj_uint8_t*)stream->enc->out_pkt,
- stream->enc->out_pkt_size);
- if (len != 0) {
- return pjmedia_transport_send_rtcp(stream->transport,
- stream->enc->out_pkt, len);
- }
+ return send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_FALSE);
}
return PJ_SUCCESS;
diff --git a/pjmedia/src/pjmedia/transport_ice.c b/pjmedia/src/pjmedia/transport_ice.c
index bf7988e5..2059b5c2 100644
--- a/pjmedia/src/pjmedia/transport_ice.c
+++ b/pjmedia/src/pjmedia/transport_ice.c
@@ -419,7 +419,9 @@ static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice,
* the session, in this case we will answer with full ICE SDP and
* new ufrag/pwd pair.
*/
- if (!restart_session && pj_ice_strans_sess_is_complete(tp_ice->ice_st)) {
+ if (!restart_session && pj_ice_strans_sess_is_complete(tp_ice->ice_st) &&
+ pj_ice_strans_get_state(tp_ice->ice_st) != PJ_ICE_STRANS_STATE_FAILED)
+ {
const pj_ice_sess_check *check;
char *attr_buf;
pjmedia_sdp_conn *conn;
@@ -549,7 +551,10 @@ static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice,
pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
}
- } else if (pj_ice_strans_has_sess(tp_ice->ice_st)) {
+ } else if (pj_ice_strans_has_sess(tp_ice->ice_st) &&
+ pj_ice_strans_get_state(tp_ice->ice_st) !=
+ PJ_ICE_STRANS_STATE_FAILED)
+ {
/* Encode all candidates to SDP media */
char *attr_buf;
unsigned comp;
diff --git a/pjmedia/src/pjmedia/transport_srtp.c b/pjmedia/src/pjmedia/transport_srtp.c
index 85ee70e9..76bd1518 100644
--- a/pjmedia/src/pjmedia/transport_srtp.c
+++ b/pjmedia/src/pjmedia/transport_srtp.c
@@ -270,9 +270,9 @@ const char* get_libsrtp_errstr(int err)
}
static pj_bool_t libsrtp_initialized;
-static void pjmedia_srtp_deinit_lib(void);
+static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt);
-PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void)
+PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt)
{
if (libsrtp_initialized == PJ_FALSE) {
err_status_t err;
@@ -284,7 +284,8 @@ PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void)
return PJMEDIA_ERRNO_FROM_LIBSRTP(err);
}
- if (pj_atexit(pjmedia_srtp_deinit_lib) != PJ_SUCCESS) {
+ if (pjmedia_endpt_atexit(endpt, pjmedia_srtp_deinit_lib) != PJ_SUCCESS)
+ {
/* There will be memory leak when it fails to schedule libsrtp
* deinitialization, however the memory leak could be harmless,
* since in modern OS's memory used by an application is released
@@ -299,10 +300,19 @@ PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void)
return PJ_SUCCESS;
}
-static void pjmedia_srtp_deinit_lib(void)
+static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt)
{
err_status_t err;
+ /* Note that currently this SRTP init/deinit is not equipped with
+ * reference counter, it should be safe as normally there is only
+ * one single instance of media endpoint and even if it isn't, the
+ * pjmedia_transport_srtp_create() will invoke SRTP init (the only
+ * drawback should be the delay described by #788).
+ */
+
+ PJ_UNUSED_ARG(endpt);
+
err = srtp_deinit();
if (err != err_status_ok) {
PJ_LOG(4, (THIS_FILE, "Failed to deinitialize libsrtp: %s",
@@ -410,7 +420,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_create(
}
/* Init libsrtp. */
- status = pjmedia_srtp_init_lib();
+ status = pjmedia_srtp_init_lib(endpt);
if (status != PJ_SUCCESS)
return status;
@@ -907,19 +917,22 @@ static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size)
(err == err_status_replay_old || err == err_status_replay_fail))
{
/* Handle such condition that stream is updated (RTP seq is reinited
- * & SRTP is restarted), but some old packets are still coming
- * so SRTP is learning wrong RTP seq. While the newly inited RTP seq
- * comes, SRTP thinks the RTP seq is replayed, so srtp_unprotect()
- * will returning err_status_replay_*. Restarting SRTP can resolve
- * this.
- */
- if (pjmedia_transport_srtp_start((pjmedia_transport*)srtp,
- &srtp->tx_policy, &srtp->rx_policy)
- != PJ_SUCCESS)
- {
+ * & SRTP is restarted), but some old packets are still coming
+ * so SRTP is learning wrong RTP seq. While the newly inited RTP seq
+ * comes, SRTP thinks the RTP seq is replayed, so srtp_unprotect()
+ * will return err_status_replay_*. Restarting SRTP can resolve this.
+ */
+ pjmedia_srtp_crypto tx, rx;
+ pj_status_t status;
+
+ tx = srtp->tx_policy;
+ rx = srtp->rx_policy;
+ status = pjmedia_transport_srtp_start((pjmedia_transport*)srtp,
+ &tx, &rx);
+ if (status != PJ_SUCCESS) {
PJ_LOG(5,(srtp->pool->obj_name, "Failed to restart SRTP, err=%s",
get_libsrtp_errstr(err)));
- } else {
+ } else if (!srtp->bypass_srtp) {
err = srtp_unprotect(srtp->srtp_rx_ctx, (pj_uint8_t*)pkt, &len);
}
}