首页 > 代码库 > PJSIP UA分析

PJSIP UA分析

一个SIP UA不外乎包括如下几方面:

1 账号管理——包括number,display,authentication name,password,domain,registrar,proxy,outbound-proxy

2 账号注册和注销

3 主叫管理——键盘事件处理、发起呼叫、暂挂(hold)、多路呼叫

4 被叫管理——暂挂、多路呼叫管理、前转、后转

5 语音数据编改码和传输

6 视频数据编改码和传输

 

只要沿着这几方面仔细去分析,我想分析起代码来比较有思路了。

 

PJSIP UA分析(2)--PJSUA主函数

 

 

1 int main(int argc, char *argv[])
2 {
3 do {
4 app_restart = PJ_FALSE; //PJ_FALSE是一个宏,一旦用户调用pjsua可执行文件进入该循环,那么默认只执行一次退出
5 //如果需要再次循环,那么在下面函数中会重置为PJ_TRUE
6 if (app_init(argc, argv) != PJ_SUCCESS)//如果用户在调用pjsua可执行文件时就配置了参数,那么将在app_init中初始化各种数据结构并用用户指定的参数赋值
7 return 1;
8
9 setup_signal_handler();//设置信号处理函数,如果是win32下开发需要设置,linux下该函数不做任何处理
10
11 app_main();//执行consold的处理,也就是处理用户指令的部分。
12 app_destroy();//销毁相关资源
13
14 /* This is on purpose */
15 app_destroy();
16 } while (app_restart);
17
18 return 0;
19 }

 

app_restart是一个pj_bool_t的类型,pj_bool_t在pjlib/include/pj/types.h中定义:

 

 

1 /** Boolean. */
2 typedef int pj_bool_t;

 

app_restart是一个全局变量,在pjsip-apps/src/pjsua/pjsua_app.c中定义:

 

 

1 pj_bool_t app_restart;
 

 

 

PJSIP UA分析(3)--PJSUA初始化

 

PJSUA的main函数中使用了pjsua_app.c中的app_init函数来进行初始化,该函数体如下:

 

