summaryrefslogtreecommitdiff
path: root/pjsip/src/pjsua-lib/pjsua_media.c
diff options
context:
space:
mode:
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;