[PATCH] New PJSUA callback on_missed_call

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If pjsua_call_on_incoming rejects an incoming call for any reason, the 
application won't be notified through the on_incoming_call callback. 
This patch adds an on_missed_call callback, so that the application has 
a chance to at least log the call that couldn't be accepted (for example 
in a call history database). Without such a callback, the only trace of 
the missed call would be in the PJSIP logs

The function that prepares the call to the user callback duplicates some 
code from pjsip_dlg_create_uas to initialize a pjsua_call_info 
structure, but it's inevitable: if the call was rejected because of one 
malformed header, pjsip_dlg_create_uas will fail, and won't provide even 
the partial information that _is_ well-formed
-------------- next part --------------
Index: pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjsip/include/pjsua-lib/pjsua.h	(revision 3711)
+++ pjsip/include/pjsua-lib/pjsua.h	(working copy)
@@ -283,6 +283,8 @@
 /** Forward declaration for pjsua_msg_data */
 typedef struct pjsua_msg_data pjsua_msg_data;
 
+/** Forward declaration for pjsua_call_info */
+typedef struct pjsua_call_info pjsua_call_info;
 
 /**
  * Maximum proxies in account.
@@ -681,6 +683,25 @@
 			     pjsip_rx_data *rdata);
 
     /**
+     * Notify application on rejected incoming call.
+     *
+     * @param acc_id	The account which match the incoming call.
+     * @param call_info	Infomation on the rejected call.
+     * @param rdata	The incoming INVITE request.
+     * @param status	The internal error that caused the call to
+     * 			be rejected.
+     * @param status_code
+     * 			The SIP code used to reject the call.
+     * @param status_text
+     * 			The SIP reason string used to reject the call.
+     */
+    void (*on_missed_call)(pjsua_acc_id acc_id,
+			   const pjsua_call_info *call_info,
+			   pjsip_rx_data *rdata, pj_status_t status,
+			   pjsip_status_code status_code,
+			   const pj_str_t *status_text);
+
+    /**
      * This is a general notification callback which is called whenever
      * a transaction within the call has changed state. Application can
      * implement this callback for example to monitor the state of
Index: pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- pjsip/src/pjsua-lib/pjsua_call.c	(revision 3711)
+++ pjsip/src/pjsua-lib/pjsua_call.c	(working copy)
@@ -1074,6 +1074,100 @@
 
 
 /**
+ * Notifies user of calls rejected by pjsua_call_on_incoming.
+ */
+static
+void on_missed_call(pjsip_rx_data *rdata, pj_status_t status, pjsip_status_code status_code, const pj_str_t *status_text)
+{
+    pjsua_call_info call_info;
+    int len;
+    pjsip_contact_hdr *contact_hdr;
+    pjsip_hdr *pos = NULL;
+
+    if (!pjsua_var.ua_cfg.cb.on_missed_call)
+	return;
+
+    if (status_text == NULL)
+	status_text = pjsip_get_status_text(status_code);
+
+    pj_bzero(&call_info, sizeof(call_info));
+
+    call_info.id = PJSUA_INVALID_ID;
+    call_info.role = PJSIP_ROLE_UAS;
+    call_info.acc_id = pjsua_acc_find_for_incoming(rdata);;
+    pjsua_call_setting_default(&call_info.setting);
+    call_info.state = PJSIP_INV_STATE_INCOMING;
+    call_info.state_text = pj_str((char *)pjsip_inv_state_name(call_info.state));
+
+    /* Local info (To: header) */
+    call_info.local_info.ptr = call_info.buf_.local_info;
+    call_info.local_info.slen = 0;
+
+    len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->msg_info.to->uri, call_info.buf_.local_info, sizeof(call_info.buf_.local_info));
+
+    if (len >= 0)
+	call_info.local_info.slen = len;
+
+    /* Local contact (outgoing Contact: header) */
+    call_info.local_contact.ptr = call_info.buf_.local_contact;
+    call_info.local_contact.slen = 0;
+
+    if (pjsua_var.acc[call_info.acc_id].contact.slen) {
+	pj_strncpy(&call_info.local_contact, &pjsua_var.acc[call_info.acc_id].contact, sizeof(call_info.buf_.local_contact));
+    } else {
+	pj_str_t contact;
+	pj_status_t status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact, call_info.acc_id, rdata);
+
+	if (status == PJ_SUCCESS) {
+	    pj_strncpy(&call_info.local_contact, &contact, sizeof(call_info.buf_.local_contact));
+	}
+    }
+
+    /* Remote info (From: header) */
+    call_info.remote_info.ptr = call_info.buf_.remote_info;
+    call_info.remote_info.slen = 0;
+
+    len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->msg_info.from->uri, call_info.buf_.remote_info, sizeof(call_info.buf_.remote_info));
+
+    if (len >= 0)
+	call_info.remote_info.slen = len;
+
+    /* Remote contact (Contact: header) */
+    call_info.remote_contact.ptr = call_info.buf_.remote_contact;
+    call_info.remote_contact.slen = 0;
+
+    do {
+	contact_hdr = (pjsip_contact_hdr *)pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, pos);
+	if (contact_hdr) {
+	    if (!contact_hdr->uri || (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri))) {
+		pos = (pjsip_hdr *)contact_hdr->next;
+		if (pos == &rdata->msg_info.msg->hdr)
+		    contact_hdr = NULL;
+	    }
+	    else {
+		break;
+	    }
+	}
+    }
+    while (contact_hdr);
+
+    if (contact_hdr) {
+	len = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri, call_info.buf_.remote_contact, sizeof(call_info.buf_.remote_contact));
+
+	if (len >= 0)
+	    call_info.remote_contact.slen = len;
+    }
+
+    /* Call id (Call-ID: header) */
+    call_info.call_id.ptr = call_info.buf_.call_id;
+    pj_strncpy(&call_info.call_id, &rdata->msg_info.cid->id, sizeof(call_info.buf_.call_id));
+
+    PJ_ASSERT_RETURN(pjsua_var.ua_cfg.cb.on_missed_call,);
+    pjsua_var.ua_cfg.cb.on_missed_call(call_info.acc_id, &call_info, rdata, status, status_code, status_text);
+}
+
+
+/**
  * Handle incoming INVITE request.
  * Called by pjsua_core.c
  */
@@ -1126,6 +1220,8 @@
 				      NULL, NULL);
 	PJ_LOG(2,(THIS_FILE,
 		  "Unable to accept incoming call (too many calls)"));
+
+	on_missed_call(rdata, PJ_SUCCESS, PJSIP_SC_BUSY_HERE, NULL);
 	goto on_return;
     }
 
@@ -1153,11 +1249,15 @@
 	    pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, response,
 				      NULL, NULL);
 
+	    on_missed_call(rdata, status, response->msg->line.status.code,
+			   &response->msg->line.status.reason);
 	} else {
 
 	    /* Respond with 500 (Internal Server Error) */
 	    pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
 					  NULL, NULL);
+
+	    on_missed_call(rdata, status, 500, NULL);
 	}
 
 	goto on_return;
@@ -1267,6 +1367,9 @@
 		pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 
 				    PJSIP_SC_UNSUPPORTED_MEDIA_TYPE,
 				    NULL, &hdr_list, NULL, NULL);
+
+		on_missed_call(rdata, status, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE,
+			       NULL);
 	    } else {
 		const pj_str_t reason = pj_str("Bad SDP");
 		pjsip_warning_hdr *w;
@@ -1282,6 +1385,8 @@
 
 		pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 400,
 				    &reason, &hdr_list, NULL, NULL);
+
+		on_missed_call(rdata, status, 400, &reason);
 	    }
 	    goto on_return;
 	}
@@ -1293,6 +1398,7 @@
 	    const pj_str_t reason = pj_str("Missing media in SDP");
 	    pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 400, &reason,
 				NULL, NULL, NULL);
