使用 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库

在pjsip android中从前到后切换相机

在 iOS 应用中集成 pjsip

在后台运行 VOIP (PJSIP) 服务

如何在 ios 中使用带有域的 pjsip 添加对 IPv6 的支持?

如何在 android 设备上使用 pjsip G.729 编解码的功能