summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-10-05 09:12:26 +0000
committerBenny Prijono <bennylp@teluu.com>2007-10-05 09:12:26 +0000
commit62e71dfa694a20d6834063926be5ce80244c67ef (patch)
tree15b03f0dfc1ce2f4a1fd8f319b17ae07695a1235
parent362cd9fea6aa2c09b301f249cb70712ebc44cca9 (diff)
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: http://svn.pjsip.org/repos/pjproject/trunk@1477 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--build.symbian/pjsua_libU.def146
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c114
-rw-r--r--pjsip/docs/pjsua.jpgbin74682 -> 62465 bytes
-rw-r--r--pjsip/include/pjsip-ua/sip_inv.h3
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h33
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c51
6 files changed, 274 insertions, 73 deletions
diff --git a/build.symbian/pjsua_libU.def b/build.symbian/pjsua_libU.def
index 2769d655..10df6bed 100644
--- a/build.symbian/pjsua_libU.def
+++ b/build.symbian/pjsua_libU.def
@@ -41,75 +41,77 @@ EXPORTS
pjsua_call_make_call @ 40 NONAME
pjsua_call_reinvite @ 41 NONAME
pjsua_call_send_im @ 42 NONAME
- pjsua_call_send_typing_ind @ 43 NONAME
- pjsua_call_set_hold @ 44 NONAME
- pjsua_call_set_user_data @ 45 NONAME
- pjsua_call_xfer @ 46 NONAME
- pjsua_call_xfer_replaces @ 47 NONAME
- pjsua_codec_get_param @ 48 NONAME
- pjsua_codec_set_param @ 49 NONAME
- pjsua_codec_set_priority @ 50 NONAME
- pjsua_conf_add_port @ 51 NONAME
- pjsua_conf_adjust_rx_level @ 52 NONAME
- pjsua_conf_adjust_tx_level @ 53 NONAME
- pjsua_conf_connect @ 54 NONAME
- pjsua_conf_disconnect @ 55 NONAME
- pjsua_conf_get_active_ports @ 56 NONAME
- pjsua_conf_get_max_ports @ 57 NONAME
- pjsua_conf_get_port_info @ 58 NONAME
- pjsua_conf_get_signal_level @ 59 NONAME
- pjsua_conf_remove_port @ 60 NONAME
- pjsua_config_default @ 61 NONAME
- pjsua_config_dup @ 62 NONAME
- pjsua_create @ 63 NONAME
- pjsua_destroy @ 64 NONAME
- pjsua_dump @ 65 NONAME
- pjsua_enum_accs @ 66 NONAME
- pjsua_enum_buddies @ 67 NONAME
- pjsua_enum_calls @ 68 NONAME
- pjsua_enum_codecs @ 69 NONAME
- pjsua_enum_conf_ports @ 70 NONAME
- pjsua_enum_snd_devs @ 71 NONAME
- pjsua_enum_transports @ 72 NONAME
- pjsua_get_buddy_count @ 73 NONAME
- pjsua_get_ec_tail @ 74 NONAME
- pjsua_get_pjmedia_endpt @ 75 NONAME
- pjsua_get_pjsip_endpt @ 76 NONAME
- pjsua_get_pool_factory @ 77 NONAME
- pjsua_get_snd_dev @ 78 NONAME
- pjsua_handle_events @ 79 NONAME
- pjsua_im_send @ 80 NONAME
- pjsua_im_typing @ 81 NONAME
- pjsua_init @ 82 NONAME
- pjsua_logging_config_default @ 83 NONAME
- pjsua_logging_config_dup @ 84 NONAME
- pjsua_media_config_default @ 85 NONAME
- pjsua_media_transports_create @ 86 NONAME
- pjsua_msg_data_init @ 87 NONAME
- pjsua_perror @ 88 NONAME
- pjsua_player_create @ 89 NONAME
- pjsua_player_destroy @ 90 NONAME
- pjsua_player_get_conf_port @ 91 NONAME
- pjsua_player_get_port @ 92 NONAME
- pjsua_player_set_pos @ 93 NONAME
- pjsua_playlist_create @ 94 NONAME
- pjsua_pool_create @ 95 NONAME
- pjsua_pres_dump @ 96 NONAME
- pjsua_reconfigure_logging @ 97 NONAME
- pjsua_recorder_create @ 98 NONAME
- pjsua_recorder_destroy @ 99 NONAME
- pjsua_recorder_get_conf_port @ 100 NONAME
- pjsua_recorder_get_port @ 101 NONAME
- pjsua_set_ec @ 102 NONAME
- pjsua_set_no_snd_dev @ 103 NONAME
- pjsua_set_null_snd_dev @ 104 NONAME
- pjsua_set_snd_dev @ 105 NONAME
- pjsua_start @ 106 NONAME
- pjsua_transport_close @ 107 NONAME
- pjsua_transport_config_default @ 108 NONAME
- pjsua_transport_config_dup @ 109 NONAME
- pjsua_transport_create @ 110 NONAME
- pjsua_transport_get_info @ 111 NONAME
- pjsua_transport_register @ 112 NONAME
- pjsua_transport_set_enable @ 113 NONAME
- pjsua_verify_sip_url @ 114 NONAME
+ pjsua_call_send_request @ 43 NONAME
+ pjsua_call_send_typing_ind @ 44 NONAME
+ pjsua_call_set_hold @ 45 NONAME
+ pjsua_call_set_user_data @ 46 NONAME
+ pjsua_call_update @ 47 NONAME
+ pjsua_call_xfer @ 48 NONAME
+ pjsua_call_xfer_replaces @ 49 NONAME
+ pjsua_codec_get_param @ 50 NONAME
+ pjsua_codec_set_param @ 51 NONAME
+ pjsua_codec_set_priority @ 52 NONAME
+ pjsua_conf_add_port @ 53 NONAME
+ pjsua_conf_adjust_rx_level @ 54 NONAME
+ pjsua_conf_adjust_tx_level @ 55 NONAME
+ pjsua_conf_connect @ 56 NONAME
+ pjsua_conf_disconnect @ 57 NONAME
+ pjsua_conf_get_active_ports @ 58 NONAME
+ pjsua_conf_get_max_ports @ 59 NONAME
+ pjsua_conf_get_port_info @ 60 NONAME
+ pjsua_conf_get_signal_level @ 61 NONAME
+ pjsua_conf_remove_port @ 62 NONAME
+ pjsua_config_default @ 63 NONAME
+ pjsua_config_dup @ 64 NONAME
+ pjsua_create @ 65 NONAME
+ pjsua_destroy @ 66 NONAME
+ pjsua_dump @ 67 NONAME
+ pjsua_enum_accs @ 68 NONAME
+ pjsua_enum_buddies @ 69 NONAME
+ pjsua_enum_calls @ 70 NONAME
+ pjsua_enum_codecs @ 71 NONAME
+ pjsua_enum_conf_ports @ 72 NONAME
+ pjsua_enum_snd_devs @ 73 NONAME
+ pjsua_enum_transports @ 74 NONAME
+ pjsua_get_buddy_count @ 75 NONAME
+ pjsua_get_ec_tail @ 76 NONAME
+ pjsua_get_pjmedia_endpt @ 77 NONAME
+ pjsua_get_pjsip_endpt @ 78 NONAME
+ pjsua_get_pool_factory @ 79 NONAME
+ pjsua_get_snd_dev @ 80 NONAME
+ pjsua_handle_events @ 81 NONAME
+ pjsua_im_send @ 82 NONAME
+ pjsua_im_typing @ 83 NONAME
+ pjsua_init @ 84 NONAME
+ pjsua_logging_config_default @ 85 NONAME
+ pjsua_logging_config_dup @ 86 NONAME
+ pjsua_media_config_default @ 87 NONAME
+ pjsua_media_transports_create @ 88 NONAME
+ pjsua_msg_data_init @ 89 NONAME
+ pjsua_perror @ 90 NONAME
+ pjsua_player_create @ 91 NONAME
+ pjsua_player_destroy @ 92 NONAME
+ pjsua_player_get_conf_port @ 93 NONAME
+ pjsua_player_get_port @ 94 NONAME
+ pjsua_player_set_pos @ 95 NONAME
+ pjsua_playlist_create @ 96 NONAME
+ pjsua_pool_create @ 97 NONAME
+ pjsua_pres_dump @ 98 NONAME
+ pjsua_reconfigure_logging @ 99 NONAME
+ pjsua_recorder_create @ 100 NONAME
+ pjsua_recorder_destroy @ 101 NONAME
+ pjsua_recorder_get_conf_port @ 102 NONAME
+ pjsua_recorder_get_port @ 103 NONAME
+ pjsua_set_ec @ 104 NONAME
+ pjsua_set_no_snd_dev @ 105 NONAME
+ pjsua_set_null_snd_dev @ 106 NONAME
+ pjsua_set_snd_dev @ 107 NONAME
+ pjsua_start @ 108 NONAME
+ pjsua_transport_close @ 109 NONAME
+ pjsua_transport_config_default @ 110 NONAME
+ pjsua_transport_config_dup @ 111 NONAME
+ pjsua_transport_create @ 112 NONAME
+ pjsua_transport_get_info @ 113 NONAME
+ pjsua_transport_register @ 114 NONAME
+ pjsua_transport_set_enable @ 115 NONAME
+ pjsua_verify_sip_url @ 116 NONAME
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index ceb97e3d..4b2b001b 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -1596,6 +1596,72 @@ static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
/*
+ * Handler when a transaction within a call has changed state.
+ */
+static void on_call_tsx_state(pjsua_call_id call_id,
+ pjsip_transaction *tsx,
+ pjsip_event *e)
+{
+ const pjsip_method info_method =
+ {
+ PJSIP_OTHER_METHOD,
+ { "INFO", 4 }
+ };
+
+ if (pjsip_method_cmp(&tsx->method, &info_method)==0) {
+ /*
+ * Handle INFO method.
+ */
+ if (tsx->role == PJSIP_ROLE_UAC &&
+ (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
+ tsx->state == PJSIP_TSX_STATE_TERMINATED &&
+ e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED))
+ {
+ /* Status of outgoing INFO request */
+ if (tsx->status_code >= 200 && tsx->status_code < 300) {
+ PJ_LOG(4,(THIS_FILE,
+ "Call %d: DTMF sent successfully with INFO",
+ call_id));
+ } else if (tsx->status_code >= 300) {
+ PJ_LOG(4,(THIS_FILE,
+ "Call %d: Failed to send DTMF with INFO: %d/%.*s",
+ call_id,
+ tsx->status_code,
+ (int)tsx->status_text.slen,
+ tsx->status_text.ptr));
+ }
+ } else if (tsx->role == PJSIP_ROLE_UAS &&
+ tsx->state == PJSIP_TSX_STATE_TRYING)
+ {
+ /* Answer incoming INFO with 200/OK */
+ pjsip_rx_data *rdata;
+ pjsip_tx_data *tdata;
+ pj_status_t status;
+
+ rdata = e->body.tsx_state.src.rdata;
+
+ if (rdata->msg_info.msg->body) {
+ status = pjsip_endpt_create_response(tsx->endpt, rdata,
+ 200, NULL, &tdata);
+ if (status == PJ_SUCCESS)
+ status = pjsip_tsx_send_msg(tsx, tdata);
+
+ PJ_LOG(3,(THIS_FILE, "Call %d: incoming INFO:\n%.*s",
+ call_id,
+ (int)rdata->msg_info.msg->body->len,
+ rdata->msg_info.msg->body->data));
+ } else {
+ status = pjsip_endpt_create_response(tsx->endpt, rdata,
+ 400, NULL, &tdata);
+ if (status == PJ_SUCCESS)
+ status = pjsip_tsx_send_msg(tsx, tdata);
+ }
+ }
+ }
+}
+
+
+/*
* Callback on media state changed event.
* The action may connect the call to sound device, to file, or
* to loop the call.
@@ -2862,6 +2928,53 @@ void console_app_main(const pj_str_t *uri_to_call)
}
break;
+ case '*':
+ /* Send DTMF with INFO */
+ if (current_call == -1) {
+
+ PJ_LOG(3,(THIS_FILE, "No current call"));
+
+ } else {
+ const pj_str_t SIP_INFO = pj_str("INFO");
+ pj_str_t digits;
+ int call = current_call;
+ int i;
+ pj_status_t status;
+
+ if (!simple_input("DTMF strings to send (0-9*#A-B)", buf,
+ sizeof(buf)))
+ {
+ break;
+ }
+
+ if (call != current_call) {
+ puts("Call has been disconnected");
+ continue;
+ }
+
+ digits = pj_str(buf);
+ for (i=0; i<digits.slen; ++i) {
+ pjsua_msg_data msg_data;
+ char body[80];
+
+ pjsua_msg_data_init(&msg_data);
+ msg_data.content_type = pj_str("application/dtmf-relay");
+
+ pj_ansi_snprintf(body, sizeof(body),
+ "Signal=%c\r\n"
+ "Duration=160",
+ buf[i]);
+ msg_data.msg_body = pj_str(body);
+
+ status = pjsua_call_send_request(current_call, &SIP_INFO,
+ &msg_data);
+ if (status != PJ_SUCCESS) {
+ break;
+ }
+ }
+ }
+ break;
+
case 'S':
/*
* Send arbitrary request
@@ -3150,6 +3263,7 @@ pj_status_t app_init(int argc, char *argv[])
app_config.cfg.cb.on_call_state = &on_call_state;
app_config.cfg.cb.on_call_media_state = &on_call_media_state;
app_config.cfg.cb.on_incoming_call = &on_incoming_call;
+ app_config.cfg.cb.on_call_tsx_state = &on_call_tsx_state;
app_config.cfg.cb.on_dtmf_digit = &call_on_dtmf_callback;
app_config.cfg.cb.on_reg_state = &on_reg_state;
app_config.cfg.cb.on_buddy_state = &on_buddy_state;
diff --git a/pjsip/docs/pjsua.jpg b/pjsip/docs/pjsua.jpg
index 479567bb..c16a7a16 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 a367fe1e..77a499ef 100644
--- a/pjsip/include/pjsip-ua/sip_inv.h
+++ b/pjsip/include/pjsip-ua/sip_inv.h
@@ -133,7 +133,8 @@ typedef struct pjsip_inv_callback
/**
* 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 b727528b..062943b7 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -545,6 +545,21 @@ typedef struct pjsua_callback
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 @@ PJ_DECL(pj_status_t) pjsua_call_send_typing_ind(pjsua_call_id call_id,
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 e737c25b..220e2b19 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -1662,6 +1662,52 @@ on_return:
/*
+ * 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 @@ static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
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)