PJSIP UA分析(1)--创建PJSUA实例
在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 }