summaryrefslogtreecommitdiff
path: root/pjsip/src/pjsua-lib/pjsua_media.c
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 /pjsip/src/pjsua-lib/pjsua_media.c
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
Diffstat (limited to 'pjsip/src/pjsua-lib/pjsua_media.c')
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c180
1 files changed, 138 insertions, 42 deletions
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;