Changeset 503 for pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
- Timestamp:
- Jun 13, 2006 10:57:13 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
r492 r503 18 18 */ 19 19 #include <pjsua-lib/pjsua.h> 20 #include "pjsua_imp.h" 21 22 /* 23 * pjsua_core.c 20 #include <pjsua-lib/pjsua_internal.h> 21 22 23 #define THIS_FILE "pjsua_core.c" 24 25 26 /* PJSUA application instance. */ 27 struct pjsua_data pjsua_var; 28 29 30 /* Display error */ 31 PJ_DEF(void) pjsua_perror( const char *sender, const char *title, 32 pj_status_t status) 33 { 34 char errmsg[PJ_ERR_MSG_SIZE]; 35 36 pj_strerror(status, errmsg, sizeof(errmsg)); 37 PJ_LOG(3,(sender, "%s: %s [status=%d]", title, errmsg, status)); 38 } 39 40 41 static void init_data() 42 { 43 unsigned i; 44 45 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) 46 pjsua_var.acc[i].index = i; 47 48 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) 49 pjsua_var.tpdata[i].index = i; 50 } 51 52 53 54 /***************************************************************************** 55 * This is a very simple PJSIP module, whose sole purpose is to display 56 * incoming and outgoing messages to log. This module will have priority 57 * higher than transport layer, which means: 24 58 * 25 * Core application functionalities. 26 */ 27 28 #define THIS_FILE "pjsua_core.c" 29 30 31 /* 32 * Global variable. 33 */ 34 struct pjsua pjsua; 35 36 37 /* 38 * Default local URI, if none is specified in cmd-line 39 */ 40 #define PJSUA_LOCAL_URI "<sip:user@127.0.0.1>" 41 42 43 44 /* 45 * Init default application parameters. 46 */ 47 PJ_DEF(void) pjsua_default_config(pjsua_config *cfg) 48 { 49 unsigned i; 50 51 pj_memset(cfg, 0, sizeof(pjsua_config)); 52 53 cfg->thread_cnt = 1; 54 cfg->media_has_ioqueue = 1; 55 cfg->media_thread_cnt = 1; 56 cfg->udp_port = 5060; 57 cfg->start_rtp_port = 4000; 58 cfg->msg_logging = PJ_TRUE; 59 cfg->max_calls = 4; 60 cfg->conf_ports = 0; 61 62 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 63 pjsua.clock_rate = 44100; 64 #endif 65 66 cfg->complexity = 10; 67 cfg->quality = 10; 59 * - incoming messages will come to this module first before reaching 60 * transaction layer. 61 * 62 * - outgoing messages will come to this module last, after the message 63 * has been 'printed' to contiguous buffer by transport layer and 64 * appropriate transport instance has been decided for this message. 65 * 66 */ 67 68 /* Notification on incoming messages */ 69 static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) 70 { 71 PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n" 72 "%s\n" 73 "--end msg--", 74 rdata->msg_info.len, 75 pjsip_rx_data_get_info(rdata), 76 rdata->pkt_info.src_name, 77 rdata->pkt_info.src_port, 78 rdata->msg_info.msg_buf)); 68 79 69 cfg->auto_answer = 100;70 cfg->uas_duration = 3600;71 72 /* Default logging settings: */ 73 cfg->log_level = 5; 74 cfg->app_log_level = 4; 75 cfg->log_decor = PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME | 76 PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE; 77 78 79 /* Also init logging settings in pjsua.config, because log80 * may be written before pjsua_init() is called.80 /* Always return false, otherwise messages will not get processed! */ 81 return PJ_FALSE; 82 } 83 84 /* Notification on outgoing messages */ 85 static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) 86 { 87 88 /* Important note: 89 * tp_info field is only valid after outgoing messages has passed 90 * transport layer. So don't try to access tp_info when the module 91 * has lower priority than transport layer. 81 92 */ 82 pjsua.config.log_level = 5; 83 pjsua.config.app_log_level = 4; 84 85 86 /* Init accounts: */ 87 for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 88 cfg->acc_config[i].reg_timeout = 55; 89 } 90 91 } 92 93 94 #define strncpy_with_null(dst,src,len) \ 95 do { \ 96 strncpy(dst, src, len); \ 97 dst[len-1] = '\0'; \ 98 } while (0) 99 100 101 102 PJ_DEF(pj_status_t) pjsua_test_config( const pjsua_config *cfg, 103 char *errmsg, 104 int len) 105 { 106 unsigned i; 107 108 /* If UDP port is zero, then sip_host and sip_port must be specified */ 109 if (cfg->udp_port == 0) { 110 if (cfg->sip_host.slen==0 || cfg->sip_port==0) { 111 strncpy_with_null(errmsg, 112 "sip_host and sip_port must be specified", 113 len); 114 return -1; 115 } 116 } 117 118 if (cfg->max_calls < 1) { 119 strncpy_with_null(errmsg, 120 "max_calls needs to be at least 1", 121 len); 122 return -1; 123 } 124 125 /* STUN */ 126 if (cfg->stun_srv1.slen || cfg->stun_port1 || cfg->stun_port2 || 127 cfg->stun_srv2.slen) 128 { 129 if (cfg->stun_port1 == 0) { 130 strncpy_with_null(errmsg, "stun_port1 required", len); 131 return -1; 132 } 133 if (cfg->stun_srv1.slen == 0) { 134 strncpy_with_null(errmsg, "stun_srv1 required", len); 135 return -1; 136 } 137 if (cfg->stun_port2 == 0) { 138 strncpy_with_null(errmsg, "stun_port2 required", len); 139 return -1; 140 } 141 if (cfg->stun_srv2.slen == 0) { 142 strncpy_with_null(errmsg, "stun_srv2 required", len); 143 return -1; 144 } 145 } 146 147 /* Verify accounts */ 148 for (i=0; i<cfg->acc_cnt; ++i) { 149 const pjsua_acc_config *acc_cfg = &cfg->acc_config[i]; 150 unsigned j; 151 152 if (acc_cfg->id.slen == 0) { 153 strncpy_with_null(errmsg, "missing account ID", len); 154 return -1; 155 } 156 157 if (acc_cfg->id.slen == 0) { 158 strncpy_with_null(errmsg, "missing registrar URI", len); 159 return -1; 160 } 161 162 if (acc_cfg->reg_timeout == 0) { 163 strncpy_with_null(errmsg, "missing registration timeout", len); 164 return -1; 165 } 166 167 168 for (j=0; j<acc_cfg->cred_count; ++j) { 169 170 if (acc_cfg->cred_info[j].scheme.slen == 0) { 171 strncpy_with_null(errmsg, "missing auth scheme in account", 172 len); 173 return -1; 174 } 175 176 if (acc_cfg->cred_info[j].realm.slen == 0) { 177 strncpy_with_null(errmsg, "missing realm in account", len); 178 return -1; 179 } 180 181 if (acc_cfg->cred_info[j].username.slen == 0) { 182 strncpy_with_null(errmsg, "missing username in account", len); 183 return -1; 184 } 185 186 } 187 } 188 93 94 PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n" 95 "%s\n" 96 "--end msg--", 97 (tdata->buf.cur - tdata->buf.start), 98 pjsip_tx_data_get_info(tdata), 99 tdata->tp_info.dst_name, 100 tdata->tp_info.dst_port, 101 tdata->buf.start)); 102 103 /* Always return success, otherwise message will not get sent! */ 189 104 return PJ_SUCCESS; 190 105 } 191 106 107 /* The module instance. */ 108 static pjsip_module pjsua_msg_logger = 109 { 110 NULL, NULL, /* prev, next. */ 111 { "mod-pjsua-log", 13 }, /* Name. */ 112 -1, /* Id */ 113 PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */ 114 NULL, /* load() */ 115 NULL, /* start() */ 116 NULL, /* stop() */ 117 NULL, /* unload() */ 118 &logging_on_rx_msg, /* on_rx_request() */ 119 &logging_on_rx_msg, /* on_rx_response() */ 120 &logging_on_tx_msg, /* on_tx_request. */ 121 &logging_on_tx_msg, /* on_tx_response() */ 122 NULL, /* on_tsx_state() */ 123 124 }; 125 126 127 /***************************************************************************** 128 * These two functions are the main callbacks registered to PJSIP stack 129 * to receive SIP request and response messages that are outside any 130 * dialogs and any transactions. 131 */ 192 132 193 133 /* … … 202 142 static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata) 203 143 { 144 pj_bool_t processed = PJ_FALSE; 145 146 PJSUA_LOCK(); 204 147 205 148 if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) { 206 149 207 return pjsua_call_on_incoming(rdata); 208 } 209 210 return PJ_FALSE; 150 processed = pjsua_call_on_incoming(rdata); 151 } 152 153 PJSUA_UNLOCK(); 154 155 return processed; 211 156 } 212 157 … … 230 175 231 176 232 static int PJ_THREAD_FUNC pjsua_poll(void *arg) 233 { 234 pj_status_t last_err = 0; 235 236 PJ_UNUSED_ARG(arg); 237 238 do { 239 pj_time_val timeout = { 0, 10 }; 240 pj_status_t status; 241 242 status = pjsip_endpt_handle_events (pjsua.endpt, &timeout); 243 if (status != PJ_SUCCESS && status != last_err) { 244 last_err = status; 245 pjsua_perror(THIS_FILE, "handle_events() returned error", status); 246 } 247 } while (!pjsua.quit_flag); 248 249 return 0; 250 } 251 252 /** 253 * Poll pjsua. 254 */ 255 PJ_DECL(int) pjsua_handle_events(unsigned msec_timeout) 256 { 257 unsigned count = 0; 258 pj_time_val tv; 177 /***************************************************************************** 178 * Logging. 179 */ 180 181 /* Log callback */ 182 static void log_writer(int level, const char *buffer, int len) 183 { 184 /* Write to stdout, file, and application callback. */ 185 186 if (level <= (int)pjsua_var.log_cfg.console_level) 187 pj_log_write(level, buffer, len); 188 189 if (pjsua_var.log_file) { 190 pj_ssize_t size = len; 191 pj_file_write(pjsua_var.log_file, buffer, &size); 192 } 193 194 if (pjsua_var.log_cfg.cb) 195 (*pjsua_var.log_cfg.cb)(level, buffer, len); 196 } 197 198 199 /* 200 * Application can call this function at any time (after pjsua_create(), of 201 * course) to change logging settings. 202 */ 203 PJ_DEF(pj_status_t) pjsua_reconfigure_logging(const pjsua_logging_config *cfg) 204 { 259 205 pj_status_t status; 260 206 261 tv.sec = 0; 262 tv.msec = msec_timeout; 263 pj_time_val_normalize(&tv); 264 265 status = pjsip_endpt_handle_events2(pjsua.endpt, &tv, &count); 266 if (status != PJ_SUCCESS) 267 return -status; 268 269 return count; 270 } 271 272 273 #define pjsua_has_stun() (pjsua.config.stun_port1 && \ 274 pjsua.config.stun_port2) 275 276 277 /* 278 * Create and initialize SIP socket (and possibly resolve public 279 * address via STUN, depending on config). 280 */ 281 static pj_status_t create_sip_udp_sock(int port, 282 pj_sock_t *p_sock, 283 pj_sockaddr_in *p_pub_addr) 284 { 285 pj_sock_t sock; 286 pj_status_t status; 287 288 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 289 if (status != PJ_SUCCESS) { 290 pjsua_perror(THIS_FILE, "socket() error", status); 291 return status; 292 } 293 294 status = pj_sock_bind_in(sock, 0, (pj_uint16_t)port); 295 if (status != PJ_SUCCESS) { 296 pjsua_perror(THIS_FILE, "bind() error", status); 297 pj_sock_close(sock); 298 return status; 299 } 300 301 if (pjsua_has_stun()) { 302 status = pj_stun_get_mapped_addr(&pjsua.cp.factory, 1, &sock, 303 &pjsua.config.stun_srv1, 304 pjsua.config.stun_port1, 305 &pjsua.config.stun_srv2, 306 pjsua.config.stun_port2, 307 p_pub_addr); 207 /* Save config. */ 208 pjsua_logging_config_dup(pjsua_var.pool, &pjsua_var.log_cfg, cfg); 209 210 /* Redirect log function to ours */ 211 pj_log_set_log_func( &log_writer ); 212 213 /* Close existing file, if any */ 214 if (pjsua_var.log_file) { 215 pj_file_close(pjsua_var.log_file); 216 pjsua_var.log_file = NULL; 217 } 218 219 /* If output log file is desired, create the file: */ 220 if (pjsua_var.log_cfg.log_filename.slen) { 221 222 status = pj_file_open(pjsua_var.pool, 223 pjsua_var.log_cfg.log_filename.ptr, 224 PJ_O_WRONLY, 225 &pjsua_var.log_file); 226 308 227 if (status != PJ_SUCCESS) { 309 pjsua_perror(THIS_FILE, "STUN resolve error", status); 310 pj_sock_close(sock); 228 pjsua_perror(THIS_FILE, "Error creating log file", status); 311 229 return status; 312 230 } 313 314 } else { 315 316 const pj_str_t *hostname = pj_gethostname(); 317 struct pj_hostent he; 318 319 status = pj_gethostbyname(hostname, &he); 320 if (status != PJ_SUCCESS) { 321 pjsua_perror(THIS_FILE, "Unable to resolve local host", status); 322 pj_sock_close(sock); 323 return status; 324 } 325 326 pj_memset(p_pub_addr, 0, sizeof(pj_sockaddr_in)); 327 p_pub_addr->sin_family = PJ_AF_INET; 328 p_pub_addr->sin_port = pj_htons((pj_uint16_t)port); 329 p_pub_addr->sin_addr = *(pj_in_addr*)he.h_addr; 330 } 331 332 *p_sock = sock; 231 } 232 233 /* Unregister msg logging if it's previously registered */ 234 if (pjsua_msg_logger.id >= 0) { 235 pjsip_endpt_unregister_module(pjsua_var.endpt, &pjsua_msg_logger); 236 pjsua_msg_logger.id = -1; 237 } 238 239 /* Enable SIP message logging */ 240 if (pjsua_var.log_cfg.msg_logging) 241 pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_msg_logger); 242 243 333 244 return PJ_SUCCESS; 334 245 } 335 246 336 247 337 /* 338 * Create RTP and RTCP socket pair, and possibly resolve their public 339 * address via STUN. 340 */ 341 static pj_status_t create_rtp_rtcp_sock(pjmedia_sock_info *skinfo) 342 { 343 enum { 344 RTP_RETRY = 100 345 }; 346 int i; 347 static pj_uint16_t rtp_port; 348 pj_sockaddr_in mapped_addr[2]; 349 pj_status_t status = PJ_SUCCESS; 350 pj_sock_t sock[2]; 351 352 if (rtp_port == 0) 353 rtp_port = (pj_uint16_t)pjsua.config.start_rtp_port; 354 355 for (i=0; i<2; ++i) 356 sock[i] = PJ_INVALID_SOCKET; 357 358 359 /* Loop retry to bind RTP and RTCP sockets. */ 360 for (i=0; i<RTP_RETRY; ++i, rtp_port += 2) { 361 362 /* Create and bind RTP socket. */ 363 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[0]); 364 if (status != PJ_SUCCESS) { 365 pjsua_perror(THIS_FILE, "socket() error", status); 366 return status; 367 } 368 369 status = pj_sock_bind_in(sock[0], 0, rtp_port); 370 if (status != PJ_SUCCESS) { 371 pj_sock_close(sock[0]); 372 sock[0] = PJ_INVALID_SOCKET; 373 continue; 374 } 375 376 /* Create and bind RTCP socket. */ 377 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[1]); 378 if (status != PJ_SUCCESS) { 379 pjsua_perror(THIS_FILE, "socket() error", status); 380 pj_sock_close(sock[0]); 381 return status; 382 } 383 384 status = pj_sock_bind_in(sock[1], 0, (pj_uint16_t)(rtp_port+1)); 385 if (status != PJ_SUCCESS) { 386 pj_sock_close(sock[0]); 387 sock[0] = PJ_INVALID_SOCKET; 388 389 pj_sock_close(sock[1]); 390 sock[1] = PJ_INVALID_SOCKET; 391 continue; 392 } 393 394 /* 395 * If we're configured to use STUN, then find out the mapped address, 396 * and make sure that the mapped RTCP port is adjacent with the RTP. 397 */ 398 if (pjsua_has_stun()) { 399 status=pj_stun_get_mapped_addr(&pjsua.cp.factory, 2, sock, 400 &pjsua.config.stun_srv1, 401 pjsua.config.stun_port1, 402 &pjsua.config.stun_srv2, 403 pjsua.config.stun_port2, 404 mapped_addr); 405 if (status != PJ_SUCCESS) { 406 pjsua_perror(THIS_FILE, "STUN resolve error", status); 407 goto on_error; 408 } 409 410 if (pj_ntohs(mapped_addr[1].sin_port) == 411 pj_ntohs(mapped_addr[0].sin_port)+1) 412 { 413 /* Success! */ 414 break; 415 } 416 417 pj_sock_close(sock[0]); 418 sock[0] = PJ_INVALID_SOCKET; 419 420 pj_sock_close(sock[1]); 421 sock[1] = PJ_INVALID_SOCKET; 422 423 } else { 424 const pj_str_t *hostname; 425 pj_sockaddr_in addr; 426 427 /* Get local IP address. */ 428 hostname = pj_gethostname(); 429 430 pj_memset( &addr, 0, sizeof(addr)); 431 addr.sin_family = PJ_AF_INET; 432 status = pj_sockaddr_in_set_str_addr( &addr, hostname); 433 if (status != PJ_SUCCESS) { 434 pjsua_perror(THIS_FILE, "Unresolvable local hostname", 435 status); 436 goto on_error; 437 } 438 439 for (i=0; i<2; ++i) 440 pj_memcpy(&mapped_addr[i], &addr, sizeof(addr)); 441 442 mapped_addr[0].sin_port=pj_htons((pj_uint16_t)rtp_port); 443 mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(rtp_port+1)); 444 break; 445 } 446 } 447 448 if (sock[0] == PJ_INVALID_SOCKET) { 449 PJ_LOG(1,(THIS_FILE, 450 "Unable to find appropriate RTP/RTCP ports combination")); 451 goto on_error; 452 } 453 454 455 skinfo->rtp_sock = sock[0]; 456 pj_memcpy(&skinfo->rtp_addr_name, 457 &mapped_addr[0], sizeof(pj_sockaddr_in)); 458 459 skinfo->rtcp_sock = sock[1]; 460 pj_memcpy(&skinfo->rtcp_addr_name, 461 &mapped_addr[1], sizeof(pj_sockaddr_in)); 462 463 PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d", 464 pj_inet_ntoa(skinfo->rtp_addr_name.sin_addr), 465 pj_ntohs(skinfo->rtp_addr_name.sin_port))); 466 PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s:%d", 467 pj_inet_ntoa(skinfo->rtcp_addr_name.sin_addr), 468 pj_ntohs(skinfo->rtcp_addr_name.sin_port))); 469 470 rtp_port += 2; 248 /***************************************************************************** 249 * PJSUA Base API. 250 */ 251 252 /* Worker thread function. */ 253 static int worker_thread(void *arg) 254 { 255 enum { TIMEOUT = 10 }; 256 257 PJ_UNUSED_ARG(arg); 258 259 while (!pjsua_var.thread_quit_flag) { 260 int count; 261 262 count = pjsua_handle_events(TIMEOUT); 263 if (count < 0) 264 pj_thread_sleep(TIMEOUT); 265 } 266 267 return 0; 268 } 269 270 271 /* 272 * Instantiate pjsua application. 273 */ 274 PJ_DEF(pj_status_t) pjsua_create(void) 275 { 276 pj_status_t status; 277 278 /* Init pjsua data */ 279 init_data(); 280 281 /* Set default logging settings */ 282 pjsua_logging_config_default(&pjsua_var.log_cfg); 283 284 /* Init PJLIB: */ 285 status = pj_init(); 286 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 287 288 289 /* Init PJLIB-UTIL: */ 290 status = pjlib_util_init(); 291 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 292 293 294 /* Init caching pool. */ 295 pj_caching_pool_init(&pjsua_var.cp, &pj_pool_factory_default_policy, 0); 296 297 /* Create memory pool for application. */ 298 pjsua_var.pool = pjsua_pool_create("pjsua", 4000, 4000); 299 300 PJ_ASSERT_RETURN(pjsua_var.pool, PJ_ENOMEM); 301 302 /* Create mutex */ 303 status = pj_mutex_create_recursive(pjsua_var.pool, "pjsua", 304 &pjsua_var.mutex); 305 if (status != PJ_SUCCESS) { 306 pjsua_perror(THIS_FILE, "Unable to create mutex", status); 307 return status; 308 } 309 310 /* Must create SIP endpoint to initialize SIP parser. The parser 311 * is needed for example when application needs to call pjsua_verify_url(). 312 */ 313 status = pjsip_endpt_create(&pjsua_var.cp.factory, 314 pj_gethostname()->ptr, 315 &pjsua_var.endpt); 316 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 317 318 471 319 return PJ_SUCCESS; 472 473 on_error: 474 for (i=0; i<2; ++i) { 475 if (sock[i] != PJ_INVALID_SOCKET) 476 pj_sock_close(sock[i]); 477 } 478 return status; 479 } 480 481 482 483 /** 484 * Create pjsua application. 485 * This initializes pjlib/pjlib-util, and creates memory pool factory to 486 * be used by application. 487 */ 488 PJ_DEF(pj_status_t) pjsua_create(void) 489 { 320 } 321 322 323 /* 324 * Initialize pjsua with the specified settings. All the settings are 325 * optional, and the default values will be used when the config is not 326 * specified. 327 */ 328 PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg, 329 const pjsua_logging_config *log_cfg, 330 const pjsua_media_config *media_cfg) 331 { 332 pjsua_config default_cfg; 333 pjsua_media_config default_media_cfg; 490 334 pj_status_t status; 491 335 492 /* Init PJLIB: */ 493 494 status = pj_init(); 495 if (status != PJ_SUCCESS) { 496 pjsua_perror(THIS_FILE, "pj_init() error", status); 497 return status; 498 } 499 500 /* Init PJLIB-UTIL: */ 501 502 status = pjlib_util_init(); 503 if (status != PJ_SUCCESS) { 504 pjsua_perror(THIS_FILE, "pjlib_util_init() error", status); 505 return status; 506 } 507 508 /* Init memory pool: */ 509 510 /* Init caching pool. */ 511 pj_caching_pool_init(&pjsua.cp, &pj_pool_factory_default_policy, 0); 512 513 /* Create memory pool for application. */ 514 pjsua.pool = pj_pool_create(&pjsua.cp.factory, "pjsua", 4000, 4000, NULL); 515 516 /* Must create endpoint to initialize SIP parser. */ 517 /* Create global endpoint: */ 518 519 status = pjsip_endpt_create(&pjsua.cp.factory, 520 pj_gethostname()->ptr, 521 &pjsua.endpt); 522 if (status != PJ_SUCCESS) { 523 pjsua_perror(THIS_FILE, "Unable to create SIP endpoint", status); 524 return status; 525 } 526 527 /* Must create media endpoint too */ 528 status = pjmedia_endpt_create(&pjsua.cp.factory, 529 pjsua.config.media_has_ioqueue? NULL : 530 pjsip_endpt_get_ioqueue(pjsua.endpt), 531 pjsua.config.media_thread_cnt, 532 &pjsua.med_endpt); 533 if (status != PJ_SUCCESS) { 534 pjsua_perror(THIS_FILE, 535 "Media stack initialization has returned error", 536 status); 537 return status; 538 } 539 540 541 return PJ_SUCCESS; 542 } 543 544 545 546 /* 547 * Init media. 548 */ 549 static pj_status_t init_media(void) 550 { 551 int i; 552 unsigned options; 553 pj_str_t codec_id; 554 pj_status_t status; 555 556 /* Register all codecs */ 557 #if PJMEDIA_HAS_SPEEX_CODEC 558 /* Register speex. */ 559 status = pjmedia_codec_speex_init(pjsua.med_endpt, 560 PJMEDIA_SPEEX_NO_UWB, 561 pjsua.config.quality, 562 pjsua.config.complexity ); 563 if (status != PJ_SUCCESS) { 564 pjsua_perror(THIS_FILE, "Error initializing Speex codec", 565 status); 566 return status; 567 } 568 569 /* Set "speex/16000/1" to have highest priority */ 570 codec_id = pj_str("speex/16000/1"); 571 pjmedia_codec_mgr_set_codec_priority( 572 pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 573 &codec_id, 574 PJMEDIA_CODEC_PRIO_HIGHEST); 575 576 #endif /* PJMEDIA_HAS_SPEEX_CODEC */ 577 578 #if PJMEDIA_HAS_GSM_CODEC 579 /* Register GSM */ 580 status = pjmedia_codec_gsm_init(pjsua.med_endpt); 581 if (status != PJ_SUCCESS) { 582 pjsua_perror(THIS_FILE, "Error initializing GSM codec", 583 status); 584 return status; 585 } 586 #endif /* PJMEDIA_HAS_GSM_CODEC */ 587 588 #if PJMEDIA_HAS_G711_CODEC 589 /* Register PCMA and PCMU */ 590 status = pjmedia_codec_g711_init(pjsua.med_endpt); 591 if (status != PJ_SUCCESS) { 592 pjsua_perror(THIS_FILE, "Error initializing G711 codec", 593 status); 594 return status; 595 } 596 #endif /* PJMEDIA_HAS_G711_CODEC */ 597 598 #if PJMEDIA_HAS_L16_CODEC 599 /* Register L16 family codecs, but disable all */ 600 status = pjmedia_codec_l16_init(pjsua.med_endpt, 0); 601 if (status != PJ_SUCCESS) { 602 pjsua_perror(THIS_FILE, "Error initializing L16 codecs", 603 status); 604 return status; 605 } 606 607 /* Disable ALL L16 codecs */ 608 codec_id = pj_str("L16"); 609 pjmedia_codec_mgr_set_codec_priority( 610 pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 611 &codec_id, 612 PJMEDIA_CODEC_PRIO_DISABLED); 613 614 #endif /* PJMEDIA_HAS_L16_CODEC */ 615 616 617 /* Enable those codecs that user put with "--add-codec", and move 618 * the priority to top 619 */ 620 for (i=0; i<(int)pjsua.config.codec_cnt; ++i) { 621 pjmedia_codec_mgr_set_codec_priority( 622 pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 623 &pjsua.config.codec_arg[i], 624 PJMEDIA_CODEC_PRIO_HIGHEST); 625 } 626 627 628 /* Init options for conference bridge. */ 629 options = PJMEDIA_CONF_NO_DEVICE; 630 631 /* Calculate maximum number of ports, if it's not specified */ 632 if (pjsua.config.conf_ports == 0) { 633 pjsua.config.conf_ports = 3 * pjsua.config.max_calls; 634 } 635 636 /* Init conference bridge. */ 637 pjsua.clock_rate = pjsua.config.clock_rate ? pjsua.config.clock_rate : 16000; 638 pjsua.samples_per_frame = pjsua.clock_rate * 10 / 1000; 639 status = pjmedia_conf_create(pjsua.pool, 640 pjsua.config.conf_ports, 641 pjsua.clock_rate, 642 1, /* mono */ 643 pjsua.samples_per_frame, 644 16, 645 options, 646 &pjsua.mconf); 647 if (status != PJ_SUCCESS) { 648 pjsua_perror(THIS_FILE, 649 "Media stack initialization has returned error", 650 status); 651 return status; 652 } 653 654 if (pjsua.config.null_audio == PJ_FALSE) { 655 pjmedia_port *conf_port; 656 657 /* Create sound device port */ 658 status = pjmedia_snd_port_create(pjsua.pool, 659 pjsua.config.snd_capture_id, 660 pjsua.config.snd_player_id, 661 pjsua.clock_rate, 1 /* mono */, 662 pjsua.samples_per_frame, 16, 663 0, &pjsua.snd_port); 664 if (status != PJ_SUCCESS) { 665 pjsua_perror(THIS_FILE, "Unable to create sound device", status); 666 return status; 667 } 668 669 /* Get the port interface of the conference bridge */ 670 conf_port = pjmedia_conf_get_master_port(pjsua.mconf); 671 672 /* Connect conference port interface to sound port */ 673 pjmedia_snd_port_connect( pjsua.snd_port, conf_port); 674 675 } else { 676 pjmedia_port *null_port, *conf_port; 677 678 /* Create NULL port */ 679 status = pjmedia_null_port_create(pjsua.pool, pjsua.clock_rate, 680 1, pjsua.samples_per_frame, 16, 681 &null_port); 682 if (status != PJ_SUCCESS) { 683 pjsua_perror(THIS_FILE, "Unable to create NULL port", status); 684 return status; 685 } 686 687 /* Get the port interface of the conference bridge */ 688 conf_port = pjmedia_conf_get_master_port(pjsua.mconf); 689 690 /* Create master port to control conference bridge's clock */ 691 status = pjmedia_master_port_create(pjsua.pool, null_port, conf_port, 692 0, &pjsua.master_port); 693 if (status != PJ_SUCCESS) { 694 pjsua_perror(THIS_FILE, "Unable to create master port", status); 695 return status; 696 } 697 } 698 699 /* Create WAV file player if required: */ 700 701 if (pjsua.config.wav_file.slen) { 702 703 status = pjsua_player_create(&pjsua.config.wav_file, NULL); 704 if (status != PJ_SUCCESS) { 705 pjsua_perror(THIS_FILE, "Unable to create file player", 706 status); 707 return status; 708 } 709 } 710 711 712 return PJ_SUCCESS; 713 } 714 715 716 /* 717 * Copy account configuration. 718 */ 719 static void copy_acc_config(pj_pool_t *pool, 720 pjsua_acc_config *dst_acc, 721 const pjsua_acc_config *src_acc) 722 { 723 unsigned j; 724 725 pj_memcpy(dst_acc, src_acc, sizeof(pjsua_acc_config)); 726 727 pj_strdup_with_null(pool, &dst_acc->id, &src_acc->id); 728 pj_strdup_with_null(pool, &dst_acc->reg_uri, &src_acc->reg_uri); 729 pj_strdup_with_null(pool, &dst_acc->contact, &src_acc->contact); 730 pj_strdup_with_null(pool, &dst_acc->proxy, &src_acc->proxy); 731 732 for (j=0; j<src_acc->cred_count; ++j) { 733 pj_strdup_with_null(pool, &dst_acc->cred_info[j].realm, 734 &src_acc->cred_info[j].realm); 735 pj_strdup_with_null(pool, &dst_acc->cred_info[j].scheme, 736 &src_acc->cred_info[j].scheme); 737 pj_strdup_with_null(pool, &dst_acc->cred_info[j].username, 738 &src_acc->cred_info[j].username); 739 pj_strdup_with_null(pool, &dst_acc->cred_info[j].data, 740 &src_acc->cred_info[j].data); 741 } 742 } 743 744 745 /* 746 * Copy configuration. 747 */ 748 void pjsua_copy_config( pj_pool_t *pool, pjsua_config *dst, 749 const pjsua_config *src) 750 { 751 unsigned i; 752 753 /* Plain memcpy */ 754 pj_memcpy(dst, src, sizeof(pjsua_config)); 755 756 /* Duplicate strings */ 757 pj_strdup_with_null(pool, &dst->sip_host, &src->sip_host); 758 pj_strdup_with_null(pool, &dst->stun_srv1, &src->stun_srv1); 759 pj_strdup_with_null(pool, &dst->stun_srv2, &src->stun_srv2); 760 pj_strdup_with_null(pool, &dst->wav_file, &src->wav_file); 761 762 for (i=0; i<src->codec_cnt; ++i) { 763 pj_strdup_with_null(pool, &dst->codec_arg[i], &src->codec_arg[i]); 764 } 765 766 pj_strdup_with_null(pool, &dst->outbound_proxy, &src->outbound_proxy); 767 //pj_strdup_with_null(pool, &dst->uri_to_call, &src->uri_to_call); 768 769 for (i=0; i<src->acc_cnt; ++i) { 770 pjsua_acc_config *dst_acc = &dst->acc_config[i]; 771 const pjsua_acc_config *src_acc = &src->acc_config[i]; 772 copy_acc_config(pool, dst_acc, src_acc); 773 } 774 775 pj_strdup_with_null(pool, &dst->log_filename, &src->log_filename); 776 777 for (i=0; i<src->buddy_cnt; ++i) { 778 pj_strdup_with_null(pool, &dst->buddy_uri[i], &src->buddy_uri[i]); 779 } 780 } 781 782 783 /***************************************************************************** 784 * Console application custom logging: 785 */ 786 787 788 static void log_writer(int level, const char *buffer, int len) 789 { 790 /* Write to both stdout and file. */ 791 792 if (level <= (int)pjsua.config.app_log_level) 793 pj_log_write(level, buffer, len); 794 795 if (pjsua.log_file) { 796 fwrite(buffer, len, 1, pjsua.log_file); 797 fflush(pjsua.log_file); 798 } 799 } 800 801 802 static pj_status_t logging_init() 803 { 804 /* Redirect log function to ours */ 805 806 pj_log_set_log_func( &log_writer ); 807 808 /* If output log file is desired, create the file: */ 809 810 if (pjsua.config.log_filename.slen) { 811 pjsua.log_file = fopen(pjsua.config.log_filename.ptr, "wt"); 812 if (pjsua.log_file == NULL) { 813 PJ_LOG(1,(THIS_FILE, "Unable to open log file %s", 814 pjsua.config.log_filename.ptr)); 815 return -1; 816 } 817 } 818 819 /* Enable SIP message logging */ 820 if (pjsua.config.msg_logging) 821 pjsip_endpt_register_module(pjsua.endpt, &pjsua_msg_logger); 822 823 return PJ_SUCCESS; 824 } 825 826 827 static void logging_shutdown(void) 828 { 829 /* Close logging file, if any: */ 830 831 if (pjsua.log_file) { 832 fclose(pjsua.log_file); 833 pjsua.log_file = NULL; 834 } 835 } 836 837 838 /* 839 * Initialize pjsua application. 840 * This will initialize all libraries, create endpoint instance, and register 841 * pjsip modules. 842 */ 843 PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *cfg, 844 const pjsua_callback *cb) 845 { 846 char errmsg[80]; 847 unsigned i; 848 pj_status_t status; 849 850 851 /* Init accounts: */ 852 for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 853 pjsua.acc[i].index = i; 854 pjsua.acc[i].online_status = PJ_TRUE; 855 pj_list_init(&pjsua.acc[i].route_set); 856 pj_list_init(&pjsua.acc[i].pres_srv_list); 857 } 858 859 /* Init call array: */ 860 for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i) { 861 pjsua.calls[i].index = i; 862 pjsua.calls[i].refresh_tm._timer_id = -1; 863 pjsua.calls[i].hangup_tm._timer_id = -1; 864 pjsua.calls[i].conf_slot = 0; 865 } 866 867 /* Init buddies array */ 868 for (i=0; i<PJ_ARRAY_SIZE(pjsua.buddies); ++i) { 869 pjsua.buddies[i].index = i; 870 } 871 872 /* Copy configuration */ 873 pjsua_copy_config(pjsua.pool, &pjsua.config, cfg); 874 875 /* Copy callback */ 876 pj_memcpy(&pjsua.cb, cb, sizeof(pjsua_callback)); 877 878 /* Test configuration */ 879 if (pjsua_test_config(&pjsua.config, errmsg, sizeof(errmsg))) { 880 PJ_LOG(1,(THIS_FILE, "Error in configuration: %s", errmsg)); 881 status = -1; 882 goto on_error; 883 } 884 885 886 /* Init PJLIB logging: */ 887 888 pj_log_set_level(pjsua.config.log_level); 889 pj_log_set_decor(pjsua.config.log_decor); 890 891 status = logging_init(); 892 if (status != PJ_SUCCESS) 893 goto on_error; 894 895 896 /* Create SIP UDP socket */ 897 if (pjsua.config.udp_port) { 898 899 status = create_sip_udp_sock( pjsua.config.udp_port, 900 &pjsua.sip_sock, 901 &pjsua.sip_sock_name); 902 if (status != PJ_SUCCESS) 903 goto on_error; 904 905 pj_strdup2_with_null(pjsua.pool, &pjsua.config.sip_host, 906 pj_inet_ntoa(pjsua.sip_sock_name.sin_addr)); 907 pjsua.config.sip_port = pj_ntohs(pjsua.sip_sock_name.sin_port); 908 909 } else { 910 911 /* Check that SIP host and port is configured */ 912 if (cfg->sip_host.slen == 0 || cfg->sip_port == 0) { 913 PJ_LOG(1,(THIS_FILE, 914 "Error: sip_host and sip_port must be specified")); 915 status = PJ_EINVAL; 916 goto on_error; 917 } 918 919 pjsua.sip_sock = PJ_INVALID_SOCKET; 920 } 921 922 923 /* Init media endpoint */ 924 status = init_media(); 925 if (status != PJ_SUCCESS) 926 goto on_error; 927 928 929 /* Init RTP sockets, only when UDP transport is enabled */ 930 for (i=0; pjsua.config.start_rtp_port && i<pjsua.config.max_calls; ++i) { 931 status = create_rtp_rtcp_sock(&pjsua.calls[i].skinfo); 932 if (status != PJ_SUCCESS) { 933 unsigned j; 934 for (j=0; j<i; ++j) { 935 if (pjsua.calls[i].med_tp) 936 pjsua.calls[i].med_tp->op->destroy(pjsua.calls[i].med_tp); 937 } 938 goto on_error; 939 } 940 status = pjmedia_transport_udp_attach(pjsua.med_endpt, NULL, 941 &pjsua.calls[i].skinfo, 0, 942 &pjsua.calls[i].med_tp); 943 } 944 945 /* Init PJSIP : */ 336 337 /* Create default configurations when the config is not supplied */ 338 339 if (ua_cfg == NULL) { 340 pjsua_config_default(&default_cfg); 341 ua_cfg = &default_cfg; 342 } 343 344 if (media_cfg == NULL) { 345 pjsua_media_config_default(&default_media_cfg); 346 media_cfg = &default_media_cfg; 347 } 348 349 /* Initialize logging first so that info/errors can be captured */ 350 if (log_cfg) { 351 status = pjsua_reconfigure_logging(log_cfg); 352 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 353 } 354 355 /* Init SIP UA: */ 946 356 947 357 /* Initialize transaction layer: */ 948 949 status = pjsip_tsx_layer_init_module(pjsua.endpt); 950 if (status != PJ_SUCCESS) { 951 pjsua_perror(THIS_FILE, "Transaction layer initialization error", 952 status); 953 goto on_error; 954 } 358 status = pjsip_tsx_layer_init_module(pjsua_var.endpt); 359 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 360 955 361 956 362 /* Initialize UA layer module: */ 957 958 status = pjsip_ua_init_module( pjsua.endpt, NULL ); 959 if (status != PJ_SUCCESS) { 960 pjsua_perror(THIS_FILE, "UA layer initialization error", status); 961 goto on_error; 962 } 963 964 /* Initialize and register pjsua's application module: */ 965 363 status = pjsip_ua_init_module( pjsua_var.endpt, NULL ); 364 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 365 366 367 /* Initialize and register PJSUA application module. */ 966 368 { 967 pjsip_module my_mod=369 const pjsip_module mod_initializer = 968 370 { 969 371 NULL, NULL, /* prev, next. */ … … 982 384 }; 983 385 984 pjsua.mod = my_mod; 985 986 status = pjsip_endpt_register_module(pjsua.endpt, &pjsua.mod); 987 if (status != PJ_SUCCESS) { 988 pjsua_perror(THIS_FILE, "Unable to register pjsua module", 989 status); 990 goto on_error; 386 pjsua_var.mod = mod_initializer; 387 388 status = pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_var.mod); 389 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 390 } 391 392 393 394 /* Initialize PJSUA call subsystem: */ 395 status = pjsua_call_subsys_init(ua_cfg); 396 if (status != PJ_SUCCESS) 397 goto on_error; 398 399 400 /* Initialize PJSUA media subsystem */ 401 status = pjsua_media_subsys_init(media_cfg); 402 if (status != PJ_SUCCESS) 403 goto on_error; 404 405 406 /* Init core SIMPLE module : */ 407 status = pjsip_evsub_init_module(pjsua_var.endpt); 408 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 409 410 411 /* Init presence module: */ 412 status = pjsip_pres_init_module( pjsua_var.endpt, pjsip_evsub_instance()); 413 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 414 415 416 /* Init xfer/REFER module */ 417 status = pjsip_xfer_init_module( pjsua_var.endpt ); 418 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 419 420 /* Init pjsua presence handler: */ 421 status = pjsua_pres_init(); 422 if (status != PJ_SUCCESS) 423 goto on_error; 424 425 /* Init out-of-dialog MESSAGE request handler. */ 426 status = pjsua_im_init(); 427 if (status != PJ_SUCCESS) 428 goto on_error; 429 430 /* Start worker thread if needed. */ 431 if (pjsua_var.ua_cfg.thread_cnt) { 432 unsigned i; 433 434 if (pjsua_var.ua_cfg.thread_cnt > PJ_ARRAY_SIZE(pjsua_var.thread)) 435 pjsua_var.ua_cfg.thread_cnt = PJ_ARRAY_SIZE(pjsua_var.thread); 436 437 for (i=0; i<pjsua_var.ua_cfg.thread_cnt; ++i) { 438 status = pj_thread_create(pjsua_var.pool, "pjsua", &worker_thread, 439 NULL, 0, 0, &pjsua_var.thread[i]); 440 if (status != PJ_SUCCESS) 441 goto on_error; 991 442 } 992 443 } 993 444 994 /* Initialize invite session module: */ 995 996 status = pjsua_call_init(); 997 if (status != PJ_SUCCESS) { 998 pjsua_perror(THIS_FILE, "Invite usage initialization error", 999 status); 1000 goto on_error; 1001 } 1002 1003 /* Init core SIMPLE module : */ 1004 1005 pjsip_evsub_init_module(pjsua.endpt); 1006 1007 /* Init presence module: */ 1008 1009 pjsip_pres_init_module( pjsua.endpt, pjsip_evsub_instance()); 1010 1011 /* Init xfer/REFER module */ 1012 1013 pjsip_xfer_init_module( pjsua.endpt ); 1014 1015 /* Init pjsua presence handler: */ 1016 1017 pjsua_pres_init(); 1018 1019 /* Init out-of-dialog MESSAGE request handler. */ 1020 1021 pjsua_im_init(); 1022 1023 1024 /* Done. */ 445 /* Done! */ 446 447 PJ_LOG(3,(THIS_FILE, "pjsua version %s for %s initialized", 448 PJ_VERSION, PJ_OS_NAME)); 449 1025 450 return PJ_SUCCESS; 1026 451 … … 1031 456 1032 457 1033 /*1034 * Find account for incoming request.1035 */1036 PJ_DEF(pjsua_acc_id) pjsua_acc_find_for_incoming(pjsip_rx_data *rdata)1037 {1038 pjsip_uri *uri;1039 pjsip_sip_uri *sip_uri;1040 unsigned acc_index;1041 1042 uri = rdata->msg_info.to->uri;1043 1044 /* Just return default account if To URI is not SIP: */1045 if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&1046 !PJSIP_URI_SCHEME_IS_SIPS(uri))1047 {1048 return pjsua.default_acc;1049 }1050 1051 1052 sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);1053 1054 /* Find account which has matching username and domain. */1055 for (acc_index=0; acc_index < pjsua.config.acc_cnt; ++acc_index) {1056 1057 pjsua_acc *acc = &pjsua.acc[acc_index];1058 1059 if (pj_stricmp(&acc->user_part, &sip_uri->user)==0 &&1060 pj_stricmp(&acc->host_part, &sip_uri->host)==0)1061 {1062 /* Match ! */1063 return acc_index;1064 }1065 }1066 1067 /* No matching, try match domain part only. */1068 for (acc_index=0; acc_index < pjsua.config.acc_cnt; ++acc_index) {1069 1070 pjsua_acc *acc = &pjsua.acc[acc_index];1071 1072 if (pj_stricmp(&acc->host_part, &sip_uri->host)==0) {1073 /* Match ! */1074 return acc_index;1075 }1076 }1077 1078 /* Still no match, use default account */1079 return pjsua.default_acc;1080 }1081 1082 1083 /*1084 * Find account for outgoing request.1085 */1086 PJ_DEF(pjsua_acc_id) pjsua_acc_find_for_outgoing(const pj_str_t *str_url)1087 {1088 pj_str_t tmp;1089 pjsip_uri *uri;1090 pjsip_sip_uri *sip_uri;1091 unsigned i;1092 1093 pj_strdup_with_null(pjsua.pool, &tmp, str_url);1094 1095 uri = pjsip_parse_uri(pjsua.pool, tmp.ptr, tmp.slen, 0);1096 if (!uri)1097 return pjsua.config.acc_cnt-1;1098 1099 if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&1100 !PJSIP_URI_SCHEME_IS_SIPS(uri))1101 {1102 /* Return the first account with proxy */1103 for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) {1104 if (!pjsua.acc[i].valid)1105 continue;1106 if (pjsua.config.acc_config[i].proxy.slen)1107 break;1108 }1109 1110 if (i != PJ_ARRAY_SIZE(pjsua.acc))1111 return i;1112 1113 /* Not found, use default account */1114 return pjsua.default_acc;1115 }1116 1117 sip_uri = pjsip_uri_get_uri(uri);1118 1119 /* Find matching domain */1120 for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) {1121 if (!pjsua.acc[i].valid)1122 continue;1123 if (pj_stricmp(&pjsua.acc[i].host_part, &sip_uri->host)==0)1124 break;1125 }1126 1127 if (i != PJ_ARRAY_SIZE(pjsua.acc))1128 return i;1129 1130 /* Just use default account */1131 return pjsua.default_acc;1132 }1133 1134 1135 /*1136 * Init account1137 */1138 static pj_status_t init_acc(unsigned acc_index)1139 {1140 pjsua_acc_config *acc_cfg = &pjsua.config.acc_config[acc_index];1141 pjsua_acc *acc = &pjsua.acc[acc_index];1142 pjsip_uri *uri;1143 pjsip_sip_uri *sip_uri;1144 1145 /* Need to parse local_uri to get the elements: */1146 1147 uri = pjsip_parse_uri(pjsua.pool, acc_cfg->id.ptr,1148 acc_cfg->id.slen, 0);1149 if (uri == NULL) {1150 pjsua_perror(THIS_FILE, "Invalid local URI",1151 PJSIP_EINVALIDURI);1152 return PJSIP_EINVALIDURI;1153 }1154 1155 /* Local URI MUST be a SIP or SIPS: */1156 1157 if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&1158 !PJSIP_URI_SCHEME_IS_SIPS(uri))1159 {1160 pjsua_perror(THIS_FILE, "Invalid local URI",1161 PJSIP_EINVALIDSCHEME);1162 return PJSIP_EINVALIDSCHEME;1163 }1164 1165 1166 /* Get the SIP URI object: */1167 1168 sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri);1169 1170 acc->user_part = sip_uri->user;1171 acc->host_part = sip_uri->host;1172 1173 /* Build Contact header */1174 1175 if (acc_cfg->contact.slen == 0) {1176 char contact[128];1177 const char *addr;1178 int port;1179 int len;1180 1181 addr = pjsua.config.sip_host.ptr;1182 port = pjsua.config.sip_port;1183 1184 /* The local Contact is the username@ip-addr, where1185 * - username is taken from the local URI,1186 * - ip-addr in UDP transport's address name (which may have been1187 * resolved from STUN.1188 */1189 1190 /* Build temporary contact string. */1191 1192 if (sip_uri->user.slen) {1193 1194 /* With the user part. */1195 len = pj_ansi_snprintf(contact, sizeof(contact),1196 "<sip:%.*s@%s:%d>",1197 (int)sip_uri->user.slen,1198 sip_uri->user.ptr,1199 addr, port);1200 } else {1201 1202 /* Without user part */1203 1204 len = pj_ansi_snprintf(contact, sizeof(contact),1205 "<sip:%s:%d>",1206 addr, port);1207 }1208 1209 if (len < 1 || len >= sizeof(contact)) {1210 pjsua_perror(THIS_FILE, "Invalid Contact", PJSIP_EURITOOLONG);1211 return PJSIP_EURITOOLONG;1212 }1213 1214 /* Duplicate Contact uri. */1215 1216 pj_strdup2(pjsua.pool, &acc_cfg->contact, contact);1217 1218 }1219 1220 1221 /* Build route-set for this account */1222 if (pjsua.config.outbound_proxy.slen) {1223 pj_str_t hname = { "Route", 5};1224 pjsip_route_hdr *r;1225 pj_str_t tmp;1226 1227 pj_strdup_with_null(pjsua.pool, &tmp, &pjsua.config.outbound_proxy);1228 r = pjsip_parse_hdr(pjsua.pool, &hname, tmp.ptr, tmp.slen, NULL);1229 pj_list_push_back(&acc->route_set, r);1230 }1231 1232 if (acc_cfg->proxy.slen) {1233 pj_str_t hname = { "Route", 5};1234 pjsip_route_hdr *r;1235 pj_str_t tmp;1236 1237 pj_strdup_with_null(pjsua.pool, &tmp, &acc_cfg->proxy);1238 r = pjsip_parse_hdr(pjsua.pool, &hname, tmp.ptr, tmp.slen, NULL);1239 pj_list_push_back(&acc->route_set, r);1240 }1241 1242 /* Mark account as valid */1243 pjsua.acc[acc_index].valid = PJ_TRUE;1244 1245 1246 return PJ_SUCCESS;1247 }1248 1249 /*1250 * Add a new account.1251 */1252 PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg,1253 pjsua_acc_id *acc_index)1254 {1255 unsigned index;1256 pj_status_t status;1257 1258 PJ_ASSERT_RETURN(pjsua.config.acc_cnt <1259 PJ_ARRAY_SIZE(pjsua.config.acc_config),1260 PJ_ETOOMANY);1261 1262 /* Find empty account index. */1263 for (index=0; index < PJ_ARRAY_SIZE(pjsua.acc); ++index) {1264 if (pjsua.acc[index].valid == PJ_FALSE)1265 break;1266 }1267 1268 /* Expect to find a slot */1269 PJ_ASSERT_RETURN(index < PJ_ARRAY_SIZE(pjsua.acc), PJ_EBUG);1270 1271 copy_acc_config(pjsua.pool, &pjsua.config.acc_config[index], cfg);1272 1273 status = init_acc(index);1274 if (status != PJ_SUCCESS) {1275 pjsua_perror(THIS_FILE, "Error adding account", status);1276 return status;1277 }1278 1279 if (acc_index)1280 *acc_index = index;1281 1282 pjsua.config.acc_cnt++;1283 1284 return PJ_SUCCESS;1285 }1286 1287 1288 /*1289 * Delete account.1290 */1291 PJ_DEF(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_index)1292 {1293 PJ_ASSERT_RETURN(acc_index < (int)pjsua.config.acc_cnt,1294 PJ_EINVAL);1295 PJ_ASSERT_RETURN(pjsua.acc[acc_index].valid, PJ_EINVALIDOP);1296 1297 /* Delete registration */1298 if (pjsua.acc[acc_index].regc != NULL)1299 pjsua_acc_set_registration(acc_index, PJ_FALSE);1300 1301 /* Invalidate */1302 pjsua.acc[acc_index].valid = PJ_FALSE;1303 1304 return PJ_SUCCESS;1305 }1306 1307 1308 /*1309 * Start pjsua stack.1310 * This will start the registration process, if registration is configured.1311 */1312 PJ_DEF(pj_status_t) pjsua_start(void)1313 {1314 int i; /* Must be signed */1315 unsigned count;1316 pj_status_t status = PJ_SUCCESS;1317 1318 1319 /* Add UDP transport: */1320 if (pjsua.sip_sock > 0) {1321 1322 /* Init the published name for the transport.1323 * Depending whether STUN is used, this may be the STUN mapped1324 * address, or socket's bound address.1325 */1326 pjsip_host_port addr_name;1327 1328 addr_name.host = pjsua.config.sip_host;1329 addr_name.port = pjsua.config.sip_port;1330 1331 /* Create UDP transport from previously created UDP socket: */1332 1333 status = pjsip_udp_transport_attach( pjsua.endpt, pjsua.sip_sock,1334 &addr_name, 1,1335 NULL);1336 if (status != PJ_SUCCESS) {1337 pjsua_perror(THIS_FILE, "Unable to start UDP transport",1338 status);1339 goto on_error;1340 }1341 }1342 1343 /* Initialize all unused accounts with default id and contact.1344 */1345 {1346 char buf[80];1347 pj_str_t tmp, id;1348 1349 tmp.ptr = buf;1350 tmp.slen = pj_ansi_sprintf(tmp.ptr, "Local <sip:%s:%d>",1351 pjsua.config.sip_host.ptr,1352 pjsua.config.sip_port);1353 pj_strdup_with_null( pjsua.pool, &id, &tmp);1354 1355 for (i=pjsua.config.acc_cnt; i<PJ_ARRAY_SIZE(pjsua.config.acc_config);1356 ++i)1357 {1358 pjsua_acc_config *acc_cfg =1359 &pjsua.config.acc_config[pjsua.config.acc_cnt];1360 1361 acc_cfg->id = id;1362 acc_cfg->contact = id;1363 }1364 }1365 1366 1367 /* Add another account as the last one.1368 * This account corresponds to local endpoint, and is user-less.1369 * This is also the default account.1370 */1371 if (pjsua.config.acc_cnt < PJ_ARRAY_SIZE(pjsua.config.acc_config)) {1372 pjsua.default_acc = pjsua.config.acc_cnt;1373 pjsua.acc[pjsua.default_acc].auto_gen = 1;1374 pjsua.config.acc_cnt++;1375 }1376 1377 1378 /* Initialize accounts: */1379 for (i=0; i<(int)pjsua.config.acc_cnt; ++i) {1380 status = init_acc(i);1381 if (status != PJ_SUCCESS) {1382 pjsua_perror(THIS_FILE, "Error initializing account", status);1383 goto on_error;1384 }1385 }1386 1387 1388 /* Create worker thread(s), if required: */1389 1390 for (i=0; i<(int)pjsua.config.thread_cnt; ++i) {1391 status = pj_thread_create( pjsua.pool, "pjsua", &pjsua_poll,1392 NULL, 0, 0, &pjsua.threads[i]);1393 if (status != PJ_SUCCESS) {1394 pjsua.quit_flag = 1;1395 for (--i; i>=0; --i) {1396 pj_thread_join(pjsua.threads[i]);1397 pj_thread_destroy(pjsua.threads[i]);1398 }1399 goto on_error;1400 }1401 }1402 1403 /* Start registration: */1404 1405 /* Create client registration session: */1406 for (i=0; i<(int)pjsua.config.acc_cnt; ++i) {1407 status = pjsua_regc_init(i);1408 if (status != PJ_SUCCESS)1409 goto on_error;1410 1411 /* Perform registration, if required. */1412 if (pjsua.acc[i].regc) {1413 pjsua_acc_set_registration(i, PJ_TRUE);1414 }1415 }1416 1417 1418 /* Re-init buddies */1419 count = pjsua.config.buddy_cnt;1420 pjsua.config.buddy_cnt = 0;1421 for (i=0; i<(int)count; ++i) {1422 pj_str_t uri = pjsua.config.buddy_uri[i];1423 pjsua_buddy_add(&uri, NULL);1424 }1425 1426 1427 /* Refresh presence */1428 pjsua_pres_refresh();1429 1430 1431 PJ_LOG(3,(THIS_FILE, "PJSUA version %s started", PJ_VERSION));1432 return PJ_SUCCESS;1433 1434 on_error:1435 pjsua_destroy();1436 return status;1437 }1438 1439 1440 458 /* Sleep with polling */ 1441 459 static void busy_sleep(unsigned msec) … … 1448 466 1449 467 do { 1450 pjsua_poll(NULL); 468 while (pjsua_handle_events(10) > 0) 469 ; 1451 470 pj_gettimeofday(&now); 1452 471 } while (PJ_TIME_VAL_LT(now, timeout)); 1453 472 } 1454 473 1455 /** 1456 * Get maxinum number of conference ports. 1457 */ 1458 PJ_DEF(unsigned) pjsua_conf_max_ports(void) 1459 { 1460 return pjsua.config.conf_ports; 1461 } 1462 1463 1464 /** 1465 * Enum all conference port ID. 1466 */ 1467 PJ_DEF(pj_status_t) pjsua_conf_enum_port_ids( pjsua_conf_port_id id[], 1468 unsigned *count) 1469 { 1470 return pjmedia_conf_enum_ports( pjsua.mconf, (unsigned*)id, count); 1471 } 1472 1473 1474 1475 /** 1476 * Get information about the specified conference port 1477 */ 1478 PJ_DEF(pj_status_t) pjsua_conf_get_port_info( pjsua_conf_port_id id, 1479 pjsua_conf_port_info *info) 1480 { 1481 pjmedia_conf_port_info cinfo; 1482 unsigned i, count; 1483 pj_status_t status; 1484 1485 status = pjmedia_conf_get_port_info( pjsua.mconf, id, &cinfo); 1486 if (status != PJ_SUCCESS) 1487 return status; 1488 1489 pj_memset(info, 0, sizeof(*info)); 1490 info->slot_id = id; 1491 info->name = cinfo.name; 1492 info->clock_rate = cinfo.clock_rate; 1493 info->channel_count = cinfo.channel_count; 1494 info->samples_per_frame = cinfo.samples_per_frame; 1495 info->bits_per_sample = cinfo.bits_per_sample; 1496 1497 /* Build array of listeners */ 1498 count = pjsua.config.conf_ports; 1499 for (i=0; i<count; ++i) { 1500 if (cinfo.listener[i]) { 1501 info->listeners[info->listener_cnt++] = i; 474 /* 475 * Destroy pjsua. 476 */ 477 PJ_DEF(pj_status_t) pjsua_destroy(void) 478 { 479 int i; /* Must be signed */ 480 481 /* Signal threads to quit: */ 482 pjsua_var.thread_quit_flag = 1; 483 484 /* Wait worker threads to quit: */ 485 for (i=0; i<(int)pjsua_var.ua_cfg.thread_cnt; ++i) { 486 if (pjsua_var.thread[i]) { 487 pj_thread_join(pjsua_var.thread[i]); 488 pj_thread_destroy(pjsua_var.thread[i]); 489 pjsua_var.thread[i] = NULL; 1502 490 } 1503 491 } 1504 1505 return PJ_SUCCESS;1506 }1507 1508 1509 /**1510 * Connect conference port.1511 */1512 PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id src_port,1513 pjsua_conf_port_id dst_port)1514 {1515 return pjmedia_conf_connect_port(pjsua.mconf, src_port, dst_port, 0);1516 }1517 1518 1519 /**1520 * Connect conference port connection.1521 */1522 PJ_DEF(pj_status_t) pjsua_conf_disconnect( pjsua_conf_port_id src_port,1523 pjsua_conf_port_id dst_port)1524 {1525 return pjmedia_conf_disconnect_port(pjsua.mconf, src_port, dst_port);1526 }1527 1528 1529 1530 /**1531 * Create a file player.1532 */1533 PJ_DEF(pj_status_t) pjsua_player_create( const pj_str_t *filename,1534 pjsua_player_id *id)1535 {1536 unsigned slot;1537 char path[128];1538 pjmedia_port *port;1539 pj_status_t status;1540 1541 if (pjsua.player_cnt >= PJ_ARRAY_SIZE(pjsua.player))1542 return PJ_ETOOMANY;1543 1544 pj_memcpy(path, filename->ptr, filename->slen);1545 path[filename->slen] = '\0';1546 status = pjmedia_wav_player_port_create(pjsua.pool, path,1547 pjsua.samples_per_frame *1548 1000 / pjsua.clock_rate,1549 0, 0, NULL,1550 &port);1551 if (status != PJ_SUCCESS)1552 return status;1553 1554 status = pjmedia_conf_add_port(pjsua.mconf, pjsua.pool,1555 port, filename, &slot);1556 if (status != PJ_SUCCESS) {1557 pjmedia_port_destroy(port);1558 return status;1559 }1560 1561 pjsua.player[pjsua.player_cnt].port = port;1562 pjsua.player[pjsua.player_cnt].slot = slot;1563 1564 if (id)1565 *id = pjsua.player_cnt;1566 1567 ++pjsua.player_cnt;1568 1569 return PJ_SUCCESS;1570 }1571 1572 1573 /**1574 * Get conference port associated with player.1575 */1576 PJ_DEF(pjsua_conf_port_id) pjsua_player_get_conf_port(pjsua_player_id id)1577 {1578 PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.player), PJ_EINVAL);1579 return pjsua.player[id].slot;1580 }1581 1582 1583 /**1584 * Re-wind playback.1585 */1586 PJ_DEF(pj_status_t) pjsua_player_set_pos(pjsua_player_id id,1587 pj_uint32_t samples)1588 {1589 PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.player), PJ_EINVAL);1590 PJ_ASSERT_RETURN(pjsua.player[id].port != NULL, PJ_EINVALIDOP);1591 1592 return pjmedia_wav_player_port_set_pos(pjsua.player[id].port, samples);1593 }1594 1595 1596 /**1597 * Get conference port associated with player.1598 */1599 PJ_DEF(pj_status_t) pjsua_player_destroy(pjsua_player_id id)1600 {1601 PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.player), PJ_EINVAL);1602 1603 if (pjsua.player[id].port) {1604 pjmedia_port_destroy(pjsua.player[id].port);1605 pjsua.player[id].port = NULL;1606 pjsua.player[id].slot = 0xFFFF;1607 pjsua.player_cnt--;1608 }1609 1610 return PJ_SUCCESS;1611 }1612 1613 1614 /**1615 * Create a file recorder.1616 */1617 PJ_DEF(pj_status_t) pjsua_recorder_create( const pj_str_t *filename,1618 pjsua_recorder_id *id)1619 {1620 unsigned slot;1621 char path[128];1622 pjmedia_port *port;1623 pj_status_t status;1624 1625 if (pjsua.recorder_cnt >= PJ_ARRAY_SIZE(pjsua.recorder))1626 return PJ_ETOOMANY;1627 1628 pj_memcpy(path, filename->ptr, filename->slen);1629 path[filename->slen] = '\0';1630 status = pjmedia_wav_writer_port_create(pjsua.pool, path,1631 pjsua.clock_rate, 1,1632 pjsua.samples_per_frame,1633 16, 0, 0, NULL,1634 &port);1635 if (status != PJ_SUCCESS)1636 return status;1637 1638 status = pjmedia_conf_add_port(pjsua.mconf, pjsua.pool,1639 port, filename, &slot);1640 if (status != PJ_SUCCESS) {1641 pjmedia_port_destroy(port);1642 return status;1643 }1644 1645 pjsua.recorder[pjsua.recorder_cnt].port = port;1646 pjsua.recorder[pjsua.recorder_cnt].slot = slot;1647 1648 if (*id)1649 *id = pjsua.recorder_cnt;1650 1651 ++pjsua.recorder_cnt;1652 1653 return PJ_SUCCESS;1654 }1655 1656 1657 /**1658 * Get conference port associated with recorder.1659 */1660 PJ_DEF(pjsua_conf_port_id) pjsua_recorder_get_conf_port(pjsua_recorder_id id)1661 {1662 PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.recorder), PJ_EINVAL);1663 return pjsua.recorder[id].slot;1664 }1665 1666 1667 /**1668 * Destroy recorder (will complete recording).1669 */1670 PJ_DEF(pj_status_t) pjsua_recorder_destroy(pjsua_recorder_id id)1671 {1672 PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.recorder), PJ_EINVAL);1673 1674 if (pjsua.recorder[id].port) {1675 pjmedia_port_destroy(pjsua.recorder[id].port);1676 pjsua.recorder[id].port = NULL;1677 pjsua.recorder[id].slot = 0xFFFF;1678 pjsua.recorder_cnt--;1679 }1680 1681 return PJ_SUCCESS;1682 }1683 1684 /**1685 * Enum sound devices.1686 */1687 PJ_DEF(pj_status_t) pjsua_enum_snd_devices( unsigned *count,1688 pjmedia_snd_dev_info info[])1689 {1690 int i, dev_count;1691 1692 dev_count = pjmedia_snd_get_dev_count();1693 if (dev_count > (int)*count)1694 dev_count = *count;1695 1696 for (i=0; i<dev_count; ++i) {1697 const pjmedia_snd_dev_info *dev_info;1698 dev_info = pjmedia_snd_get_dev_info(i);1699 pj_memcpy(&info[i], dev_info, sizeof(pjmedia_snd_dev_info));1700 }1701 1702 *count = dev_count;1703 return PJ_SUCCESS;1704 }1705 1706 1707 /**1708 * Select or change sound device.1709 */1710 PJ_DEF(pj_status_t) pjsua_set_snd_dev( int snd_capture_id,1711 int snd_player_id)1712 {1713 pjsua.config.snd_capture_id = snd_capture_id;1714 pjsua.config.snd_player_id = snd_player_id;1715 return PJ_SUCCESS;1716 }1717 1718 1719 /*1720 * Destroy pjsua.1721 */1722 PJ_DEF(pj_status_t) pjsua_destroy(void)1723 {1724 int i; /* Must be signed */1725 1726 /* Signal threads to quit: */1727 pjsua.quit_flag = 1;1728 1729 /* Wait worker threads to quit: */1730 for (i=0; i<(int)pjsua.config.thread_cnt; ++i) {1731 1732 if (pjsua.threads[i]) {1733 pj_thread_join(pjsua.threads[i]);1734 pj_thread_destroy(pjsua.threads[i]);1735 pjsua.threads[i] = NULL;1736 }1737 }1738 1739 492 1740 if (pjsua .endpt) {493 if (pjsua_var.endpt) { 1741 494 /* Terminate all calls. */ 1742 495 pjsua_call_hangup_all(); … … 1746 499 1747 500 /* Unregister, if required: */ 1748 for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 1749 if (pjsua.acc[i].regc) { 501 for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { 502 if (!pjsua_var.acc[i].valid) 503 continue; 504 505 if (pjsua_var.acc[i].regc) { 1750 506 pjsua_acc_set_registration(i, PJ_FALSE); 1751 507 } … … 1757 513 } 1758 514 1759 /* If we have master port, destroying master port will recursively 1760 * destroy conference bridge, otherwise must destroy it manually. 515 /* Destroy media */ 516 pjsua_media_subsys_destroy(); 517 518 /* Destroy endpoint. */ 519 if (pjsua_var.endpt) { 520 pjsip_endpt_destroy(pjsua_var.endpt); 521 pjsua_var.endpt = NULL; 522 } 523 524 /* Destroy mutex */ 525 if (pjsua_var.mutex) { 526 pj_mutex_destroy(pjsua_var.mutex); 527 pjsua_var.mutex = NULL; 528 } 529 530 /* Destroy pool and pool factory. */ 531 if (pjsua_var.pool) { 532 pj_pool_release(pjsua_var.pool); 533 pjsua_var.pool = NULL; 534 pj_caching_pool_destroy(&pjsua_var.cp); 535 } 536 537 538 PJ_LOG(4,(THIS_FILE, "PJSUA destroyed...")); 539 540 /* End logging */ 541 if (pjsua_var.log_file) { 542 pj_file_close(pjsua_var.log_file); 543 pjsua_var.log_file = NULL; 544 } 545 546 /* Done. */ 547 return PJ_SUCCESS; 548 } 549 550 551 /** 552 * Application is recommended to call this function after all initialization 553 * is done, so that the library can do additional checking set up 554 * additional 555 * 556 * @return PJ_SUCCESS on success, or the appropriate error code. 557 */ 558 PJ_DEF(pj_status_t) pjsua_start(void) 559 { 560 pj_status_t status; 561 562 status = pjsua_call_subsys_start(); 563 if (status != PJ_SUCCESS) 564 return status; 565 566 status = pjsua_media_subsys_start(); 567 if (status != PJ_SUCCESS) 568 return status; 569 570 status = pjsua_pres_start(); 571 if (status != PJ_SUCCESS) 572 return status; 573 574 return PJ_SUCCESS; 575 } 576 577 578 /** 579 * Poll pjsua for events, and if necessary block the caller thread for 580 * the specified maximum interval (in miliseconds). 581 */ 582 PJ_DEF(int) pjsua_handle_events(unsigned msec_timeout) 583 { 584 unsigned count = 0; 585 pj_time_val tv; 586 pj_status_t status; 587 588 tv.sec = 0; 589 tv.msec = msec_timeout; 590 pj_time_val_normalize(&tv); 591 592 status = pjsip_endpt_handle_events2(pjsua_var.endpt, &tv, &count); 593 594 if (status != PJ_SUCCESS) 595 return -status; 596 597 return count; 598 } 599 600 601 /* 602 * Create memory pool. 603 */ 604 PJ_DEF(pj_pool_t*) pjsua_pool_create( const char *name, pj_size_t init_size, 605 pj_size_t increment) 606 { 607 /* Pool factory is thread safe, no need to lock */ 608 return pj_pool_create(&pjsua_var.cp.factory, name, init_size, increment, 609 NULL); 610 } 611 612 613 /* 614 * Internal function to get SIP endpoint instance of pjsua, which is 615 * needed for example to register module, create transports, etc. 616 * Probably is only valid after #pjsua_init() is called. 617 */ 618 PJ_DEF(pjsip_endpoint*) pjsua_get_pjsip_endpt(void) 619 { 620 return pjsua_var.endpt; 621 } 622 623 /* 624 * Internal function to get media endpoint instance. 625 * Only valid after #pjsua_init() is called. 626 */ 627 PJ_DEF(pjmedia_endpt*) pjsua_get_pjmedia_endpt(void) 628 { 629 return pjsua_var.med_endpt; 630 } 631 632 633 /***************************************************************************** 634 * PJSUA SIP Transport API. 635 */ 636 637 /* 638 * Create and initialize SIP socket (and possibly resolve public 639 * address via STUN, depending on config). 640 */ 641 static pj_status_t create_sip_udp_sock(pj_in_addr bound_addr, 642 int port, 643 pj_bool_t use_stun, 644 const pjsua_stun_config *stun_param, 645 pj_sock_t *p_sock, 646 pj_sockaddr_in *p_pub_addr) 647 { 648 pjsua_stun_config stun; 649 pj_sock_t sock; 650 pj_status_t status; 651 652 PJSUA_LOCK(); 653 654 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 655 if (status != PJ_SUCCESS) { 656 pjsua_perror(THIS_FILE, "socket() error", status); 657 goto on_return; 658 } 659 660 status = pj_sock_bind_in(sock, bound_addr.s_addr, (pj_uint16_t)port); 661 if (status != PJ_SUCCESS) { 662 pjsua_perror(THIS_FILE, "bind() error", status); 663 pj_sock_close(sock); 664 goto on_return; 665 } 666 667 /* Copy and normalize STUN param */ 668 if (use_stun) { 669 pj_memcpy(&stun, stun_param, sizeof(*stun_param)); 670 pjsua_normalize_stun_config(&stun); 671 } else { 672 pj_memset(&stun, 0, sizeof(pjsua_stun_config)); 673 } 674 675 /* Get the published address, either by STUN or by resolving 676 * the name of local host. 1761 677 */ 1762 if (pjsua.master_port) { 1763 pjmedia_master_port_destroy(pjsua.master_port); 1764 pjsua.master_port = NULL; 678 if (stun.stun_srv1.slen) { 679 status = pj_stun_get_mapped_addr(&pjsua_var.cp.factory, 1, &sock, 680 &stun.stun_srv1, 681 stun.stun_port1, 682 &stun.stun_srv2, 683 stun.stun_port2, 684 p_pub_addr); 685 if (status != PJ_SUCCESS) { 686 pjsua_perror(THIS_FILE, "Error resolving with STUN", status); 687 pj_sock_close(sock); 688 goto on_return; 689 } 690 1765 691 } else { 1766 if (pjsua.snd_port) { 1767 pjmedia_snd_port_destroy(pjsua.snd_port); 1768 pjsua.snd_port = NULL; 692 693 const pj_str_t *hostname = pj_gethostname(); 694 struct pj_hostent he; 695 696 status = pj_gethostbyname(hostname, &he); 697 if (status != PJ_SUCCESS) { 698 pjsua_perror(THIS_FILE, "Unable to resolve local host", status); 699 pj_sock_close(sock); 700 goto on_return; 1769 701 } 1770 if (pjsua.mconf) { 1771 pjmedia_conf_destroy(pjsua.mconf); 1772 pjsua.mconf = NULL; 702 703 pj_memset(p_pub_addr, 0, sizeof(pj_sockaddr_in)); 704 p_pub_addr->sin_family = PJ_AF_INET; 705 p_pub_addr->sin_port = pj_htons((pj_uint16_t)port); 706 p_pub_addr->sin_addr = *(pj_in_addr*)he.h_addr; 707 } 708 709 *p_sock = sock; 710 711 on_return: 712 713 PJSUA_UNLOCK(); 714 715 PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d", 716 pj_inet_ntoa(p_pub_addr->sin_addr), 717 (int)pj_ntohs(p_pub_addr->sin_port))); 718 719 return status; 720 } 721 722 723 /* 724 * Create SIP transport. 725 */ 726 PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type, 727 const pjsua_transport_config *cfg, 728 pjsua_transport_id *p_id) 729 { 730 pjsip_transport *tp; 731 unsigned id; 732 pj_status_t status; 733 734 PJSUA_LOCK(); 735 736 /* Find empty transport slot */ 737 for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) { 738 if (pjsua_var.tpdata[id].tp == NULL) 739 break; 740 } 741 742 if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) { 743 status = PJ_ETOOMANY; 744 pjsua_perror(THIS_FILE, "Error creating transport", status); 745 goto on_return; 746 } 747 748 /* Create the transport */ 749 if (type == PJSIP_TRANSPORT_UDP) { 750 751 pjsua_transport_config config; 752 pj_sock_t sock; 753 pj_sockaddr_in pub_addr; 754 pjsip_host_port addr_name; 755 756 /* Supply default config if it's not specified */ 757 if (cfg == NULL) { 758 pjsua_transport_config_default(&config); 759 cfg = &config; 1773 760 } 1774 } 1775 1776 /* Destroy file players */ 1777 for (i=0; i<PJ_ARRAY_SIZE(pjsua.player); ++i) { 1778 if (pjsua.player[i].port) { 1779 pjmedia_port_destroy(pjsua.player[i].port); 1780 pjsua.player[i].port = NULL; 761 762 /* Create the socket and possibly resolve the address with STUN */ 763 status = create_sip_udp_sock(cfg->ip_addr, cfg->port, cfg->use_stun, 764 &cfg->stun_config, &sock, &pub_addr); 765 if (status != PJ_SUCCESS) 766 goto on_return; 767 768 addr_name.host = pj_str(pj_inet_ntoa(pub_addr.sin_addr)); 769 addr_name.port = pj_ntohs(pub_addr.sin_port); 770 771 /* Create UDP transport */ 772 status = pjsip_udp_transport_attach( pjsua_var.endpt, sock, 773 &addr_name, 1, 774 &tp); 775 if (status != PJ_SUCCESS) { 776 pjsua_perror(THIS_FILE, "Error creating SIP UDP transport", 777 status); 778 pj_sock_close(sock); 779 goto on_return; 1781 780 } 1782 } 1783 1784 1785 /* Destroy file recorders */ 1786 for (i=0; i<PJ_ARRAY_SIZE(pjsua.recorder); ++i) { 1787 if (pjsua.recorder[i].port) { 1788 pjmedia_port_destroy(pjsua.recorder[i].port); 1789 pjsua.recorder[i].port = NULL; 1790 } 1791 } 1792 1793 1794 /* Close transports */ 1795 for (i=0; i<(int)pjsua.config.max_calls; ++i) { 1796 if (pjsua.calls[i].med_tp) { 1797 (*pjsua.calls[i].med_tp->op->destroy)(pjsua.calls[i].med_tp); 1798 pjsua.calls[i].med_tp = NULL; 1799 } 1800 } 1801 1802 /* Destroy media endpoint. */ 1803 if (pjsua.med_endpt) { 1804 1805 /* Shutdown all codecs: */ 1806 # if PJMEDIA_HAS_SPEEX_CODEC 1807 pjmedia_codec_speex_deinit(); 1808 # endif /* PJMEDIA_HAS_SPEEX_CODEC */ 1809 1810 # if PJMEDIA_HAS_GSM_CODEC 1811 pjmedia_codec_gsm_deinit(); 1812 # endif /* PJMEDIA_HAS_GSM_CODEC */ 1813 1814 # if PJMEDIA_HAS_G711_CODEC 1815 pjmedia_codec_g711_deinit(); 1816 # endif /* PJMEDIA_HAS_G711_CODEC */ 1817 1818 # if PJMEDIA_HAS_L16_CODEC 1819 pjmedia_codec_l16_deinit(); 1820 # endif /* PJMEDIA_HAS_L16_CODEC */ 1821 1822 1823 pjmedia_endpt_destroy(pjsua.med_endpt); 1824 pjsua.med_endpt = NULL; 1825 } 1826 1827 /* Destroy endpoint. */ 1828 if (pjsua.endpt) { 1829 pjsip_endpt_destroy(pjsua.endpt); 1830 pjsua.endpt = NULL; 1831 } 1832 1833 /* Destroy caching pool. */ 1834 pj_caching_pool_destroy(&pjsua.cp); 1835 1836 1837 PJ_LOG(4,(THIS_FILE, "PJSUA destroyed...")); 1838 1839 /* End logging */ 1840 logging_shutdown(); 1841 1842 /* Done. */ 781 782 } else { 783 status = PJSIP_EUNSUPTRANSPORT; 784 pjsua_perror(THIS_FILE, "Error creating transport", status); 785 goto on_return; 786 } 787 788 /* Save the transport */ 789 pjsua_var.tpdata[id].tp = tp; 790 791 /* Return the ID */ 792 if (p_id) *p_id = id; 793 794 status = PJ_SUCCESS; 795 796 on_return: 797 798 PJSUA_UNLOCK(); 1843 799 1844 800 return PJ_SUCCESS; … … 1846 802 1847 803 1848 /** 1849 * Get SIP endpoint instance. 1850 * Only valid after pjsua_init(). 1851 */ 1852 PJ_DEF(pjsip_endpoint*) pjsua_get_pjsip_endpt(void) 1853 { 1854 return pjsua.endpt; 1855 } 1856 1857 /** 1858 * Get media endpoint instance. 1859 * Only valid after pjsua_init(). 1860 */ 1861 PJ_DEF(pjmedia_endpt*) pjsua_get_pjmedia_endpt(void) 1862 { 1863 return pjsua.med_endpt; 1864 } 1865 804 /* 805 * Register transport that has been created by application. 806 */ 807 PJ_DEF(pj_status_t) pjsua_transport_register( pjsip_transport *tp, 808 pjsua_transport_id *p_id) 809 { 810 unsigned id; 811 812 PJSUA_LOCK(); 813 814 /* Find empty transport slot */ 815 for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) { 816 if (pjsua_var.tpdata[id].tp == NULL) 817 break; 818 } 819 820 if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) { 821 pjsua_perror(THIS_FILE, "Error creating transport", PJ_ETOOMANY); 822 PJSUA_UNLOCK(); 823 return PJ_ETOOMANY; 824 } 825 826 /* Save the transport */ 827 pjsua_var.tpdata[id].tp = tp; 828 829 /* Return the ID */ 830 if (p_id) *p_id = id; 831 832 PJSUA_UNLOCK(); 833 834 return PJ_SUCCESS; 835 } 836 837 838 /* 839 * Enumerate all transports currently created in the system. 840 */ 841 PJ_DEF(pj_status_t) pjsua_enum_transports( pjsua_transport_id id[], 842 unsigned *p_count ) 843 { 844 unsigned i, count; 845 846 PJSUA_LOCK(); 847 848 for (i=0, count=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata) && count<*p_count; 849 ++i) 850 { 851 if (!pjsua_var.tpdata[i].tp) 852 continue; 853 854 id[count++] = i; 855 } 856 857 *p_count = count; 858 859 PJSUA_UNLOCK(); 860 861 return PJ_SUCCESS; 862 } 863 864 865 /* 866 * Get information about transports. 867 */ 868 PJ_DEF(pj_status_t) pjsua_transport_get_info( pjsua_transport_id id, 869 pjsua_transport_info *info) 870 { 871 pjsip_transport *tp; 872 873 pj_memset(info, 0, sizeof(*info)); 874 875 /* Make sure id is in range. */ 876 PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL); 877 878 /* Make sure that transport exists */ 879 PJ_ASSERT_RETURN(pjsua_var.tpdata[id].tp != NULL, PJ_EINVAL); 880 881 PJSUA_LOCK(); 882 883 tp = pjsua_var.tpdata[id].tp; 884 if (tp == NULL) { 885 PJSUA_UNLOCK(); 886 return PJ_EINVALIDOP; 887 } 888 889 info->id = id; 890 info->type = tp->key.type; 891 info->type_name = pj_str(tp->type_name); 892 info->info = pj_str(tp->info); 893 info->flag = tp->flag; 894 info->addr_len = tp->addr_len; 895 info->local_addr = tp->local_addr; 896 info->local_name = tp->local_name; 897 info->usage_count = pj_atomic_get(tp->ref_cnt); 898 899 PJSUA_UNLOCK(); 900 901 return PJ_EINVALIDOP; 902 } 903 904 905 /* 906 * Disable a transport or re-enable it. 907 */ 908 PJ_DEF(pj_status_t) pjsua_transport_set_enable( pjsua_transport_id id, 909 pj_bool_t enabled) 910 { 911 /* Make sure id is in range. */ 912 PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL); 913 914 /* Make sure that transport exists */ 915 PJ_ASSERT_RETURN(pjsua_var.tpdata[id].tp != NULL, PJ_EINVAL); 916 917 918 /* To be done!! */ 919 PJ_TODO(pjsua_transport_set_enable); 920 921 return PJ_EINVALIDOP; 922 } 923 924 925 /* 926 * Close the transport. 927 */ 928 PJ_DEF(pj_status_t) pjsua_transport_close( pjsua_transport_id id, 929 pj_bool_t force ) 930 { 931 /* Make sure id is in range. */ 932 PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL); 933 934 /* Make sure that transport exists */ 935 PJ_ASSERT_RETURN(pjsua_var.tpdata[id].tp != NULL, PJ_EINVAL); 936 937 938 /* To be done!! */ 939 940 941 PJ_TODO(pjsua_transport_close); 942 943 return PJ_EINVALIDOP; 944 } 945 946 947 /* 948 * Add additional headers etc in msg_data specified by application 949 * when sending requests. 950 */ 951 void pjsua_process_msg_data(pjsip_tx_data *tdata, 952 const pjsua_msg_data *msg_data) 953 { 954 pj_bool_t allow_body; 955 const pjsip_hdr *hdr; 956 957 if (!msg_data) 958 return; 959 960 hdr = msg_data->hdr_list.next; 961 while (hdr && hdr != &msg_data->hdr_list) { 962 pjsip_hdr *new_hdr; 963 964 new_hdr = pjsip_hdr_clone(tdata->pool, hdr); 965 pjsip_msg_add_hdr(tdata->msg, new_hdr); 966 967 hdr = hdr->next; 968 } 969 970 allow_body = (tdata->msg->body == NULL); 971 972 if (allow_body && msg_data->content_type.slen && msg_data->msg_body.slen) { 973 pjsip_media_type ctype; 974 pjsip_msg_body *body; 975 976 pjsua_parse_media_type(tdata->pool, &msg_data->content_type, &ctype); 977 body = pjsip_msg_body_create(tdata->pool, &ctype.type, &ctype.subtype, 978 &msg_data->msg_body); 979 tdata->msg->body = body; 980 } 981 } 982 983 984 /* 985 * Add route_set to outgoing requests 986 */ 987 void pjsua_set_msg_route_set( pjsip_tx_data *tdata, 988 const pjsip_route_hdr *route_set ) 989 { 990 const pjsip_route_hdr *r; 991 992 r = route_set->next; 993 while (r != route_set) { 994 pjsip_route_hdr *new_r; 995 996 new_r = pjsip_hdr_clone(tdata->pool, r); 997 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)new_r); 998 999 r = r->next; 1000 } 1001 } 1002 1003 1004 /* 1005 * Simple version of MIME type parsing (it doesn't support parameters) 1006 */ 1007 void pjsua_parse_media_type( pj_pool_t *pool, 1008 const pj_str_t *mime, 1009 pjsip_media_type *media_type) 1010 { 1011 pj_str_t tmp; 1012 char *pos; 1013 1014 pj_memset(media_type, 0, sizeof(*media_type)); 1015 1016 pj_strdup_with_null(pool, &tmp, mime); 1017 1018 pos = pj_strchr(&tmp, '/'); 1019 if (pos) { 1020 media_type->type.ptr = tmp.ptr; 1021 media_type->type.slen = (pos-tmp.ptr); 1022 media_type->subtype.ptr = pos+1; 1023 media_type->subtype.slen = tmp.ptr+tmp.slen-pos-1; 1024 } else { 1025 media_type->type = tmp; 1026 } 1027 } 1028 1029 1030 /* 1031 * Verify that valid SIP url is given. 1032 */ 1033 PJ_DEF(pj_status_t) pjsua_verify_sip_url(const char *c_url) 1034 { 1035 pjsip_uri *p; 1036 pj_pool_t *pool; 1037 char *url; 1038 int len = (c_url ? pj_ansi_strlen(c_url) : 0); 1039 1040 if (!len) return -1; 1041 1042 pool = pj_pool_create(&pjsua_var.cp.factory, "check%p", 1024, 0, NULL); 1043 if (!pool) return -1; 1044 1045 url = pj_pool_alloc(pool, len+1); 1046 pj_ansi_strcpy(url, c_url); 1047 1048 p = pjsip_parse_uri(pool, url, len, 0); 1049 if (!p || pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0) 1050 p = NULL; 1051 1052 pj_pool_release(pool); 1053 return p ? 0 : -1; 1054 }
Note: See TracChangeset
for help on using the changeset viewer.