summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2012-04-24 05:40:32 +0000
committerNanang Izzuddin <nanang@teluu.com>2012-04-24 05:40:32 +0000
commit603594518c4cbe3c564df98e3cd86f34b89e5971 (patch)
tree37acdb3307a94d23e1d834b304570a7cad3b4757
parentd73368a020b5723e58b529f0ed6401459b7750b3 (diff)
Fix #1423:
- Added provisional media in call for generating initial and subsequent SDP offer/answer. If a reoffer is rejected by peer, the main call media will remain unchanged and the provisional media will be cleaned up (the cleanup is currently delayed until call gets destroyed or another reoffer/answer occurs). - Reenabled media transport dump in pjsua_core.c. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4071 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h6
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c26
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c53
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c180
-rw-r--r--pjsip/src/pjsua-lib/pjsua_vid.c23
5 files changed, 214 insertions, 74 deletions
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index 646c8d7c..61007d8a 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -136,6 +136,10 @@ struct pjsua_call
unsigned med_cnt; /**< Number of media in SDP. */
pjsua_call_media media[PJSUA_MAX_CALL_MEDIA]; /**< Array of media */
+ unsigned med_prov_cnt;/**< Number of provisional media. */
+ pjsua_call_media media_prov[PJSUA_MAX_CALL_MEDIA];
+ /**< Array of provisional media. */
+
int audio_idx; /**< First active audio media. */
pj_mutex_t *med_ch_mutex;/**< Media channel callback's mutex. */
pjsua_med_tp_state_cb med_ch_cb;/**< Media channel callback. */
@@ -603,6 +607,8 @@ pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
pjsua_med_tp_state_cb cb);
void pjsua_set_media_tp_state(pjsua_call_media *call_med, pjsua_med_tp_st tp_st);
+void pjsua_media_prov_clean_up(pjsua_call_id call_id);
+
/* Callback to receive media events */
pj_status_t call_media_on_event(pjmedia_event *event,
void *user_data);
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index b8cf6b37..6dc49fdf 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -544,9 +544,12 @@ static pj_status_t apply_call_setting(pjsua_call *call,
old_opt = call->opt;
call->opt = *opt;
- /* Reinit media channel when media count is changed */
- if (opt->aud_cnt != old_opt.aud_cnt ||
- opt->vid_cnt != old_opt.vid_cnt)
+ /* Reinit media channel when media count is changed or we are the
+ * answerer (as remote offer may 'extremely' modify the existing
+ * media session, e.g: media type order).
+ */
+ if (rem_sdp ||
+ opt->aud_cnt!=old_opt.aud_cnt || opt->vid_cnt!=old_opt.vid_cnt)
{
pjsip_role_e role = rem_sdp? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC;
status = pjsua_media_channel_init(call->index, role,
@@ -1198,7 +1201,6 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
/* Can't terminate dialog because transaction is in progress.
pjsip_dlg_terminate(dlg);
*/
- pjsua_media_channel_deinit(call->index);
goto on_return;
}
@@ -1317,6 +1319,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
status = pjsip_inv_send_msg(inv, response);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
+ pjsua_media_channel_deinit(call->index);
goto on_return;
}
}
@@ -3224,6 +3227,9 @@ static void pjsua_call_on_media_update(pjsip_inv_session *inv,
pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
+ /* Clean up provisional media */
+ pjsua_media_prov_clean_up(call->index);
+
/* Do not deinitialize media since this may be a re-INVITE or
* UPDATE (which in this case the media should not get affected
* by the failed re-INVITE/UPDATE). The media will be shutdown
@@ -3427,17 +3433,11 @@ static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
call->opt = opt;
}
-
+
/* Re-init media for the new remote offer before creating SDP */
- status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,
- call->secure_level,
- call->inv->pool_prov,
- offer, NULL,
- PJ_FALSE, NULL);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Error re-initializing media channel", status);
+ status = apply_call_setting(call, &call->opt, offer);
+ if (status != PJ_SUCCESS)
goto on_return;
- }
status = pjsua_media_channel_create_sdp(call->index,
call->inv->pool_prov,
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index aeb85ebf..8b6dc46e 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -2770,26 +2770,47 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail)
pjmedia_endpt_dump(pjsua_get_pjmedia_endpt());
PJ_LOG(3,(THIS_FILE, "Dumping media transports:"));
- // Suppress compile warning caused by unreferenced var.
- PJ_UNUSED_ARG(i);
-#if DISABLED_FOR_TICKET_1185
for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
pjsua_call *call = &pjsua_var.calls[i];
- pjmedia_transport_info tpinfo;
- char addr_buf[80];
-
- /* MSVC complains about tpinfo not being initialized */
- //pj_bzero(&tpinfo, sizeof(tpinfo));
-
- pjmedia_transport_info_init(&tpinfo);
- pjmedia_transport_get_info(call->med_tp, &tpinfo);
+ pjmedia_transport *tp[PJSUA_MAX_CALL_MEDIA*2];
+ unsigned tp_cnt = 0;
+ unsigned j;
+
+ /* Collect media transports in this call */
+ for (j = 0; j < call->med_cnt; ++j) {
+ if (call->media[j].tp != NULL)
+ tp[tp_cnt++] = call->media[j].tp;
+ }
+ for (j = 0; j < call->med_prov_cnt; ++j) {
+ pjmedia_transport *med_tp = call->media_prov[j].tp;
+ if (med_tp) {
+ unsigned k;
+ pj_bool_t used = PJ_FALSE;
+ for (k = 0; k < tp_cnt; ++k) {
+ if (med_tp == tp[k]) {
+ used = PJ_TRUE;
+ break;
+ }
+ }
+ if (!used)
+ tp[tp_cnt++] = med_tp;
+ }
+ }
- PJ_LOG(3,(THIS_FILE, " %s: %s",
- (pjsua_var.media_cfg.enable_ice ? "ICE" : "UDP"),
- pj_sockaddr_print(&tpinfo.sock_info.rtp_addr_name, addr_buf,
- sizeof(addr_buf), 3)));
+ /* Dump the media transports in this call */
+ for (j = 0; j < tp_cnt; ++j) {
+ pjmedia_transport_info tpinfo;
+ char addr_buf[80];
+
+ pjmedia_transport_info_init(&tpinfo);
+ pjmedia_transport_get_info(tp[j], &tpinfo);
+ PJ_LOG(3,(THIS_FILE, " %s: %s",
+ (pjsua_var.media_cfg.enable_ice ? "ICE" : "UDP"),
+ pj_sockaddr_print(&tpinfo.sock_info.rtp_addr_name,
+ addr_buf,
+ sizeof(addr_buf), 3)));
+ }
}
-#endif
pjsip_tsx_layer_dump(detail);
pjsip_ua_dump(detail);
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index db36b236..394ac0b4 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -1145,6 +1145,7 @@ static pj_status_t call_media_init_cb(pjsua_call_media *call_med,
/* Always create SRTP adapter */
pjmedia_srtp_setting_default(&srtp_opt);
srtp_opt.close_member_tp = PJ_TRUE;
+
/* If media session has been ever established, let's use remote's
* preference in SRTP usage policy, especially when it is stricter.
*/
@@ -1179,6 +1180,7 @@ static pj_status_t call_media_init_cb(pjsua_call_media *call_med,
on_return:
if (status != PJ_SUCCESS && call_med->tp) {
+ pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
pjmedia_transport_close(call_med->tp);
call_med->tp = NULL;
}
@@ -1217,7 +1219,14 @@ pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
*/
call_med->type = type;
- /* Create the media transport for initial call. */
+ /* Create the media transport for initial call. Here are the possible
+ * media transport state and the action needed:
+ * - PJSUA_MED_TP_NULL or call_med->tp==NULL, create one.
+ * - PJSUA_MED_TP_RUNNING, do nothing.
+ * - PJSUA_MED_TP_DISABLED, re-init (media_create(), etc). Currently,
+ * this won't happen as media_channel_update() will always clean up
+ * the unused transport of a disabled media.
+ */
if (call_med->tp == NULL) {
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
/* While in initial call, set default video devices */
@@ -1257,7 +1266,9 @@ pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
} else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) {
/* Media is being reenabled. */
- pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_INIT);
+ //pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
+
+ pj_assert(!"Currently no media transport reuse");
}
return call_media_init_cb(call_med, status, security_level,
@@ -1280,7 +1291,7 @@ static pj_status_t media_channel_init_cb(pjsua_call_id call_id,
/* Set the callback to NULL to indicate that the async operation
* has completed.
*/
- call->media[info->med_idx].med_init_cb = NULL;
+ call->media_prov[info->med_idx].med_init_cb = NULL;
/* In case of failure, save the information to be returned
* by the last media transport to finish.
@@ -1291,8 +1302,8 @@ static pj_status_t media_channel_init_cb(pjsua_call_id call_id,
/* Check whether all the call's medias have finished calling their
* callbacks.
*/
- for (mi=0; mi < call->med_cnt; ++mi) {
- pjsua_call_media *call_med = &call->media[mi];
+ for (mi=0; mi < call->med_prov_cnt; ++mi) {
+ pjsua_call_media *call_med = &call->media_prov[mi];
if (call_med->med_init_cb) {
pj_mutex_unlock(call->med_ch_mutex);
@@ -1313,13 +1324,13 @@ static pj_status_t media_channel_init_cb(pjsua_call_id call_id,
}
if (status != PJ_SUCCESS) {
- pjsua_media_channel_deinit(call_id);
+ pjsua_media_prov_clean_up(call_id);
goto on_return;
}
/* Tell the media transport of a new offer/answer session */
- for (mi=0; mi < call->med_cnt; ++mi) {
- pjsua_call_media *call_med = &call->media[mi];
+ for (mi=0; mi < call->med_prov_cnt; ++mi) {
+ pjsua_call_media *call_med = &call->media_prov[mi];
/* Note: tp may be NULL if this media line is disabled */
if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) {
@@ -1354,7 +1365,7 @@ static pj_status_t media_channel_init_cb(pjsua_call_id call_id,
call->med_ch_info.med_idx = mi;
call->med_ch_info.state = call_med->tp_st;
call->med_ch_info.sip_err_code = PJSIP_SC_NOT_ACCEPTABLE;
- pjsua_media_channel_deinit(call_id);
+ pjsua_media_prov_clean_up(call_id);
goto on_return;
}
@@ -1371,6 +1382,43 @@ on_return:
return status;
}
+
+/* Clean up media transports in provisional media that is not used
+ * by call media.
+ */
+void pjsua_media_prov_clean_up(pjsua_call_id call_id)
+{
+ pjsua_call *call = &pjsua_var.calls[call_id];
+ unsigned i;
+
+ for (i = 0; i < call->med_prov_cnt; ++i) {
+ pjsua_call_media *call_med = &call->media_prov[i];
+ unsigned j;
+ pj_bool_t used = PJ_FALSE;
+
+ if (call_med->tp == NULL)
+ continue;
+
+ for (j = 0; j < call->med_cnt; ++j) {
+ if (call->media[j].tp == call_med->tp) {
+ used = PJ_TRUE;
+ break;
+ }
+ }
+
+ if (!used) {
+ if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
+ pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
+ pjmedia_transport_media_stop(call_med->tp);
+ }
+ 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;
+ }
+ }
+}
+
+
pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
pjsip_role_e role,
int security_level,
@@ -1422,6 +1470,24 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
pj_log_push_indent();
+ /* Init provisional media state */
+ if (call->med_cnt == 0) {
+ /* New media session, just copy whole from call media state. */
+ pj_memcpy(call->media_prov, call->media, sizeof(call->media));
+ } else {
+ /* Clean up any unused transports. Note that when local SDP reoffer
+ * is rejected by remote, there may be any initialized transports that
+ * are not used by call media and currently there is no notification
+ * from PJSIP level regarding the reoffer rejection.
+ */
+ pjsua_media_prov_clean_up(call_id);
+
+ /* Updating media session, copy from call media state. */
+ pj_memcpy(call->media_prov, call->media,
+ sizeof(call->media[0]) * call->med_cnt);
+ }
+ call->med_prov_cnt = call->med_cnt;
+
#if DISABLED_FOR_TICKET_1185
/* Return error if media transport has not been created yet
* (e.g. application is starting)
@@ -1441,7 +1507,6 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
if (maudcnt==0) {
/* Expecting audio in the offer */
if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
- pjsua_media_channel_deinit(call_id);
status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
goto on_error;
}
@@ -1458,8 +1523,9 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
* must never decrease. Also note that we shouldn't apply the media
* count setting (of the call setting) before the SDP negotiation.
*/
- if (call->med_cnt < rem_sdp->media_count)
- call->med_cnt = PJ_MIN(rem_sdp->media_count, PJSUA_MAX_CALL_MEDIA);
+ if (call->med_prov_cnt < rem_sdp->media_count)
+ call->med_prov_cnt = PJ_MIN(rem_sdp->media_count,
+ PJSUA_MAX_CALL_MEDIA);
call->rem_offerer = PJ_TRUE;
call->rem_aud_cnt = maudcnt;
@@ -1495,7 +1561,7 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
mtotaudcnt < call->opt.aud_cnt)
{
for (mi = 0; mi < call->opt.aud_cnt - mtotaudcnt; ++mi)
- maudidx[maudcnt++] = (pj_uint8_t)call->med_cnt++;
+ maudidx[maudcnt++] = (pj_uint8_t)call->med_prov_cnt++;
mtotaudcnt = call->opt.aud_cnt;
}
@@ -1506,7 +1572,7 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
mtotvidcnt < call->opt.vid_cnt)
{
for (mi = 0; mi < call->opt.vid_cnt - mtotvidcnt; ++mi)
- mvididx[mvidcnt++] = (pj_uint8_t)call->med_cnt++;
+ mvididx[mvidcnt++] = (pj_uint8_t)call->med_prov_cnt++;
mtotvidcnt = call->opt.vid_cnt;
}
@@ -1522,18 +1588,18 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
for (mi=0; mi<mvidcnt; ++mi) {
mvididx[mi] = (pj_uint8_t)(maudcnt + mi);
}
- call->med_cnt = maudcnt + mvidcnt;
+ call->med_prov_cnt = maudcnt + mvidcnt;
/* Need to publish supported media? */
if (call->opt.flag & PJSUA_CALL_INCLUDE_DISABLED_MEDIA) {
if (mtotaudcnt == 0) {
mtotaudcnt = 1;
- maudidx[0] = (pj_uint8_t)call->med_cnt++;
+ maudidx[0] = (pj_uint8_t)call->med_prov_cnt++;
}
#if PJMEDIA_HAS_VIDEO
if (mtotvidcnt == 0) {
mtotvidcnt = 1;
- mvididx[0] = (pj_uint8_t)call->med_cnt++;
+ mvididx[0] = (pj_uint8_t)call->med_prov_cnt++;
}
#endif
}
@@ -1542,10 +1608,9 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
call->rem_offerer = PJ_FALSE;
}
- if (call->med_cnt == 0) {
+ if (call->med_prov_cnt == 0) {
/* Expecting at least one media */
if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
- pjsua_media_channel_deinit(call_id);
status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
goto on_error;
}
@@ -1564,8 +1629,8 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
call->async_call.pool_prov = tmp_pool;
/* Initialize each media line */
- for (mi=0; mi < call->med_cnt; ++mi) {
- pjsua_call_media *call_med = &call->media[mi];
+ for (mi=0; mi < call->med_prov_cnt; ++mi) {
+ pjsua_call_media *call_med = &call->media_prov[mi];
pj_bool_t enabled = PJ_FALSE;
pjmedia_type media_type = PJMEDIA_TYPE_UNKNOWN;
@@ -1609,7 +1674,7 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
return PJ_EPENDING;
}
- pjsua_media_channel_deinit(call_id);
+ pjsua_media_prov_clean_up(call_id);
goto on_error;
}
} else {
@@ -1618,7 +1683,9 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
*/
if (call_med->tp) {
// Don't close transport here, as SDP negotiation has not been
- // done and stream may be still active.
+ // done and stream may be still active. Once SDP negotiation
+ // is done (channel_update() invoked), this transport will be
+ // closed there.
//pjmedia_transport_close(call_med->tp);
//call_med->tp = NULL;
pj_assert(call_med->tp_st == PJSUA_MED_TP_INIT ||
@@ -1735,14 +1802,14 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
/* Get one address to use in the origin field */
pj_bzero(&origin, sizeof(origin));
- for (mi=0; mi<call->med_cnt; ++mi) {
+ for (mi=0; mi<call->med_prov_cnt; ++mi) {
pjmedia_transport_info tpinfo;
- if (call->media[mi].tp == NULL)
+ if (call->media_prov[mi].tp == NULL)
continue;
pjmedia_transport_info_init(&tpinfo);
- pjmedia_transport_get_info(call->media[mi].tp, &tpinfo);
+ pjmedia_transport_get_info(call->media_prov[mi].tp, &tpinfo);
pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name);
break;
}
@@ -1754,8 +1821,8 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
return status;
/* Process each media line */
- for (mi=0; mi<call->med_cnt; ++mi) {
- pjsua_call_media *call_med = &call->media[mi];
+ for (mi=0; mi<call->med_prov_cnt; ++mi) {
+ pjsua_call_media *call_med = &call->media_prov[mi];
pjmedia_sdp_media *m = NULL;
pjmedia_transport_info tpinfo;
unsigned i;
@@ -1998,6 +2065,34 @@ static void stop_media_session(pjsua_call_id call_id)
call_id, mi));
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];
+
+ /* 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;
+
+ /* 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
+ }
}
pj_log_pop_indent();
@@ -2028,21 +2123,19 @@ pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
stop_media_session(call_id);
+ /* Clean up media transports */
+ pjsua_media_prov_clean_up(call_id);
+ call->med_prov_cnt = 0;
for (mi=0; mi<call->med_cnt; ++mi) {
pjsua_call_media *call_med = &call->media[mi];
if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
- pjmedia_transport_media_stop(call_med->tp);
pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
+ pjmedia_transport_media_stop(call_med->tp);
}
- //if (call_med->tp_orig && call_med->tp &&
- // call_med->tp != call_med->tp_orig)
- //{
- // pjmedia_transport_close(call_med->tp);
- // call_med->tp = call_med->tp_orig;
- //}
if (call_med->tp) {
+ 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;
}
@@ -2088,7 +2181,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
/* 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.
*/
- pj_assert(call->med_cnt >= local_sdp->media_count);
+ pj_assert(call->med_prov_cnt >= local_sdp->media_count);
/* Reset audio_idx first */
call->audio_idx = -1;
@@ -2135,8 +2228,8 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
}
/* Process each media stream */
- for (mi=0; mi < call->med_cnt; ++mi) {
- pjsua_call_media *call_med = &call->media[mi];
+ for (mi=0; mi < call->med_prov_cnt; ++mi) {
+ pjsua_call_media *call_med = &call->media_prov[mi];
if (mi >= local_sdp->media_count ||
mi >= remote_sdp->media_count)
@@ -2287,10 +2380,8 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
/* Check if no media is active */
if (si->dir == PJMEDIA_DIR_NONE) {
- /* Call media state */
+ /* Update call media state and direction */
call_med->state = PJSUA_CALL_MEDIA_NONE;
-
- /* Call media direction */
call_med->dir = PJMEDIA_DIR_NONE;
} else {
@@ -2393,9 +2484,9 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
* (account) setting.
*/
if (local_sdp->media[mi]->desc.port==0 && call_med->tp) {
+ 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;
- pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
}
if (status != PJ_SUCCESS) {
@@ -2406,6 +2497,11 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
}
}
+ /* Update call media from provisional media */
+ call->med_cnt = call->med_prov_cnt;
+ pj_memcpy(call->media, call->media_prov,
+ sizeof(call->media_prov[0]) * call->med_prov_cnt);
+
/* Perform SDP re-negotiation if needed. */
if (got_media && need_renego_sdp) {
pjmedia_sdp_neg *neg = call->inv->neg;
diff --git a/pjsip/src/pjsua-lib/pjsua_vid.c b/pjsip/src/pjsua-lib/pjsua_vid.c
index 5b5f83a2..6e5a83e9 100644
--- a/pjsip/src/pjsua-lib/pjsua_vid.c
+++ b/pjsip/src/pjsua-lib/pjsua_vid.c
@@ -1532,9 +1532,16 @@ static pj_status_t call_add_video(pjsua_call *call,
sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, current_sdp);
- /* Initialize call media */
- call_med = &call->media[call->med_cnt++];
+ /* Clean up provisional media before using it */
+ pjsua_media_prov_clean_up(call->index);
+
+ /* Update provisional media from call media */
+ call->med_prov_cnt = call->med_cnt;
+ pj_memcpy(call->media_prov, call->media,
+ sizeof(call->media[0]) * call->med_cnt);
+ /* Initialize call media */
+ call_med = &call->media_prov[call->med_prov_cnt++];
status = pjsua_call_media_init(call_med, PJMEDIA_TYPE_VIDEO,
&acc_cfg->rtp_cfg, call->secure_level,
NULL, PJ_FALSE, NULL);
@@ -1597,6 +1604,7 @@ static pj_status_t call_add_video(pjsua_call *call,
on_error:
if (call_med->tp) {
+ 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;
}
@@ -1629,7 +1637,15 @@ static pj_status_t call_modify_video(pjsua_call *call,
med_idx = first_active;
}
- call_med = &call->media[med_idx];
+ /* Clean up provisional media before using it */
+ pjsua_media_prov_clean_up(call->index);
+
+ /* Update provisional media from call media */
+ call->med_prov_cnt = call->med_cnt;
+ pj_memcpy(call->media_prov, call->media,
+ sizeof(call->media[0]) * call->med_cnt);
+
+ call_med = &call->media_prov[med_idx];
/* Verify if the stream media type is video */
if (call_med->type != PJMEDIA_TYPE_VIDEO)
@@ -1735,6 +1751,7 @@ static pj_status_t call_modify_video(pjsua_call *call,
on_error:
if (status != PJ_SUCCESS) {
+ pjsua_media_prov_clean_up(call->index);
return status;
}