Ticket #391: Added framework to send and receive arbitrary requests within call in PJSUA-LIB, with samples to send/receive DTMF with INFO in pjsua application

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1477 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/docs/pjsua.jpg b/pjsip/docs/pjsua.jpg
index 479567b..c16a7a1 100644
--- a/pjsip/docs/pjsua.jpg
+++ b/pjsip/docs/pjsua.jpg
Binary files differ
diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h
index a367fe1..77a499e 100644
--- a/pjsip/include/pjsip-ua/sip_inv.h
+++ b/pjsip/include/pjsip-ua/sip_inv.h
@@ -133,7 +133,8 @@
     /**
      * This callback is called whenever any transactions within the session
      * has changed their state. Application MAY implement this callback, 
-     * e.g. to monitor the progress of an outgoing request.
+     * e.g. to monitor the progress of an outgoing request, or to send
+     * response to unhandled incoming request (such as INFO).
      *
      * This callback is optional.
      *
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index b727528..062943b 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -545,6 +545,21 @@
 			     pjsip_rx_data *rdata);
 
     /**
+     * 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 
+     * outgoing requests, or to answer unhandled incoming requests 
+     * (such as INFO) with a final response.
+     *
+     * @param call_id	Call identification.
+     * @param tsx	The transaction which has changed state.
+     * @param e		Transaction event that caused the state change.
+     */
+    void (*on_call_tsx_state)(pjsua_call_id call_id, 
+			      pjsip_transaction *tsx,
+			      pjsip_event *e);
+
+    /**
      * Notify application when media state in the call has changed.
      * Normal application would need to implement this callback, e.g.
      * to connect the call's media to sound device.
@@ -2907,6 +2922,24 @@
 						const pjsua_msg_data*msg_data);
 
 /**
+ * Send arbitrary request with the call. This is useful for example to send
+ * INFO request. Note that application should not use this function to send
+ * requests which would change the invite session's state, such as re-INVITE,
+ * UPDATE, PRACK, and BYE.
+ *
+ * @param call_id	Call identification.
+ * @param method	SIP method of the request.
+ * @param msg_data	Optional message body and/or list of headers to be 
+ *			included in outgoing request.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_call_send_request(pjsua_call_id call_id,
+					     const pj_str_t *method,
+					     const pjsua_msg_data *msg_data);
+
+
+/**
  * Terminate all calls. This will initiate #pjsua_call_hangup() for all
  * currently active calls. 
  *
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index e737c25..220e2b1 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -1662,6 +1662,52 @@
 
 
 /*
+ * Send arbitrary request.
+ */
+PJ_DEF(pj_status_t) pjsua_call_send_request(pjsua_call_id call_id,
+					    const pj_str_t *method_str,
+					    const pjsua_msg_data *msg_data)
+{
+    pjsua_call *call;
+    pjsip_dialog *dlg;
+    pjsip_method method;
+    pjsip_tx_data *tdata;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
+		     PJ_EINVAL);
+
+    status = acquire_call("pjsua_call_send_request", call_id, &call, &dlg);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Init method */
+    pjsip_method_init_np(&method, (pj_str_t*)method_str);
+
+    /* Create request message. */
+    status = pjsip_dlg_create_request( call->inv->dlg, &method, -1, &tdata);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Unable to create request", status);
+	goto on_return;
+    }
+
+    /* Add additional headers etc */
+    pjsua_process_msg_data( tdata, msg_data);
+
+    /* Send the request. */
+    status = pjsip_dlg_send_request( call->inv->dlg, tdata, -1, NULL);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Unable to send request", status);
+	goto on_return;
+    }
+
+on_return:
+    pjsip_dlg_dec_lock(dlg);
+    return status;
+}
+
+
+/*
  * Terminate all calls.
  */
 PJ_DEF(void) pjsua_call_hangup_all(void)
@@ -2845,6 +2891,11 @@
 
     PJSUA_LOCK();
 
+    /* Notify application callback first */
+    if (pjsua_var.ua_cfg.cb.on_call_tsx_state) {
+	(*pjsua_var.ua_cfg.cb.on_call_tsx_state)(call->index, tsx, e);
+    }
+
     if (tsx->role==PJSIP_ROLE_UAS &&
 	tsx->state==PJSIP_TSX_STATE_TRYING &&
 	pjsip_method_cmp(&tsx->method, pjsip_get_refer_method())==0)