1 pj_status_t app_init(int argc, char *argv[])
2 {
3 pjsua_transport_id transport_id = -1;
4 pjsua_transport_config tcp_cfg;
5 unsigned i;
6 pj_status_t status;
7
8
9 app_restart = PJ_FALSE; /*重置app_restart的值*/
10
11 /* Create pjsua */
12 status = pjsua_create();
13 if (status != PJ_SUCCESS)
14 return status;
15
16 /* Create pool for application */
17 app_config.pool = pjsua_pool_create("pjsua-app", 1000, 1000);
18
19 /* Initialize default config */
20 default_config(&app_config);
21
22 /* Parse the arguments */
23 status = parse_args(argc, argv, &app_config, &uri_arg);
24 if (status != PJ_SUCCESS)
25 return status;
26
27 /* Initialize application callbacks */
28 app_config.cfg.cb.on_call_state = &on_call_state;
29 app_config.cfg.cb.on_call_media_state = &on_call_media_state;
30 app_config.cfg.cb.on_incoming_call = &on_incoming_call;
31 app_config.cfg.cb.on_call_tsx_state = &on_call_tsx_state;
32 app_config.cfg.cb.on_dtmf_digit = &call_on_dtmf_callback;
33 app_config.cfg.cb.on_call_redirected = &call_on_redirected;
34 app_config.cfg.cb.on_reg_state = &on_reg_state;
35 app_config.cfg.cb.on_incoming_subscribe = &on_incoming_subscribe;
36 app_config.cfg.cb.on_buddy_state = &on_buddy_state;
37 app_config.cfg.cb.on_pager = &on_pager;
38 app_config.cfg.cb.on_typing = &on_typing;
39 app_config.cfg.cb.on_call_transfer_status = &on_call_transfer_status;
40 app_config.cfg.cb.on_call_replaced = &on_call_replaced;
41 app_config.cfg.cb.on_nat_detect = &on_nat_detect;
42 app_config.cfg.cb.on_mwi_info = &on_mwi_info;
43 app_config.cfg.cb.on_transport_state = &on_transport_state;
44 app_config.cfg.cb.on_ice_transport_error = &on_ice_transport_error;
45 app_config.log_cfg.cb = log_cb;
46
47 /* Set sound device latency */
48 if (app_config.capture_lat > 0)
49 app_config.media_cfg.snd_rec_latency = app_config.capture_lat;
50 if (app_config.playback_lat)
51 app_config.media_cfg.snd_play_latency = app_config.playback_lat;
52
53 /* Initialize pjsua */
54 status = pjsua_init(&app_config.cfg, &app_config.log_cfg,
55 &app_config.media_cfg);
56 if (status != PJ_SUCCESS)
57 return status;
58
59 /* Initialize our module to handle otherwise unhandled request */
60 status = pjsip_endpt_register_module(pjsua_get_pjsip_endpt(),
61 &mod_default_handler);
62 if (status != PJ_SUCCESS)
63 return status;
64
65 #ifdef STEREO_DEMO
66 stereo_demo();
67  #endif
68
69 /* Initialize calls data */
70 for (i=0; i<PJ_ARRAY_SIZE(app_config.call_data); ++i) {
71 app_config.call_data[i].timer.id = PJSUA_INVALID_ID;
72 app_config.call_data[i].timer.cb = &call_timeout_callback;
73 }
74
75 /* Optionally registers WAV file */
76 for (i=0; i<app_config.wav_count; ++i) {
77 pjsua_player_id wav_id;
78 unsigned play_options = 0;
79
80 if (app_config.auto_play_hangup)
81 play_options |= PJMEDIA_FILE_NO_LOOP;
82
83 status = pjsua_player_create(&app_config.wav_files[i], play_options,
84 &wav_id);
85 if (status != PJ_SUCCESS)
86 goto on_error;
87
88 if (app_config.wav_id == PJSUA_INVALID_ID) {
89 app_config.wav_id = wav_id;
90 app_config.wav_port = pjsua_player_get_conf_port(app_config.wav_id);
91 if (app_config.auto_play_hangup) {
92 pjmedia_port *port;
93
94 pjsua_player_get_port(app_config.wav_id, &port);
95 status = pjmedia_wav_player_set_eof_cb(port, NULL,
96 &on_playfile_done);
97 if (status != PJ_SUCCESS)
98 goto on_error;
99
100 pj_timer_entry_init(&app_config.auto_hangup_timer, 0, NULL,
101 &hangup_timeout_callback);
102 }
103 }
104 }
105
106 /* Optionally registers tone players */
107 for (i=0; i<app_config.tone_count; ++i) {
108 pjmedia_port *tport;
109 char name[80];
110 pj_str_t label;
111 pj_status_t status;
112
113 pj_ansi_snprintf(name, sizeof(name), "tone-%d,%d",
114 app_config.tones[i].freq1,
115 app_config.tones[i].freq2);
116 label = pj_str(name);
117 status = pjmedia_tonegen_create2(app_config.pool, &label,
118 8000, 1, 160, 16,
119 PJMEDIA_TONEGEN_LOOP, &tport);
120 if (status != PJ_SUCCESS) {
121 pjsua_perror(THIS_FILE, "Unable to create tone generator", status);
122 goto on_error;
123 }
124
125 status = pjsua_conf_add_port(app_config.pool, tport,
126 &app_config.tone_slots[i]);
127 pj_assert(status == PJ_SUCCESS);
128
129 status = pjmedia_tonegen_play(tport, 1, &app_config.tones[i], 0);
130 pj_assert(status == PJ_SUCCESS);
131 }
132
133 /* Optionally create recorder file, if any. */
134 if (app_config.rec_file.slen) {
135 status = pjsua_recorder_create(&app_config.rec_file, 0, NULL, 0, 0,
136 &app_config.rec_id);
137 if (status != PJ_SUCCESS)
138 goto on_error;
139
140 app_config.rec_port = pjsua_recorder_get_conf_port(app_config.rec_id);
141 }
142
143 pj_memcpy(&tcp_cfg, &app_config.udp_cfg, sizeof(tcp_cfg));
144
145 /* Create ringback tones */
146 if (app_config.no_tones == PJ_FALSE) {
147 unsigned i, samples_per_frame;
148 pjmedia_tone_desc tone[RING_CNT+RINGBACK_CNT];
149 pj_str_t name;
150
151 samples_per_frame = app_config.media_cfg.audio_frame_ptime *
152 app_config.media_cfg.clock_rate *
153 app_config.media_cfg.channel_count / 1000;
154
155 /* Ringback tone (call is ringing) */
156 name = pj_str("ringback");
157 status = pjmedia_tonegen_create2(app_config.pool, &name,
158 app_config.media_cfg.clock_rate,
159 app_config.media_cfg.channel_count,
160 samples_per_frame,
161 16, PJMEDIA_TONEGEN_LOOP,
162 &app_config.ringback_port);
163 if (status != PJ_SUCCESS)
164 goto on_error;
165
166 pj_bzero(&tone, sizeof(tone));
167 for (i=0; i<RINGBACK_CNT; ++i) {
168 tone[i].freq1 = RINGBACK_FREQ1;
169 tone[i].freq2 = RINGBACK_FREQ2;
170 tone[i].on_msec = RINGBACK_ON;
171 tone[i].off_msec = RINGBACK_OFF;
172 }
173 tone[RINGBACK_CNT-1].off_msec = RINGBACK_INTERVAL;
174
175 pjmedia_tonegen_play(app_config.ringback_port, RINGBACK_CNT, tone,
176 PJMEDIA_TONEGEN_LOOP);
177
178
179 status = pjsua_conf_add_port(app_config.pool, app_config.ringback_port,
180 &app_config.ringback_slot);
181 if (status != PJ_SUCCESS)
182 goto on_error;
183
184 /* Ring (to alert incoming call) */
185 name = pj_str("ring");
186 status = pjmedia_tonegen_create2(app_config.pool, &name,
187 app_config.media_cfg.clock_rate,
188 app_config.media_cfg.channel_count,
189 samples_per_frame,
190 16, PJMEDIA_TONEGEN_LOOP,
191 &app_config.ring_port);
192 if (status != PJ_SUCCESS)
193 goto on_error;
194
195 for (i=0; i<RING_CNT; ++i) {
196 tone[i].freq1 = RING_FREQ1;
197 tone[i].freq2 = RING_FREQ2;
198 tone[i].on_msec = RING_ON;
199 tone[i].off_msec = RING_OFF;
200 }
201 tone[RING_CNT-1].off_msec = RING_INTERVAL;
202
203 pjmedia_tonegen_play(app_config.ring_port, RING_CNT,
204 tone, PJMEDIA_TONEGEN_LOOP);
205
206 status = pjsua_conf_add_port(app_config.pool, app_config.ring_port,
207 &app_config.ring_slot);
208 if (status != PJ_SUCCESS)
209 goto on_error;
210
211 }
212
213 /* Add UDP transport unless it‘s disabled. */
214 if (!app_config.no_udp) {
215 pjsua_acc_id aid;
216 pjsip_transport_type_e type = PJSIP_TRANSPORT_UDP;
217
218 if (app_config.ipv6)
219 type = PJSIP_TRANSPORT_UDP6;
220
221 status = pjsua_transport_create(type,
222 &app_config.udp_cfg,
223 &transport_id);
224 if (status != PJ_SUCCESS)
225 goto on_error;
226
227 /* Add local account */
228 pjsua_acc_add_local(transport_id, PJ_TRUE, &aid);
229 //pjsua_acc_set_transport(aid, transport_id);
230   pjsua_acc_set_online_status(current_acc, PJ_TRUE);
231
232 if (app_config.udp_cfg.port == 0) {
233 pjsua_transport_info ti;
234 pj_sockaddr_in *a;
235
236 pjsua_transport_get_info(transport_id, &ti);
237 a = (pj_sockaddr_in*)&ti.local_addr;
238
239 tcp_cfg.port = pj_ntohs(a->sin_port);
240 }
241 }
242
243 /* Add TCP transport unless it‘s disabled */
244 if (!app_config.no_tcp) {
245 status = pjsua_transport_create(PJSIP_TRANSPORT_TCP,
246 &tcp_cfg,
247 &transport_id);
248 if (status != PJ_SUCCESS)
249 goto on_error;
250
251 /* Add local account */
252 pjsua_acc_add_local(transport_id, PJ_TRUE, NULL);
253 pjsua_acc_set_online_status(current_acc, PJ_TRUE);
254
255 }
256
257
258 #if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
259 /* Add TLS transport when application wants one */
260 if (app_config.use_tls) {
261
262 pjsua_acc_id acc_id;
263
264 /* Copy the QoS settings */
265 tcp_cfg.tls_setting.qos_type = tcp_cfg.qos_type;
266 pj_memcpy(&tcp_cfg.tls_setting.qos_params, &tcp_cfg.qos_params,
267 sizeof(tcp_cfg.qos_params));
268
269 /* Set TLS port as TCP port+1 */
270 tcp_cfg.port++;
271 status = pjsua_transport_create(PJSIP_TRANSPORT_TLS,
272 &tcp_cfg,
273 &transport_id);
274 tcp_cfg.port--;
275 if (status != PJ_SUCCESS)
276 goto on_error;
277
278 /* Add local account */
279 pjsua_acc_add_local(transport_id, PJ_FALSE, &acc_id);
280 pjsua_acc_set_online_status(acc_id, PJ_TRUE);
281 }
282 #endif
283
284 if (transport_id == -1) {
285 PJ_LOG(1,(THIS_FILE, "Error: no transport is configured"));
286 status = -1;
287 goto on_error;
288 }
289
290
291 /* Add accounts */
292 for (i=0; i<app_config.acc_cnt; ++i) {
293 status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL);
294 if (status != PJ_SUCCESS)
295 goto on_error;
296 pjsua_acc_set_online_status(current_acc, PJ_TRUE);
297 }
298
299 /* Add buddies */
300 for (i=0; i<app_config.buddy_cnt; ++i) {
301 status = pjsua_buddy_add(&app_config.buddy_cfg[i], NULL);
302 if (status != PJ_SUCCESS)
303 goto on_error;
304 }
305
306 /* Optionally disable some codec */
307 for (i=0; i<app_config.codec_dis_cnt; ++i) {
308 pjsua_codec_set_priority(&app_config.codec_dis[i],PJMEDIA_CODEC_PRIO_DISABLED);
309 }
310
311 /* Optionally set codec orders */
312 for (i=0; i<app_config.codec_cnt; ++i) {
313 pjsua_codec_set_priority(&app_config.codec_arg[i],
314 (pj_uint8_t)(PJMEDIA_CODEC_PRIO_NORMAL+i+9));
315 }
316
317 /* Add RTP transports */
318 #ifdef TRANSPORT_ADAPTER_SAMPLE
319 status = transport_adapter_sample();
320
321 #else
322 if (app_config.ipv6)
323 status = create_ipv6_media_transports();
324 else
325 status = pjsua_media_transports_create(&app_config.rtp_cfg);
326 #endif
327 if (status != PJ_SUCCESS)
328 goto on_error;
329
330 /* Use null sound device? */
331 #ifndef STEREO_DEMO
332 if (app_config.null_audio) {
333 status = pjsua_set_null_snd_dev();
334 if (status != PJ_SUCCESS)
335 return status;
336 }
337 #endif
338
339 if (app_config.capture_dev != PJSUA_INVALID_ID ||
340 app_config.playback_dev != PJSUA_INVALID_ID)
341 {
342 status = pjsua_set_snd_dev(app_config.capture_dev,
343 app_config.playback_dev);
344 if (status != PJ_SUCCESS)
345 goto on_error;
346 }
347
348 return PJ_SUCCESS;
349
350 on_error:
351 app_destroy();
352 return status;
353 }
354

 

