📄 pjsua_call.c
字号:
{
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
pjsua_var.calls[call_id].user_data = user_data;
return PJ_SUCCESS;
}
/*
* Get user data attached to the call.
*/
PJ_DEF(void*) pjsua_call_get_user_data(pjsua_call_id call_id)
{
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
NULL);
return pjsua_var.calls[call_id].user_data;
}
/*
* Send response to incoming INVITE request.
*/
PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id,
unsigned code,
const pj_str_t *reason,
const pjsua_msg_data *msg_data)
{
pjsua_call *call;
pjsip_dialog *dlg;
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_answer()", call_id, &call, &dlg);
if (status != PJ_SUCCESS)
return status;
if (call->res_time.sec == 0)
pj_gettimeofday(&call->res_time);
if (reason && reason->slen == 0)
reason = NULL;
/* Create response message */
status = pjsip_inv_answer(call->inv, code, reason, NULL, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error creating response",
status);
pjsip_dlg_dec_lock(dlg);
return status;
}
/* Call might have been disconnected if application is answering with
* 200/OK and the media failed to start.
*/
if (call->inv == NULL) {
pjsip_dlg_dec_lock(dlg);
return PJSIP_ESESSIONTERMINATED;
}
/* Add additional headers etc */
pjsua_process_msg_data( tdata, msg_data);
/* Send the message */
status = pjsip_inv_send_msg(call->inv, tdata);
if (status != PJ_SUCCESS)
pjsua_perror(THIS_FILE, "Error sending response",
status);
pjsip_dlg_dec_lock(dlg);
return status;
}
/*
* Hangup call by using method that is appropriate according to the
* call state.
*/
PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
unsigned code,
const pj_str_t *reason,
const pjsua_msg_data *msg_data)
{
pjsua_call *call;
pjsip_dialog *dlg;
pj_status_t status;
pjsip_tx_data *tdata;
if (call_id<0 || call_id>=(int)pjsua_var.ua_cfg.max_calls) {
PJ_LOG(1,(THIS_FILE, "pjsua_call_hangup(): invalid call id %d",
call_id));
}
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
status = acquire_call("pjsua_call_hangup()", call_id, &call, &dlg);
if (status != PJ_SUCCESS)
return status;
if (code==0) {
if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
code = PJSIP_SC_OK;
else if (call->inv->role == PJSIP_ROLE_UAS)
code = PJSIP_SC_DECLINE;
else
code = PJSIP_SC_REQUEST_TERMINATED;
}
status = pjsip_inv_end_session(call->inv, code, reason, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Failed to create end session message",
status);
pjsip_dlg_dec_lock(dlg);
return status;
}
/* pjsip_inv_end_session may return PJ_SUCCESS with NULL
* as p_tdata when INVITE transaction has not been answered
* with any provisional responses.
*/
if (tdata == NULL) {
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
/* Add additional headers etc */
pjsua_process_msg_data( tdata, msg_data);
/* Send the message */
status = pjsip_inv_send_msg(call->inv, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Failed to send end session message",
status);
pjsip_dlg_dec_lock(dlg);
return status;
}
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
/*
* Put the specified call on hold.
*/
PJ_DEF(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id,
const pjsua_msg_data *msg_data)
{
pjmedia_sdp_session *sdp;
pjsua_call *call;
pjsip_dialog *dlg;
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_set_hold()", call_id, &call, &dlg);
if (status != PJ_SUCCESS)
return status;
if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
pjsip_dlg_dec_lock(dlg);
return PJSIP_ESESSIONSTATE;
}
status = create_inactive_sdp(call, &sdp);
if (status != PJ_SUCCESS) {
pjsip_dlg_dec_lock(dlg);
return status;
}
/* Create re-INVITE with new offer */
status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
pjsip_dlg_dec_lock(dlg);
return status;
}
/* Add additional headers etc */
pjsua_process_msg_data( tdata, msg_data);
/* Send the request */
status = pjsip_inv_send_msg( call->inv, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
pjsip_dlg_dec_lock(dlg);
return status;
}
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
/*
* Send re-INVITE (to release hold).
*/
PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id,
pj_bool_t unhold,
const pjsua_msg_data *msg_data)
{
pjmedia_sdp_session *sdp;
pjsip_tx_data *tdata;
pjsua_call *call;
pjsip_dialog *dlg;
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_reinvite()", call_id, &call, &dlg);
if (status != PJ_SUCCESS)
return status;
if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
pjsip_dlg_dec_lock(dlg);
return PJSIP_ESESSIONSTATE;
}
/* Create SDP */
PJ_UNUSED_ARG(unhold);
PJ_TODO(create_active_inactive_sdp_based_on_unhold_arg);
status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt, call->inv->pool,
1, &call->skinfo, &sdp);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",
status);
pjsip_dlg_dec_lock(dlg);
return status;
}
/* Create re-INVITE with new offer */
status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
pjsip_dlg_dec_lock(dlg);
return status;
}
/* Add additional headers etc */
pjsua_process_msg_data( tdata, msg_data);
/* Send the request */
status = pjsip_inv_send_msg( call->inv, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
pjsip_dlg_dec_lock(dlg);
return status;
}
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
/*
* Initiate call transfer to the specified address.
*/
PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id,
const pj_str_t *dest,
const pjsua_msg_data *msg_data)
{
pjsip_evsub *sub;
pjsip_tx_data *tdata;
pjsua_call *call;
pjsip_dialog *dlg;
pjsip_generic_string_hdr *gs_hdr;
const pj_str_t str_ref_by = { "Referred-By", 11 };
struct pjsip_evsub_user xfer_cb;
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_xfer()", call_id, &call, &dlg);
if (status != PJ_SUCCESS)
return status;
/* Create xfer client subscription. */
pj_bzero(&xfer_cb, sizeof(xfer_cb));
xfer_cb.on_evsub_state = &xfer_client_on_evsub_state;
status = pjsip_xfer_create_uac(call->inv->dlg, &xfer_cb, &sub);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create xfer", status);
pjsip_dlg_dec_lock(dlg);
return status;
}
/* Associate this call with the client subscription */
pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, call);
/*
* Create REFER request.
*/
status = pjsip_xfer_initiate(sub, dest, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
pjsip_dlg_dec_lock(dlg);
return status;
}
/* Add Referred-By header */
gs_hdr = pjsip_generic_string_hdr_create(tdata->pool, &str_ref_by,
&dlg->local.info_str);
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)gs_hdr);
/* Add additional headers etc */
pjsua_process_msg_data( tdata, msg_data);
/* Send. */
status = pjsip_xfer_send_request(sub, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
pjsip_dlg_dec_lock(dlg);
return status;
}
/* For simplicity (that's what this program is intended to be!),
* leave the original invite session as it is. More advanced application
* may want to hold the INVITE, or terminate the invite, or whatever.
*/
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
/*
* Initiate attended call transfer to the specified address.
*/
PJ_DEF(pj_status_t) pjsua_call_xfer_replaces( pjsua_call_id call_id,
pjsua_call_id dest_call_id,
unsigned options,
const pjsua_msg_data *msg_data)
{
pjsua_call *dest_call;
pjsip_dialog *dest_dlg;
char str_dest_buf[512];
pj_str_t str_dest;
int len;
pjsip_uri *uri;
pj_status_t status;
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
PJ_ASSERT_RETURN(dest_call_id>=0 &&
dest_call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
status = acquire_call("pjsua_call_xfer_replaces()", dest_call_id,
&dest_call, &dest_dlg);
if (status != PJ_SUCCESS)
return status;
/*
* Create REFER destination URI with Replaces field.
*/
/* Make sure we have sufficient buffer's length */
PJ_ASSERT_RETURN( dest_dlg->remote.info_str.slen +
dest_dlg->call_id->id.slen +
dest_dlg->remote.info->tag.slen +
dest_dlg->local.info->tag.slen + 32
< sizeof(str_dest_buf), PJSIP_EURITOOLONG);
/* Print URI */
str_dest_buf[0] = '<';
str_dest.slen = 1;
uri = pjsip_uri_get_uri(dest_dlg->remote.info->uri);
len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri,
str_dest_buf+1, sizeof(str_dest_buf)-1);
if (len < 0)
return PJSIP_EURITOOLONG;
str_dest.slen += len;
/* Build the URI */
len = pj_ansi_snprintf(str_dest_buf + str_dest.slen,
sizeof(str_dest_buf) - str_dest.slen,
"?%s"
"Replaces=%.*s"
"%%3Bto-tag%%3D%.*s"
"%%3Bfrom-tag%%3D%.*s>",
((options&PJSUA_XFER_NO_REQUIRE_REPLACES) ?
"" : "Require=replaces&"),
(int)dest_dlg->call_id->id.slen,
dest_dlg->call_id->id.ptr,
(int)dest_dlg->remote.info->tag.slen,
dest_dlg->remote.info->tag.ptr,
(int)dest_dlg->local.info->tag.slen,
dest_dlg->local.info->tag.ptr);
PJ_ASSERT_RETURN(len > 0 && len <= (int)sizeof(str_dest_buf)-str_dest.slen,
PJSIP_EURITOOLONG);
str_dest.ptr = str_dest_buf;
str_dest.slen += len;
pjsip_dlg_dec_lock(dest_dlg);
return pjsua_call_xfer(call_id, &str_dest, msg_data);
}
/*
* Send DTMF digits to remote using RFC 2833 payload formats.
*/
PJ_DEF(pj_status_t) pjsua_call_dial_dtmf( pjsua_call_id call_id,
const pj_str_t *digits)
{
pjsua_call *call;
pjsip_dialog *dlg;
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_dial_dtmf()", call_id, &call, &dlg);
if (status != PJ_SUCCESS)
return status;
if (!call->session) {
PJ_LOG(3,(THIS_FILE, "Media is not established yet!"));
pjsip_dlg_dec_lock(dlg);
return PJ_EINVALIDOP;
}
status = pjmedia_session_dial_dtmf( call->session, 0, digits);
pjsip_dlg_dec_lock(dlg);
return status;
}
/**
* Send instant messaging inside INVITE session.
*/
PJ_DEF(pj_status_t) pjsua_call_send_im( pjsua_call_id call_id,
const pj_str_t *mime_type,
const pj_str_t *content,
const pjsua_msg_data *msg_data,
void *user_data)
{
pjsua_call *call;
pjsip_dialog *dlg;
const pj_str_t mime_text_plain = pj_str("text/plain");
pjsip_media_type ctype;
pjsua_im_data *im_data;
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_im()", call_id, &call, &dlg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -