summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-06-20 10:03:46 +0000
committerBenny Prijono <bennylp@teluu.com>2007-06-20 10:03:46 +0000
commita73bec4fabd296d54db391af0a29a97c5a149e2a (patch)
tree053eb1a8c0deae0ae278883e4b6d592a262dd1c1 /pjsip
parentff591488bfa7b642ae00ab48cff03129f6c71ae1 (diff)
More on ticket #399: a)send full offer on 200/OK response when re-INVITE does not have SDP, b) added on_create_offer() callback, c) handle some error cases
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1379 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/include/pjsip-ua/sip_inv.h21
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c58
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c53
3 files changed, 124 insertions, 8 deletions
diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h
index 3a144f80..e74abfac 100644
--- a/pjsip/include/pjsip-ua/sip_inv.h
+++ b/pjsip/include/pjsip-ua/sip_inv.h
@@ -149,7 +149,10 @@ typedef struct pjsip_inv_callback
/**
* This callback is called when the invite session has received
* new offer from peer. Application can inspect the remote offer
- * in "offer".
+ * in "offer", and set the SDP answer with #pjsip_inv_set_sdp_answer().
+ * When the application sends a SIP message to send the answer,
+ * this SDP answer will be negotiated with the offer, and the result
+ * will be sent with the SIP message.
*
* @param inv The invite session.
* @param offer Remote offer.
@@ -158,6 +161,22 @@ typedef struct pjsip_inv_callback
const pjmedia_sdp_session *offer);
/**
+ * This callback is optional, and it is used to ask the application
+ * to create a fresh offer, when the invite session has received
+ * re-INVITE without offer. This offer then will be sent in the
+ * 200/OK response to the re-INVITE request.
+ *
+ * If application doesn't implement this callback, the invite session
+ * will send the currently active SDP as the offer.
+ *
+ * @param inv The invite session.
+ * @param p_offer Pointer to receive the SDP offer created by
+ * application.
+ */
+ void (*on_create_offer)(pjsip_inv_session *inv,
+ pjmedia_sdp_session **p_offer);
+
+ /**
* This callback is called after SDP offer/answer session has completed.
* The status argument specifies the status of the offer/answer,
* as returned by pjmedia_sdp_neg_negotiate().
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index 984501f6..c26c8bce 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -1225,8 +1225,13 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
/* MUST NOT do multiple SDP offer/answer in a single transaction.
*/
- if (tsx_inv_data->sdp_done)
+ if (tsx_inv_data->sdp_done) {
+ if (rdata->msg_info.msg->body) {
+ PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
+ "body is ignored"));
+ }
return PJ_SUCCESS;
+ }
/* Check if SDP is present in the message. */
@@ -1383,11 +1388,19 @@ static pj_status_t process_answer( pjsip_inv_session *inv,
} else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
pjmedia_sdp_neg_has_local_answer(inv->neg) )
{
+ struct tsx_inv_data *tsx_inv_data;
+
+ /* Get invite session's transaction data */
+ tsx_inv_data = (struct tsx_inv_data*)
+ inv->invite_tsx->mod_data[mod_inv.mod.id];
status = inv_negotiate_sdp(inv);
if (status != PJ_SUCCESS)
return status;
+ /* Mark this transaction has having SDP offer/answer done. */
+ tsx_inv_data->sdp_done = 1;
+
status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
}
}
@@ -2503,12 +2516,33 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
if (rdata->msg_info.msg->body != NULL) {
status = process_answer(inv, 200, tdata, NULL);
} else {
- const pjmedia_sdp_session *active_sdp;
- status = pjmedia_sdp_neg_send_local_offer(dlg->pool,
- inv->neg,
- &active_sdp);
- if (status == PJ_SUCCESS) {
- tdata->msg->body = create_sdp_body(tdata->pool, active_sdp);
+ /* INVITE does not have SDP.
+ * If on_create_offer() callback is implemented, ask app.
+ * to generate an offer, otherwise just send active local
+ * SDP to signal that nothing gets modified.
+ */
+ pjmedia_sdp_session *sdp = NULL;
+
+ if (mod_inv.cb.on_create_offer) {
+ (*mod_inv.cb.on_create_offer)(inv, &sdp);
+ if (sdp) {
+ status = pjmedia_sdp_neg_modify_local_offer(dlg->pool,
+ inv->neg,
+ sdp);
+ }
+ }
+
+ if (sdp == NULL) {
+ const pjmedia_sdp_session *active_sdp = NULL;
+ status = pjmedia_sdp_neg_send_local_offer(dlg->pool,
+ inv->neg,
+ &active_sdp);
+ if (status == PJ_SUCCESS)
+ sdp = (pjmedia_sdp_session*) active_sdp;
+ }
+
+ if (sdp) {
+ tdata->msg->body = create_sdp_body(tdata->pool, sdp);
}
}
@@ -2604,6 +2638,16 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
*/
inv_set_cause(inv, tsx->status_code, &tsx->status_text);
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+
+ } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
+
+ pjmedia_sdp_neg_state neg_state;
+
+ /* Outgoing INVITE transaction has failed, cancel SDP nego */
+ neg_state = pjmedia_sdp_neg_get_state(inv->neg);
+ if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
+ pjmedia_sdp_neg_cancel_offer(inv->neg);
+ }
}
}
}
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index 247c3085..e362679d 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -50,6 +50,12 @@ static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
const pjmedia_sdp_session *offer);
/*
+ * Called to generate new offer.
+ */
+static void pjsua_call_on_create_offer(pjsip_inv_session *inv,
+ pjmedia_sdp_session **offer);
+
+/*
* This callback is called when transaction state has changed in INVITE
* session. We use this to trap:
* - incoming REFER request.
@@ -118,6 +124,7 @@ pj_status_t pjsua_call_subsys_init(const pjsua_config *cfg)
inv_cb.on_new_session = &pjsua_call_on_forked;
inv_cb.on_media_update = &pjsua_call_on_media_update;
inv_cb.on_rx_offer = &pjsua_call_on_rx_offer;
+ inv_cb.on_create_offer = &pjsua_call_on_create_offer;
inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed;
@@ -2295,6 +2302,52 @@ static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
/*
+ * Called to generate new offer.
+ */
+static void pjsua_call_on_create_offer(pjsip_inv_session *inv,
+ pjmedia_sdp_session **offer)
+{
+ pjsua_call *call;
+ pj_status_t status;
+
+ PJSUA_LOCK();
+
+ call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id];
+
+ /* See if we've put call on hold. */
+ if (call->media_st == PJSUA_CALL_MEDIA_LOCAL_HOLD) {
+ PJ_LOG(4,(THIS_FILE,
+ "Call %d: call is on-hold locally, creating inactive SDP ",
+ call->index));
+ status = create_inactive_sdp( call, offer );
+ } else {
+
+ PJ_LOG(4,(THIS_FILE, "Call %d: asked to send a new offer",
+ call->index));
+
+ /* Init media channel */
+ status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error initializing media channel", status);
+ PJSUA_UNLOCK();
+ return;
+ }
+
+ status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, offer);
+ }
+
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
+ PJSUA_UNLOCK();
+ return;
+ }
+
+
+ PJSUA_UNLOCK();
+}
+
+
+/*
* Callback called by event framework when the xfer subscription state
* has changed.
*/