该函数虽然比较长,但只要硬着头皮看下去,相信会掌握pjsua中的大部分主要结构,努力吧。

 

PJSIP UA分析(4)--创建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函数定义

 

 

 

一 init_data函数:pjsua_core.c

 

init_data

该函数主要初始化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,定义如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/**
 * 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 }

 

PJSIP UA分析(5)——内存管理

 

 

1 池工厂

1 /**
2 * @} // PJ_POOL_FACTORY
3  */
4
5  /* **************************************************************************/
6
7  /**
8 * @defgroup PJ_CACHING_POOL Caching Pool Factory
9 * @ingroup PJ_POOL_GROUP
10 * @brief
11 * Caching pool 是池工厂的一个简单实现,能够重用内存创建pool。应用程序
13 * 定义了池工厂能够容纳的最大内存量,还定义了一个pool被释放之后,是
14 * 销毁这个pool还是保留它用于未来使用。
15 * 如果Caching pool中的内存总量仍然在限定的量之内,那么这个工厂会保留
 16 * 这个pool,否则,将会被销毁,将占用的内存返回给系统。
17 *
18 *
19 * @{
20  */
21
22 /**
23 * Number of unique sizes, to be used as index to the free list.
24 * Each pool in the free list is organized by it‘s size.
25 */
26 #define PJ_CACHING_POOL_ARRAY_SIZE 16
27
28 /**
29 * Declaration for caching pool. Application doesn‘t normally need to
30 * care about the contents of this struct, it is only provided here because
31 * application need to define an instance of this struct (we can not allocate
32 * the struct from a pool since there is no pool factory yet!).
33 */
34 struct pj_caching_pool
35 {
36 /** Pool factory interface, must be declared first. */
37 pj_pool_factory factory;
38
39 /** Current factory‘s capacity, i.e. number of bytes that are allocated
40 * and available for application in this factory. The factory‘s
41 * capacity represents the size of all pools kept by this factory
42 * in it‘s free list, which will be returned to application when it
43 * requests to create a new pool.
44 */
45 pj_size_t capacity; /*分配给应用程序以及应用程序能够使用的总的字节数*/
46
47 /** Maximum size that can be held by this factory. Once the capacity
48 * has exceeded @a max_capacity, further #pj_pool_release() will
49 * flush the pool. If the capacity is still below the @a max_capacity,
50 * #pj_pool_release() will save the pool to the factory‘s free list.
51 */
52 pj_size_t max_capacity;/*一旦capacity超过了这个值,pj_pool_release将清空这个factory?*/
53
54 /**
55 * Number of pools currently held by applications. This number gets
56 * incremented everytime #pj_pool_create() is called, and gets
57 * decremented when #pj_pool_release() is called.
58 */
59 pj_size_t used_count;
60
61 /**
62 * Total size of memory currently used by application.
63 */
64 pj_size_t used_size;
65
66 /**
67 * The maximum size of memory used by application throughout the life
68 * of the caching pool.
69 */
70 pj_size_t peak_used_size;
71
72 /**
73 * Lists of pools in the cache, indexed by pool size.
74 */
75 pj_list free_list[PJ_CACHING_POOL_ARRAY_SIZE];
76
77 /**
78 * List of pools currently allocated by applications.
79 */
80 pj_list used_list;
81
82 /**
83 * Internal pool.
84 */
85 char pool_buf[256 * (sizeof(long) / 4)];
86
87 /**
88 * Mutex.
89 */
90 pj_lock_t *lock;
91 };

 

