summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2012-09-14 04:06:29 +0000
committerNanang Izzuddin <nanang@teluu.com>2012-09-14 04:06:29 +0000
commit69848a09610618abe49a4b5211af0a0d784a54a4 (patch)
tree37f34b87c58c073eaf47f8227ad2e3a583545010
parentb5e8e2f6d6d2353c94181498299ce5c0ffbdc87b (diff)
Close #1568:
- Added media change detection based on SDP negotiation result and local codec param settings, the detection result will decide whether the media should be re-initialized after the SDP negotiation. - Fixed stream to keep the duplicate of codec param for the stream info (was only copying the pointer). - Introduced macro PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO & PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4254 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/include/pjmedia/codec.h12
-rw-r--r--pjmedia/src/pjmedia/codec.c50
-rw-r--r--pjmedia/src/pjmedia/stream.c1
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h36
-rw-r--r--pjsip/src/pjsua-lib/pjsua_aud.c9
-rw-r--r--pjsip/src/pjsua-lib/pjsua_dump.c22
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c355
-rw-r--r--pjsip/src/pjsua-lib/pjsua_vid.c7
8 files changed, 408 insertions, 84 deletions
diff --git a/pjmedia/include/pjmedia/codec.h b/pjmedia/include/pjmedia/codec.h
index 8e2f23bc..94aff738 100644
--- a/pjmedia/include/pjmedia/codec.h
+++ b/pjmedia/include/pjmedia/codec.h
@@ -308,6 +308,18 @@ typedef struct pjmedia_codec_param
} pjmedia_codec_param;
+/**
+ * Duplicate codec parameter.
+ *
+ * @param pool The pool.
+ * @param src The codec parameter to be duplicated.
+ *
+ * @return Duplicated codec parameter.
+ */
+PJ_DECL(pjmedia_codec_param*) pjmedia_codec_param_clone(
+ pj_pool_t *pool,
+ const pjmedia_codec_param *src);
+
/*
* Forward declaration for pjmedia_codec.
diff --git a/pjmedia/src/pjmedia/codec.c b/pjmedia/src/pjmedia/codec.c
index 111ad0c7..3c647670 100644
--- a/pjmedia/src/pjmedia/codec.c
+++ b/pjmedia/src/pjmedia/codec.c
@@ -41,6 +41,39 @@ static void sort_codecs(pjmedia_codec_mgr *mgr);
/*
+ * Duplicate codec parameter.
+ */
+PJ_DEF(pjmedia_codec_param*) pjmedia_codec_param_clone(
+ pj_pool_t *pool,
+ const pjmedia_codec_param *src)
+{
+ pjmedia_codec_param *p;
+ unsigned i;
+
+ PJ_ASSERT_RETURN(pool && src, NULL);
+
+ p = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_param);
+
+ /* Update codec param */
+ pj_memcpy(p, src, sizeof(pjmedia_codec_param));
+ for (i = 0; i < src->setting.dec_fmtp.cnt; ++i) {
+ pj_strdup(pool, &p->setting.dec_fmtp.param[i].name,
+ &src->setting.dec_fmtp.param[i].name);
+ pj_strdup(pool, &p->setting.dec_fmtp.param[i].val,
+ &src->setting.dec_fmtp.param[i].val);
+ }
+ for (i = 0; i < src->setting.enc_fmtp.cnt; ++i) {
+ pj_strdup(pool, &p->setting.enc_fmtp.param[i].name,
+ &src->setting.enc_fmtp.param[i].name);
+ pj_strdup(pool, &p->setting.enc_fmtp.param[i].val,
+ &src->setting.enc_fmtp.param[i].val);
+ }
+
+ return p;
+}
+
+
+/*
* Initialize codec manager.
*/
PJ_DEF(pj_status_t) pjmedia_codec_mgr_init (pjmedia_codec_mgr *mgr,
@@ -600,22 +633,11 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_set_default_param(
codec_desc->param = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_default_param);
p = codec_desc->param;
p->pool = pool;
- p->param = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_param);
/* Update codec param */
- pj_memcpy(p->param, param, sizeof(pjmedia_codec_param));
- for (i = 0; i < param->setting.dec_fmtp.cnt; ++i) {
- pj_strdup(pool, &p->param->setting.dec_fmtp.param[i].name,
- &param->setting.dec_fmtp.param[i].name);
- pj_strdup(pool, &p->param->setting.dec_fmtp.param[i].val,
- &param->setting.dec_fmtp.param[i].val);
- }
- for (i = 0; i < param->setting.enc_fmtp.cnt; ++i) {
- pj_strdup(pool, &p->param->setting.enc_fmtp.param[i].name,
- &param->setting.enc_fmtp.param[i].name);
- pj_strdup(pool, &p->param->setting.enc_fmtp.param[i].val,
- &param->setting.enc_fmtp.param[i].val);
- }
+ p->param = pjmedia_codec_param_clone(pool, param);
+ if (!p->param)
+ return PJ_EINVAL;
pj_mutex_unlock(mgr->mutex);
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index 19b5523e..54dfb831 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -1989,6 +1989,7 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM);
stream->own_pool = own_pool;
pj_memcpy(&stream->si, info, sizeof(*info));
+ stream->si.param = pjmedia_codec_param_clone(pool, info->param);
/* Init stream/port name */
name.ptr = (char*) pj_pool_alloc(pool, M);
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 9b5032a0..922190a3 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -5236,6 +5236,28 @@ PJ_DECL(pj_status_t) pjsua_im_typing(pjsua_acc_id acc_id,
/**
+ * Specify whether the third party stream has the capability of retrieving
+ * the stream info, i.e: pjmedia_stream_get_info() and
+ * pjmedia_vid_stream_get_info(). Currently this capability is required
+ * by smart media update and call dump.
+ */
+#ifndef PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO
+# define PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO 0
+#endif
+
+
+/**
+ * Specify whether the third party stream has the capability of retrieving
+ * the stream statistics, i.e: pjmedia_stream_get_stat() and
+ * pjmedia_vid_stream_get_stat(). Currently this capability is required
+ * by call dump.
+ */
+#ifndef PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT
+# define PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT 0
+#endif
+
+
+/**
* Max ports in the conference bridge. This setting is the default value
* for pjsua_media_config.max_media_ports.
*/
@@ -5548,6 +5570,20 @@ struct pjsua_media_config
* Default: PJ_TRUE
*/
pj_bool_t vid_preview_enable_native;
+
+ /**
+ * Disable smart media update (ticket #1568). The smart media update
+ * will check for any changes in the media properties after a successful
+ * SDP negotiation and the media will only be reinitialized when any
+ * change is found. When it is disabled, media streams will always be
+ * reinitialized after a successful SDP negotiation.
+ *
+ * Note for third party media, the smart media update requires stream info
+ * retrieval capability, see #PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO.
+ *
+ * Default: PJ_FALSE
+ */
+ pj_bool_t no_smart_media_update;
};
diff --git a/pjsip/src/pjsua-lib/pjsua_aud.c b/pjsip/src/pjsua-lib/pjsua_aud.c
index daf98c2a..480aea41 100644
--- a/pjsip/src/pjsua-lib/pjsua_aud.c
+++ b/pjsip/src/pjsua-lib/pjsua_aud.c
@@ -560,7 +560,12 @@ static void dtmf_callback(pjmedia_stream *strm, void *user_data,
pj_log_pop_indent();
}
-
+/* Internal function: update audio channel after SDP negotiation.
+ * Warning: do not use temporary/flip-flop pool, e.g: inv->pool_prov,
+ * for creating stream, etc, as after SDP negotiation and when
+ * the SDP media is not changed, the stream should remain running
+ * while the temporary/flip-flop pool may be released.
+ */
pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
pj_pool_t *tmp_pool,
pjmedia_stream_info *si,
@@ -679,7 +684,7 @@ pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
port_name = pj_str("call");
}
status = pjmedia_conf_add_port( pjsua_var.mconf,
- call->inv->pool_prov,
+ call->inv->pool,
media_port,
&port_name,
(unsigned*)
diff --git a/pjsip/src/pjsua-lib/pjsua_dump.c b/pjsip/src/pjsua-lib/pjsua_dump.c
index ed18475b..87201cc8 100644
--- a/pjsip/src/pjsua-lib/pjsua_dump.c
+++ b/pjsip/src/pjsua-lib/pjsua_dump.c
@@ -212,6 +212,10 @@ static unsigned dump_media_stat(const char *indent,
/* Dump media session */
+#if PJSUA_MEDIA_HAS_PJMEDIA || \
+ (PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO && \
+ PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT)
+
static void dump_media_session(const char *indent,
char *buf, unsigned maxlen,
pjsua_call *call)
@@ -858,6 +862,24 @@ static void dump_media_session(const char *indent,
}
}
+#else /* PJSUA_MEDIA_HAS_PJMEDIA ||
+ (PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO &&
+ PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT) */
+
+static void dump_media_session(const char *indent,
+ char *buf, unsigned maxlen,
+ pjsua_call *call)
+{
+ PJ_UNUSED_ARG(indent);
+ PJ_UNUSED_ARG(buf);
+ PJ_UNUSED_ARG(maxlen);
+ PJ_UNUSED_ARG(call);
+}
+
+#endif /* PJSUA_MEDIA_HAS_PJMEDIA ||
+ (PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO &&
+ PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT) */
+
/* Print call info */
void print_call(const char *title,
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index 40bd2df7..483df783 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -2084,63 +2084,73 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
}
-static void stop_media_session(pjsua_call_id call_id)
+static void stop_media_stream(pjsua_call *call, unsigned med_idx)
{
- pjsua_call *call = &pjsua_var.calls[call_id];
- unsigned mi;
+ pjsua_call_media *call_med = &call->media[med_idx];
- pj_log_push_indent();
+ /* Check if stream does not exist */
+ if (med_idx >= call->med_cnt)
+ return;
- for (mi=0; mi<call->med_cnt; ++mi) {
- pjsua_call_media *call_med = &call->media[mi];
+ pj_log_push_indent();
- if (call_med->type == PJMEDIA_TYPE_AUDIO) {
- pjsua_aud_stop_stream(call_med);
- }
+ if (call_med->type == PJMEDIA_TYPE_AUDIO) {
+ pjsua_aud_stop_stream(call_med);
+ }
#if PJMEDIA_HAS_VIDEO
- else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
- pjsua_vid_stop_stream(call_med);
- }
+ else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
+ pjsua_vid_stop_stream(call_med);
+ }
#endif
- PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed",
- call_id, mi));
- call_med->prev_state = call_med->state;
- call_med->state = PJSUA_CALL_MEDIA_NONE;
+ PJ_LOG(4,(THIS_FILE, "Media stream call%02d:%d is destroyed",
+ call->index, med_idx));
+ call_med->prev_state = call_med->state;
+ call_med->state = PJSUA_CALL_MEDIA_NONE;
- /* Try to sync recent changes to provisional media */
- if (mi<call->med_prov_cnt && call->media_prov[mi].tp==call_med->tp)
- {
- pjsua_call_media *prov_med = &call->media_prov[mi];
+ /* Try to sync recent changes to provisional media */
+ if (med_idx < call->med_prov_cnt &&
+ call->media_prov[med_idx].tp == call_med->tp)
+ {
+ pjsua_call_media *prov_med = &call->media_prov[med_idx];
- /* Media state */
- prov_med->prev_state = call_med->prev_state;
- prov_med->state = call_med->state;
+ /* Media state */
+ prov_med->prev_state = call_med->prev_state;
+ prov_med->state = call_med->state;
- /* RTP seq/ts */
- prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set;
- prov_med->rtp_tx_seq = call_med->rtp_tx_seq;
- prov_med->rtp_tx_ts = call_med->rtp_tx_ts;
+ /* RTP seq/ts */
+ prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set;
+ prov_med->rtp_tx_seq = call_med->rtp_tx_seq;
+ prov_med->rtp_tx_ts = call_med->rtp_tx_ts;
- /* Stream */
- if (call_med->type == PJMEDIA_TYPE_AUDIO) {
- prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot;
- prov_med->strm.a.stream = call_med->strm.a.stream;
- }
+ /* Stream */
+ if (call_med->type == PJMEDIA_TYPE_AUDIO) {
+ prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot;
+ prov_med->strm.a.stream = call_med->strm.a.stream;
+ }
#if PJMEDIA_HAS_VIDEO
- else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
- prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id;
- prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id;
- prov_med->strm.v.stream = call_med->strm.v.stream;
- }
-#endif
+ else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
+ prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id;
+ prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id;
+ prov_med->strm.v.stream = call_med->strm.v.stream;
}
+#endif
}
pj_log_pop_indent();
}
+static void stop_media_session(pjsua_call_id call_id)
+{
+ pjsua_call *call = &pjsua_var.calls[call_id];
+ unsigned mi;
+
+ for (mi=0; mi<call->med_cnt; ++mi) {
+ stop_media_stream(call, mi);
+ }
+}
+
pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
{
pjsua_call *call = &pjsua_var.calls[call_id];
@@ -2188,6 +2198,171 @@ pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
}
+/* Match codec fmtp. This will compare the values and the order. */
+static pj_bool_t match_codec_fmtp(const pjmedia_codec_fmtp *fmtp1,
+ const pjmedia_codec_fmtp *fmtp2)
+{
+ unsigned i;
+
+ if (fmtp1->cnt != fmtp2->cnt)
+ return PJ_FALSE;
+
+ for (i = 0; i < fmtp1->cnt; ++i) {
+ if (pj_stricmp(&fmtp1->param[i].name, &fmtp2->param[i].name))
+ return PJ_FALSE;
+ if (pj_stricmp(&fmtp1->param[i].val, &fmtp2->param[i].val))
+ return PJ_FALSE;
+ }
+
+ return PJ_TRUE;
+}
+
+#if PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO
+
+static pj_bool_t is_media_changed(const pjsua_call *call,
+ unsigned med_idx,
+ const pjsua_stream_info *new_si_)
+{
+ const pjsua_call_media *call_med = &call->media[med_idx];
+
+ /* Check for newly added media */
+ if (med_idx >= call->med_cnt)
+ return PJ_TRUE;
+
+ /* Compare media type */
+ if (call_med->type != new_si_->type)
+ return PJ_TRUE;
+
+ /* Audio update checks */
+ if (call_med->type == PJMEDIA_TYPE_AUDIO) {
+ pjmedia_stream_info the_old_si;
+ const pjmedia_stream_info *old_si = NULL;
+ const pjmedia_stream_info *new_si = &new_si_->info.aud;
+ const pjmedia_codec_info *old_ci = NULL;
+ const pjmedia_codec_info *new_ci = &new_si->fmt;
+ const pjmedia_codec_param *old_cp = NULL;
+ const pjmedia_codec_param *new_cp = new_si->param;
+
+ /* Compare media direction */
+ if (call_med->dir != new_si->dir)
+ return PJ_TRUE;
+
+ /* Get current active stream info */
+ if (call_med->strm.a.stream) {
+ pjmedia_stream_get_info(call_med->strm.a.stream, &the_old_si);
+ old_si = &the_old_si;
+ old_ci = &old_si->fmt;
+ old_cp = old_si->param;
+ } else {
+ /* The stream is inactive. */
+ return (new_si->dir != PJMEDIA_DIR_NONE);
+ }
+
+ /* Compare remote RTP address */
+ if (pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
+ return PJ_TRUE;
+
+ /* Compare codec info */
+ if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) ||
+ old_ci->clock_rate != new_ci->clock_rate ||
+ old_ci->channel_cnt != new_ci->channel_cnt ||
+ old_si->rx_pt != new_si->rx_pt ||
+ old_si->tx_pt != new_si->tx_pt ||
+ old_si->rx_event_pt != new_si->tx_event_pt ||
+ old_si->tx_event_pt != new_si->tx_event_pt)
+ {
+ return PJ_TRUE;
+ }
+
+ /* Compare codec param */
+ if (old_cp->setting.frm_per_pkt != new_cp->setting.frm_per_pkt ||
+ old_cp->setting.vad != new_cp->setting.vad ||
+ old_cp->setting.cng != new_cp->setting.cng ||
+ old_cp->setting.plc != new_cp->setting.plc ||
+ old_cp->setting.penh != new_cp->setting.penh ||
+ !match_codec_fmtp(&old_cp->setting.dec_fmtp,
+ &new_cp->setting.dec_fmtp) ||
+ !match_codec_fmtp(&old_cp->setting.enc_fmtp,
+ &new_cp->setting.enc_fmtp))
+ {
+ return PJ_TRUE;
+ }
+ }
+
+#if PJMEDIA_HAS_VIDEO
+ else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
+ pjmedia_vid_stream_info the_old_si;
+ const pjmedia_vid_stream_info *old_si = NULL;
+ const pjmedia_vid_stream_info *new_si = &new_si_->info.vid;
+ const pjmedia_vid_codec_info *old_ci = NULL;
+ const pjmedia_vid_codec_info *new_ci = &new_si->codec_info;
+ const pjmedia_vid_codec_param *old_cp = NULL;
+ const pjmedia_vid_codec_param *new_cp = new_si->codec_param;
+
+ /* Compare media direction */
+ if (call_med->dir != new_si->dir)
+ return PJ_TRUE;
+
+ /* Get current active stream info */
+ if (call_med->strm.v.stream) {
+ pjmedia_vid_stream_get_info(call_med->strm.v.stream, &the_old_si);
+ old_si = &the_old_si;
+ old_ci = &old_si->codec_info;
+ old_cp = old_si->codec_param;
+ } else {
+ /* The stream is inactive. */
+ return (new_si->dir != PJMEDIA_DIR_NONE);
+ }
+
+ /* Compare remote RTP address */
+ if (pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
+ return PJ_TRUE;
+
+ /* Compare codec info */
+ if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) ||
+ old_si->rx_pt != new_si->rx_pt ||
+ old_si->tx_pt != new_si->tx_pt)
+ {
+ return PJ_TRUE;
+ }
+
+ /* Compare codec param */
+ if (/* old_cp->enc_mtu != new_cp->enc_mtu || */
+ pj_memcmp(&old_cp->enc_fmt.det, &new_cp->enc_fmt.det,
+ sizeof(pjmedia_video_format_detail)) ||
+ !match_codec_fmtp(&old_cp->dec_fmtp, &new_cp->dec_fmtp) ||
+ !match_codec_fmtp(&old_cp->enc_fmtp, &new_cp->enc_fmtp))
+ {
+ return PJ_TRUE;
+ }
+ }
+
+#endif
+
+ else {
+ /* Just return PJ_TRUE for other media type */
+ return PJ_TRUE;
+ }
+
+ return PJ_FALSE;
+}
+
+#else /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */
+
+static pj_bool_t is_media_changed(const pjsua_call *call,
+ unsigned med_idx,
+ const pjsua_stream_info *new_si_)
+{
+ PJ_UNUSED_ARG(call);
+ PJ_UNUSED_ARG(med_idx);
+ PJ_UNUSED_ARG(new_si_);
+ /* Always assume that media has been changed */
+ return PJ_TRUE;
+}
+
+#endif /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */
+
+
pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
const pjmedia_sdp_session *local_sdp,
const pjmedia_sdp_session *remote_sdp)
@@ -2216,7 +2391,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
pj_log_push_indent();
/* Destroy existing media session, if any. */
- stop_media_session(call->index);
+ //stop_media_session(call->index);
/* Call media count must be at least equal to SDP media. Note that
* it may not be equal when remote removed any SDP media line.
@@ -2270,6 +2445,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
/* Process each media stream */
for (mi=0; mi < call->med_prov_cnt; ++mi) {
pjsua_call_media *call_med = &call->media_prov[mi];
+ pj_bool_t media_changed = PJ_FALSE;
if (mi >= local_sdp->media_count ||
mi >= remote_sdp->media_count)
@@ -2277,8 +2453,12 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
/* This may happen when remote removed any SDP media lines in
* its re-offer.
*/
+
+ /* Stop stream */
+ stop_media_stream(call, mi);
+
+ /* Close the media transport */
if (call_med->tp) {
- /* Close the media transport */
pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
pjmedia_transport_close(call_med->tp);
call_med->tp = call_med->tp_orig = NULL;
@@ -2293,11 +2473,14 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
#endif
}
+ /* Apply media update action */
if (call_med->type==PJMEDIA_TYPE_AUDIO) {
pjmedia_stream_info the_si, *si = &the_si;
+ pjsua_stream_info stream_info;
- status = pjmedia_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt,
- local_sdp, remote_sdp, mi);
+ status = pjmedia_stream_info_from_sdp(
+ si, tmp_pool, pjsua_var.med_endpt,
+ local_sdp, remote_sdp, mi);
if (status != PJ_SUCCESS) {
PJ_PERROR(1,(THIS_FILE, status,
"pjmedia_stream_info_from_sdp() failed "
@@ -2306,8 +2489,23 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
continue;
}
+ /* Check if this media is changed */
+ stream_info.type = PJMEDIA_TYPE_AUDIO;
+ stream_info.info.aud = the_si;
+ if (pjsua_var.media_cfg.no_smart_media_update ||
+ is_media_changed(call, mi, &stream_info))
+ {
+ media_changed = PJ_TRUE;
+ /* Stop the media */
+ stop_media_stream(call, mi);
+ } else {
+ PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (audio) unchanged.",
+ call_id, mi));
+ }
+
/* Check if no media is active */
if (si->dir == PJMEDIA_DIR_NONE) {
+
/* Update call media state and direction */
call_med->state = PJSUA_CALL_MEDIA_NONE;
call_med->dir = PJMEDIA_DIR_NONE;
@@ -2335,10 +2533,11 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
if (tp_info.specific_info_cnt > 0) {
unsigned i;
for (i = 0; i < tp_info.specific_info_cnt; ++i) {
- if (tp_info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP)
+ if (tp_info.spc_info[i].type ==
+ PJMEDIA_TRANSPORT_TYPE_SRTP)
{
pjmedia_srtp_info *srtp_info =
- (pjmedia_srtp_info*) tp_info.spc_info[i].buffer;
+ (pjmedia_srtp_info*)tp_info.spc_info[i].buffer;
call_med->rem_srtp_use = srtp_info->peer_use;
break;
@@ -2346,6 +2545,20 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
}
}
+ /* Update audio channel */
+ if (media_changed) {
+ status = pjsua_aud_channel_update(call_med,
+ call->inv->pool, si,
+ local_sdp, remote_sdp);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status,
+ "pjsua_aud_channel_update() failed "
+ "for call_id %d media %d",
+ call_id, mi));
+ continue;
+ }
+ }
+
/* Call media direction */
call_med->dir = si->dir;
@@ -2358,17 +2571,6 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
}
- /* Call implementation */
- status = pjsua_aud_channel_update(call_med, tmp_pool, si,
- local_sdp, remote_sdp);
- if (status != PJ_SUCCESS) {
- PJ_PERROR(1,(THIS_FILE, status,
- "pjsua_aud_channel_update() failed "
- "for call_id %d media %d",
- call_id, mi));
- continue;
- }
-
/* Print info. */
if (status == PJ_SUCCESS) {
char info[80];
@@ -2413,9 +2615,11 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
} else if (call_med->type==PJMEDIA_TYPE_VIDEO) {
pjmedia_vid_stream_info the_si, *si = &the_si;
+ pjsua_stream_info stream_info;
- status = pjmedia_vid_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt,
- local_sdp, remote_sdp, mi);
+ status = pjmedia_vid_stream_info_from_sdp(
+ si, tmp_pool, pjsua_var.med_endpt,
+ local_sdp, remote_sdp, mi);
if (status != PJ_SUCCESS) {
PJ_PERROR(1,(THIS_FILE, status,
"pjmedia_vid_stream_info_from_sdp() failed "
@@ -2424,8 +2628,21 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
continue;
}
+ /* Check if this media is changed */
+ stream_info.type = PJMEDIA_TYPE_VIDEO;
+ stream_info.info.vid = the_si;
+ if (is_media_changed(call, mi, &stream_info)) {
+ media_changed = PJ_TRUE;
+ /* Stop the media */
+ stop_media_stream(call, mi);
+ } else {
+ PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (video) unchanged.",
+ call_id, mi));
+ }
+
/* Check if no media is active */
if (si->dir == PJMEDIA_DIR_NONE) {
+
/* Update call media state and direction */
call_med->state = PJSUA_CALL_MEDIA_NONE;
call_med->dir = PJMEDIA_DIR_NONE;
@@ -2464,6 +2681,20 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
}
}
+ /* Update audio channel */
+ if (media_changed) {
+ status = pjsua_vid_channel_update(call_med,
+ call->inv->pool, si,
+ local_sdp, remote_sdp);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status,
+ "pjsua_vid_channel_update() failed "
+ "for call_id %d media %d",
+ call_id, mi));
+ continue;
+ }
+ }
+
/* Call media direction */
call_med->dir = si->dir;
@@ -2476,16 +2707,6 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
}
- status = pjsua_vid_channel_update(call_med, tmp_pool, si,
- local_sdp, remote_sdp);
- if (status != PJ_SUCCESS) {
- PJ_PERROR(1,(THIS_FILE, status,
- "pjsua_vid_channel_update() failed "
- "for call_id %d media %d",
- call_id, mi));
- continue;
- }
-
/* Print info. */
{
char info[80];
diff --git a/pjsip/src/pjsua-lib/pjsua_vid.c b/pjsip/src/pjsua-lib/pjsua_vid.c
index b818e5f5..6ab6e18a 100644
--- a/pjsip/src/pjsua-lib/pjsua_vid.c
+++ b/pjsip/src/pjsua-lib/pjsua_vid.c
@@ -705,7 +705,12 @@ pj_status_t pjsua_vid_channel_init(pjsua_call_media *call_med)
return PJ_SUCCESS;
}
-/* Internal function: update video channel after SDP negotiation */
+/* Internal function: update video channel after SDP negotiation.
+ * Warning: do not use temporary/flip-flop pool, e.g: inv->pool_prov,
+ * for creating stream, etc, as after SDP negotiation and when
+ * the SDP media is not changed, the stream should remain running
+ * while the temporary/flip-flop pool may be released.
+ */
pj_status_t pjsua_vid_channel_update(pjsua_call_media *call_med,
pj_pool_t *tmp_pool,
pjmedia_vid_stream_info *si,