📄 pjsua_core.c
字号:
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Initialize UA layer module: */ status = pjsip_ua_init_module( pjsua_var.endpt, NULL ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Initialize Replaces support. */ status = pjsip_replaces_init_module( pjsua_var.endpt ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Initialize and register PJSUA application module. */ { const pjsip_module mod_initializer = { NULL, NULL, /* prev, next. */ { "mod-pjsua", 9 }, /* Name. */ -1, /* Id */ PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */ NULL, /* load() */ NULL, /* start() */ NULL, /* stop() */ NULL, /* unload() */ &mod_pjsua_on_rx_request, /* on_rx_request() */ &mod_pjsua_on_rx_response, /* on_rx_response() */ NULL, /* on_tx_request. */ NULL, /* on_tx_response() */ NULL, /* on_tsx_state() */ }; pjsua_var.mod = mod_initializer; status = pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_var.mod); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); } /* Initialize PJSUA call subsystem: */ status = pjsua_call_subsys_init(ua_cfg); if (status != PJ_SUCCESS) goto on_error; /* Initialize PJSUA media subsystem */ status = pjsua_media_subsys_init(media_cfg); if (status != PJ_SUCCESS) goto on_error; /* Init core SIMPLE module : */ status = pjsip_evsub_init_module(pjsua_var.endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Init presence module: */ status = pjsip_pres_init_module( pjsua_var.endpt, pjsip_evsub_instance()); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Init PUBLISH module */ pjsip_publishc_init_module(pjsua_var.endpt); /* Init xfer/REFER module */ status = pjsip_xfer_init_module( pjsua_var.endpt ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Init pjsua presence handler: */ status = pjsua_pres_init(); if (status != PJ_SUCCESS) goto on_error; /* Init out-of-dialog MESSAGE request handler. */ status = pjsua_im_init(); if (status != PJ_SUCCESS) goto on_error; /* Register OPTIONS handler */ pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_options_handler); /* Add OPTIONS in Allow header */ pjsip_endpt_add_capability(pjsua_var.endpt, NULL, PJSIP_H_ALLOW, NULL, 1, &STR_OPTIONS); /* Start worker thread if needed. */ if (pjsua_var.ua_cfg.thread_cnt) { unsigned i; if (pjsua_var.ua_cfg.thread_cnt > PJ_ARRAY_SIZE(pjsua_var.thread)) pjsua_var.ua_cfg.thread_cnt = PJ_ARRAY_SIZE(pjsua_var.thread); for (i=0; i<pjsua_var.ua_cfg.thread_cnt; ++i) { status = pj_thread_create(pjsua_var.pool, "pjsua", &worker_thread, NULL, 0, 0, &pjsua_var.thread[i]); if (status != PJ_SUCCESS) goto on_error; } PJ_LOG(4,(THIS_FILE, "%d SIP worker threads created", pjsua_var.ua_cfg.thread_cnt)); } else { PJ_LOG(4,(THIS_FILE, "No SIP worker threads created")); } /* Done! */ PJ_LOG(3,(THIS_FILE, "pjsua version %s for %s initialized", PJ_VERSION, PJ_OS_NAME)); return PJ_SUCCESS;on_error: pjsua_destroy(); return status;}/* Sleep with polling */static void busy_sleep(unsigned msec){ pj_time_val timeout, now; pj_gettimeofday(&timeout); timeout.msec += msec; pj_time_val_normalize(&timeout); do { while (pjsua_handle_events(10) > 0) ; pj_gettimeofday(&now); } while (PJ_TIME_VAL_LT(now, timeout));}/* * Destroy pjsua. */PJ_DEF(pj_status_t) pjsua_destroy(void){ int i; /* Must be signed */ /* Signal threads to quit: */ pjsua_var.thread_quit_flag = 1; /* Wait worker threads to quit: */ for (i=0; i<(int)pjsua_var.ua_cfg.thread_cnt; ++i) { if (pjsua_var.thread[i]) { pj_thread_join(pjsua_var.thread[i]); pj_thread_destroy(pjsua_var.thread[i]); pjsua_var.thread[i] = NULL; } } if (pjsua_var.endpt) { /* Terminate all calls. */ pjsua_call_hangup_all(); /* Terminate all presence subscriptions. */ pjsua_pres_shutdown(); /* Unregister, if required: */ for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { if (!pjsua_var.acc[i].valid) continue; if (pjsua_var.acc[i].regc) { pjsua_acc_set_registration(i, PJ_FALSE); } } /* Wait for some time to allow unregistration to complete: */ PJ_LOG(4,(THIS_FILE, "Shutting down...")); busy_sleep(1000); } /* Destroy media */ pjsua_media_subsys_destroy(); /* Destroy endpoint. */ if (pjsua_var.endpt) { pjsip_endpt_destroy(pjsua_var.endpt); pjsua_var.endpt = NULL; } /* Destroy mutex */ if (pjsua_var.mutex) { pj_mutex_destroy(pjsua_var.mutex); pjsua_var.mutex = NULL; } /* Destroy pool and pool factory. */ if (pjsua_var.pool) { pj_pool_release(pjsua_var.pool); pjsua_var.pool = NULL; pj_caching_pool_destroy(&pjsua_var.cp); PJ_LOG(4,(THIS_FILE, "PJSUA destroyed...")); /* End logging */ if (pjsua_var.log_file) { pj_file_close(pjsua_var.log_file); pjsua_var.log_file = NULL; } /* Shutdown PJLIB */ pj_shutdown(); } /* Clear pjsua_var */ pj_bzero(&pjsua_var, sizeof(pjsua_var)); /* Done. */ return PJ_SUCCESS;}/** * Application is recommended to call this function after all initialization * is done, so that the library can do additional checking set up * additional * * @return PJ_SUCCESS on success, or the appropriate error code. */PJ_DEF(pj_status_t) pjsua_start(void){ pj_status_t status; status = pjsua_call_subsys_start(); if (status != PJ_SUCCESS) return status; status = pjsua_media_subsys_start(); if (status != PJ_SUCCESS) return status; status = pjsua_pres_start(); if (status != PJ_SUCCESS) return status; return PJ_SUCCESS;}/** * Poll pjsua for events, and if necessary block the caller thread for * the specified maximum interval (in miliseconds). */PJ_DEF(int) pjsua_handle_events(unsigned msec_timeout){ unsigned count = 0; pj_time_val tv; pj_status_t status; tv.sec = 0; tv.msec = msec_timeout; pj_time_val_normalize(&tv); status = pjsip_endpt_handle_events2(pjsua_var.endpt, &tv, &count); if (status != PJ_SUCCESS) return -status; return count;}/* * Create memory pool. */PJ_DEF(pj_pool_t*) pjsua_pool_create( const char *name, pj_size_t init_size, pj_size_t increment){ /* Pool factory is thread safe, no need to lock */ return pj_pool_create(&pjsua_var.cp.factory, name, init_size, increment, NULL);}/* * Internal function to get SIP endpoint instance of pjsua, which is * needed for example to register module, create transports, etc. * Probably is only valid after #pjsua_init() is called. */PJ_DEF(pjsip_endpoint*) pjsua_get_pjsip_endpt(void){ return pjsua_var.endpt;}/* * Internal function to get media endpoint instance. * Only valid after #pjsua_init() is called. */PJ_DEF(pjmedia_endpt*) pjsua_get_pjmedia_endpt(void){ return pjsua_var.med_endpt;}/* * Internal function to get PJSUA pool factory. */PJ_DEF(pj_pool_factory*) pjsua_get_pool_factory(void){ return &pjsua_var.cp.factory;}/***************************************************************************** * PJSUA SIP Transport API. *//* * Create and initialize SIP socket (and possibly resolve public * address via STUN, depending on config). */static pj_status_t create_sip_udp_sock(pj_in_addr bound_addr, int port, pj_bool_t use_stun, const pjsua_stun_config *stun_param, pj_sock_t *p_sock, pj_sockaddr_in *p_pub_addr){ pjsua_stun_config stun; pj_sock_t sock; pj_status_t status; status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "socket() error", status); return status; } status = pj_sock_bind_in(sock, pj_ntohl(bound_addr.s_addr), (pj_uint16_t)port); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "bind() error", status); pj_sock_close(sock); return status; } /* If port is zero, get the bound port */ if (port == 0) { pj_sockaddr_in bound_addr; int namelen = sizeof(bound_addr); status = pj_sock_getsockname(sock, &bound_addr, &namelen); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "getsockname() error", status); pj_sock_close(sock); return status; } port = pj_ntohs(bound_addr.sin_port); } /* Copy and normalize STUN param */ if (use_stun) { pj_memcpy(&stun, stun_param, sizeof(*stun_param)); pjsua_normalize_stun_config(&stun); } else { pj_bzero(&stun, sizeof(pjsua_stun_config)); } /* Get the published address, either by STUN or by resolving * the name of local host. */ if (stun.stun_srv1.slen) { /* * STUN is specified, resolve the address with STUN. */ status = pj_stun_get_mapped_addr(&pjsua_var.cp.factory, 1, &sock, &stun.stun_srv1, stun.stun_port1, &stun.stun_srv2, stun.stun_port2, p_pub_addr); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error resolving with STUN", status); pj_sock_close(sock); return status; } } else if (p_pub_addr->sin_addr.s_addr != 0) { /* * Public address is already specified, no need to resolve the * address, only set the port. */ if (p_pub_addr->sin_port == 0) p_pub_addr->sin_port = pj_htons((pj_uint16_t)port); } else { pj_bzero(p_pub_addr, sizeof(pj_sockaddr_in)); status = pj_gethostip(&p_pub_addr->sin_addr); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to get local host IP", status); pj_sock_close(sock); return status; } p_pub_addr->sin_family = PJ_AF_INET; p_pub_addr->sin_port = pj_htons((pj_uint16_t)port); } *p_sock = sock; PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d", pj_inet_ntoa(p_pub_addr->sin_addr), (int)pj_ntohs(p_pub_addr->sin_port))); return PJ_SUCCESS;}/* * Create SIP transport. */PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type, const pjsua_transport_config *cfg, pjsua_transport_id *p_id){ pjsip_transport *tp; unsigned id; pj_status_t status; PJSUA_LOCK(); /* Find empty transport slot */ for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) { if (pjsua_var.tpdata[id].data.ptr == NULL) break; } if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) { status = PJ_ETOOMANY; pjsua_perror(THIS_FILE, "Error creating transport", status); goto on_return; } /* Create the transport */ if (type == PJSIP_TRANSPORT_UDP) { /* * Create UDP transport. */ pjsua_transport_config config; pj_sock_t sock = PJ_INVALID_SOCKET; pj_sockaddr_in bound_addr; pj_sockaddr_in pub_addr; pjsip_host_port addr_name; /* Supply default config if it's not specified */ if (cfg == NULL) { pjsua_transport_config_default(&config); cfg = &config; } /* Initialize bound address, if any */ bound_addr.sin_addr.s_addr = PJ_INADDR_ANY; if (cfg->bound_addr.slen) { status = pj_sockaddr_in_set_str_addr(&bound_addr,&cfg->bound_addr); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to resolve transport bound address", status); goto on_return; } } /* Initialize the public address from the config, if any */ pj_sockaddr_in_init(&pub_addr, NULL, (pj_uint16_t)cfg->port); if (cfg->public_addr.slen) { status = pj_sockaddr_in_set_str_addr(&pub_addr, &cfg->public_addr); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to resolve transport public address", status); goto on_return; } } /* Create the socket and possibly resolve the address with STUN * (only when public address is not specified). */ status = create_sip_udp_sock(bound_addr.sin_addr, cfg->port, cfg->use_stun, &cfg->stun_config, &sock, &pub_addr); if (status != PJ_SUCCESS) goto on_return; addr_name.host = pj_str(pj_inet_ntoa(pub_addr.sin_addr)); addr_name.port = pj_ntohs(pub_addr.sin_port); /* Create UDP transport */ status = pjsip_udp_transport_attach( pjsua_var.endpt, sock, &addr_name, 1, &tp); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error creating SIP UDP transport", status); pj_sock_close(sock); goto on_return; } /* Save the transport */ pjsua_var.tpdata[id].type = type; pjsua_var.tpdata[id].local_name = tp->local_name; pjsua_var.tpdata[id].data.tp = tp;#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -