PJSIP UA分析(1)--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中的大部分主要结构,努力吧。