⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pjsua_call.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: pjsua_call.c 1107 2007-03-27 10:53:57Z bennylp $ *//*  * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  */#include <pjsua-lib/pjsua.h>#include <pjsua-lib/pjsua_internal.h>#define THIS_FILE		"pjsua_call.c"/* This callback receives notification from invite session when the * session state has changed. */static void pjsua_call_on_state_changed(pjsip_inv_session *inv, 					pjsip_event *e);/* This callback is called by invite session framework when UAC session * has forked. */static void pjsua_call_on_forked( pjsip_inv_session *inv, 				  pjsip_event *e);/* * Callback to be called when SDP offer/answer negotiation has just completed * in the session. This function will start/update media if negotiation * has succeeded. */static void pjsua_call_on_media_update(pjsip_inv_session *inv,				       pj_status_t status);/* * Called when session received new offer. */static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,				   const pjmedia_sdp_session *offer);/* * This callback is called when transaction state has changed in INVITE * session. We use this to trap: *  - incoming REFER request. *  - incoming MESSAGE request. */static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,					    pjsip_transaction *tsx,					    pjsip_event *e);/* Destroy the call's media */static pj_status_t call_destroy_media(int call_id);/* Create inactive SDP for call hold. */static pj_status_t create_inactive_sdp(pjsua_call *call,				       pjmedia_sdp_session **p_answer);/* * Callback called by event framework when the xfer subscription state * has changed. */static void xfer_client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);static void xfer_server_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);/* * Reset call descriptor. */static void reset_call(pjsua_call_id id){    pjsua_call *call = &pjsua_var.calls[id];    call->index = id;    call->inv = NULL;    call->user_data = NULL;    call->session = NULL;    call->xfer_sub = NULL;    call->last_code = 0;    call->conf_slot = PJSUA_INVALID_ID;    call->last_text.ptr = call->last_text_buf_;    call->last_text.slen = 0;    call->conn_time.sec = 0;    call->conn_time.msec = 0;    call->res_time.sec = 0;    call->res_time.msec = 0;}/* * Init call subsystem. */pj_status_t pjsua_call_subsys_init(const pjsua_config *cfg){    pjsip_inv_callback inv_cb;    unsigned i;    const pj_str_t str_norefersub = { "norefersub", 10 };    pj_status_t status;    /* Init calls array. */    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.calls); ++i)	reset_call(i);    /* Copy config */    pjsua_config_dup(pjsua_var.pool, &pjsua_var.ua_cfg, cfg);    /* Initialize invite session callback. */    pj_bzero(&inv_cb, sizeof(inv_cb));    inv_cb.on_state_changed = &pjsua_call_on_state_changed;    inv_cb.on_new_session = &pjsua_call_on_forked;    inv_cb.on_media_update = &pjsua_call_on_media_update;    inv_cb.on_rx_offer = &pjsua_call_on_rx_offer;    inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed;    /* Initialize invite session module: */    status = pjsip_inv_usage_init(pjsua_var.endpt, &inv_cb);    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /* Add "norefersub" in Supported header */    pjsip_endpt_add_capability(pjsua_var.endpt, NULL, PJSIP_H_SUPPORTED,			       NULL, 1, &str_norefersub);    return status;}/* * Start call subsystem. */pj_status_t pjsua_call_subsys_start(void){    /* Nothing to do */    return PJ_SUCCESS;}/* * Get maximum number of calls configured in pjsua. */PJ_DEF(unsigned) pjsua_call_get_max_count(void){    return pjsua_var.ua_cfg.max_calls;}/* * Get number of currently active calls. */PJ_DEF(unsigned) pjsua_call_get_count(void){    return pjsua_var.call_cnt;}/* * Enum calls. */PJ_DEF(pj_status_t) pjsua_enum_calls( pjsua_call_id ids[],				      unsigned *count){    unsigned i, c;    PJ_ASSERT_RETURN(ids && *count, PJ_EINVAL);    PJSUA_LOCK();    for (i=0, c=0; c<*count && i<pjsua_var.ua_cfg.max_calls; ++i) {	if (!pjsua_var.calls[i].inv)	    continue;	ids[c] = i;	++c;    }    *count = c;    PJSUA_UNLOCK();    return PJ_SUCCESS;}/* * Make outgoing call to the specified URI using the specified account. */PJ_DEF(pj_status_t) pjsua_call_make_call( pjsua_acc_id acc_id,					  const pj_str_t *dest_uri,					  unsigned options,					  void *user_data,					  const pjsua_msg_data *msg_data,					  pjsua_call_id *p_call_id){    pjsip_dialog *dlg = NULL;    pjmedia_sdp_session *offer;    pjsip_inv_session *inv = NULL;    pjsua_acc *acc;    pjsua_call *call;    unsigned call_id;    pj_str_t contact;    pjsip_tx_data *tdata;    pj_status_t status;    /* Check that account is valid */    PJ_ASSERT_RETURN(acc_id>=0 || acc_id<PJ_ARRAY_SIZE(pjsua_var.acc), 		     PJ_EINVAL);    /* Options must be zero for now */    PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);    /* Check arguments */    PJ_ASSERT_RETURN(dest_uri, PJ_EINVAL);    PJSUA_LOCK();    acc = &pjsua_var.acc[acc_id];    if (!acc->valid) {	pjsua_perror(THIS_FILE, "Unable to make call because account "		     "is not valid", PJ_EINVALIDOP);	PJSUA_UNLOCK();	return PJ_EINVALIDOP;    }    /* Find free call slot. */    for (call_id=0; call_id<pjsua_var.ua_cfg.max_calls; ++call_id) {	if (pjsua_var.calls[call_id].inv == NULL)	    break;    }    if (call_id == pjsua_var.ua_cfg.max_calls) {	pjsua_perror(THIS_FILE, "Error making file", PJ_ETOOMANY);	PJSUA_UNLOCK();	return PJ_ETOOMANY;    }    call = &pjsua_var.calls[call_id];    /* Verify that destination URI is valid before calling      * pjsua_acc_create_uac_contact, or otherwise there       * a misleading "Invalid Contact URI" error will be printed     * when pjsua_acc_create_uac_contact() fails.     */    if (1) {	pj_pool_t *pool;	pjsip_uri *uri;	pj_str_t dup;	pool = pjsua_pool_create("tmp-uri", 4000, 4000);	if (!pool) {	    pjsua_perror(THIS_FILE, "Unable to create pool", PJ_ENOMEM);	    PJSUA_UNLOCK();	    return PJ_ENOMEM;	}		pj_strdup_with_null(pool, &dup, dest_uri);	uri = pjsip_parse_uri(pool, dup.ptr, dup.slen, 0);	pj_pool_release(pool);	if (uri == NULL) {	    pjsua_perror(THIS_FILE, "Unable to make call", 			 PJSIP_EINVALIDREQURI);	    PJSUA_UNLOCK();	    return PJSIP_EINVALIDREQURI;	}    }    PJ_LOG(4,(THIS_FILE, "Making call with acc #%d to %.*s", acc_id,	      (int)dest_uri->slen, dest_uri->ptr));    /* Mark call start time. */    pj_gettimeofday(&call->start_time);    /* Reset first response time */    call->res_time.sec = 0;    /* Create suitable Contact header */    status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,					  acc_id, dest_uri);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);	PJSUA_UNLOCK();	return status;    }    /* Create outgoing dialog: */    status = pjsip_dlg_create_uac( pjsip_ua_instance(), 				   &acc->cfg.id, &contact,				   dest_uri, dest_uri, &dlg);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Dialog creation failed", status);	PJSUA_UNLOCK();	return status;    }    /* Get media capability from media endpoint: */    status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt, dlg->pool, 1, 				       &call->skinfo, &offer);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status);	goto on_error;    }    /* Create the INVITE session: */    status = pjsip_inv_create_uac( dlg, offer, 0, &inv);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Invite session creation failed", status);	goto on_error;    }    /* Create and associate our data in the session. */    call->inv = inv;    dlg->mod_data[pjsua_var.mod.id] = call;    inv->mod_data[pjsua_var.mod.id] = call;    /* Attach user data */    call->user_data = user_data;    /* If account is locked to specific transport, then lock dialog     * to this transport too.     */    if (acc->cfg.transport_id != PJSUA_INVALID_ID) {	pjsip_tpselector tp_sel;	pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);	pjsip_dlg_set_transport(dlg, &tp_sel);    }    /* Set dialog Route-Set: */    if (!pj_list_empty(&acc->route_set))	pjsip_dlg_set_route_set(dlg, &acc->route_set);    /* Set credentials: */    if (acc->cred_cnt) {	pjsip_auth_clt_set_credentials( &dlg->auth_sess, 					acc->cred_cnt, acc->cred);    }    /* Create initial INVITE: */    status = pjsip_inv_invite(inv, &tdata);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to create initial INVITE request", 		     status);	goto on_error;    }    /* Add additional headers etc */    pjsua_process_msg_data( tdata, msg_data);    /* Must increment call counter now */    ++pjsua_var.call_cnt;    /* Send initial INVITE: */    status = pjsip_inv_send_msg(inv, tdata);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to send initial INVITE request", 		     status);	/* Upon failure to send first request, both dialog and invite 	 * session would have been cleared.	 */	inv = NULL;	dlg = NULL;	goto on_error;    }    /* Done. */    if (p_call_id)	*p_call_id = call_id;    PJSUA_UNLOCK();    return PJ_SUCCESS;on_error:    if (inv != NULL) {	pjsip_inv_terminate(inv, PJSIP_SC_OK, PJ_FALSE);    } else if (dlg) {	pjsip_dlg_terminate(dlg);    }    if (call_id != -1) {	reset_call(call_id);    }    PJSUA_UNLOCK();    return status;}/** * Handle incoming INVITE request. * Called by pjsua_core.c */pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata){    pj_str_t contact;    pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);    pjsip_dialog *replaced_dlg = NULL;    pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);    pjsip_msg *msg = rdata->msg_info.msg;    pjsip_tx_data *response = NULL;    unsigned options = 0;    pjsip_inv_session *inv = NULL;    int acc_id;    pjsua_call *call;    int call_id = -1;    pjmedia_sdp_session *answer;    pj_status_t status;    /* Don't want to handle anything but INVITE */    if (msg->line.req.method.id != PJSIP_INVITE_METHOD)	return PJ_FALSE;    /* Don't want to handle anything that's already associated with     * existing dialog or transaction.     */    if (dlg || tsx)	return PJ_FALSE;    PJSUA_LOCK();    /* Find free call slot. */    for (call_id=0; call_id<(int)pjsua_var.ua_cfg.max_calls; ++call_id) {	if (pjsua_var.calls[call_id].inv == NULL)	    break;    }    if (call_id == (int)pjsua_var.ua_cfg.max_calls) {	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 				      PJSIP_SC_BUSY_HERE, NULL,				      NULL, NULL);	PJ_LOG(2,(THIS_FILE, 		  "Unable to accept incoming call (too many calls)"));	PJSUA_UNLOCK();	return PJ_TRUE;    }    /* Clear call descriptor */    reset_call(call_id);    call = &pjsua_var.calls[call_id];    /* Mark call start time. */    pj_gettimeofday(&call->start_time);    /* Check INVITE request for Replaces header. If Replaces header is     * present, the function will make sure that we can handle the request.     */    status = pjsip_replaces_verify_request(rdata, &replaced_dlg, PJ_FALSE,					   &response);    if (status != PJ_SUCCESS) {	/*	 * Something wrong with the Replaces header.	 */	if (response) {	    pjsip_response_addr res_addr;	    pjsip_get_response_addr(response->pool, rdata, &res_addr);	    pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, response, 				      NULL, NULL);	} else {	    /* Respond with 500 (Internal Server Error) */	    pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,					  NULL, NULL);	}	PJSUA_UNLOCK();	return PJ_TRUE;    }    /* If this INVITE request contains Replaces header, notify application     * about the request so that application can do subsequent checking     * if it wants to.     */    if (replaced_dlg != NULL && pjsua_var.ua_cfg.cb.on_call_replace_request) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -