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
This commit is contained in:
Benny Prijono 2007-10-05 09:12:26 +00:00
parent 97acefd361
commit feb69f445d
6 changed files with 274 additions and 73 deletions

View File

@ -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

View File

@ -1595,6 +1595,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
@ -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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -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.
*

View File

@ -544,6 +544,21 @@ typedef struct pjsua_callback
void (*on_incoming_call)(pjsua_acc_id acc_id, pjsua_call_id call_id,
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.
@ -2906,6 +2921,24 @@ PJ_DECL(pj_status_t) pjsua_call_send_typing_ind(pjsua_call_id call_id,
pj_bool_t is_typing,
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.

View File

@ -1661,6 +1661,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.
*/
@ -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)