PJSIP UA分析(1)--创建PJSUA实例

时间:2024-02-20 17:24:38

在app_init函数中,我们看到使用pjsua_create函数来创建pjsua的实例,如下:

1 /* Create pjsua */
2 status = pjsua_create();
3 if (status != PJ_SUCCESS)
4 return status;

接下来,我们来分析该函数。

 

 

该函数定义如下:pjsua_core.c

 

pjsua_create函数定义
1 /*
2 * Instantiate pjsua application.
3 */
4 PJ_DEF(pj_status_t) pjsua_create(void)
5 {
6 pj_status_t status;
7
8 /* Init pjsua data */
9 init_data();
10
11 /* Set default logging settings */
12 pjsua_logging_config_default(&pjsua_var.log_cfg);/*配置log系统的参数*/
13
14 /* Init PJLIB: */
15 status = pj_init();
16 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
17
18 /* Init random seed */
19 init_random_seed();
20
21 /* Init PJLIB-UTIL: */
22 status = pjlib_util_init();
23 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
24
25 /* Init PJNATH */
26 status = pjnath_init();
27 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
28
29 /* Set default sound device ID */
30 pjsua_var.cap_dev = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
31 pjsua_var.play_dev = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
32
33 /* Init caching pool. */
34 pj_caching_pool_init(&pjsua_var.cp, NULL, 0);
35
36 /* Create memory pool for application. */
37 pjsua_var.pool = pjsua_pool_create("pjsua", 1000, 1000);
38
39 PJ_ASSERT_RETURN(pjsua_var.pool, PJ_ENOMEM);
40
41 /* Create mutex */
42 status = pj_mutex_create_recursive(pjsua_var.pool, "pjsua",
43 &pjsua_var.mutex);
44 if (status != PJ_SUCCESS) {
45 pjsua_perror(THIS_FILE, "Unable to create mutex", status);
46 return status;
47 }
48
49 /* Must create SIP endpoint to initialize SIP parser. The parser
50 * is needed for example when application needs to call pjsua_verify_url().
51 */
52 status = pjsip_endpt_create(&pjsua_var.cp.factory,
53 pj_gethostname()->ptr,
54 &pjsua_var.endpt);
55 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
56
57
58 return PJ_SUCCESS;
59 }
60  

 

 

 

一 init_data函数:pjsua_core.c

 

init_data
1 static void init_data()
2 {
3 unsigned i;
4
5 pj_bzero(&pjsua_var, sizeof(pjsua_var));
6
7 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i)
8 pjsua_var.acc[i].index = i;/*初始化账号索引*/
9
10 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i)
11 pjsua_var.tpdata[i].index = i;
12
13 pjsua_var.stun_status = PJ_EUNKNOWN;
14 pjsua_var.nat_status = PJ_EPENDING;
15 pj_list_init(&pjsua_var.stun_res);/*初始化stun服务器列表*/
16 pj_list_init(&pjsua_var.outbound_proxy);/*初始化outbound_proxy列表*/
17
18 pjsua_config_default(&pjsua_var.ua_cfg);/*ua_cfg是UA的一些配置数据,
    指定了最大呼叫数、route模式等参数。这儿进行默认配置*/
19 }

该函数主要初始化pjsua_var全局变量,pjsua_var的定义如下:pjsua_core.c

1 /* PJSUA application instance. */
2  struct pjsua_data pjsua_var;

 

接下来需要好好分析struct pjsua_data这个结构的定义了,因为这个数据结构是pjsua的核心数据结构,定义如下:

