📄 pjsua_core.c
字号:
/* $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 + -