+	    on_missed_call(rdata, PJ_SUCCESS, 400, &reason);
 	    goto on_return;
 	}
 
@@ -1326,10 +1432,14 @@
 	    pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, response,
 				      NULL, NULL);
 
+	    on_missed_call(rdata, status, response->msg->line.status.code,
+			   &response->msg->line.status.reason);
 	} else {
 	    /* Respond with 500 (Internal Server Error) */
 	    pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 500, NULL,
 				NULL, NULL, NULL);
+
+	    on_missed_call(rdata, status, 500, NULL);
 	}
 
 	goto on_return;
@@ -1346,6 +1456,7 @@
 			 status);
 	    pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
 					  NULL, NULL);
+	    on_missed_call(rdata, status, 500, NULL);
 	    goto on_return;
 	}
     }
@@ -1356,6 +1467,7 @@
     if (status != PJ_SUCCESS) {
 	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
 				      NULL, NULL);
+	on_missed_call(rdata, status, 500, NULL);
 	goto on_return;
     }
 
@@ -1434,6 +1546,7 @@
 	pj_list_push_back(&hdr_list, w);
 
 	pjsip_dlg_respond(dlg, rdata, 500, NULL, &hdr_list, NULL);
+	on_missed_call(rdata, status, 500, NULL);
 
 	/* Can't terminate dialog because transaction is in progress.
 	pjsip_dlg_terminate(dlg);
@@ -1486,6 +1599,7 @@
 		}
 		call->inv = NULL;
 		call->async_call.dlg = NULL;
+		on_missed_call(rdata, status, sip_err_code, NULL);
 		goto on_return;
 	    }
 	} else if (status != PJ_EPENDING) {
@@ -1496,6 +1610,7 @@
 	    }
 	    call->inv = NULL;
 	    call->async_call.dlg = NULL;
+	    on_missed_call(rdata, status, sip_err_code, NULL);
 	    goto on_return;
 	}
     }
@@ -1508,6 +1623,7 @@
 	pjsua_perror(THIS_FILE, "Error creating SDP answer", status);
 	pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata,
 			    sip_err_code, NULL, NULL, NULL, NULL);
+	on_missed_call(rdata, status, sip_err_code, NULL);
 	goto on_return;
     }
 */
@@ -1524,6 +1640,7 @@
 	call->inv = NULL;
 	call->async_call.dlg = NULL;
 
+	on_missed_call(rdata, status, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL);
 	goto on_return;
     }
 
@@ -1555,10 +1672,13 @@
 			 status);
 	    pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL);
 	    pjsip_inv_terminate(inv, 500, PJ_FALSE);
+	    on_missed_call(rdata, status, 500, NULL);
 	} else {
 	    pjsip_inv_send_msg(inv, response);
 	    pjsip_inv_terminate(inv, response->msg->line.status.code,
 				PJ_FALSE);
+	    on_missed_call(rdata, status, response->msg->line.status.code,
+			   &response->msg->line.status.reason);
 	}
 	pjsua_media_channel_deinit(call->index);
 	call->inv = NULL;
@@ -1572,6 +1692,7 @@
 	    pjsua_media_channel_deinit(call->index);
 	    call->inv = NULL;
 	    call->async_call.dlg = NULL;
+	    on_missed_call(rdata, status, 0, NULL);
 	    goto on_return;
 	}
     }
@@ -1605,6 +1726,8 @@
 	} else {
 	    pjsua_call_hangup(call_id, PJSIP_SC_TEMPORARILY_UNAVAILABLE,
 			      NULL, NULL);
+	    on_missed_call(rdata, PJ_SUCCESS, PJSIP_SC_TEMPORARILY_UNAVAILABLE,
+			   NULL);
 	}
     }
 


[Index of Archives]     [Asterisk Users]     [Asterisk App Development]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [Linux API]
  Powered by Linux