1 /**
2 * Global pjsua application data.
3 */
4  struct pjsua_data
5 {
6
7 /* Control: */
8 pj_caching_pool cp; /**< Global pool factory. */
9 pj_pool_t *pool; /**< pjsua\'s private pool. */
10 pj_mutex_t *mutex; /**< Mutex protection for this data */
11
12 /* Logging: */
13 pjsua_logging_config log_cfg; /**< Current logging config. */
14 pj_oshandle_t log_file; /**<Output log file handle */
15
16 /* SIP: */
17 pjsip_endpoint *endpt; /**< Global endpoint. */
18 pjsip_module mod; /**< pjsua\'s PJSIP module. */
19 pjsua_transport_data tpdata[8]; /**< Array of transports. */
20 pjsip_tp_state_callback old_tp_cb; /**< Old transport callback. */
21
22 /* Threading: */
23 pj_bool_t thread_quit_flag; /**< Thread quit flag. */
24 pj_thread_t *thread[4]; /**< Array of threads. */
25
26 /* STUN and resolver */
27 pj_stun_config stun_cfg; /**< Global STUN settings. */
28 pj_sockaddr stun_srv; /**< Resolved STUN server address */
29 pj_status_t stun_status; /**< STUN server status. */
30 pjsua_stun_resolve stun_res; /**< List of pending STUN resolution*/
31 pj_dns_resolver *resolver; /**< DNS resolver. */
32
33 /* Detected NAT type */
34 pj_stun_nat_type nat_type; /**< NAT type. */
35 pj_status_t nat_status; /**< Detection status. */
36 pj_bool_t nat_in_progress; /**< Detection in progress */
37
38 /* List of outbound proxies: */
39 pjsip_route_hdr outbound_proxy;
40
41 /* Account: */
42 unsigned acc_cnt; /**< Number of accounts. */
43 pjsua_acc_id default_acc; /**< Default account ID */
44 pjsua_acc acc[PJSUA_MAX_ACC]; /**< Account array. */
45 pjsua_acc_id acc_ids[PJSUA_MAX_ACC]; /**< Acc sorted by prio*/
46
47 /* Calls: */
48 pjsua_config ua_cfg; /**< UA config. */
49 unsigned call_cnt; /**< Call counter. */
50 pjsua_call calls[PJSUA_MAX_CALLS];/**< Calls array. */
51 pjsua_call_id next_call_id; /**< Next call id to use*/
52
53 /* Buddy; */
54 unsigned buddy_cnt; /**< Buddy count. */
55 pjsua_buddy buddy[PJSUA_MAX_BUDDIES]; /**< Buddy array. */
56
57 /* Presence: */
58 pj_timer_entry pres_timer;/**< Presence refresh timer. */
59
60 /* Media: */
61 pjsua_media_config media_cfg; /**< Media config. */
62 pjmedia_endpt *med_endpt; /**< Media endpoint. */
63 pjsua_conf_setting mconf_cfg; /**< Additionan conf. bridge. param */
64 pjmedia_conf *mconf; /**< Conference bridge. */
65 pj_bool_t is_mswitch;/**< Are we using audio switchboard
66 (a.k.a APS-Direct) */
67
68 /* Sound device */
69 pjmedia_aud_dev_index cap_dev; /**< Capture device ID. */
70 pjmedia_aud_dev_index play_dev; /**< Playback device ID. */
71 pj_uint32_t aud_svmask;/**< Which settings to save */
72 pjmedia_aud_param aud_param; /**< User settings to sound dev */
73 pj_bool_t aud_open_cnt;/**< How many # device is opened */
74 pj_bool_t no_snd; /**< No sound (app will manage it) */
75 pj_pool_t *snd_pool; /**< Sound\'s private pool. */
76 pjmedia_snd_port *snd_port; /**< Sound port. */
77 pj_timer_entry snd_idle_timer;/**< Sound device idle timer. */
78 pjmedia_master_port *null_snd; /**< Master port for null sound. */
79 pjmedia_port *null_port; /**< Null port. */
80
81
82 /* File players: */
83 unsigned player_cnt;/**< Number of file players. */
84 pjsua_file_data player[PJSUA_MAX_PLAYERS];/**< Array of players.*/
85
86 /* File recorders: */
87 unsigned rec_cnt; /**< Number of file recorders. */
88 pjsua_file_data recorder[PJSUA_MAX_RECORDERS];/**< Array of recs.*/
89 };

 init_date函数的最后调用pjsua_config_default函数初始化pjsua_var.ua_cfg,这个成员的类型是struct pjsua_config,定义如下:

/**
 * This structure describes the settings to control the API and
 * user agent behavior, and can be specified when calling #pjsua_init().
 * Before setting the values, application must call #pjsua_config_default()
 * to initialize this structure with the default values.
 */
