使用 pjsip 代码独立开发
Posted 磨叽开发者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 pjsip 代码独立开发相关的知识,希望对你有一定的参考价值。
1、在不改动pjsip代码的情况下,和pjsip工程目录并行建立win32控制台程序工程P2PTraversal
目录结构如下:
.
├── pjproject-2.6
└── pjsipdemo
2、在VS2008下,新建项目
3、工程引入pjsip的相关配置
本例按照引入pjlib、pjlib-util、pjnath三个模块进行设置,如果引入更多需要参考如下设置增加对应的lib或.h目录设置
① 增加“附加包含目录”(针对引用头文件)
为了减少配置次数,在配置页面选择“所有配置”,可以一次性将“Debug”和“Release”全部配置好。主要是针对头文件,静态库则需要分别设置。
在工程属性页面中,找到C/C++选项的常规配置,在附加包含目录中添加如下路径(相对路径,按照目录层次关系)
../pjproject-2.6/pjlib/include/
../pjproject-2.6/pjlib-util/include/
../pjproject-2.6/pjnath/include/
② 设置“附加库目录”
../pjproject-2.6/pjlib/lib/
../pjproject-2.6/pjlib-util/lib/
../pjproject-2.6/pjnath/lib/
③ 设置“附加依赖项”
Debug设置:
ws2_32.lib
pjlib-i386-Win32-vc8-Debug.lib
pjlib-util-i386-Win32-vc8-Debug.lib
pjnath-i386-Win32-vc8-Debug.lib
Release设置
ws2_32.lib
pjlib-i386-Win32-vc8-Release.lib
pjlib-util-i386-Win32-vc8-Release.lib
pjnath-i386-Win32-vc8-Release.lib
4、在main.cpp文件中加入实现(以改造的icedemo为例)
1 /* $Id: icedemo.c 4624 2013-10-21 06:37:30Z ming $ */ 2 /* 3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <pjlib.h> 22 #include <pjlib-util.h> 23 #include <pjnath.h> 24 25 26 #define THIS_FILE "icedemo.c" 27 28 /* For this demo app, configure longer STUN keep-alive time 29 * so that it does\'t clutter the screen output. 30 */ 31 #define KA_INTERVAL 300 32 33 34 /* This is our global variables */ 35 static struct app_t 36 { 37 /* Command line options are stored here */ 38 struct options 39 { 40 unsigned comp_cnt; 41 pj_str_t ns; 42 int max_host; 43 pj_bool_t regular; 44 pj_str_t stun_srv; 45 pj_str_t turn_srv; 46 pj_bool_t turn_tcp; 47 pj_str_t turn_username; 48 pj_str_t turn_password; 49 pj_bool_t turn_fingerprint; 50 const char *log_file; 51 } opt; 52 53 /* Our global variables */ 54 pj_caching_pool cp; 55 pj_pool_t *pool; 56 pj_thread_t *thread; 57 pj_bool_t thread_quit_flag; 58 pj_ice_strans_cfg ice_cfg; 59 pj_ice_strans *icest; 60 FILE *log_fhnd; 61 62 /* Variables to store parsed remote ICE info */ 63 struct rem_info 64 65 { 66 char ufrag[80]; 67 char pwd[80]; 68 unsigned comp_cnt; 69 pj_sockaddr def_addr[PJ_ICE_MAX_COMP]; 70 unsigned cand_cnt; 71 pj_ice_sess_cand cand[PJ_ICE_ST_MAX_CAND]; 72 } rem; 73 74 } icedemo; 75 76 /* Utility to display error messages */ 77 static void icedemo_perror(const char *title, pj_status_t status) 78 { 79 char errmsg[PJ_ERR_MSG_SIZE]; 80 81 pj_strerror(status, errmsg, sizeof(errmsg)); 82 PJ_LOG(1,(THIS_FILE, "%s: %s", title, errmsg)); 83 } 84 85 /* Utility: display error message and exit application (usually 86 * because of fatal error. 87 */ 88 static void err_exit(const char *title, pj_status_t status) 89 { 90 if (status != PJ_SUCCESS) 91 { 92 icedemo_perror(title, status); 93 } 94 PJ_LOG(3,(THIS_FILE, "Shutting down..")); 95 96 if (icedemo.icest) 97 pj_ice_strans_destroy(icedemo.icest); 98 99 pj_thread_sleep(500); 100 101 icedemo.thread_quit_flag = PJ_TRUE; 102 if (icedemo.thread) 103 { 104 pj_thread_join(icedemo.thread); 105 pj_thread_destroy(icedemo.thread); 106 } 107 108 if (icedemo.ice_cfg.stun_cfg.ioqueue) 109 pj_ioqueue_destroy(icedemo.ice_cfg.stun_cfg.ioqueue); 110 111 if (icedemo.ice_cfg.stun_cfg.timer_heap) 112 pj_timer_heap_destroy(icedemo.ice_cfg.stun_cfg.timer_heap); 113 114 pj_caching_pool_destroy(&icedemo.cp); 115 116 pj_shutdown(); 117 118 if (icedemo.log_fhnd) 119 { 120 fclose(icedemo.log_fhnd); 121 icedemo.log_fhnd = NULL; 122 } 123 124 exit(status != PJ_SUCCESS); 125 } 126 127 #define CHECK(expr) status=expr; \\ 128 if (status!=PJ_SUCCESS) { \\ 129 err_exit(#expr, status); \\ 130 } 131 132 /* 133 * This function checks for events from both timer and ioqueue (for 134 * network events). It is invoked by the worker thread. 135 */ 136 static pj_status_t handle_events(unsigned max_msec, unsigned *p_count) 137 { 138 enum { MAX_NET_EVENTS = 1 }; 139 pj_time_val max_timeout = {0, 0}; 140 pj_time_val timeout = { 0, 0}; 141 unsigned count = 0, net_event_count = 0; 142 int c; 143 144 max_timeout.msec = max_msec; 145 146 /* Poll the timer to run it and also to retrieve the earliest entry. */ 147 timeout.sec = timeout.msec = 0; 148 c = pj_timer_heap_poll( icedemo.ice_cfg.stun_cfg.timer_heap, &timeout ); 149 if (c > 0) 150 count += c; 151 152 /* timer_heap_poll should never ever returns negative value, or otherwise 153 * ioqueue_poll() will block forever! 154 */ 155 pj_assert(timeout.sec >= 0 && timeout.msec >= 0); 156 if (timeout.msec >= 1000) timeout.msec = 999; 157 158 /* compare the value with the timeout to wait from timer, and use the 159 * minimum value. 160 */ 161 if (PJ_TIME_VAL_GT(timeout, max_timeout)) 162 timeout = max_timeout; 163 164 /* Poll ioqueue. 165 * Repeat polling the ioqueue while we have immediate events, because 166 * timer heap may process more than one events, so if we only process 167 * one network events at a time (such as when IOCP backend is used), 168 * the ioqueue may have trouble keeping up with the request rate. 169 * 170 * For example, for each send() request, one network event will be 171 * reported by ioqueue for the send() completion. If we don\'t poll 172 * the ioqueue often enough, the send() completion will not be 173 * reported in timely manner. 174 */ 175 do 176 { 177 c = pj_ioqueue_poll( icedemo.ice_cfg.stun_cfg.ioqueue, &timeout); 178 if (c < 0) 179 { 180 pj_status_t err = pj_get_netos_error(); 181 pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout)); 182 if (p_count) 183 *p_count = count; 184 return err; 185 } 186 else if (c == 0) 187 { 188 break; 189 } 190 else 191 { 192 net_event_count += c; 193 timeout.sec = timeout.msec = 0; 194 } 195 } while (c > 0 && net_event_count < MAX_NET_EVENTS); 196 197 count += net_event_count; 198 if (p_count) 199 *p_count = count; 200 201 return PJ_SUCCESS; 202 203 } 204 205 /* 206 * This is the worker thread that polls event in the background. 207 */ 208 static int icedemo_worker_thread(void *unused) 209 { 210 PJ_UNUSED_ARG(unused); 211 212 while (!icedemo.thread_quit_flag) 213 { 214 handle_events(500, NULL); 215 } 216 217 return 0; 218 } 219 220 /* 221 * This is the callback that is registered to the ICE stream transport to 222 * receive notification about incoming data. By "data" it means application 223 * data such as RTP/RTCP, and not packets that belong to ICE signaling (such 224 * as STUN connectivity checks or TURN signaling). 225 */ 226 static void cb_on_rx_data(pj_ice_strans *ice_st, 227 unsigned comp_id, 228 void *pkt, pj_size_t size, 229 const pj_sockaddr_t *src_addr, 230 unsigned src_addr_len) 231 { 232 char ipstr[PJ_INET6_ADDRSTRLEN+10]; 233 234 PJ_UNUSED_ARG(ice_st); 235 PJ_UNUSED_ARG(src_addr_len); 236 PJ_UNUSED_ARG(pkt); 237 238 // Don\'t do this! It will ruin the packet buffer in case TCP is used! 239 //((char*)pkt)[size] = \'\\0\'; 240 241 PJ_LOG(3,(THIS_FILE, "Component %d: received %d bytes data from %s: \\"%.*s\\"", 242 comp_id, size, 243 pj_sockaddr_print(src_addr, ipstr, sizeof(ipstr), 3), 244 (unsigned)size, 245 (char*)pkt)); 246 } 247 248 /* 249 * This is the callback that is registered to the ICE stream transport to 250 * receive notification about ICE state progression. 251 */ 252 static void cb_on_ice_complete(pj_ice_strans *ice_st, 253 pj_ice_strans_op op, 254 pj_status_t status) 255 { 256 const char *opname = 257 (op==PJ_ICE_STRANS_OP_INIT? "initialization" : 258 (op==PJ_ICE_STRANS_OP_NEGOTIATION ? "negotiation" : "unknown_op")); 259 260 if (status == PJ_SUCCESS) 261 { 262 PJ_LOG(3,(THIS_FILE, "ICE %s successful", opname)); 263 } 264 else 265 { 266 char errmsg[PJ_ERR_MSG_SIZE]; 267 268 pj_strerror(status, errmsg, sizeof(errmsg)); 269 PJ_LOG(1,(THIS_FILE, "ICE %s failed: %s", opname, errmsg)); 270 pj_ice_strans_destroy(ice_st); 271 icedemo.icest = NULL; 272 } 273 } 274 275 /* log callback to write to file */ 276 static void log_func(int level, const char *data, int len) 277 { 278 pj_log_write(level, data, len); 279 if (icedemo.log_fhnd) 280 { 281 if (fwrite(data, len, 1, icedemo.log_fhnd) != 1) 282 return; 283 } 284 } 285 286 /* 287 * This is the main application initialization function. It is called 288 * once (and only once) during application initialization sequence by 289 * main(). 290 */ 291 static pj_status_t icedemo_init(void) 292 { 293 pj_status_t status; 294 295 296 //设置日志文件路径 297 icedemo.opt.log_file = pj_str(".\\\\Demo.log").ptr; 298 pj_log_set_level(6); 299 300 if (icedemo.opt.log_file) 301 { 302 icedemo.log_fhnd = fopen(icedemo.opt.log_file, "a"); 303 pj_log_set_log_func(&log_func); 304 } 305 306 /* Initialize the libraries before anything else */ 307 CHECK( pj_init() ); 308 CHECK( pjlib_util_init() ); 309 CHECK( pjnath_init() ); 310 311 /* Must create pool factory, where memory allocations come from */ 312 pj_caching_pool_init(&icedemo.cp, NULL, 0); 313 314 /* Init our ICE settings with null values */ 315 pj_ice_strans_cfg_default(&icedemo.ice_cfg); 316 317 icedemo.ice_cfg.stun_cfg.pf = &icedemo.cp.factory; 318 319 /* Create application memory pool */ 320 icedemo.pool = pj_pool_create(&icedemo.cp.factory, "icedemo", 321 512, 512, NULL); 322 323 /* Create timer heap for timer stuff */ 324 CHECK( pj_timer_heap_create(icedemo.pool, 100, 325 &icedemo.ice_cfg.stun_cfg.timer_heap) ); 326 327 /* and create ioqueue for network I/O stuff */ 328 CHECK( pj_ioqueue_create(icedemo.pool, 16, 329 &icedemo.ice_cfg.stun_cfg.ioqueue) ); 330 331 /* something must poll the timer heap and ioqueue, 332 * unless we\'re on Symbian where the timer heap and ioqueue run 333 * on themselves. 334 */ 335 CHECK( pj_thread_create(icedemo.pool, "icedemo", &icedemo_worker_thread, 336 NULL, 0, 0, &icedemo.thread) ); 337 338 icedemo.ice_cfg.af = pj_AF_INET(); 339 340 /* Create DNS resolver if nameserver is set */ 341 if (icedemo.opt.ns.slen) 342 { 343 CHECK( pj_dns_resolver_create(&icedemo.cp.factory, 344 "resolver", 345 0, 346 icedemo.ice_cfg.stun_cfg.timer_heap, 347 icedemo.ice_cfg.stun_cfg.ioqueue, 348 &icedemo.ice_cfg.resolver) ); 349 350 CHECK( pj_dns_resolver_set_ns(icedemo.ice_cfg.resolver, 1, 351 &icedemo.opt.ns, NULL) ); 352 } 353 354 /* -= Start initializing ICE stream transport config =- */ 355 356 /* Maximum number of host candidates */ 357 if (icedemo.opt.max_host != -1) 358 icedemo.ice_cfg.stun.max_host_cands = icedemo.opt.max_host; 359 360 /* Nomination strategy */ 361 if (icedemo.opt.regular) 362 icedemo.ice_cfg.opt.aggressive = PJ_FALSE; 363 else 364 icedemo.ice_cfg.opt.aggressive = PJ_TRUE; 365 366 /* 手动设置TURN服务信息 */ 367 icedemo.opt.turn_srv = pj_str("11.11.11.11:8888"); 368 icedemo.opt.stun_srv = icedemo.opt.turn_srv; 369 icedemo.opt.turn_username = pj_str("test"); 370 icedemo.opt.turn_password = pj_str("test"); 371 372 /* Configure STUN/srflx candidate resolution */ 373 if (icedemo.opt.stun_srv.slen) 374 { 375 char *pos; 376 377 /* Command line option may contain port number */ 378 if ((pos=pj_strchr(&icedemo.opt.stun_srv, \':\')) != NULL) 379 { 380 icedemo.ice_cfg.stun.server.ptr = icedemo.opt.stun_srv.ptr; 381 icedemo.ice_cfg.stun.server.slen = (pos - icedemo.opt.stun_srv.ptr); 382 383 icedemo.ice_cfg.stun.port = (pj_uint16_t)atoi(pos+1); 384 } 385 else 386 { 387 icedemo.ice_cfg.stun.server = icedemo.opt.stun_srv; 388 icedemo.ice_cfg.stun.port = PJ_STUN_PORT; 389 } 390 391 /* For this demo app, configure longer STUN keep-alive time 392 * so that it does\'t clutter the screen output. 393 */ 394 icedemo.ice_cfg.stun.cfg.ka_interval = KA_INTERVAL; 395 } 396 397 /* Configure TURN candidate */ 398 if (icedemo.opt.turn_srv.slen) 399 { 400 char *pos; 401 402 /* Command line option may contain port number */ 403 if ((pos=pj_strchr(&icedemo.opt.turn_srv, \':\')) != NULL) 404 { 405 icedemo.ice_cfg.turn.server.ptr = icedemo.opt.turn_srv.ptr; 406 icedemo.ice_cfg.turn.server.slen = (pos - icedemo.opt.turn_srv.ptr); 407 408 icedemo.ice_cfg.turn.port = (pj_uint16_t)atoi(pos+1); 409 } 410 else 411 { 412 icedemo.ice_cfg.turn.server = icedemo.opt.turn_srv; 413 icedemo.ice_cfg.turn.port = PJ_STUN_PORT; 414 } 415 416 /*为所有体系结构编译PJSIP 2.5库