diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-10-05 09:12:26 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-10-05 09:12:26 +0000 |
commit | 62e71dfa694a20d6834063926be5ce80244c67ef (patch) | |
tree | 15b03f0dfc1ce2f4a1fd8f319b17ae07695a1235 | |
parent | 362cd9fea6aa2c09b301f249cb70712ebc44cca9 (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.def | 146 | ||||
-rw-r--r-- | pjsip-apps/src/pjsua/pjsua_app.c | 114 | ||||
-rw-r--r-- | pjsip/docs/pjsua.jpg | bin | 74682 -> 62465 bytes | |||
-rw-r--r-- | pjsip/include/pjsip-ua/sip_inv.h | 3 | ||||
-rw-r--r-- | pjsip/include/pjsua-lib/pjsua.h | 33 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_call.c | 51 |
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 Binary files differindex 479567bb..c16a7a16 100644 --- a/pjsip/docs/pjsua.jpg +++ b/pjsip/docs/pjsua.jpg 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) |