typedef struct pjsua_config
{

    /** 
     * Maximum calls to support (default: 4). The value specified here
     * must be smaller than the compile time maximum settings 
     * PJSUA_MAX_CALLS, which by default is 32. To increase this 
     * limit, the library must be recompiled with new PJSUA_MAX_CALLS
     * value.
     */
    unsigned	    max_calls;

    /** 
     * Number of worker threads. Normally application will want to have at
     * least one worker thread, unless when it wants to poll the library
     * periodically, which in this case the worker thread can be set to
     * zero.
     */
    unsigned	    thread_cnt;

    /**
     * Number of nameservers. If no name server is configured, the SIP SRV
     * resolution would be disabled, and domain will be resolved with
     * standard pj_gethostbyname() function.
     */
    unsigned	    nameserver_count;

    /**
     * Array of nameservers to be used by the SIP resolver subsystem.
     * The order of the name server specifies the priority (first name
     * server will be used first, unless it is not reachable).
     */
    pj_str_t	    nameserver[4];

    /**
     * Force loose-route to be used in all route/proxy URIs (outbound_proxy
     * and account\'s proxy settings). When this setting is enabled, the
     * library will check all the route/proxy URIs specified in the settings
     * and append ";lr" parameter to the URI if the parameter is not present.
     *
     * Default: 1
     */
    pj_bool_t	    force_lr;

    /**
     * Number of outbound proxies in the \a outbound_proxy array.
     */
    unsigned	    outbound_proxy_cnt;

    /** 
     * Specify the URL of outbound proxies to visit for all outgoing requests.
     * The outbound proxies will be used for all accounts, and it will
     * be used to build the route set for outgoing requests. The final
     * route set for outgoing requests will consists of the outbound proxies
     * and the proxy configured in the account.
     */
    pj_str_t	    outbound_proxy[4];

    /**
     * Warning: deprecated, please use \a stun_srv field instead. To maintain
     * backward compatibility, if \a stun_srv_cnt is zero then the value of
     * this field will be copied to \a stun_srv field, if present.
     *
     * Specify domain name to be resolved with DNS SRV resolution to get the
     * address of the STUN server. Alternatively application may specify
     * \a stun_host instead.
     *
     * If DNS SRV resolution failed for this domain, then DNS A resolution
     * will be performed only if \a stun_host is specified.
     */
    pj_str_t	    stun_domain; /*指定stun服务器的域名,已过时,这儿是为了兼容才存在。*/
                                        /*最好使用stun_srv*/
    /**
     * Warning: deprecated, please use \a stun_srv field instead. To maintain
     * backward compatibility, if \a stun_srv_cnt is zero then the value of
     * this field will be copied to \a stun_srv field, if present.
     *
     * Specify STUN server to be used, in "HOST[:PORT]" format. If port is
     * not specified, default port 3478 will be used.
     */
    pj_str_t	    stun_host;/*stun服务器的ip地址和端口,也已过时。*/

    /**
     * Number of STUN server entries in \a stun_srv array.
     */
    unsigned	    stun_srv_cnt;

    /**
     * Array of STUN servers to try. The library will try to resolve and
     * contact each of the STUN server entry until it finds one that is
     * usable. Each entry may be a domain name, host name, IP address, and
     * it may contain an optional port number. For example:
     *	- "pjsip.org" (domain name)
     *	- "sip.pjsip.org" (host name)
     *	- "pjsip.org:33478" (domain name and a non-standard port number)
     *	- "10.0.0.1:3478" (IP address and port number)
     *
     * When nameserver is configured in the \a pjsua_config.nameserver field,
     * if entry is not an IP address, it will be resolved with DNS SRV 
     * resolution first, and it will fallback to use DNS A resolution if this
     * fails. Port number may be specified even if the entry is a domain name,
     * in case the DNS SRV resolution should fallback to a non-standard port.
     *
     * When nameserver is not configured, entries will be resolved with
     * #pj_gethostbyname() if it\'s not an IP address. Port number may be
     * specified if the server is not listening in standard STUN port.
     */
    pj_str_t	    stun_srv[8]; /*stun服务器主要使用的是这个*/

    /**
     * This specifies if the library startup should ignore failure with the
     * STUN servers. If this is set to PJ_FALSE, the library will refuse to
     * start if it fails to resolve or contact any of the STUN servers.
     *
     * Default: PJ_TRUE
     */
    pj_bool_t	    stun_ignore_failure;

    /**
     * Support for adding and parsing NAT type in the SDP to assist 
     * troubleshooting. The valid values are:
     *	- 0: no information will be added in SDP, and parsing is disabled.
     *	- 1: only the NAT type number is added.
     *	- 2: add both NAT type number and name.
     *
     * Default: 1
     */
    int		    nat_type_in_sdp;

    /**
     * Specify whether support for reliable provisional response (100rel and
     * PRACK) should be required by default. Note that this setting can be
     * further customized in account configuration (#pjsua_acc_config).
     *
     * Default: PJ_FALSE
     */
    pj_bool_t	    require_100rel;

    /**
     * Specify the usage of Session Timers for all sessions. See the
     * #pjsua_sip_timer_use for possible values. Note that this setting can be
     * further customized in account configuration (#pjsua_acc_config).
     *
     * Default: PJSUA_SIP_TIMER_OPTIONAL
     */
    pjsua_sip_timer_use use_timer;

    /**
     * Handle unsolicited NOTIFY requests containing message waiting 
     * indication (MWI) info. Unsolicited MWI is incoming NOTIFY requests 
     * which are not requested by client with SUBSCRIBE request. 
     *
     * If this is enabled, the library will respond 200/OK to the NOTIFY
     * request and forward the request to \a on_mwi_info() callback.
     *
     * See also \a mwi_enabled field #on pjsua_acc_config.
     *
     * Default: PJ_TRUE
     *
     */
    pj_bool_t	    enable_unsolicited_mwi;

    /**
     * Specify Session Timer settings, see #pjsip_timer_setting. 
     * Note that this setting can be further customized in account 
     * configuration (#pjsua_acc_config).
     */
    pjsip_timer_setting timer_setting;

    /** 
     * Number of credentials in the credential array.
     */
    unsigned	    cred_count;

    /** 
     * Array of credentials. These credentials will be used by all accounts,
     * and can be used to authenticate against outbound proxies. If the
     * credential is specific to the account, then application should set
     * the credential in the pjsua_acc_config rather than the credential
     * here.
     */
    pjsip_cred_info cred_info[PJSUA_ACC_MAX_PROXIES];

    /**
     * Application callback to receive various event notifications from
     * the library.
     */
    pjsua_callback  cb;

    /**
     * Optional user agent string (default empty). If it\'s empty, no
     * User-Agent header will be sent with outgoing requests.
     */
    pj_str_t	    user_agent;

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /**
     * Specify default value of secure media transport usage. 
     * Valid values are PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, and
     * PJMEDIA_SRTP_MANDATORY.
     *
     * Note that this setting can be further customized in account 
     * configuration (#pjsua_acc_config).
     *
     * Default: #PJSUA_DEFAULT_USE_SRTP
     */
    pjmedia_srtp_use	use_srtp;

    /**
     * Specify whether SRTP requires secure signaling to be used. This option
     * is only used when \a use_srtp option above is non-zero.
     *
     * Valid values are:
     *	0: SRTP does not require secure signaling
     *	1: SRTP requires secure transport such as TLS
     *	2: SRTP requires secure end-to-end transport (SIPS)
     *
     * Note that this setting can be further customized in account 
     * configuration (#pjsua_acc_config).
     *
     * Default: #PJSUA_DEFAULT_SRTP_SECURE_SIGNALING
     */
    int		     srtp_secure_signaling;

    /**
     * Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose 
     * duplicated media in SDP offer, i.e: unsecured and secured version.
     * Otherwise, the SDP media will be composed as unsecured media but 
     * with SDP "crypto" attribute.
     *
     * Default: PJ_FALSE
     */
    pj_bool_t	     srtp_optional_dup_offer;
#endif

    /**
     * Disconnect other call legs when more than one 2xx responses for 
     * outgoing INVITE are received due to forking. Currently the library
     * is not able to handle simultaneous forked media, so disconnecting
     * the other call legs is necessary. 
     *
     * With this setting enabled, the library will handle only one of the
     * connected call leg, and the other connected call legs will be
     * disconnected. 
     *
     * Default: PJ_TRUE (only disable this setting for testing purposes).
     */
    pj_bool_t	     hangup_forked_call;

} pjsua_config;

 下面再看pjsua_config_default函数的定义:

 

代码
1 PJ_DEF(void) pjsua_config_default(pjsua_config *cfg)
2 {
3 pj_bzero(cfg, sizeof(*cfg));
4
5 cfg->max_calls = ((PJSUA_MAX_CALLS) < 4) ? (PJSUA_MAX_CALLS) : 4;
6 cfg->thread_cnt = 1;
7 cfg->nat_type_in_sdp = 1;
8 cfg->stun_ignore_failure = PJ_TRUE;
9 cfg->force_lr = PJ_TRUE;
10 cfg->enable_unsolicited_mwi = PJ_TRUE;
11  #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
12 cfg->use_srtp = PJSUA_DEFAULT_USE_SRTP;
13 cfg->srtp_secure_signaling = PJSUA_DEFAULT_SRTP_SECURE_SIGNALING;
14  #endif
15 cfg->hangup_forked_call = PJ_TRUE;
16
17 cfg->use_timer = PJSUA_SIP_TIMER_OPTIONAL;
18 pjsip_timer_setting_default(&cfg->timer_setting);
19 }

 

该函数最后使用pjsip_timer_setting_default函数配置默认的会话定时器,如下:

 

代码
1 /*
2 * Initialize Session Timers setting with default values.
3 */
4 PJ_DEF(pj_status_t) pjsip_timer_setting_default(pjsip_timer_setting *setting)
5 {
6 pj_bzero(setting, sizeof(pjsip_timer_setting));
7
8 setting->sess_expires = PJSIP_SESS_TIMER_DEF_SE; /*1800*/
9 setting->min_se = ABS_MIN_SE;/*90*/
10
11 return PJ_SUCCESS;
12 }