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:
parent
97acefd361
commit
feb69f445d
|
@ -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
|
||||
|
|
|
@ -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 |
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue