summaryrefslogtreecommitdiff
path: root/pjsip/src/pjsua-lib/pjsua_call.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip/src/pjsua-lib/pjsua_call.c')
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c520
1 files changed, 302 insertions, 218 deletions
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index 29fbf6e7..bd72485f 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -106,6 +106,12 @@ static pj_status_t create_sdp_of_call_hold(pjsua_call *call,
static void xfer_client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
static void xfer_server_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
+/* Timer callback to send re-INVITE/UPDATE to lock codec or ICE update */
+static void reinv_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry);
+
+/* Check and send reinvite for lock codec and ICE update */
+static pj_status_t process_pending_reinvite(pjsua_call *call);
+
/*
* Reset call descriptor.
*/
@@ -128,6 +134,8 @@ static void reset_call(pjsua_call_id id)
call_med->tp_auto_del = PJ_TRUE;
}
pjsua_call_setting_default(&call->opt);
+ pj_timer_entry_init(&call->reinv_timer, PJ_FALSE,
+ (void*)(pj_size_t)id, &reinv_timer_cb);
}
@@ -2200,11 +2208,10 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
goto on_return;
}
- /* Stop lock codec timer, if it is active */
- if (call->lock_codec.reinv_timer.id) {
- pjsip_endpt_cancel_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer);
- call->lock_codec.reinv_timer.id = PJ_FALSE;
+ /* Stop reinvite timer, if it is active */
+ if (call->reinv_timer.id) {
+ pjsua_cancel_timer(&call->reinv_timer);
+ call->reinv_timer.id = PJ_FALSE;
}
on_return:
@@ -2894,12 +2901,8 @@ PJ_DEF(void) pjsua_call_hangup_all(void)
}
-/* Proto */
-static pj_status_t perform_lock_codec(pjsua_call *call);
-
-/* Timer callback to send re-INVITE or UPDATE to lock codec */
-static void reinv_timer_cb(pj_timer_heap_t *th,
- pj_timer_entry *entry)
+/* Timer callback to send re-INVITE/UPDATE to lock codec or ICE update */
+static void reinv_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry)
{
pjsua_call_id call_id = (pjsua_call_id)(pj_size_t)entry->user_data;
pjsip_dialog *dlg;
@@ -2908,21 +2911,27 @@ static void reinv_timer_cb(pj_timer_heap_t *th,
PJ_UNUSED_ARG(th);
- pjsua_var.calls[call_id].lock_codec.reinv_timer.id = PJ_FALSE;
+ pjsua_var.calls[call_id].reinv_timer.id = PJ_FALSE;
+
+ pj_log_push_indent();
status = acquire_call("reinv_timer_cb()", call_id, &call, &dlg);
- if (status != PJ_SUCCESS)
+ if (status != PJ_SUCCESS) {
+ pj_log_pop_indent();
return;
+ }
- status = perform_lock_codec(call);
+ process_pending_reinvite(call);
pjsip_dlg_dec_lock(dlg);
+
+ pj_log_pop_indent();
}
/* Check if the specified format can be skipped in counting codecs */
static pj_bool_t is_non_av_fmt(const pjmedia_sdp_media *m,
- const pj_str_t *fmt)
+ const pj_str_t *fmt)
{
const pj_str_t STR_TEL = {"telephone-event", 15};
unsigned pt;
@@ -2955,62 +2964,62 @@ static pj_bool_t is_non_av_fmt(const pjmedia_sdp_media *m,
}
-/* Send re-INVITE or UPDATE with new SDP offer to select only one codec
- * out of several codecs presented by callee in his answer.
+/* Schedule check for the need of re-INVITE/UPDATE after media update, cases:
+ * - lock codec if remote answerer has given us more than one codecs
+ * - update ICE default transport address if it has changed after ICE
+ * connectivity check.
*/
-static pj_status_t perform_lock_codec(pjsua_call *call)
+void pjsua_call_schedule_reinvite_check(pjsua_call *call, unsigned delay_ms)
{
- const pj_str_t STR_UPDATE = {"UPDATE", 6};
- const pjmedia_sdp_session *local_sdp = NULL, *new_sdp;
+ pj_time_val delay;
+
+ /* Stop reinvite timer, if it is active */
+ if (call->reinv_timer.id)
+ pjsua_cancel_timer(&call->reinv_timer);
+
+ delay.sec = 0;
+ delay.msec = delay_ms;
+ pj_time_val_normalize(&delay);
+ call->reinv_timer.id = PJ_TRUE;
+ pjsua_schedule_timer(&call->reinv_timer, &delay);
+}
+
+
+/* Check if lock codec is needed */
+static pj_bool_t check_lock_codec(pjsua_call *call)
+{
+ const pjmedia_sdp_session *local_sdp, *remote_sdp;
+ pj_bool_t has_mult_fmt = PJ_FALSE;
unsigned i;
- pj_bool_t rem_can_update;
- pj_bool_t need_lock_codec = PJ_FALSE;
- pjsip_tx_data *tdata;
pj_status_t status;
- PJ_ASSERT_RETURN(call->lock_codec.reinv_timer.id==PJ_FALSE,
- PJ_EINVALIDOP);
+ /* Check if lock codec is disabled */
+ if (!pjsua_var.acc[call->acc_id].cfg.lock_codec)
+ return PJ_FALSE;
- /* Verify if another SDP negotiation is in progress, e.g: session timer
- * or another re-INVITE.
- */
- if (call->inv==NULL || call->inv->neg==NULL ||
- pjmedia_sdp_neg_get_state(call->inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE)
- {
- return PJMEDIA_SDPNEG_EINSTATE;
- }
+ /* Check lock codec retry count */
+ if (call->lock_codec.retry_cnt >= LOCK_CODEC_MAX_RETRY)
+ return PJ_FALSE;
- /* Don't do this if call is disconnecting! */
- if (call->inv->state > PJSIP_INV_STATE_CONFIRMED ||
- call->inv->cause >= 200)
- {
- return PJ_EINVALIDOP;
- }
+ /* Check if we are the answerer, we shouldn't need to lock codec */
+ if (!call->inv->neg || !pjmedia_sdp_neg_was_answer_remote(call->inv->neg))
+ return PJ_FALSE;
- /* Verify if another SDP negotiation has been completed by comparing
- * the SDP version.
- */
+ /* Check if remote answerer has given us more than one codecs. */
status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
if (status != PJ_SUCCESS)
- return status;
- if (local_sdp->origin.version > call->lock_codec.sdp_ver)
- return PJMEDIA_SDP_EINVER;
-
- PJ_LOG(3, (THIS_FILE, "Updating media session to use only one codec.."));
-
- /* Update the new offer so it contains only a codec. Note that formats
- * order in the offer should have been matched to the answer, so we can
- * just directly update the offer without looking-up the answer.
- */
- new_sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, local_sdp);
+ return PJ_FALSE;
+ status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
+ if (status != PJ_SUCCESS)
+ return PJ_FALSE;
- for (i = 0; i < call->med_cnt; ++i) {
- unsigned j = 0, codec_cnt = 0;
- const pjmedia_sdp_media *ref_m;
- pjmedia_sdp_media *m;
+ for (i = 0; i < call->med_cnt && !has_mult_fmt; ++i) {
pjsua_call_media *call_med = &call->media[i];
+ const pjmedia_sdp_media *rem_m, *loc_m;
+ unsigned codec_cnt = 0;
+ unsigned j;
- /* Verify if media is deactivated */
+ /* Skip this if the media is inactive or error */
if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
call_med->state == PJSUA_CALL_MEDIA_ERROR ||
call_med->dir == PJMEDIA_DIR_NONE)
@@ -3018,196 +3027,279 @@ static pj_status_t perform_lock_codec(pjsua_call *call)
continue;
}
- ref_m = local_sdp->media[i];
- m = new_sdp->media[i];
-
- /* Verify that media must be active. */
- pj_assert(ref_m->desc.port);
+ /* Remote may answer with less media lines. */
+ if (i >= remote_sdp->media_count)
+ continue;
- while (j < m->desc.fmt_count) {
- pjmedia_sdp_attr *a;
- pj_str_t *fmt = &m->desc.fmt[j];
+ rem_m = remote_sdp->media[i];
+ loc_m = local_sdp->media[i];
- if (is_non_av_fmt(m, fmt) || (++codec_cnt == 1)) {
- ++j;
- continue;
- }
+ /* Verify that media must be active. */
+ pj_assert(loc_m->desc.port && rem_m->desc.port);
- /* Remove format */
- a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "rtpmap", fmt);
- if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a);
- a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "fmtp", fmt);
- if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a);
- pj_array_erase(m->desc.fmt, sizeof(m->desc.fmt[0]),
- m->desc.fmt_count, j);
- --m->desc.fmt_count;
+ /* Count the formats in the answer. */
+ for (j=0; j<rem_m->desc.fmt_count && codec_cnt <= 1; ++j) {
+ if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[j]) && ++codec_cnt > 1)
+ has_mult_fmt = PJ_TRUE;
}
-
- need_lock_codec |= (ref_m->desc.fmt_count > m->desc.fmt_count);
}
- /* Last check if SDP trully needs to be updated. It is possible that OA
- * negotiations have completed and SDP has changed but we didn't
- * increase the SDP version (should not happen!).
- */
- if (!need_lock_codec)
- return PJ_SUCCESS;
+ /* Reset retry count when remote answer has one codec */
+ if (!has_mult_fmt)
+ call->lock_codec.retry_cnt = 0;
- /* Send UPDATE or re-INVITE */
- rem_can_update = pjsip_dlg_remote_has_cap(call->inv->dlg,
- PJSIP_H_ALLOW,
- NULL, &STR_UPDATE) ==
- PJSIP_DIALOG_CAP_SUPPORTED;
- if (rem_can_update) {
- status = pjsip_inv_update(call->inv, NULL, new_sdp, &tdata);
- } else {
- status = pjsip_inv_reinvite(call->inv, NULL, new_sdp, &tdata);
- }
+ return has_mult_fmt;
+}
- if (status==PJ_EINVALIDOP &&
- ++call->lock_codec.retry_cnt <= LOCK_CODEC_MAX_RETRY)
- {
- /* Ups, let's reschedule again */
- pj_time_val delay = {0, LOCK_CODEC_RETRY_INTERVAL};
- pj_time_val_normalize(&delay);
- call->lock_codec.reinv_timer.id = PJ_TRUE;
- pjsip_endpt_schedule_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer, &delay);
- return status;
- } else if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Error creating UPDATE/re-INVITE to lock codec",
- status);
- return status;
- }
+/* Check if ICE setup is complete and if it needs to send reinvite */
+static pj_bool_t check_ice_complete(pjsua_call *call, pj_bool_t *need_reinv)
+{
+ pj_bool_t ice_need_reinv = PJ_FALSE;
+ pj_bool_t ice_complete = PJ_TRUE;
+ unsigned i;
- /* Send the UPDATE/re-INVITE request */
- status = pjsip_inv_send_msg(call->inv, tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Error sending UPDATE/re-INVITE in lock codec",
- status);
- return status;
+ /* Check if ICE setup is complete and if it needs reinvite */
+ for (i = 0; i < call->med_cnt && ice_complete; ++i) {
+ pjsua_call_media *call_med = &call->media[i];
+ pjmedia_transport_info tpinfo;
+ unsigned j;
+
+ if (call_med->tp_st == PJSUA_MED_TP_NULL ||
+ call_med->tp_st == PJSUA_MED_TP_DISABLED ||
+ call_med->state == PJSUA_CALL_MEDIA_ERROR)
+ {
+ continue;
+ }
+
+ pjmedia_transport_info_init(&tpinfo);
+ pjmedia_transport_get_info(call_med->tp, &tpinfo);
+ for (j = 0; j < tpinfo.specific_info_cnt; ++j) {
+ pjmedia_ice_transport_info *ice_info;
+
+ if (tpinfo.spc_info[j].type != PJMEDIA_TRANSPORT_TYPE_ICE)
+ continue;
+
+ ice_info = (pjmedia_ice_transport_info*)tpinfo.spc_info[j].buffer;
+
+ /* Check if ICE setup not completed yet */
+ if (ice_info->sess_state < PJ_ICE_STRANS_STATE_RUNNING) {
+ ice_complete = PJ_FALSE;
+ break;
+ }
+
+ /* Check if ICE needs to send reinvite */
+ if (!ice_need_reinv &&
+ ice_info->sess_state == PJ_ICE_STRANS_STATE_RUNNING &&
+ ice_info->role == PJ_ICE_SESS_ROLE_CONTROLLING)
+ {
+ pjsua_ice_config *cfg=&pjsua_var.acc[call->acc_id].cfg.ice_cfg;
+ if ((cfg->ice_always_update && !call->reinv_ice_sent) ||
+ pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name,
+ &call_med->rtp_addr))
+ {
+ ice_need_reinv = PJ_TRUE;
+ }
+ }
+ break;
+ }
}
-
- return status;
+
+ if (ice_complete && need_reinv)
+ *need_reinv = ice_need_reinv;
+
+ return ice_complete;
}
-/* Check if remote answerer has given us more than one codecs. If so,
- * create another offer with one codec only to lock down the codec.
- */
-static pj_status_t lock_codec(pjsua_call *call)
+/* Check and send reinvite for lock codec and ICE update */
+static pj_status_t process_pending_reinvite(pjsua_call *call)
{
+ const pj_str_t ST_UPDATE = {"UPDATE", 6};
+ pj_pool_t *pool = call->inv->pool_prov;
pjsip_inv_session *inv = call->inv;
- const pjmedia_sdp_session *local_sdp, *remote_sdp;
- pj_time_val delay = {0, 0};
- const pj_str_t st_update = {"UPDATE", 6};
+ pj_bool_t ice_need_reinv;
+ pj_bool_t ice_completed;
+ pj_bool_t need_lock_codec;
+ pj_bool_t rem_can_update;
+ pjmedia_sdp_session *new_offer;
+ pjsip_tx_data *tdata;
unsigned i;
- pj_bool_t has_mult_fmt = PJ_FALSE;
pj_status_t status;
- if (!pjsua_var.acc[call->acc_id].cfg.lock_codec) {
- return PJ_SUCCESS;
- }
-
- /* Stop lock codec timer, if it is active */
- if (call->lock_codec.reinv_timer.id) {
- pjsip_endpt_cancel_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer);
- call->lock_codec.reinv_timer.id = PJ_FALSE;
+ /* Verify if another SDP negotiation is in progress, e.g: session timer
+ * or another re-INVITE.
+ */
+ if (inv==NULL || inv->neg==NULL ||
+ pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE)
+ {
+ return PJMEDIA_SDPNEG_EINSTATE;
}
- /* Skip this if we are the answerer */
- if (!inv->neg || !pjmedia_sdp_neg_was_answer_remote(inv->neg)) {
- return PJ_SUCCESS;
+ /* Don't do this if call is disconnecting! */
+ if (inv->state > PJSIP_INV_STATE_CONFIRMED || inv->cause >= 200)
+ {
+ return PJ_EINVALIDOP;
}
/* Delay this when the SDP negotiation done in call state EARLY and
* remote does not support UPDATE method.
*/
if (inv->state == PJSIP_INV_STATE_EARLY &&
- pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &st_update)!=
+ pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &ST_UPDATE)!=
PJSIP_DIALOG_CAP_SUPPORTED)
{
- call->lock_codec.pending = PJ_TRUE;
- return PJ_SUCCESS;
+ call->reinv_pending = PJ_TRUE;
+ return PJ_EPENDING;
}
- status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
- if (status != PJ_SUCCESS)
- return status;
- status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
- if (status != PJ_SUCCESS)
- return status;
+ /* Check if ICE setup is complete and if it needs reinvite */
+ ice_completed = check_ice_complete(call, &ice_need_reinv);
+ if (!ice_completed)
+ return PJ_EPENDING;
- /* Find multiple codecs answer in all media */
- for (i = 0; i < call->med_cnt; ++i) {
- pjsua_call_media *call_med = &call->media[i];
- const pjmedia_sdp_media *rem_m, *loc_m;
- unsigned codec_cnt = 0;
+ /* Check if we need to lock codec */
+ need_lock_codec = check_lock_codec(call);
- /* Skip this if the media is inactive or error */
- if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
- call_med->state == PJSUA_CALL_MEDIA_ERROR ||
- call_med->dir == PJMEDIA_DIR_NONE)
- {
- continue;
- }
+ /* Check if reinvite is really needed */
+ if (!need_lock_codec && !ice_need_reinv)
+ return PJ_SUCCESS;
- /* Remote may answer with less media lines. */
- if (i >= remote_sdp->media_count)
- continue;
+
+ /* Okay! So we need to send re-INVITE/UPDATE */
- rem_m = remote_sdp->media[i];
- loc_m = local_sdp->media[i];
+ /* Check if remote support UPDATE */
+ rem_can_update = pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL,
+ &ST_UPDATE) ==
+ PJSIP_DIALOG_CAP_SUPPORTED;
- /* Verify that media must be active. */
- pj_assert(loc_m->desc.port && rem_m->desc.port);
+ /* Logging stuff */
+ {
+ const char *ST_ICE_UPDATE = "ICE transport address after "
+ "ICE negotiation";
+ const char *ST_LOCK_CODEC = "media session to use only one codec";
+ PJ_LOG(4,(THIS_FILE, "Call %d sending %s for updating %s%s%s",
+ call->index,
+ (rem_can_update? "UPDATE" : "re-INVITE"),
+ (ice_need_reinv? ST_ICE_UPDATE : ST_LOCK_CODEC),
+ (ice_need_reinv && need_lock_codec? " and " : ""),
+ (ice_need_reinv && need_lock_codec? ST_LOCK_CODEC : "")
+ ));
+ }
+
+ /* Generate SDP re-offer */
+ status = pjsua_media_channel_create_sdp(call->index, pool, NULL,
+ &new_offer, NULL);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
+ return status;
+ }
- /* Count the formats in the answer. */
- if (rem_m->desc.fmt_count==1) {
- codec_cnt = 1;
- } else {
- unsigned j;
- for (j=0; j<rem_m->desc.fmt_count && codec_cnt <= 1; ++j) {
- if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[j]))
- ++codec_cnt;
- }
+ /* Update the new offer so it contains only a codec. Note that
+ * SDP nego has removed unmatched codecs from the offer and the codec
+ * order in the offer has been matched to the answer, so we'll override
+ * the codecs in the just generated SDP with the ones from the active
+ * local SDP and leave just one codec for the next SDP re-offer.
+ */
+ if (need_lock_codec) {
+ const pjmedia_sdp_session *ref_sdp;
+
+ /* Get local active SDP as reference */
+ status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &ref_sdp);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Verify media count. Note that remote may add/remove media line
+ * in the answer. When answer has less media, it must have been
+ * handled by pjsua_media_channel_update() as disabled media.
+ * When answer has more media, it must have been ignored (treated
+ * as non-exist) anywhere. Local media count should not be updated
+ * at this point, as modifying media count operation (i.e: reinvite,
+ * update, vid_set_strm) is currently blocking, protected with
+ * dialog mutex, and eventually reset SDP nego state to LOCAL OFFER.
+ */
+ if (call->med_cnt != ref_sdp->media_count ||
+ ref_sdp->media_count != new_offer->media_count)
+ {
+ /* Anyway, just in case, let's just return error */
+ return PJMEDIA_SDPNEG_EINSTATE;
}
- if (codec_cnt > 1) {
- has_mult_fmt = PJ_TRUE;
- break;
+ for (i = 0; i < call->med_cnt; ++i) {
+ unsigned j, codec_cnt = 0;
+ const pjmedia_sdp_media *ref_m = ref_sdp->media[i];
+ pjmedia_sdp_media *m = new_offer->media[i];
+ pjsua_call_media *call_med = &call->media[i];
+
+ /* Verify if media is deactivated */
+ if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
+ call_med->state == PJSUA_CALL_MEDIA_ERROR ||
+ call_med->dir == PJMEDIA_DIR_NONE)
+ {
+ continue;
+ }
+
+ /* Reset formats */
+ m->desc.fmt_count = 0;
+ pjmedia_sdp_attr_remove_all(&m->attr_count, m->attr, "rtpmap");
+ pjmedia_sdp_attr_remove_all(&m->attr_count, m->attr, "fmtp");
+
+ /* Copy only the first format + any non-AV formats from
+ * the active local SDP.
+ */
+ for (j = 0; j < ref_m->desc.fmt_count; ++j) {
+ const pj_str_t *fmt = &ref_m->desc.fmt[j];
+
+ if (is_non_av_fmt(ref_m, fmt) || (++codec_cnt == 1)) {
+ pjmedia_sdp_attr *a;
+
+ m->desc.fmt[m->desc.fmt_count++] = *fmt;
+ a = pjmedia_sdp_attr_find2(ref_m->attr_count, ref_m->attr,
+ "rtpmap", fmt);
+ if (a) pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
+ a = pjmedia_sdp_attr_find2(ref_m->attr_count, ref_m->attr,
+ "fmtp", fmt);
+ if (a) pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
+ }
+
+ }
}
}
+
+ if (rem_can_update) {
+ status = pjsip_inv_update(inv, NULL, new_offer, &tdata);
+ } else {
+ status = pjsip_inv_reinvite(inv, NULL, new_offer, &tdata);
+ }
- /* Each media in the answer already contains single codec. */
- if (!has_mult_fmt) {
- call->lock_codec.retry_cnt = 0;
+ if (status==PJ_EINVALIDOP &&
+ ++call->lock_codec.retry_cnt < LOCK_CODEC_MAX_RETRY)
+ {
+ /* Ups, let's reschedule again */
+ pjsua_call_schedule_reinvite_check(call, LOCK_CODEC_RETRY_INTERVAL);
return PJ_SUCCESS;
+ } else if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating UPDATE/re-INVITE",
+ status);
+ return status;
}
- /* Remote keeps answering with multiple codecs, let's just give up
- * locking codec to avoid infinite retry loop.
- */
- if (++call->lock_codec.retry_cnt > LOCK_CODEC_MAX_RETRY)
- return PJ_SUCCESS;
-
- PJ_LOG(4, (THIS_FILE, "Got answer with multiple codecs, scheduling "
- "updating media session to use only one codec.."));
-
- call->lock_codec.sdp_ver = local_sdp->origin.version;
-
- /* Can't send UPDATE or re-INVITE now, so just schedule it immediately.
- * See: https://trac.pjsip.org/repos/ticket/1149
- */
- pj_timer_entry_init(&call->lock_codec.reinv_timer, PJ_TRUE,
- (void*)(pj_size_t)call->index,
- &reinv_timer_cb);
- pjsip_endpt_schedule_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer, &delay);
+ /* Send the UPDATE/re-INVITE request */
+ status = pjsip_inv_send_msg(inv, tdata);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error sending UPDATE/re-INVITE",
+ status);
+ return status;
+ }
+ /* Update flags */
+ if (ice_need_reinv)
+ call->reinv_ice_sent = PJ_TRUE;
+ if (need_lock_codec)
+ ++call->lock_codec.retry_cnt;
+
return PJ_SUCCESS;
}
+
/*
* This callback receives notification from invite session when the
* session state has changed.
@@ -3242,16 +3334,12 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
case PJSIP_INV_STATE_CONFIRMED:
pj_gettimeofday(&call->conn_time);
- /* See if lock codec was pended as media update was done in the
+ /* See if auto reinvite was pended as media update was done in the
* EARLY state and remote does not support UPDATE.
*/
- if (call->lock_codec.pending) {
- pj_status_t status;
- status = lock_codec(call);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to lock codec", status);
- }
- call->lock_codec.pending = PJ_FALSE;
+ if (call->reinv_pending) {
+ call->reinv_pending = PJ_FALSE;
+ pjsua_call_schedule_reinvite_check(call, 0);
}
break;
case PJSIP_INV_STATE_DISCONNECTED:
@@ -3273,11 +3361,10 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
sizeof(call->last_text_buf_));
}
- /* Stop lock codec timer, if it is active */
- if (call->lock_codec.reinv_timer.id) {
- pjsip_endpt_cancel_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer);
- call->lock_codec.reinv_timer.id = PJ_FALSE;
+ /* Stop reinvite timer, if it is active */
+ if (call->reinv_timer.id) {
+ pjsua_cancel_timer(&call->reinv_timer);
+ call->reinv_timer.id = PJ_FALSE;
}
break;
default:
@@ -3560,10 +3647,7 @@ static void pjsua_call_on_media_update(pjsip_inv_session *inv,
}
/* Ticket #476: make sure only one codec is specified in the answer. */
- status = lock_codec(call);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to lock codec", status);
- }
+ pjsua_call_schedule_reinvite_check(call, 0);
/* Call application callback, if any */
if (pjsua_var.ua_cfg.cb.on_call_media_state)