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

📄 pjsua_core.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: pjsua_core.c 1223 2007-04-29 12:20:33Z 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_core.c"/* PJSUA application instance. */struct pjsua_data pjsua_var;/* Display error */PJ_DEF(void) pjsua_perror( const char *sender, const char *title, 			   pj_status_t status){    char errmsg[PJ_ERR_MSG_SIZE];    pj_strerror(status, errmsg, sizeof(errmsg));    PJ_LOG(3,(sender, "%s: %s [status=%d]", title, errmsg, status));}static void init_data(){    unsigned i;    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i)	pjsua_var.acc[i].index = i;        for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i)	pjsua_var.tpdata[i].index = i;}/***************************************************************************** * This is a very simple PJSIP module, whose sole purpose is to display * incoming and outgoing messages to log. This module will have priority * higher than transport layer, which means: * *  - incoming messages will come to this module first before reaching *    transaction layer. * *  - outgoing messages will come to this module last, after the message *    has been 'printed' to contiguous buffer by transport layer and *    appropriate transport instance has been decided for this message. * *//* Notification on incoming messages */static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata){    PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"			 "%.*s\n"			 "--end msg--",			 rdata->msg_info.len,			 pjsip_rx_data_get_info(rdata),			 rdata->tp_info.transport->type_name,			 rdata->pkt_info.src_name,			 rdata->pkt_info.src_port,			 (int)rdata->msg_info.len,			 rdata->msg_info.msg_buf));        /* Always return false, otherwise messages will not get processed! */    return PJ_FALSE;}/* Notification on outgoing messages */static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata){        /* Important note:     *	tp_info field is only valid after outgoing messages has passed     *	transport layer. So don't try to access tp_info when the module     *	has lower priority than transport layer.     */    PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s %s:%d:\n"			 "%.*s\n"			 "--end msg--",			 (tdata->buf.cur - tdata->buf.start),			 pjsip_tx_data_get_info(tdata),			 tdata->tp_info.transport->type_name,			 tdata->tp_info.dst_name,			 tdata->tp_info.dst_port,			 (int)(tdata->buf.cur - tdata->buf.start),			 tdata->buf.start));    /* Always return success, otherwise message will not get sent! */    return PJ_SUCCESS;}/* The module instance. */static pjsip_module pjsua_msg_logger = {    NULL, NULL,				/* prev, next.		*/    { "mod-pjsua-log", 13 },		/* Name.		*/    -1,					/* Id			*/    PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority	        */    NULL,				/* load()		*/    NULL,				/* start()		*/    NULL,				/* stop()		*/    NULL,				/* unload()		*/    &logging_on_rx_msg,			/* on_rx_request()	*/    &logging_on_rx_msg,			/* on_rx_response()	*/    &logging_on_tx_msg,			/* on_tx_request.	*/    &logging_on_tx_msg,			/* on_tx_response()	*/    NULL,				/* on_tsx_state()	*/};/***************************************************************************** * Another simple module to handle incoming OPTIONS request *//* Notification on incoming request */static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata){    pjsip_tx_data *tdata;    pjsip_response_addr res_addr;    pjmedia_sdp_session *sdp;    const pjsip_hdr *cap_hdr;    pj_status_t status;    /* Only want to handle OPTIONS requests */    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,			 &pjsip_options_method) != 0)    {	return PJ_FALSE;    }    /* Create basic response. */    status = pjsip_endpt_create_response(pjsua_var.endpt, rdata, 200, NULL, 					 &tdata);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to create OPTIONS response", status);	return PJ_TRUE;    }    /* Add Allow header */    cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ALLOW, NULL);    if (cap_hdr) {	pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));    }    /* Add Accept header */    cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ACCEPT, NULL);    if (cap_hdr) {	pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));    }    /* Add Supported header */    cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_SUPPORTED, NULL);    if (cap_hdr) {	pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));    }    /* Add Allow-Events header from the evsub module */    cap_hdr = pjsip_evsub_get_allow_events_hdr(NULL);    if (cap_hdr) {	pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));    }    /* Add User-Agent header */    if (pjsua_var.ua_cfg.user_agent.slen) {	const pj_str_t USER_AGENT = { "User-Agent", 10};	pjsip_hdr *h;	h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool,							 &USER_AGENT,							 &pjsua_var.ua_cfg.user_agent);	pjsip_msg_add_hdr(tdata->msg, h);    }    /* Add SDP body, using call0's RTP address */    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, tdata->pool, 1,				      &pjsua_var.calls[0].skinfo, &sdp);    if (status == PJ_SUCCESS) {	pjsip_create_sdp_body(tdata->pool, sdp, &tdata->msg->body);    }    /* Send response statelessly */    pjsip_get_response_addr(tdata->pool, rdata, &res_addr);    status = pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, tdata, NULL, NULL);    if (status != PJ_SUCCESS)	pjsip_tx_data_dec_ref(tdata);    return PJ_TRUE;}/* The module instance. */static pjsip_module pjsua_options_handler = {    NULL, NULL,				/* prev, next.		*/    { "mod-pjsua-options", 17 },	/* Name.		*/    -1,					/* Id			*/    PJSIP_MOD_PRIORITY_APPLICATION,	/* Priority	        */    NULL,				/* load()		*/    NULL,				/* start()		*/    NULL,				/* stop()		*/    NULL,				/* unload()		*/    &options_on_rx_request,		/* on_rx_request()	*/    NULL,				/* on_rx_response()	*/    NULL,				/* on_tx_request.	*/    NULL,				/* on_tx_response()	*/    NULL,				/* on_tsx_state()	*/};/***************************************************************************** * These two functions are the main callbacks registered to PJSIP stack * to receive SIP request and response messages that are outside any * dialogs and any transactions. *//* * Handler for receiving incoming requests. * * This handler serves multiple purposes: *  - it receives requests outside dialogs. *  - it receives requests inside dialogs, when the requests are *    unhandled by other dialog usages. Example of these *    requests are: MESSAGE. */static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata){    pj_bool_t processed = PJ_FALSE;    PJSUA_LOCK();    if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) {	processed = pjsua_call_on_incoming(rdata);    }    PJSUA_UNLOCK();    return processed;}/* * Handler for receiving incoming responses. * * This handler serves multiple purposes: *  - it receives strayed responses (i.e. outside any dialog and *    outside any transactions). *  - it receives responses coming to a transaction, when pjsua *    module is set as transaction user for the transaction. *  - it receives responses inside a dialog, when these responses *    are unhandled by other dialog usages. */static pj_bool_t mod_pjsua_on_rx_response(pjsip_rx_data *rdata){    PJ_UNUSED_ARG(rdata);    return PJ_FALSE;}/***************************************************************************** * Logging. *//* Log callback */static void log_writer(int level, const char *buffer, int len){    /* Write to file, stdout or application callback. */    if (pjsua_var.log_file) {	pj_ssize_t size = len;	pj_file_write(pjsua_var.log_file, buffer, &size);	/* This will slow things down considerably! Don't do it!	 pj_file_flush(pjsua_var.log_file);	*/    }    if (level <= (int)pjsua_var.log_cfg.console_level) {	if (pjsua_var.log_cfg.cb)	    (*pjsua_var.log_cfg.cb)(level, buffer, len);	else	    pj_log_write(level, buffer, len);    }}/* * Application can call this function at any time (after pjsua_create(), of * course) to change logging settings. */PJ_DEF(pj_status_t) pjsua_reconfigure_logging(const pjsua_logging_config *cfg){    pj_status_t status;    /* Save config. */    pjsua_logging_config_dup(pjsua_var.pool, &pjsua_var.log_cfg, cfg);    /* Redirect log function to ours */    pj_log_set_log_func( &log_writer );    /* Close existing file, if any */    if (pjsua_var.log_file) {	pj_file_close(pjsua_var.log_file);	pjsua_var.log_file = NULL;    }    /* If output log file is desired, create the file: */    if (pjsua_var.log_cfg.log_filename.slen) {	status = pj_file_open(pjsua_var.pool, 			      pjsua_var.log_cfg.log_filename.ptr,			      PJ_O_WRONLY, 			      &pjsua_var.log_file);	if (status != PJ_SUCCESS) {	    pjsua_perror(THIS_FILE, "Error creating log file", status);	    return status;	}    }    /* Unregister msg logging if it's previously registered */    if (pjsua_msg_logger.id >= 0) {	pjsip_endpt_unregister_module(pjsua_var.endpt, &pjsua_msg_logger);	pjsua_msg_logger.id = -1;    }    /* Enable SIP message logging */    if (pjsua_var.log_cfg.msg_logging)	pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_msg_logger);    return PJ_SUCCESS;}/***************************************************************************** * PJSUA Base API. *//* Worker thread function. */static int worker_thread(void *arg){    enum { TIMEOUT = 10 };    PJ_UNUSED_ARG(arg);    while (!pjsua_var.thread_quit_flag) {	int count;	count = pjsua_handle_events(TIMEOUT);	if (count < 0)	    pj_thread_sleep(TIMEOUT);    }    return 0;}/* * Instantiate pjsua application. */PJ_DEF(pj_status_t) pjsua_create(void){    pj_status_t status;    /* Init pjsua data */    init_data();    /* Set default logging settings */    pjsua_logging_config_default(&pjsua_var.log_cfg);    /* Init PJLIB: */    status = pj_init();    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /* Init PJLIB-UTIL: */    status = pjlib_util_init();    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /* Set default sound device ID */    pjsua_var.cap_dev = pjsua_var.play_dev = -1;    /* Init caching pool. */    pj_caching_pool_init(&pjsua_var.cp, &pj_pool_factory_default_policy, 0);    /* Create memory pool for application. */    pjsua_var.pool = pjsua_pool_create("pjsua", 4000, 4000);        PJ_ASSERT_RETURN(pjsua_var.pool, PJ_ENOMEM);    /* Create mutex */    status = pj_mutex_create_recursive(pjsua_var.pool, "pjsua", 				       &pjsua_var.mutex);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to create mutex", status);	return status;    }    /* Must create SIP endpoint to initialize SIP parser. The parser     * is needed for example when application needs to call pjsua_verify_url().     */    status = pjsip_endpt_create(&pjsua_var.cp.factory, 				pj_gethostname()->ptr, 				&pjsua_var.endpt);    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    return PJ_SUCCESS;}/* * Initialize pjsua with the specified settings. All the settings are  * optional, and the default values will be used when the config is not * specified. */PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg,				const pjsua_logging_config *log_cfg,				const pjsua_media_config *media_cfg){    pjsua_config	 default_cfg;    pjsua_media_config	 default_media_cfg;    const pj_str_t	 STR_OPTIONS = { "OPTIONS", 7 };    pj_status_t status;    /* Create default configurations when the config is not supplied */    if (ua_cfg == NULL) {	pjsua_config_default(&default_cfg);	ua_cfg = &default_cfg;    }    if (media_cfg == NULL) {	pjsua_media_config_default(&default_media_cfg);	media_cfg = &default_media_cfg;    }    /* Initialize logging first so that info/errors can be captured */    if (log_cfg) {	status = pjsua_reconfigure_logging(log_cfg);	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    }    /* If nameserver is configured, create DNS resolver instance and     * set it to be used by SIP resolver.     */    if (ua_cfg->nameserver_count) {#if PJSIP_HAS_RESOLVER	pj_dns_resolver *resv;	unsigned i;	/* Create DNS resolver */	status = pjsip_endpt_create_resolver(pjsua_var.endpt, &resv);	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);	/* Configure nameserver for the DNS resolver */	status = pj_dns_resolver_set_ns(resv, ua_cfg->nameserver_count,					ua_cfg->nameserver, NULL);	if (status != PJ_SUCCESS) {	    pjsua_perror(THIS_FILE, "Error setting nameserver", status);	    return status;	}	/* Set this DNS resolver to be used by the SIP resolver */	status = pjsip_endpt_set_resolver(pjsua_var.endpt, resv);	if (status != PJ_SUCCESS) {	    pjsua_perror(THIS_FILE, "Error setting DNS resolver", status);	    return status;	}	/* Print nameservers */	for (i=0; i<ua_cfg->nameserver_count; ++i) {	    PJ_LOG(4,(THIS_FILE, "Nameserver %.*s added",		      (int)ua_cfg->nameserver[i].slen,		      ua_cfg->nameserver[i].ptr));	}#else	PJ_LOG(2,(THIS_FILE, 		  "DNS resolver is disabled (PJSIP_HAS_RESOLVER==0)"));#endif    }    /* Init SIP UA: */    /* Initialize transaction layer: */    status = pjsip_tsx_layer_init_module(pjsua_var.endpt);

⌨️ 快捷键说明

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