2 池

 

1 /**
2 * This structure describes the memory pool. Only implementors of pool factory
3 * need to care about the contents of this structure.
4 */
5 struct pj_pool_t
6 {
7 PJ_DECL_LIST_MEMBER(struct pj_pool_t); /**< Standard list elements. */
8
9 /** Pool name */
10 char obj_name[PJ_MAX_OBJ_NAME];
11
12 /** Pool factory. */
13 pj_pool_factory *factory;
14
15 /** Data put by factory */
16 void *factory_data;
17
18 /** Current capacity allocated by the pool. */
19 pj_size_t capacity;
20
21 /** Size of memory block to be allocated when the pool runs out of memory */
22 pj_size_t increment_size;
23
24 /** List of memory blocks allcoated by the pool. */
25 pj_pool_block block_list;
26
27 /** The callback to be called when the pool is unable to allocate memory. */
28 pj_pool_callback *callback;
29
30 };
31

PJSIP UA分析(6)——log管理

 

1 log配置结构

 

1 /**
2 * Logging configuration, which can be (optionally) specified when calling
3 * #pjsua_init(). Application must call #pjsua_logging_config_default() to
4 * initialize this structure with the default values.
5 */
6 typedef struct pjsua_logging_config
7 {
8 /**
9 * Log incoming and outgoing SIP message? Yes!
10 */
11 pj_bool_t msg_logging;
12
13 /**
14 * Input verbosity level. Value 5 is reasonable.
15 */
16 unsigned level;
17
18 /**
19 * Verbosity level for console. Value 4 is reasonable.
20 */
21 unsigned console_level;
22
23 /**
24 * Log decoration.
25 */
26 unsigned decor;
27
28 /**
29 * Optional log filename.
30 */
31 pj_str_t log_filename;
32
33 /**
34 * Additional flags to be given to #pj_file_open() when opening
35 * the log file. By default, the flag is PJ_O_WRONLY. Application
36 * may set PJ_O_APPEND here so that logs are appended to existing
37 * file instead of overwriting it.
38 *
39 * Default is 0.
40 */
41 unsigned log_file_flags;
42
43 /**
44 * Optional callback function to be called to write log to
45 * application specific device. This function will be called for
46 * log messages on input verbosity level.
47 */
48 void (*cb)(int level, const char *data, int len);
49
50
51 } pjsua_logging_config;

2 默认配置函数

 

1 PJ_DEF(void) pjsua_logging_config_default(pjsua_logging_config *cfg)
2 {
3 pj_bzero(cfg, sizeof(*cfg));
4
5 cfg->msg_logging = PJ_TRUE;
6 cfg->level = 5;
7 cfg->console_level = 4;
8 cfg->decor = PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME |
9 PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE |
10 PJ_LOG_HAS_SPACE;
11  #if defined(PJ_WIN32) && PJ_WIN32 != 0
12 cfg->decor |= PJ_LOG_HAS_COLOR;
13  #endif
14 }
 

PJSIP UA分析