BLOG | DOCUMENTATION | GITHUB

Home --> Documentations --> PJSIP Reference

PJSUA

This is the reference implementation for PJSIP and PJMEDIA. PJSUA is a console based application, designed to be simple enough to be readble, but powerful enough to demonstrate all features available in PJSIP and PJMEDIA.

This file is pjsip-apps/src/pjsua/pjsua_app.c

Screenshot on WinXP:

pjsua on WinXP
1/*
2 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
3 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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 "pjsua_app.h"
20
21#define THIS_FILE "pjsua_app.c"
22
23//#define STEREO_DEMO
24//#define TRANSPORT_ADAPTER_SAMPLE
25//#define HAVE_MULTIPART_TEST
26
27/* Ringtones US UK */
28#define RINGBACK_FREQ1 440 /* 400 */
29#define RINGBACK_FREQ2 480 /* 450 */
30#define RINGBACK_ON 2000 /* 400 */
31#define RINGBACK_OFF 4000 /* 200 */
32#define RINGBACK_CNT 1 /* 2 */
33#define RINGBACK_INTERVAL 4000 /* 2000 */
34
35#define RING_FREQ1 800
36#define RING_FREQ2 640
37#define RING_ON 200
38#define RING_OFF 100
39#define RING_CNT 3
40#define RING_INTERVAL 3000
41
42#define current_acc pjsua_acc_get_default()
43
44#ifdef STEREO_DEMO
45static void stereo_demo();
46#endif
47
48#ifdef USE_GUI
49pj_bool_t showNotification(pjsua_call_id call_id);
50#endif
51
52static void ringback_start(pjsua_call_id call_id);
53static void ring_start(pjsua_call_id call_id);
54static void ring_stop(pjsua_call_id call_id);
55static pj_status_t app_init(void);
56static pj_status_t app_destroy(void);
57
58static pjsua_app_cfg_t app_cfg;
59pj_str_t uri_arg;
60pj_bool_t app_running = PJ_FALSE;
61
62/*****************************************************************************
63 * Configuration manipulation
64 */
65
66/*****************************************************************************
67 * Callback
68 */
69static void ringback_start(pjsua_call_id call_id)
70{
71 if (app_config.no_tones)
72 return;
73
74 if (app_config.call_data[call_id].ringback_on)
75 return;
76
77 app_config.call_data[call_id].ringback_on = PJ_TRUE;
78
79 if (++app_config.ringback_cnt==1 &&
80 app_config.ringback_slot!=PJSUA_INVALID_ID)
81 {
82 pjsua_conf_connect(app_config.ringback_slot, 0);
83 }
84}
85
86static void ring_stop(pjsua_call_id call_id)
87{
88 if (app_config.no_tones)
89 return;
90
91 if (app_config.call_data[call_id].ringback_on) {
92 app_config.call_data[call_id].ringback_on = PJ_FALSE;
93
94 pj_assert(app_config.ringback_cnt>0);
95 if (--app_config.ringback_cnt == 0 &&
96 app_config.ringback_slot!=PJSUA_INVALID_ID)
97 {
98 pjsua_conf_disconnect(app_config.ringback_slot, 0);
99 pjmedia_tonegen_rewind(app_config.ringback_port);
100 }
101 }
102
103 if (app_config.call_data[call_id].ring_on) {
104 app_config.call_data[call_id].ring_on = PJ_FALSE;
105
106 pj_assert(app_config.ring_cnt>0);
107 if (--app_config.ring_cnt == 0 &&
108 app_config.ring_slot!=PJSUA_INVALID_ID)
109 {
110 pjsua_conf_disconnect(app_config.ring_slot, 0);
111 pjmedia_tonegen_rewind(app_config.ring_port);
112 }
113 }
114}
115
116static void ring_start(pjsua_call_id call_id)
117{
118 if (app_config.no_tones)
119 return;
120
121 if (app_config.call_data[call_id].ring_on)
122 return;
123
124 app_config.call_data[call_id].ring_on = PJ_TRUE;
125
126 if (++app_config.ring_cnt==1 &&
127 app_config.ring_slot!=PJSUA_INVALID_ID)
128 {
129 pjsua_conf_connect(app_config.ring_slot, 0);
130 }
131}
132
133/* Callback from timer when the maximum call duration has been
134 * exceeded.
135 */
136static void call_timeout_callback(pj_timer_heap_t *timer_heap,
137 struct pj_timer_entry *entry)
138{
139 pjsua_call_id call_id = entry->id;
140 pjsua_msg_data msg_data_;
142 pj_str_t hname = pj_str("Warning");
143 pj_str_t hvalue = pj_str("399 pjsua \"Call duration exceeded\"");
144
145 PJ_UNUSED_ARG(timer_heap);
146
147 if (call_id == PJSUA_INVALID_ID) {
148 PJ_LOG(1,(THIS_FILE, "Invalid call ID in timer callback"));
149 return;
150 }
151
152 /* Add warning header */
153 pjsua_msg_data_init(&msg_data_);
154 pjsip_generic_string_hdr_init2(&warn, &hname, &hvalue);
155 pj_list_push_back(&msg_data_.hdr_list, &warn);
156
157 /* Call duration has been exceeded; disconnect the call */
158 PJ_LOG(3,(THIS_FILE, "Duration (%d seconds) has been exceeded "
159 "for call %d, disconnecting the call",
160 app_config.duration, call_id));
161 entry->id = PJSUA_INVALID_ID;
162 pjsua_call_hangup(call_id, 200, NULL, &msg_data_);
163}
164
165/*
166 * Handler when invite state has changed.
167 */
168static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
169{
170 pjsua_call_info call_info;
171
172 PJ_UNUSED_ARG(e);
173
174 pjsua_call_get_info(call_id, &call_info);
175
176 if (call_info.state == PJSIP_INV_STATE_DISCONNECTED) {
177
178 /* Stop all ringback for this call */
179 ring_stop(call_id);
180
181 /* Cancel duration timer, if any */
182 if (app_config.call_data[call_id].timer.id != PJSUA_INVALID_ID) {
183 app_call_data *cd = &app_config.call_data[call_id];
185
186 cd->timer.id = PJSUA_INVALID_ID;
187 pjsip_endpt_cancel_timer(endpt, &cd->timer);
188 }
189
190 /* Rewind play file when hangup automatically,
191 * since file is not looped
192 */
193 if (app_config.auto_play_hangup)
194 pjsua_player_set_pos(app_config.wav_id, 0);
195
196
197 PJ_LOG(3,(THIS_FILE, "Call %d is DISCONNECTED [reason=%d (%.*s)]",
198 call_id,
199 call_info.last_status,
200 (int)call_info.last_status_text.slen,
201 call_info.last_status_text.ptr));
202
203 if (call_id == current_call) {
204 find_next_call();
205 }
206
207 /* Dump media state upon disconnected.
208 * Now pjsua_media_channel_deinit() automatically log the call dump.
209 */
210 if (0) {
211 PJ_LOG(5,(THIS_FILE,
212 "Call %d disconnected, dumping media stats..",
213 call_id));
214 log_call_dump(call_id);
215 }
216
217 } else {
218
219 if (app_config.duration != PJSUA_APP_NO_LIMIT_DURATION &&
220 call_info.state == PJSIP_INV_STATE_CONFIRMED)
221 {
222 /* Schedule timer to hangup call after the specified duration */
223 app_call_data *cd = &app_config.call_data[call_id];
225 pj_time_val delay;
226
227 cd->timer.id = call_id;
228 delay.sec = app_config.duration;
229 delay.msec = 0;
230 pjsip_endpt_schedule_timer(endpt, &cd->timer, &delay);
231 }
232
233 if (call_info.state == PJSIP_INV_STATE_EARLY) {
234 int code;
235 pj_str_t reason;
236 pjsip_msg *msg;
237
238 /* This can only occur because of TX or RX message */
240
242 msg = e->body.tsx_state.src.rdata->msg_info.msg;
243 } else {
244 msg = e->body.tsx_state.src.tdata->msg;
245 }
246
247 code = msg->line.status.code;
248 reason = msg->line.status.reason;
249
250 /* Start ringback for 180 for UAC unless there's SDP in 180 */
251 if (call_info.role==PJSIP_ROLE_UAC && code==180 &&
252 msg->body == NULL &&
254 {
255 ringback_start(call_id);
256 }
257
258 PJ_LOG(3,(THIS_FILE, "Call %d state changed to %.*s (%d %.*s)",
259 call_id, (int)call_info.state_text.slen,
260 call_info.state_text.ptr, code,
261 (int)reason.slen, reason.ptr));
262 } else {
263 PJ_LOG(3,(THIS_FILE, "Call %d state changed to %.*s",
264 call_id,
265 (int)call_info.state_text.slen,
266 call_info.state_text.ptr));
267 }
268
269 if (current_call==PJSUA_INVALID_ID)
270 current_call = call_id;
271
272 }
273}
274
275/*
276 * Handler when audio stream is destroyed.
277 */
278static void on_stream_destroyed(pjsua_call_id call_id,
279 pjmedia_stream *strm,
280 unsigned stream_idx)
281{
282 PJ_UNUSED_ARG(strm);
283
284 /* Now pjsua_media_channel_deinit() automatically log the call dump. */
285 if (0) {
286 PJ_LOG(5,(THIS_FILE,
287 "Call %d stream %d destroyed, dumping media stats..",
288 call_id, stream_idx));
289 log_call_dump(call_id);
290 }
291}
292
296static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
297 pjsip_rx_data *rdata)
298{
299 pjsua_call_info call_info;
300
301 PJ_UNUSED_ARG(acc_id);
302 PJ_UNUSED_ARG(rdata);
303
304 pjsua_call_get_info(call_id, &call_info);
305
306 if (current_call==PJSUA_INVALID_ID)
307 current_call = call_id;
308
309#ifdef USE_GUI
310 showNotification(call_id);
311#endif
312
313 /* Start ringback */
314 if (call_info.rem_aud_cnt)
315 ring_start(call_id);
316
317 if (app_config.auto_answer > 0) {
319
321 opt.aud_cnt = app_config.aud_cnt;
322 opt.vid_cnt = app_config.vid.vid_cnt;
323
324 pjsua_call_answer2(call_id, &opt, app_config.auto_answer, NULL,
325 NULL);
326 }
327
328 if (app_config.auto_answer < 200) {
329 char notif_st[80] = {0};
330
331#if PJSUA_HAS_VIDEO
332 if (call_info.rem_offerer && call_info.rem_vid_cnt) {
333 snprintf(notif_st, sizeof(notif_st),
334 "To %s the video, type \"vid %s\" first, "
335 "before answering the call!\n",
336 (app_config.vid.vid_cnt? "reject":"accept"),
337 (app_config.vid.vid_cnt? "disable":"enable"));
338 }
339#endif
340
341 PJ_LOG(3,(THIS_FILE,
342 "Incoming call for account %d!\n"
343 "Media count: %d audio & %d video\n"
344 "%s"
345 "From: %.*s\n"
346 "To: %.*s\n"
347 "Press %s to answer or %s to reject call",
348 acc_id,
349 call_info.rem_aud_cnt,
350 call_info.rem_vid_cnt,
351 notif_st,
352 (int)call_info.remote_info.slen,
353 call_info.remote_info.ptr,
354 (int)call_info.local_info.slen,
355 call_info.local_info.ptr,
356 (app_config.use_cli?"ca a":"a"),
357 (app_config.use_cli?"g":"h")));
358 }
359}
360
361/* General processing for media state. "mi" is the media index */
362static void on_call_generic_media_state(pjsua_call_info *ci, unsigned mi,
363 pj_bool_t *has_error)
364{
365 const char *status_name[] = {
366 "None",
367 "Active",
368 "Local hold",
369 "Remote hold",
370 "Error"
371 };
372
373 PJ_UNUSED_ARG(has_error);
374
375 pj_assert(ci->media[mi].status <= PJ_ARRAY_SIZE(status_name));
377
378 PJ_LOG(4,(THIS_FILE, "Call %d media %d [type=%s], status is %s",
379 ci->id, mi, pjmedia_type_name(ci->media[mi].type),
380 status_name[ci->media[mi].status]));
381}
382
383/* Process audio media state. "mi" is the media index. */
384static void on_call_audio_state(pjsua_call_info *ci, unsigned mi,
385 pj_bool_t *has_error)
386{
387 PJ_UNUSED_ARG(has_error);
388
389 /* Stop ringback */
390 ring_stop(ci->id);
391
392 /* Connect ports appropriately when media status is ACTIVE or REMOTE HOLD,
393 * otherwise we should NOT connect the ports.
394 */
395 if (ci->media[mi].status == PJSUA_CALL_MEDIA_ACTIVE ||
397 {
398 pj_bool_t connect_sound = PJ_TRUE;
399 pj_bool_t disconnect_mic = PJ_FALSE;
400 pjsua_conf_port_id call_conf_slot;
401
402 call_conf_slot = ci->media[mi].stream.aud.conf_slot;
403
404 /* Make sure conf slot is valid (e.g: media dir is not "inactive") */
405 if (call_conf_slot == PJSUA_INVALID_ID)
406 return;
407
408 /* Loopback sound, if desired */
409 if (app_config.auto_loop) {
410 pjsua_conf_connect(call_conf_slot, call_conf_slot);
411 connect_sound = PJ_FALSE;
412 }
413
414 /* Automatically record conversation, if desired */
415 if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) {
416 pjsua_conf_connect(call_conf_slot, app_config.rec_port);
417 }
418
419 /* Stream a file, if desired */
420 if ((app_config.auto_play || app_config.auto_play_hangup) &&
421 app_config.wav_port != PJSUA_INVALID_ID)
422 {
423 pjsua_conf_connect(app_config.wav_port, call_conf_slot);
424 connect_sound = PJ_FALSE;
425 }
426
427 /* Stream AVI, if desired */
428 if (app_config.avi_auto_play &&
429 app_config.avi_def_idx != PJSUA_INVALID_ID &&
430 app_config.avi[app_config.avi_def_idx].slot != PJSUA_INVALID_ID)
431 {
432 pjsua_conf_connect(app_config.avi[app_config.avi_def_idx].slot,
433 call_conf_slot);
434 disconnect_mic = PJ_TRUE;
435 }
436
437 /* Put call in conference with other calls, if desired */
438 if (app_config.auto_conf) {
440 unsigned call_cnt=PJ_ARRAY_SIZE(call_ids);
441 unsigned i;
442
443 /* Get all calls, and establish media connection between
444 * this call and other calls.
445 */
446 pjsua_enum_calls(call_ids, &call_cnt);
447
448 for (i=0; i<call_cnt; ++i) {
449 if (call_ids[i] == ci->id)
450 continue;
451
452 if (!pjsua_call_has_media(call_ids[i]))
453 continue;
454
455 pjsua_conf_connect(call_conf_slot,
456 pjsua_call_get_conf_port(call_ids[i]));
458 call_conf_slot);
459
460 /* Automatically record conversation, if desired */
461 if (app_config.auto_rec && app_config.rec_port !=
462 PJSUA_INVALID_ID)
463 {
465 app_config.rec_port);
466 }
467
468 }
469
470 /* Also connect call to local sound device */
471 connect_sound = PJ_TRUE;
472 }
473
474 /* Otherwise connect to sound device */
475 if (connect_sound) {
476 pjsua_conf_connect(call_conf_slot, 0);
477 if (!disconnect_mic)
478 pjsua_conf_connect(0, call_conf_slot);
479
480 /* Automatically record conversation, if desired */
481 if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID)
482 {
483 pjsua_conf_connect(call_conf_slot, app_config.rec_port);
484 pjsua_conf_connect(0, app_config.rec_port);
485 }
486 }
487 }
488}
489
490/* Process video media state. "mi" is the media index. */
491static void on_call_video_state(pjsua_call_info *ci, unsigned mi,
492 pj_bool_t *has_error)
493{
495 return;
496
497 arrange_window(ci->media[mi].stream.vid.win_in);
498
499 PJ_UNUSED_ARG(has_error);
500}
501
502/*
503 * Callback on media state changed event.
504 * The action may connect the call to sound device, to file, or
505 * to loop the call.
506 */
507static void on_call_media_state(pjsua_call_id call_id)
508{
509 pjsua_call_info call_info;
510 unsigned mi;
511 pj_bool_t has_error = PJ_FALSE;
512
513 pjsua_call_get_info(call_id, &call_info);
514
515 for (mi=0; mi<call_info.media_cnt; ++mi) {
516 on_call_generic_media_state(&call_info, mi, &has_error);
517
518 switch (call_info.media[mi].type) {
520 on_call_audio_state(&call_info, mi, &has_error);
521 break;
523 on_call_video_state(&call_info, mi, &has_error);
524 break;
525 default:
526 /* Make gcc happy about enum not handled by switch/case */
527 break;
528 }
529 }
530
531 if (has_error) {
532 pj_str_t reason = pj_str("Media failed");
533 pjsua_call_hangup(call_id, 500, &reason, NULL);
534 }
535
536#if PJSUA_HAS_VIDEO
537 /* Check if remote has just tried to enable video */
538 if (call_info.rem_offerer && call_info.rem_vid_cnt)
539 {
540 int vid_idx;
541
542 /* Check if there is active video */
543 vid_idx = pjsua_call_get_vid_stream_idx(call_id);
544 if (vid_idx == -1 || call_info.media[vid_idx].dir == PJMEDIA_DIR_NONE) {
545 PJ_LOG(3,(THIS_FILE,
546 "Just rejected incoming video offer on call %d, "
547 "use \"vid call enable %d\" or \"vid call add\" to "
548 "enable video!", call_id, vid_idx));
549 }
550 }
551#endif
552}
553
554/*
555 * DTMF callback.
556 */
557/*
558static void call_on_dtmf_callback(pjsua_call_id call_id, int dtmf)
559{
560 PJ_LOG(3,(THIS_FILE, "Incoming DTMF on call %d: %c", call_id, dtmf));
561}
562*/
563
564static void call_on_dtmf_callback2(pjsua_call_id call_id,
565 const pjsua_dtmf_info *info)
566{
567 char duration[16];
568 char method[16];
569
570 duration[0] = '\0';
571
572 switch (info->method) {
574 pj_ansi_snprintf(method, sizeof(method), "RFC2833");
575 break;
577 pj_ansi_snprintf(method, sizeof(method), "SIP INFO");
578 pj_ansi_snprintf(duration, sizeof(duration), ":duration(%d)",
579 info->duration);
580 break;
581 };
582 PJ_LOG(3,(THIS_FILE, "Incoming DTMF on call %d: %c%s, using %s method",
583 call_id, info->digit, duration, method));
584}
585
586/*
587 * Redirection handler.
588 */
589static pjsip_redirect_op call_on_redirected(pjsua_call_id call_id,
590 const pjsip_uri *target,
591 const pjsip_event *e)
592{
593 PJ_UNUSED_ARG(e);
594
595 if (app_config.redir_op == PJSIP_REDIRECT_PENDING) {
596 char uristr[PJSIP_MAX_URL_SIZE];
597 int len;
598
599 len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, target, uristr,
600 sizeof(uristr));
601 if (len < 1) {
602 pj_ansi_strcpy(uristr, "--URI too long--");
603 }
604
605 PJ_LOG(3,(THIS_FILE, "Call %d is being redirected to %.*s. "
606 "Press 'Ra' to accept+replace To header, 'RA' to accept, "
607 "'Rr' to reject, or 'Rd' to disconnect.",
608 call_id, len, uristr));
609 }
610
611 return app_config.redir_op;
612}
613
614/*
615 * Handler registration status has changed.
616 */
617static void on_reg_state(pjsua_acc_id acc_id)
618{
619 PJ_UNUSED_ARG(acc_id);
620
621 // Log already written.
622}
623
624/*
625 * Handler for incoming presence subscription request
626 */
627static void on_incoming_subscribe(pjsua_acc_id acc_id,
628 pjsua_srv_pres *srv_pres,
629 pjsua_buddy_id buddy_id,
630 const pj_str_t *from,
631 pjsip_rx_data *rdata,
632 pjsip_status_code *code,
633 pj_str_t *reason,
634 pjsua_msg_data *msg_data_)
635{
636 /* Just accept the request (the default behavior) */
637 PJ_UNUSED_ARG(acc_id);
638 PJ_UNUSED_ARG(srv_pres);
639 PJ_UNUSED_ARG(buddy_id);
640 PJ_UNUSED_ARG(from);
641 PJ_UNUSED_ARG(rdata);
642 PJ_UNUSED_ARG(code);
643 PJ_UNUSED_ARG(reason);
644 PJ_UNUSED_ARG(msg_data_);
645}
646
647
648/*
649 * Handler on buddy state changed.
650 */
651static void on_buddy_state(pjsua_buddy_id buddy_id)
652{
653 pjsua_buddy_info info;
654 pjsua_buddy_get_info(buddy_id, &info);
655
656 PJ_LOG(3,(THIS_FILE, "%.*s status is %.*s, subscription state is %s "
657 "(last termination reason code=%d %.*s)",
658 (int)info.uri.slen,
659 info.uri.ptr,
660 (int)info.status_text.slen,
661 info.status_text.ptr,
662 info.sub_state_name,
663 info.sub_term_code,
664 (int)info.sub_term_reason.slen,
665 info.sub_term_reason.ptr));
666}
667
668
669/*
670 * Subscription state has changed.
671 */
672static void on_buddy_evsub_state(pjsua_buddy_id buddy_id,
673 pjsip_evsub *sub,
674 pjsip_event *event)
675{
676 char event_info[80];
677
678 PJ_UNUSED_ARG(sub);
679
680 event_info[0] = '\0';
681
682 if (event->type == PJSIP_EVENT_TSX_STATE &&
684 {
685 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
686 snprintf(event_info, sizeof(event_info),
687 " (RX %s)",
689 }
690
691 PJ_LOG(4,(THIS_FILE,
692 "Buddy %d: subscription state: %s (event: %s%s)",
693 buddy_id, pjsip_evsub_get_state_name(sub),
694 pjsip_event_str(event->type),
695 event_info));
696
697}
698
699
703static void on_pager(pjsua_call_id call_id, const pj_str_t *from,
704 const pj_str_t *to, const pj_str_t *contact,
705 const pj_str_t *mime_type, const pj_str_t *text)
706{
707 /* Note: call index may be -1 */
708 PJ_UNUSED_ARG(call_id);
709 PJ_UNUSED_ARG(to);
710 PJ_UNUSED_ARG(contact);
711 PJ_UNUSED_ARG(mime_type);
712
713 PJ_LOG(3,(THIS_FILE,"MESSAGE from %.*s: %.*s (%.*s)",
714 (int)from->slen, from->ptr,
715 (int)text->slen, text->ptr,
716 (int)mime_type->slen, mime_type->ptr));
717}
718
719
723static void on_typing(pjsua_call_id call_id, const pj_str_t *from,
724 const pj_str_t *to, const pj_str_t *contact,
725 pj_bool_t is_typing)
726{
727 PJ_UNUSED_ARG(call_id);
728 PJ_UNUSED_ARG(to);
729 PJ_UNUSED_ARG(contact);
730
731 PJ_LOG(3,(THIS_FILE, "IM indication: %.*s %s",
732 (int)from->slen, from->ptr,
733 (is_typing?"is typing..":"has stopped typing")));
734}
735
736
740static void on_call_transfer_status(pjsua_call_id call_id,
741 int status_code,
742 const pj_str_t *status_text,
743 pj_bool_t final,
744 pj_bool_t *p_cont)
745{
746 PJ_LOG(3,(THIS_FILE, "Call %d: transfer status=%d (%.*s) %s",
747 call_id, status_code,
748 (int)status_text->slen, status_text->ptr,
749 (final ? "[final]" : "")));
750
751 if (status_code/100 == 2) {
752 PJ_LOG(3,(THIS_FILE,
753 "Call %d: call transferred successfully, disconnecting call",
754 call_id));
755 pjsua_call_hangup(call_id, PJSIP_SC_GONE, NULL, NULL);
756 *p_cont = PJ_FALSE;
757 }
758}
759
760
761/*
762 * Notification that call is being replaced.
763 */
764static void on_call_replaced(pjsua_call_id old_call_id,
765 pjsua_call_id new_call_id)
766{
767 pjsua_call_info old_ci, new_ci;
768
769 pjsua_call_get_info(old_call_id, &old_ci);
770 pjsua_call_get_info(new_call_id, &new_ci);
771
772 PJ_LOG(3,(THIS_FILE, "Call %d with %.*s is being replaced by "
773 "call %d with %.*s",
774 old_call_id,
775 (int)old_ci.remote_info.slen, old_ci.remote_info.ptr,
776 new_call_id,
777 (int)new_ci.remote_info.slen, new_ci.remote_info.ptr));
778}
779
780
781/*
782 * NAT type detection callback.
783 */
784static void on_nat_detect(const pj_stun_nat_detect_result *res)
785{
786 if (res->status != PJ_SUCCESS) {
787 pjsua_perror(THIS_FILE, "NAT detection failed", res->status);
788 } else {
789 PJ_LOG(3, (THIS_FILE, "NAT detected as %s", res->nat_type_name));
790 }
791}
792
793
794/*
795 * MWI indication
796 */
797static void on_mwi_info(pjsua_acc_id acc_id, pjsua_mwi_info *mwi_info)
798{
799 pj_str_t body;
800
801 PJ_LOG(3,(THIS_FILE, "Received MWI for acc %d:", acc_id));
802
803 if (mwi_info->rdata->msg_info.ctype) {
804 const pjsip_ctype_hdr *ctype = mwi_info->rdata->msg_info.ctype;
805
806 PJ_LOG(3,(THIS_FILE, " Content-Type: %.*s/%.*s",
807 (int)ctype->media.type.slen,
808 ctype->media.type.ptr,
809 (int)ctype->media.subtype.slen,
810 ctype->media.subtype.ptr));
811 }
812
813 if (!mwi_info->rdata->msg_info.msg->body) {
814 PJ_LOG(3,(THIS_FILE, " no message body"));
815 return;
816 }
817
818 body.ptr = (char *)mwi_info->rdata->msg_info.msg->body->data;
819 body.slen = mwi_info->rdata->msg_info.msg->body->len;
820
821 PJ_LOG(3,(THIS_FILE, " Body:\n%.*s", (int)body.slen, body.ptr));
822}
823
824
825/*
826 * Transport status notification
827 */
828static void on_transport_state(pjsip_transport *tp,
830 const pjsip_transport_state_info *info)
831{
832 char host_port[128];
833
835 tp->remote_name.port, host_port, sizeof(host_port), 1);
836 switch (state) {
838 {
839 PJ_LOG(3,(THIS_FILE, "SIP %s transport is connected to %s",
840 tp->type_name, host_port));
841 }
842 break;
843
845 {
846 char buf[100];
847 int len;
848
849 len = pj_ansi_snprintf(buf, sizeof(buf), "SIP %s transport is "
850 "disconnected from %s", tp->type_name, host_port);
851 PJ_CHECK_TRUNC_STR(len, buf, sizeof(buf));
852 pjsua_perror(THIS_FILE, buf, info->status);
853 }
854 break;
855
856 default:
857 break;
858 }
859
860#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
861
862 if (!pj_ansi_stricmp(tp->type_name, "tls") && info->ext_info &&
863 (state == PJSIP_TP_STATE_CONNECTED ||
865 ssl_sock_info->verify_status != PJ_SUCCESS))
866 {
868 pj_ssl_sock_info *ssl_sock_info = tls_info->ssl_sock_info;
869 char buf[2048];
870 const char *verif_msgs[32];
871 unsigned verif_msg_cnt;
872
873 /* Dump server TLS cipher */
874 PJ_LOG(4,(THIS_FILE, "TLS cipher used: 0x%06X/%s",
875 ssl_sock_info->cipher,
876 pj_ssl_cipher_name(ssl_sock_info->cipher) ));
877
878 /* Dump server TLS certificate */
879 pj_ssl_cert_info_dump(ssl_sock_info->remote_cert_info, " ",
880 buf, sizeof(buf));
881 PJ_LOG(4,(THIS_FILE, "TLS cert info of %s:\n%s", host_port, buf));
882
883 /* Dump server TLS certificate verification result */
884 verif_msg_cnt = PJ_ARRAY_SIZE(verif_msgs);
885 pj_ssl_cert_get_verify_status_strings(ssl_sock_info->verify_status,
886 verif_msgs, &verif_msg_cnt);
887 PJ_LOG(3,(THIS_FILE, "TLS cert verification result of %s : %s",
888 host_port,
889 (verif_msg_cnt == 1? verif_msgs[0]:"")));
890 if (verif_msg_cnt > 1) {
891 unsigned i;
892 for (i = 0; i < verif_msg_cnt; ++i)
893 PJ_LOG(3,(THIS_FILE, "- %s", verif_msgs[i]));
894 }
895
896 if (ssl_sock_info->verify_status &&
897 !app_config.udp_cfg.tls_setting.verify_server)
898 {
899 PJ_LOG(3,(THIS_FILE, "PJSUA is configured to ignore TLS cert "
900 "verification errors"));
901 }
902 }
903
904#endif
905
906}
907
908/*
909 * Notification on ICE error.
910 */
911static void on_ice_transport_error(int index, pj_ice_strans_op op,
912 pj_status_t status, void *param)
913{
914 PJ_UNUSED_ARG(op);
915 PJ_UNUSED_ARG(param);
916 PJ_PERROR(1,(THIS_FILE, status,
917 "ICE keep alive failure for transport %d", index));
918}
919
920/*
921 * Notification on sound device operation.
922 */
923static pj_status_t on_snd_dev_operation(int operation)
924{
925 int cap_dev, play_dev;
926
927 pjsua_get_snd_dev(&cap_dev, &play_dev);
928 PJ_LOG(3,(THIS_FILE, "Turning sound device %d %d %s", cap_dev, play_dev,
929 (operation? "ON":"OFF")));
930 return PJ_SUCCESS;
931}
932
933static char *get_media_dir(pjmedia_dir dir) {
934 switch (dir) {
936 return "TX";
938 return "RX";
940 return "TX+RX";
941 default:
942 return "unknown dir";
943 }
944}
945
946/* Callback on media events */
947static void on_call_media_event(pjsua_call_id call_id,
948 unsigned med_idx,
949 pjmedia_event *event)
950{
951 char event_name[5];
952
953 PJ_LOG(5,(THIS_FILE, "Event %s",
954 pjmedia_fourcc_name(event->type, event_name)));
955
956 if (event->type == PJMEDIA_EVENT_MEDIA_TP_ERR) {
958
959 err_data = &event->data.med_tp_err;
960 PJ_PERROR(3, (THIS_FILE, err_data->status,
961 "Media transport error event (%s %s %s)",
962 (err_data->type==PJMEDIA_TYPE_AUDIO)?"Audio":"Video",
963 (err_data->is_rtp)?"RTP":"RTCP",
964 get_media_dir(err_data->dir)));
965 }
966#if PJSUA_HAS_VIDEO
967 else if (event->type == PJMEDIA_EVENT_FMT_CHANGED) {
968 /* Adjust renderer window size to original video size */
970
971 pjsua_call_get_info(call_id, &ci);
972
973 if ((ci.media[med_idx].type == PJMEDIA_TYPE_VIDEO) &&
974 (ci.media[med_idx].dir & PJMEDIA_DIR_DECODING))
975 {
978 pjsua_vid_win_info win_info;
979
980 wid = ci.media[med_idx].stream.vid.win_in;
981 pjsua_vid_win_get_info(wid, &win_info);
982
983 size = event->data.fmt_changed.new_fmt.det.vid.size;
984 if (size.w != win_info.size.w || size.h != win_info.size.h) {
985 pjsua_vid_win_set_size(wid, &size);
986
987 /* Re-arrange video windows */
988 arrange_window(PJSUA_INVALID_ID);
989 }
990 }
991 }
992#else
993 PJ_UNUSED_ARG(call_id);
994 PJ_UNUSED_ARG(med_idx);
995#endif
996}
997
998#ifdef TRANSPORT_ADAPTER_SAMPLE
999/*
1000 * This callback is called when media transport needs to be created.
1001 */
1002static pjmedia_transport* on_create_media_transport(pjsua_call_id call_id,
1003 unsigned media_idx,
1004 pjmedia_transport *base_tp,
1005 unsigned flags)
1006{
1007 pjmedia_transport *adapter;
1008 pj_status_t status;
1009
1010 /* Create the adapter */
1012 NULL, base_tp,
1013 (flags & PJSUA_MED_TP_CLOSE_MEMBER),
1014 &adapter);
1015 if (status != PJ_SUCCESS) {
1016 PJ_PERROR(1,(THIS_FILE, status, "Error creating adapter"));
1017 return NULL;
1018 }
1019
1020 PJ_LOG(3,(THIS_FILE, "Media transport is created for call %d media %d",
1021 call_id, media_idx));
1022
1023 return adapter;
1024}
1025#endif
1026
1027/* Playfile done notification, set timer to hangup calls */
1028void on_playfile_done(pjmedia_port *port, void *usr_data)
1029{
1030 pj_time_val delay;
1031
1032 PJ_UNUSED_ARG(port);
1033 PJ_UNUSED_ARG(usr_data);
1034
1035 /* Just rewind WAV when it is played outside of call */
1036 if (pjsua_call_get_count() == 0) {
1037 pjsua_player_set_pos(app_config.wav_id, 0);
1038 }
1039
1040 /* Timer is already active */
1041 if (app_config.auto_hangup_timer.id == 1)
1042 return;
1043
1044 app_config.auto_hangup_timer.id = 1;
1045 delay.sec = 0;
1046 delay.msec = 200; /* Give 200 ms before hangup */
1048 &app_config.auto_hangup_timer,
1049 &delay);
1050}
1051
1052/* IP change progress callback. */
1053void on_ip_change_progress(pjsua_ip_change_op op,
1054 pj_status_t status,
1055 const pjsua_ip_change_op_info *info)
1056{
1057 char info_str[128];
1058 pjsua_acc_info acc_info;
1059 pjsua_transport_info tp_info;
1060
1061 if (status == PJ_SUCCESS) {
1062 switch (op) {
1064 pjsua_transport_get_info(info->lis_restart.transport_id, &tp_info);
1065 pj_ansi_snprintf(info_str, sizeof(info_str),
1066 "restart transport %.*s",
1067 (int)tp_info.info.slen, tp_info.info.ptr);
1068 break;
1070 pjsua_acc_get_info(info->acc_shutdown_tp.acc_id, &acc_info);
1071
1072 pj_ansi_snprintf(info_str, sizeof(info_str),
1073 "transport shutdown for account %.*s",
1074 (int)acc_info.acc_uri.slen,
1075 acc_info.acc_uri.ptr);
1076 break;
1078 pjsua_acc_get_info(info->acc_shutdown_tp.acc_id, &acc_info);
1079 if (info->acc_update_contact.code) {
1080 pj_ansi_snprintf(info_str, sizeof(info_str),
1081 "update contact for account %.*s, code[%d]",
1082 (int)acc_info.acc_uri.slen,
1083 acc_info.acc_uri.ptr,
1084 info->acc_update_contact.code);
1085 } else {
1086 pj_ansi_snprintf(info_str, sizeof(info_str),
1087 "update contact for account %.*s",
1088 (int)acc_info.acc_uri.slen,
1089 acc_info.acc_uri.ptr);
1090 }
1091 break;
1093 pjsua_acc_get_info(info->acc_shutdown_tp.acc_id, &acc_info);
1094 pj_ansi_snprintf(info_str, sizeof(info_str),
1095 "hangup call for account %.*s, call_id[%d]",
1096 (int)acc_info.acc_uri.slen, acc_info.acc_uri.ptr,
1097 info->acc_hangup_calls.call_id);
1098 break;
1100 pjsua_acc_get_info(info->acc_shutdown_tp.acc_id, &acc_info);
1101 pj_ansi_snprintf(info_str, sizeof(info_str),
1102 "reinvite call for account %.*s, call_id[%d]",
1103 (int)acc_info.acc_uri.slen, acc_info.acc_uri.ptr,
1104 info->acc_reinvite_calls.call_id);
1105 break;
1107 pj_ansi_snprintf(info_str, sizeof(info_str),
1108 "done");
1109 default:
1110 break;
1111 }
1112 PJ_LOG(3,(THIS_FILE, "IP change progress report : %s", info_str));
1113
1114 } else {
1115 PJ_PERROR(3,(THIS_FILE, status, "IP change progress fail"));
1116 }
1117}
1118
1119/* Auto hangup timer callback */
1120static void hangup_timeout_callback(pj_timer_heap_t *timer_heap,
1121 struct pj_timer_entry *entry)
1122{
1123 PJ_UNUSED_ARG(timer_heap);
1124 PJ_UNUSED_ARG(entry);
1125
1126 app_config.auto_hangup_timer.id = 0;
1128}
1129
1130/*
1131 * A simple registrar, invoked by default_mod_on_rx_request()
1132 */
1133static void simple_registrar(pjsip_rx_data *rdata)
1134{
1135 pjsip_tx_data *tdata;
1136 const pjsip_expires_hdr *exp;
1137 const pjsip_hdr *h;
1138 unsigned cnt = 0;
1140 pj_status_t status;
1141
1143 rdata, 200, NULL, &tdata);
1144 if (status != PJ_SUCCESS)
1145 return;
1146
1148 PJSIP_H_EXPIRES, NULL);
1149
1150 h = rdata->msg_info.msg->hdr.next;
1151 while (h != &rdata->msg_info.msg->hdr) {
1152 if (h->type == PJSIP_H_CONTACT) {
1153 const pjsip_contact_hdr *c = (const pjsip_contact_hdr*)h;
1154 unsigned e = c->expires;
1155
1156 if (e != PJSIP_EXPIRES_NOT_SPECIFIED) {
1157 if (exp)
1158 e = exp->ivalue;
1159 else
1160 e = 3600;
1161 }
1162
1163 if (e > 0) {
1165 tdata->pool, h);
1166 nc->expires = e;
1167 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)nc);
1168 ++cnt;
1169 }
1170 }
1171 h = h->next;
1172 }
1173
1174 srv = pjsip_generic_string_hdr_create(tdata->pool, NULL, NULL);
1175 srv->name = pj_str("Server");
1176 srv->hvalue = pj_str("pjsua simple registrar");
1177 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)srv);
1178
1180 rdata, tdata, NULL, NULL);
1181 if (status != PJ_SUCCESS) {
1182 pjsip_tx_data_dec_ref(tdata);
1183 }
1184
1185}
1186
1187/*****************************************************************************
1188 * A simple module to handle otherwise unhandled request. We will register
1189 * this with the lowest priority.
1190 */
1191
1192/* Notification on incoming request */
1193static pj_bool_t default_mod_on_rx_request(pjsip_rx_data *rdata)
1194{
1195 pjsip_tx_data *tdata;
1196 pjsip_status_code status_code;
1197 pj_status_t status;
1198
1199 /* Don't respond to ACK! */
1201 &pjsip_ack_method) == 0)
1202 return PJ_TRUE;
1203
1204 /* Simple registrar */
1206 &pjsip_register_method) == 0)
1207 {
1208 simple_registrar(rdata);
1209 return PJ_TRUE;
1210 }
1211
1212 /* Create basic response. */
1214 &pjsip_notify_method) == 0)
1215 {
1216 /* Unsolicited NOTIFY's, send with Bad Request */
1217 status_code = PJSIP_SC_BAD_REQUEST;
1218 } else {
1219 /* Probably unknown method */
1220 status_code = PJSIP_SC_METHOD_NOT_ALLOWED;
1221 }
1223 rdata, status_code,
1224 NULL, &tdata);
1225 if (status != PJ_SUCCESS) {
1226 pjsua_perror(THIS_FILE, "Unable to create response", status);
1227 return PJ_TRUE;
1228 }
1229
1230 /* Add Allow if we're responding with 405 */
1231 if (status_code == PJSIP_SC_METHOD_NOT_ALLOWED) {
1232 const pjsip_hdr *cap_hdr;
1234 PJSIP_H_ALLOW, NULL);
1235 if (cap_hdr) {
1237 tdata->pool, cap_hdr));
1238 }
1239 }
1240
1241 /* Add User-Agent header */
1242 {
1243 pj_str_t user_agent;
1244 char tmp[80];
1245 const pj_str_t USER_AGENT = { "User-Agent", 10};
1246 pjsip_hdr *h;
1247
1248 pj_ansi_snprintf(tmp, sizeof(tmp), "PJSUA v%s/%s",
1249 pj_get_version(), PJ_OS_NAME);
1250 pj_strdup2_with_null(tdata->pool, &user_agent, tmp);
1251
1253 &USER_AGENT,
1254 &user_agent);
1255 pjsip_msg_add_hdr(tdata->msg, h);
1256 }
1257
1258 status = pjsip_endpt_send_response2(pjsua_get_pjsip_endpt(), rdata, tdata,
1259 NULL, NULL);
1260 if (status != PJ_SUCCESS) pjsip_tx_data_dec_ref(tdata);
1261
1262 return PJ_TRUE;
1263}
1264
1265/* The module instance. */
1266static pjsip_module mod_default_handler =
1267{
1268 NULL, NULL, /* prev, next. */
1269 { "mod-default-handler", 19 }, /* Name. */
1270 -1, /* Id */
1271 PJSIP_MOD_PRIORITY_APPLICATION+99, /* Priority */
1272 NULL, /* load() */
1273 NULL, /* start() */
1274 NULL, /* stop() */
1275 NULL, /* unload() */
1276 &default_mod_on_rx_request, /* on_rx_request() */
1277 NULL, /* on_rx_response() */
1278 NULL, /* on_tx_request. */
1279 NULL, /* on_tx_response() */
1280 NULL, /* on_tsx_state() */
1281
1282};
1283
1286/* Called on CLI (re)started, e.g: initial start, after iOS bg */
1287void cli_on_started(pj_status_t status)
1288{
1289 /* Notify app */
1290 if (app_cfg.on_started) {
1291 if (status == PJ_SUCCESS) {
1292 char info[128];
1293 cli_get_info(info, sizeof(info));
1294 if (app_cfg.on_started) {
1295 (*app_cfg.on_started)(status, info);
1296 }
1297 } else {
1298 if (app_cfg.on_started) {
1299 (*app_cfg.on_started)(status, NULL);
1300 }
1301 }
1302 }
1303}
1304
1305/* Called on CLI quit */
1306void cli_on_stopped(pj_bool_t restart, int argc, char* argv[])
1307{
1308 /* Notify app */
1309 if (app_cfg.on_stopped)
1310 (*app_cfg.on_stopped)(restart, argc, argv);
1311}
1312
1313
1314/* Called on pjsua legacy quit */
1315void legacy_on_stopped(pj_bool_t restart)
1316{
1317 /* Notify app */
1318 if (app_cfg.on_stopped)
1319 (*app_cfg.on_stopped)(restart, 1, NULL);
1320}
1321
1322/*****************************************************************************
1323 * Public API
1324 */
1325
1326int stdout_refresh_proc(void *arg)
1327{
1328 extern char *stdout_refresh_text;
1329
1330 PJ_UNUSED_ARG(arg);
1331
1332 /* Set thread to lowest priority so that it doesn't clobber
1333 * stdout output
1334 */
1337
1338 while (!stdout_refresh_quit) {
1339 pj_thread_sleep(stdout_refresh * 1000);
1340 puts(stdout_refresh_text);
1341 fflush(stdout);
1342 }
1343
1344 return 0;
1345}
1346
1347
1348static pj_status_t app_init(void)
1349{
1350 pjsua_transport_id transport_id = -1;
1351 pjsua_transport_config tcp_cfg;
1352 unsigned i;
1353 pj_pool_t *tmp_pool;
1354 pj_status_t status;
1355
1357 status = pjsua_create();
1358 if (status != PJ_SUCCESS)
1359 return status;
1360
1361 /* Create pool for application */
1362 app_config.pool = pjsua_pool_create("pjsua-app", 1000, 1000);
1363 tmp_pool = pjsua_pool_create("tmp-pjsua", 1000, 1000);;
1364
1365 /* Init CLI & its FE settings */
1366 if (!app_running) {
1367 pj_cli_cfg_default(&app_config.cli_cfg.cfg);
1368 pj_cli_telnet_cfg_default(&app_config.cli_cfg.telnet_cfg);
1369 pj_cli_console_cfg_default(&app_config.cli_cfg.console_cfg);
1370 app_config.cli_cfg.telnet_cfg.on_started = cli_on_started;
1371 }
1372
1374 status = load_config(app_cfg.argc, app_cfg.argv, &uri_arg);
1375 if (status != PJ_SUCCESS) {
1376 pj_pool_release(tmp_pool);
1377 return status;
1378 }
1379
1380 /* Initialize application callbacks */
1381 app_config.cfg.cb.on_call_state = &on_call_state;
1382 app_config.cfg.cb.on_stream_destroyed = &on_stream_destroyed;
1383 app_config.cfg.cb.on_call_media_state = &on_call_media_state;
1384 app_config.cfg.cb.on_incoming_call = &on_incoming_call;
1385 app_config.cfg.cb.on_dtmf_digit2 = &call_on_dtmf_callback2;
1386 app_config.cfg.cb.on_call_redirected = &call_on_redirected;
1387 app_config.cfg.cb.on_reg_state = &on_reg_state;
1388 app_config.cfg.cb.on_incoming_subscribe = &on_incoming_subscribe;
1389 app_config.cfg.cb.on_buddy_state = &on_buddy_state;
1390 app_config.cfg.cb.on_buddy_evsub_state = &on_buddy_evsub_state;
1391 app_config.cfg.cb.on_pager = &on_pager;
1392 app_config.cfg.cb.on_typing = &on_typing;
1393 app_config.cfg.cb.on_call_transfer_status = &on_call_transfer_status;
1394 app_config.cfg.cb.on_call_replaced = &on_call_replaced;
1395 app_config.cfg.cb.on_nat_detect = &on_nat_detect;
1396 app_config.cfg.cb.on_mwi_info = &on_mwi_info;
1397 app_config.cfg.cb.on_transport_state = &on_transport_state;
1398 app_config.cfg.cb.on_ice_transport_error = &on_ice_transport_error;
1399 app_config.cfg.cb.on_snd_dev_operation = &on_snd_dev_operation;
1400 app_config.cfg.cb.on_call_media_event = &on_call_media_event;
1401 app_config.cfg.cb.on_ip_change_progress = &on_ip_change_progress;
1402#ifdef TRANSPORT_ADAPTER_SAMPLE
1403 app_config.cfg.cb.on_create_media_transport = &on_create_media_transport;
1404#endif
1405
1406 /* Set sound device latency */
1407 if (app_config.capture_lat > 0)
1408 app_config.media_cfg.snd_rec_latency = app_config.capture_lat;
1409 if (app_config.playback_lat)
1410 app_config.media_cfg.snd_play_latency = app_config.playback_lat;
1411
1412 if (app_cfg.on_config_init)
1413 (*app_cfg.on_config_init)(&app_config);
1414
1415 /* Initialize pjsua */
1416 status = pjsua_init(&app_config.cfg, &app_config.log_cfg,
1417 &app_config.media_cfg);
1418 if (status != PJ_SUCCESS) {
1419 pj_pool_release(tmp_pool);
1420 return status;
1421 }
1422
1423 /* Initialize our module to handle otherwise unhandled request */
1425 &mod_default_handler);
1426 if (status != PJ_SUCCESS)
1427 return status;
1428
1429#ifdef STEREO_DEMO
1430 stereo_demo();
1431#endif
1432
1433 /* Initialize calls data */
1434 for (i=0; i<PJ_ARRAY_SIZE(app_config.call_data); ++i) {
1435 app_config.call_data[i].timer.id = PJSUA_INVALID_ID;
1436 app_config.call_data[i].timer.cb = &call_timeout_callback;
1437 }
1438
1439 /* Optionally registers WAV file */
1440 for (i=0; i<app_config.wav_count; ++i) {
1441 pjsua_player_id wav_id;
1442 unsigned play_options = 0;
1443
1444 if (app_config.auto_play_hangup)
1445 play_options |= PJMEDIA_FILE_NO_LOOP;
1446
1447 status = pjsua_player_create(&app_config.wav_files[i], play_options,
1448 &wav_id);
1449 if (status != PJ_SUCCESS)
1450 goto on_error;
1451
1452 if (app_config.wav_id == PJSUA_INVALID_ID) {
1453 app_config.wav_id = wav_id;
1454 app_config.wav_port = pjsua_player_get_conf_port(app_config.wav_id);
1455 if (app_config.auto_play_hangup) {
1456 pjmedia_port *port;
1457
1458 pjsua_player_get_port(app_config.wav_id, &port);
1459 status = pjmedia_wav_player_set_eof_cb2(port, NULL,
1460 &on_playfile_done);
1461 if (status != PJ_SUCCESS)
1462 goto on_error;
1463
1464 pj_timer_entry_init(&app_config.auto_hangup_timer, 0, NULL,
1465 &hangup_timeout_callback);
1466 }
1467 }
1468 }
1469
1470 /* Optionally registers tone players */
1471 for (i=0; i<app_config.tone_count; ++i) {
1472 pjmedia_port *tport;
1473 char name[80];
1474 pj_str_t label;
1475 pj_status_t status2;
1476
1477 pj_ansi_snprintf(name, sizeof(name), "tone-%d,%d",
1478 app_config.tones[i].freq1,
1479 app_config.tones[i].freq2);
1480 label = pj_str(name);
1481 status2 = pjmedia_tonegen_create2(app_config.pool, &label,
1482 8000, 1, 160, 16,
1483 PJMEDIA_TONEGEN_LOOP, &tport);
1484 if (status2 != PJ_SUCCESS) {
1485 pjsua_perror(THIS_FILE, "Unable to create tone generator", status);
1486 goto on_error;
1487 }
1488
1489 status2 = pjsua_conf_add_port(app_config.pool, tport,
1490 &app_config.tone_slots[i]);
1491 pj_assert(status2 == PJ_SUCCESS);
1492
1493 status2 = pjmedia_tonegen_play(tport, 1, &app_config.tones[i], 0);
1494 pj_assert(status2 == PJ_SUCCESS);
1495 }
1496
1497 /* Optionally create recorder file, if any. */
1498 if (app_config.rec_file.slen) {
1499 status = pjsua_recorder_create(&app_config.rec_file, 0, NULL, 0, 0,
1500 &app_config.rec_id);
1501 if (status != PJ_SUCCESS)
1502 goto on_error;
1503
1504 app_config.rec_port = pjsua_recorder_get_conf_port(app_config.rec_id);
1505 }
1506
1507 pj_memcpy(&tcp_cfg, &app_config.udp_cfg, sizeof(tcp_cfg));
1508
1509 /* Create ringback tones */
1510 if (app_config.no_tones == PJ_FALSE) {
1511 unsigned samples_per_frame;
1512 pjmedia_tone_desc tone[RING_CNT+RINGBACK_CNT];
1513 pj_str_t name;
1514
1515 samples_per_frame = app_config.media_cfg.audio_frame_ptime *
1516 app_config.media_cfg.clock_rate *
1517 app_config.media_cfg.channel_count / 1000;
1518
1519 /* Ringback tone (call is ringing) */
1520 name = pj_str("ringback");
1521 status = pjmedia_tonegen_create2(app_config.pool, &name,
1522 app_config.media_cfg.clock_rate,
1523 app_config.media_cfg.channel_count,
1524 samples_per_frame,
1526 &app_config.ringback_port);
1527 if (status != PJ_SUCCESS)
1528 goto on_error;
1529
1530 pj_bzero(&tone, sizeof(tone));
1531 for (i=0; i<RINGBACK_CNT; ++i) {
1532 tone[i].freq1 = RINGBACK_FREQ1;
1533 tone[i].freq2 = RINGBACK_FREQ2;
1534 tone[i].on_msec = RINGBACK_ON;
1535 tone[i].off_msec = RINGBACK_OFF;
1536 }
1537 tone[RINGBACK_CNT-1].off_msec = RINGBACK_INTERVAL;
1538
1539 pjmedia_tonegen_play(app_config.ringback_port, RINGBACK_CNT, tone,
1541
1542
1543 status = pjsua_conf_add_port(app_config.pool, app_config.ringback_port,
1544 &app_config.ringback_slot);
1545 if (status != PJ_SUCCESS)
1546 goto on_error;
1547
1548 /* Ring (to alert incoming call) */
1549 name = pj_str("ring");
1550 status = pjmedia_tonegen_create2(app_config.pool, &name,
1551 app_config.media_cfg.clock_rate,
1552 app_config.media_cfg.channel_count,
1553 samples_per_frame,
1555 &app_config.ring_port);
1556 if (status != PJ_SUCCESS)
1557 goto on_error;
1558
1559 for (i=0; i<RING_CNT; ++i) {
1560 tone[i].freq1 = RING_FREQ1;
1561 tone[i].freq2 = RING_FREQ2;
1562 tone[i].on_msec = RING_ON;
1563 tone[i].off_msec = RING_OFF;
1564 }
1565 tone[RING_CNT-1].off_msec = RING_INTERVAL;
1566
1567 pjmedia_tonegen_play(app_config.ring_port, RING_CNT,
1568 tone, PJMEDIA_TONEGEN_LOOP);
1569
1570 status = pjsua_conf_add_port(app_config.pool, app_config.ring_port,
1571 &app_config.ring_slot);
1572 if (status != PJ_SUCCESS)
1573 goto on_error;
1574
1575 }
1576
1577 /* Create AVI player virtual devices */
1578 if (app_config.avi_cnt) {
1579#if PJMEDIA_HAS_VIDEO && PJMEDIA_VIDEO_DEV_HAS_AVI
1580 pjmedia_vid_dev_factory *avi_factory;
1581
1583 app_config.avi_cnt,
1584 &avi_factory);
1585 if (status != PJ_SUCCESS) {
1586 PJ_PERROR(1,(THIS_FILE, status, "Error creating AVI factory"));
1587 goto on_error;
1588 }
1589
1590 for (i=0; i<app_config.avi_cnt; ++i) {
1593 unsigned strm_idx, strm_cnt;
1594
1595 app_config.avi[i].dev_id = PJMEDIA_VID_INVALID_DEV;
1596 app_config.avi[i].slot = PJSUA_INVALID_ID;
1597
1599 avdp.path = app_config.avi[i].path;
1600
1601 status = pjmedia_avi_dev_alloc(avi_factory, &avdp, &avid);
1602 if (status != PJ_SUCCESS) {
1603 PJ_PERROR(1,(THIS_FILE, status,
1604 "Error creating AVI player for %.*s",
1605 (int)avdp.path.slen, avdp.path.ptr));
1606 goto on_error;
1607 }
1608
1609 PJ_LOG(4,(THIS_FILE, "AVI player %.*s created, dev_id=%d",
1610 (int)avdp.title.slen, avdp.title.ptr, avid));
1611
1612 app_config.avi[i].dev_id = avid;
1613 if (app_config.avi_def_idx == PJSUA_INVALID_ID)
1614 app_config.avi_def_idx = i;
1615
1617 for (strm_idx=0; strm_idx<strm_cnt; ++strm_idx) {
1618 pjmedia_port *aud;
1619 pjmedia_format *fmt;
1620 pjsua_conf_port_id slot;
1621 char fmt_name[5];
1622
1624 strm_idx);
1625 fmt = &aud->info.fmt;
1626
1627 pjmedia_fourcc_name(fmt->id, fmt_name);
1628
1629 if (fmt->id == PJMEDIA_FORMAT_PCM) {
1630 status = pjsua_conf_add_port(app_config.pool, aud,
1631 &slot);
1632 if (status == PJ_SUCCESS) {
1633 PJ_LOG(4,(THIS_FILE,
1634 "AVI %.*s: audio added to slot %d",
1635 (int)avdp.title.slen, avdp.title.ptr,
1636 slot));
1637 app_config.avi[i].slot = slot;
1638 }
1639 } else {
1640 PJ_LOG(4,(THIS_FILE,
1641 "AVI %.*s: audio ignored, format=%s",
1642 (int)avdp.title.slen, avdp.title.ptr,
1643 fmt_name));
1644 }
1645 }
1646 }
1647#else
1648 PJ_LOG(2,(THIS_FILE,
1649 "Warning: --play-avi is ignored because AVI is disabled"));
1650#endif /* PJMEDIA_VIDEO_DEV_HAS_AVI */
1651 }
1652
1653 /* Add UDP transport unless it's disabled. */
1654 if (!app_config.no_udp) {
1655 pjsua_acc_id aid;
1657
1658 status = pjsua_transport_create(type,
1659 &app_config.udp_cfg,
1660 &transport_id);
1661 if (status != PJ_SUCCESS)
1662 goto on_error;
1663
1664 /* Add local account */
1665 pjsua_acc_add_local(transport_id, PJ_TRUE, &aid);
1666
1667 /* Adjust local account config based on pjsua app config */
1668 {
1669 pjsua_acc_config acc_cfg;
1670 pjsua_acc_get_config(aid, tmp_pool, &acc_cfg);
1671
1672 app_config_init_video(&acc_cfg);
1673 acc_cfg.rtp_cfg = app_config.rtp_cfg;
1674 pjsua_acc_modify(aid, &acc_cfg);
1675 }
1676
1677 //pjsua_acc_set_transport(aid, transport_id);
1679
1680 if (app_config.udp_cfg.port == 0) {
1682 pj_sockaddr_in *a;
1683
1684 pjsua_transport_get_info(transport_id, &ti);
1685 a = (pj_sockaddr_in*)&ti.local_addr;
1686
1687 tcp_cfg.port = pj_ntohs(a->sin_port);
1688 }
1689 }
1690
1691 /* Add UDP IPv6 transport unless it's disabled. */
1692 if (!app_config.no_udp && app_config.ipv6) {
1693 pjsua_acc_id aid;
1695 pjsua_transport_config udp_cfg;
1696
1697 udp_cfg = app_config.udp_cfg;
1698 if (udp_cfg.port == 0)
1699 udp_cfg.port = 5060;
1700 else
1701 udp_cfg.port += 10;
1702 status = pjsua_transport_create(type,
1703 &udp_cfg,
1704 &transport_id);
1705 if (status != PJ_SUCCESS)
1706 goto on_error;
1707
1708 /* Add local account */
1709 pjsua_acc_add_local(transport_id, PJ_TRUE, &aid);
1710
1711 /* Adjust local account config based on pjsua app config */
1712 {
1713 pjsua_acc_config acc_cfg;
1714 pjsua_acc_get_config(aid, tmp_pool, &acc_cfg);
1715
1716 app_config_init_video(&acc_cfg);
1717 acc_cfg.rtp_cfg = app_config.rtp_cfg;
1719 pjsua_acc_modify(aid, &acc_cfg);
1720 }
1721
1722 //pjsua_acc_set_transport(aid, transport_id);
1724
1725 if (app_config.udp_cfg.port == 0) {
1727
1728 pjsua_transport_get_info(transport_id, &ti);
1729 tcp_cfg.port = pj_sockaddr_get_port(&ti.local_addr);
1730 }
1731 }
1732
1733 /* Add TCP transport unless it's disabled */
1734 if (!app_config.no_tcp) {
1735 pjsua_acc_id aid;
1736
1738 &tcp_cfg,
1739 &transport_id);
1740 if (status != PJ_SUCCESS)
1741 goto on_error;
1742
1743 /* Add local account */
1744 pjsua_acc_add_local(transport_id, PJ_TRUE, &aid);
1745
1746 /* Adjust local account config based on pjsua app config */
1747 {
1748 pjsua_acc_config acc_cfg;
1749 pjsua_acc_get_config(aid, tmp_pool, &acc_cfg);
1750
1751 app_config_init_video(&acc_cfg);
1752 acc_cfg.rtp_cfg = app_config.rtp_cfg;
1753 pjsua_acc_modify(aid, &acc_cfg);
1754 }
1755
1757
1758 }
1759
1760 /* Add TCP IPv6 transport unless it's disabled. */
1761 if (!app_config.no_tcp && app_config.ipv6) {
1762 pjsua_acc_id aid;
1764
1765 tcp_cfg.port += 10;
1766
1767 status = pjsua_transport_create(type,
1768 &tcp_cfg,
1769 &transport_id);
1770 if (status != PJ_SUCCESS)
1771 goto on_error;
1772
1773 /* Add local account */
1774 pjsua_acc_add_local(transport_id, PJ_TRUE, &aid);
1775
1776 /* Adjust local account config based on pjsua app config */
1777 {
1778 pjsua_acc_config acc_cfg;
1779 pjsua_acc_get_config(aid, tmp_pool, &acc_cfg);
1780
1781 app_config_init_video(&acc_cfg);
1782 acc_cfg.rtp_cfg = app_config.rtp_cfg;
1784 pjsua_acc_modify(aid, &acc_cfg);
1785 }
1786
1787 //pjsua_acc_set_transport(aid, transport_id);
1789 }
1790
1791
1792#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
1793 /* Add TLS transport when application wants one */
1794 if (app_config.use_tls) {
1795
1796 pjsua_acc_id acc_id;
1797
1798 /* Copy the QoS settings */
1799 tcp_cfg.tls_setting.qos_type = tcp_cfg.qos_type;
1800 pj_memcpy(&tcp_cfg.tls_setting.qos_params, &tcp_cfg.qos_params,
1801 sizeof(tcp_cfg.qos_params));
1802
1803 /* Set TLS port as TCP port+1 */
1804 tcp_cfg.port++;
1806 &tcp_cfg,
1807 &transport_id);
1808 tcp_cfg.port--;
1809 if (status != PJ_SUCCESS)
1810 goto on_error;
1811
1812 /* Add local account */
1813 pjsua_acc_add_local(transport_id, PJ_FALSE, &acc_id);
1814
1815 /* Adjust local account config based on pjsua app config */
1816 {
1817 pjsua_acc_config acc_cfg;
1818 pjsua_acc_get_config(acc_id, tmp_pool, &acc_cfg);
1819
1820 app_config_init_video(&acc_cfg);
1821 acc_cfg.rtp_cfg = app_config.rtp_cfg;
1822 pjsua_acc_modify(acc_id, &acc_cfg);
1823 }
1824
1826 }
1827
1828 /* Add TLS IPv6 transport unless it's disabled. */
1829 if (app_config.use_tls && app_config.ipv6) {
1830 pjsua_acc_id aid;
1832
1833 tcp_cfg.port += 10;
1834
1835 status = pjsua_transport_create(type,
1836 &tcp_cfg,
1837 &transport_id);
1838 if (status != PJ_SUCCESS)
1839 goto on_error;
1840
1841 /* Add local account */
1842 pjsua_acc_add_local(transport_id, PJ_TRUE, &aid);
1843
1844 /* Adjust local account config based on pjsua app config */
1845 {
1846 pjsua_acc_config acc_cfg;
1847 pjsua_acc_get_config(aid, tmp_pool, &acc_cfg);
1848
1849 app_config_init_video(&acc_cfg);
1850 acc_cfg.rtp_cfg = app_config.rtp_cfg;
1852 pjsua_acc_modify(aid, &acc_cfg);
1853 }
1854
1855 //pjsua_acc_set_transport(aid, transport_id);
1857 }
1858
1859#endif
1860
1861 if (transport_id == -1) {
1862 PJ_LOG(1,(THIS_FILE, "Error: no transport is configured"));
1863 status = -1;
1864 goto on_error;
1865 }
1866
1867
1868 /* Add accounts */
1869 for (i=0; i<app_config.acc_cnt; ++i) {
1870 app_config.acc_cfg[i].rtp_cfg = app_config.rtp_cfg;
1871 app_config.acc_cfg[i].reg_retry_interval = 300;
1872 app_config.acc_cfg[i].reg_first_retry_interval = 60;
1873
1874 app_config_init_video(&app_config.acc_cfg[i]);
1875
1876 status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL);
1877 if (status != PJ_SUCCESS)
1878 goto on_error;
1880 }
1881
1882 /* Add buddies */
1883 for (i=0; i<app_config.buddy_cnt; ++i) {
1884 status = pjsua_buddy_add(&app_config.buddy_cfg[i], NULL);
1885 if (status != PJ_SUCCESS) {
1886 PJ_PERROR(1,(THIS_FILE, status, "Error adding buddy"));
1887 goto on_error;
1888 }
1889 }
1890
1891 /* Optionally disable some codec */
1892 for (i=0; i<app_config.codec_dis_cnt; ++i) {
1893 pjsua_codec_set_priority(&app_config.codec_dis[i],
1895#if PJSUA_HAS_VIDEO
1896 pjsua_vid_codec_set_priority(&app_config.codec_dis[i],
1898#endif
1899 }
1900
1901 /* Optionally set codec orders */
1902 for (i=0; i<app_config.codec_cnt; ++i) {
1903 pjsua_codec_set_priority(&app_config.codec_arg[i],
1905#if PJSUA_HAS_VIDEO
1906 pjsua_vid_codec_set_priority(&app_config.codec_arg[i],
1908#endif
1909 }
1910
1911 /* Use null sound device? */
1912#ifndef STEREO_DEMO
1913 if (app_config.null_audio) {
1914 status = pjsua_set_null_snd_dev();
1915 if (status != PJ_SUCCESS)
1916 goto on_error;
1917 }
1918#endif
1919
1920 if (app_config.capture_dev != PJSUA_INVALID_ID ||
1921 app_config.playback_dev != PJSUA_INVALID_ID)
1922 {
1923 status = pjsua_set_snd_dev(app_config.capture_dev,
1924 app_config.playback_dev);
1925 if (status != PJ_SUCCESS)
1926 goto on_error;
1927 }
1928
1929 /* Init call setting */
1930 pjsua_call_setting_default(&call_opt);
1931 call_opt.aud_cnt = app_config.aud_cnt;
1932 call_opt.vid_cnt = app_config.vid.vid_cnt;
1933
1934#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
1935 /* Wipe out TLS key settings in transport configs */
1936 pjsip_tls_setting_wipe_keys(&app_config.udp_cfg.tls_setting);
1937#endif
1938
1939 pj_pool_release(tmp_pool);
1940 return PJ_SUCCESS;
1941
1942on_error:
1943
1944#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
1945 /* Wipe out TLS key settings in transport configs */
1946 pjsip_tls_setting_wipe_keys(&app_config.udp_cfg.tls_setting);
1947#endif
1948
1949 pj_pool_release(tmp_pool);
1950 app_destroy();
1951 return status;
1952}
1953
1954pj_status_t pjsua_app_init(const pjsua_app_cfg_t *cfg)
1955{
1956 pj_status_t status;
1957 pj_memcpy(&app_cfg, cfg, sizeof(app_cfg));
1958
1959 status = app_init();
1960 if (status != PJ_SUCCESS)
1961 return status;
1962
1963 /* Init CLI if configured */
1964 if (app_config.use_cli) {
1965 status = cli_init();
1966 }
1967 return status;
1968}
1969
1970pj_status_t pjsua_app_run(pj_bool_t wait_telnet_cli)
1971{
1972 pj_thread_t *stdout_refresh_thread = NULL;
1973 pj_status_t status;
1974
1975 /* Start console refresh thread */
1976 if (stdout_refresh > 0) {
1977 pj_thread_create(app_config.pool, "stdout", &stdout_refresh_proc,
1978 NULL, 0, 0, &stdout_refresh_thread);
1979 }
1980
1981 status = pjsua_start();
1982 if (status != PJ_SUCCESS)
1983 goto on_return;
1984
1985 if (app_config.use_cli && (app_config.cli_cfg.cli_fe & CLI_FE_TELNET)) {
1986 char info[128];
1987 cli_get_info(info, sizeof(info));
1988 if (app_cfg.on_started) {
1989 (*app_cfg.on_started)(status, info);
1990 }
1991 } else {
1992 if (app_cfg.on_started) {
1993 (*app_cfg.on_started)(status, "Ready");
1994 }
1995 }
1996
1997 /* If user specifies URI to call, then call the URI */
1998 if (uri_arg.slen) {
1999 pjsua_call_setting_default(&call_opt);
2000 call_opt.aud_cnt = app_config.aud_cnt;
2001 call_opt.vid_cnt = app_config.vid.vid_cnt;
2002
2003 pjsua_call_make_call(current_acc, &uri_arg, &call_opt, NULL,
2004 NULL, NULL);
2005 }
2006
2007 app_running = PJ_TRUE;
2008
2009 if (app_config.use_cli)
2010 cli_main(wait_telnet_cli);
2011 else
2012 legacy_main();
2013
2014 status = PJ_SUCCESS;
2015
2016on_return:
2017 if (stdout_refresh_thread) {
2018 stdout_refresh_quit = PJ_TRUE;
2019 pj_thread_join(stdout_refresh_thread);
2020 pj_thread_destroy(stdout_refresh_thread);
2021 stdout_refresh_quit = PJ_FALSE;
2022 }
2023 return status;
2024}
2025
2026static pj_status_t app_destroy(void)
2027{
2028 pj_status_t status = PJ_SUCCESS;
2029 unsigned i;
2030 pj_bool_t use_cli = PJ_FALSE;
2031 int cli_fe = 0;
2032 pj_uint16_t cli_telnet_port = 0;
2033
2034#ifdef STEREO_DEMO
2035 if (app_config.snd) {
2036 pjmedia_snd_port_destroy(app_config.snd);
2037 app_config.snd = NULL;
2038 }
2039 if (app_config.sc_ch1) {
2040 pjsua_conf_remove_port(app_config.sc_ch1_slot);
2041 app_config.sc_ch1_slot = PJSUA_INVALID_ID;
2042 pjmedia_port_destroy(app_config.sc_ch1);
2043 app_config.sc_ch1 = NULL;
2044 }
2045 if (app_config.sc) {
2046 pjmedia_port_destroy(app_config.sc);
2047 app_config.sc = NULL;
2048 }
2049#endif
2050
2051 /* Close avi devs and ports */
2052 for (i=0; i<app_config.avi_cnt; ++i) {
2053 if (app_config.avi[i].slot != PJSUA_INVALID_ID) {
2054 pjsua_conf_remove_port(app_config.avi[i].slot);
2055 app_config.avi[i].slot = PJSUA_INVALID_ID;
2056 }
2057#if PJMEDIA_HAS_VIDEO && PJMEDIA_VIDEO_DEV_HAS_AVI
2058 if (app_config.avi[i].dev_id != PJMEDIA_VID_INVALID_DEV) {
2059 pjmedia_avi_dev_free(app_config.avi[i].dev_id);
2060 app_config.avi[i].dev_id = PJMEDIA_VID_INVALID_DEV;
2061 }
2062#endif
2063 }
2064
2065 /* Close ringback port */
2066 if (app_config.ringback_port &&
2067 app_config.ringback_slot != PJSUA_INVALID_ID)
2068 {
2069 pjsua_conf_remove_port(app_config.ringback_slot);
2070 app_config.ringback_slot = PJSUA_INVALID_ID;
2071 pjmedia_port_destroy(app_config.ringback_port);
2072 app_config.ringback_port = NULL;
2073 }
2074
2075 /* Close ring port */
2076 if (app_config.ring_port && app_config.ring_slot != PJSUA_INVALID_ID) {
2077 pjsua_conf_remove_port(app_config.ring_slot);
2078 app_config.ring_slot = PJSUA_INVALID_ID;
2079 pjmedia_port_destroy(app_config.ring_port);
2080 app_config.ring_port = NULL;
2081 }
2082
2083 /* Close wav player */
2084 if (app_config.wav_id != PJSUA_INVALID_ID) {
2085 pjsua_player_destroy(app_config.wav_id);
2086 app_config.wav_id = PJSUA_INVALID_ID;
2087 app_config.wav_port = PJSUA_INVALID_ID;
2088 }
2089
2090 /* Close wav recorder */
2091 if (app_config.rec_id != PJSUA_INVALID_ID) {
2092 pjsua_recorder_destroy(app_config.rec_id);
2093 app_config.rec_id = PJSUA_INVALID_ID;
2094 app_config.rec_port = PJSUA_INVALID_ID;
2095 }
2096
2097 /* Close tone generators */
2098 for (i=0; i<app_config.tone_count; ++i) {
2099 if (app_config.tone_slots[i] != PJSUA_INVALID_ID) {
2100 pjsua_conf_remove_port(app_config.tone_slots[i]);
2101 app_config.tone_slots[i] = PJSUA_INVALID_ID;
2102 }
2103 }
2104
2105#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
2106 /* Wipe out TLS key settings in transport configs */
2107 pjsip_tls_setting_wipe_keys(&app_config.udp_cfg.tls_setting);
2108#endif
2109
2110 pj_pool_safe_release(&app_config.pool);
2111
2112 status = pjsua_destroy();
2113
2114 if (app_config.use_cli) {
2115 use_cli = app_config.use_cli;
2116 cli_fe = app_config.cli_cfg.cli_fe;
2117 cli_telnet_port = app_config.cli_cfg.telnet_cfg.port;
2118 }
2119
2120 /* Reset config */
2121 pj_bzero(&app_config, sizeof(app_config));
2122 app_config.wav_id = PJSUA_INVALID_ID;
2123 app_config.rec_id = PJSUA_INVALID_ID;
2124
2125 if (use_cli) {
2126 app_config.use_cli = use_cli;
2127 app_config.cli_cfg.cli_fe = cli_fe;
2128 app_config.cli_cfg.telnet_cfg.port = cli_telnet_port;
2129 }
2130
2131 return status;
2132}
2133
2134pj_status_t pjsua_app_destroy(void)
2135{
2136 pj_status_t status;
2137
2138 status = app_destroy();
2139
2140 if (app_config.use_cli) {
2141 cli_destroy();
2142 }
2143
2144 return status;
2145}
2146
2149#ifdef STEREO_DEMO
2150/*
2151 * In this stereo demo, we open the sound device in stereo mode and
2152 * arrange the attachment to the PJSUA-LIB conference bridge as such
2153 * so that channel0/left channel of the sound device corresponds to
2154 * slot 0 in the bridge, and channel1/right channel of the sound
2155 * device corresponds to slot 1 in the bridge. Then user can independently
2156 * feed different media to/from the speakers/microphones channels, by
2157 * connecting them to slot 0 or 1 respectively.
2158 *
2159 * Here's how the connection looks like:
2160 *
2161 +-----------+ stereo +-----------------+ 2x mono +-----------+
2162 | AUDIO DEV |<------>| SPLITCOMB left|<------->|#0 BRIDGE |
2163 +-----------+ | right|<------->|#1 |
2164 +-----------------+ +-----------+
2165 */
2166static void stereo_demo()
2167{
2168 pjmedia_port *conf;
2169 pj_status_t status;
2170
2171 /* Disable existing sound device */
2172 conf = pjsua_set_no_snd_dev();
2173
2174 /* Create stereo-mono splitter/combiner */
2175 status = pjmedia_splitcomb_create(app_config.pool,
2176 PJMEDIA_PIA_SRATE(&conf->info) /* clock rate */,
2177 2 /* stereo */,
2178 2 * PJMEDIA_PIA_SPF(&conf->info),
2179 PJMEDIA_PIA_BITS(&conf->info),
2180 0 /* options */,
2181 &app_config.sc);
2182 pj_assert(status == PJ_SUCCESS);
2183
2184 /* Connect channel0 (left channel?) to conference port slot0 */
2185 status = pjmedia_splitcomb_set_channel(app_config.sc, 0 /* ch0 */,
2186 0 /*options*/,
2187 conf);
2188 pj_assert(status == PJ_SUCCESS);
2189
2190 /* Create reverse channel for channel1 (right channel?)... */
2191 status = pjmedia_splitcomb_create_rev_channel(app_config.pool,
2192 app_config.sc,
2193 1 /* ch1 */,
2194 0 /* options */,
2195 &app_config.sc_ch1);
2196 pj_assert(status == PJ_SUCCESS);
2197
2198 /* .. and register it to conference bridge (it would be slot1
2199 * if there's no other devices connected to the bridge)
2200 */
2201 status = pjsua_conf_add_port(app_config.pool, app_config.sc_ch1,
2202 &app_config.sc_ch1_slot);
2203 pj_assert(status == PJ_SUCCESS);
2204
2205 /* Create sound device */
2206 status = pjmedia_snd_port_create(app_config.pool, -1, -1,
2207 PJMEDIA_PIA_SRATE(&conf->info),
2208 2 /* stereo */,
2209 2 * PJMEDIA_PIA_SPF(&conf->info),
2210 PJMEDIA_PIA_BITS(&conf->info),
2211 0, &app_config.snd);
2212
2213 pj_assert(status == PJ_SUCCESS);
2214
2215
2216 /* Connect the splitter to the sound device */
2217 status = pjmedia_snd_port_connect(app_config.snd, app_config.sc);
2218 pj_assert(status == PJ_SUCCESS);
2219}
2220#endif
void pj_cli_console_cfg_default(pj_cli_console_cfg *param)
void pj_cli_telnet_cfg_default(pj_cli_telnet_cfg *param)
const char * pj_get_version(void)
void pj_cli_cfg_default(pj_cli_cfg *param)
unsigned pjmedia_avi_streams_get_num_streams(pjmedia_avi_streams *streams)
pjmedia_avi_stream * pjmedia_avi_streams_get_stream(pjmedia_avi_streams *streams, unsigned idx)
PJMEDIA_CODEC_PRIO_DISABLED
PJMEDIA_CODEC_PRIO_NORMAL
PJMEDIA_EVENT_FMT_CHANGED
PJMEDIA_EVENT_MEDIA_TP_ERR
pj_status_t pjmedia_wav_player_set_eof_cb2(pjmedia_port *port, void *user_data, void(*cb)(pjmedia_port *port, void *usr_data))
PJMEDIA_FILE_NO_LOOP
PJMEDIA_FORMAT_PCM
pj_status_t pjmedia_tonegen_rewind(pjmedia_port *tonegen)
pj_status_t pjmedia_tonegen_play(pjmedia_port *tonegen, unsigned count, const pjmedia_tone_desc tones[], unsigned options)
pj_status_t pjmedia_tonegen_create2(pj_pool_t *pool, const pj_str_t *name, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned options, pjmedia_port **p_port)
PJMEDIA_TONEGEN_LOOP
pj_status_t pjmedia_port_destroy(pjmedia_port *port)
unsigned PJMEDIA_PIA_BITS(const pjmedia_port_info *pia)
unsigned PJMEDIA_PIA_SPF(const pjmedia_port_info *pia)
unsigned PJMEDIA_PIA_SRATE(const pjmedia_port_info *pia)
pj_status_t pjmedia_splitcomb_create(pj_pool_t *pool, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned options, pjmedia_port **p_splitcomb)
pj_status_t pjmedia_splitcomb_create_rev_channel(pj_pool_t *pool, pjmedia_port *splitcomb, unsigned ch_num, unsigned options, pjmedia_port **p_chport)
pj_status_t pjmedia_splitcomb_set_channel(pjmedia_port *splitcomb, unsigned ch_num, unsigned options, pjmedia_port *port)
pj_status_t pjmedia_tp_adapter_create(pjmedia_endpt *endpt, const char *name, pjmedia_transport *base_tp, pj_bool_t del_base, pjmedia_transport **p_tp)
const char * pjmedia_type_name(pjmedia_type t)
const char * pjmedia_fourcc_name(pj_uint32_t sig, char buf[])
pjmedia_dir
PJMEDIA_TYPE_AUDIO
PJMEDIA_TYPE_VIDEO
PJMEDIA_DIR_ENCODING
PJMEDIA_DIR_NONE
PJMEDIA_DIR_DECODING
pj_status_t pjmedia_snd_port_connect(pjmedia_snd_port *snd_port, pjmedia_port *port)
pj_status_t pjmedia_snd_port_create(pj_pool_t *pool, int rec_id, int play_id, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned options, pjmedia_snd_port **p_port)
pj_status_t pjmedia_snd_port_destroy(pjmedia_snd_port *snd_port)
pj_ice_strans_op
#define PJSIP_MAX_URL_SIZE
Definition: sip_config.h:354
pj_status_t pjsip_endpt_send_response2(pjsip_endpoint *endpt, pjsip_rx_data *rdata, pjsip_tx_data *tdata, void *token, pjsip_send_callback cb)
pj_status_t pjsip_endpt_create_response(pjsip_endpoint *endpt, const pjsip_rx_data *rdata, int st_code, const pj_str_t *st_text, pjsip_tx_data **p_tdata)
pjsip_redirect_op
Definition: sip_util.h:80
@ PJSIP_REDIRECT_PENDING
Definition: sip_util.h:104
pj_status_t pjsip_endpt_register_module(pjsip_endpoint *endpt, pjsip_module *module)
pj_status_t pjsip_endpt_schedule_timer(pjsip_endpoint *endpt, pj_timer_entry *entry, const pj_time_val *delay)
void pjsip_endpt_cancel_timer(pjsip_endpoint *endpt, pj_timer_entry *entry)
const pjsip_hdr * pjsip_endpt_get_capability(pjsip_endpoint *endpt, int htype, const pj_str_t *hname)
const char * pjsip_evsub_get_state_name(const pjsip_evsub *sub)
const pjsip_method pjsip_notify_method
Definition: evsub.h:219
struct pjsip_evsub pjsip_evsub
Definition: evsub.h:50
const char * pjsip_event_str(pjsip_event_id_e e)
@ PJSIP_EVENT_RX_MSG
Definition: sip_event.h:54
@ PJSIP_EVENT_TSX_STATE
Definition: sip_event.h:60
@ PJSIP_INV_STATE_EARLY
Definition: sip_inv.h:92
@ PJSIP_INV_STATE_DISCONNECTED
Definition: sip_inv.h:95
@ PJSIP_INV_STATE_CONFIRMED
Definition: sip_inv.h:94
@ PJSIP_MOD_PRIORITY_APPLICATION
Definition: sip_module.h:210
void pjsip_generic_string_hdr_init2(pjsip_generic_string_hdr *h, pj_str_t *hname, pj_str_t *hvalue)
pjsip_generic_string_hdr * pjsip_generic_string_hdr_create(pj_pool_t *pool, const pj_str_t *hname, const pj_str_t *hvalue)
void * pjsip_hdr_clone(pj_pool_t *pool, const void *hdr)
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition: sip_msg.h:1427
pjsip_status_code
Definition: sip_msg.h:456
int pjsip_method_cmp(const pjsip_method *m1, const pjsip_method *m2)
const pjsip_method pjsip_ack_method
Definition: sip_msg.h:94
const pjsip_method pjsip_register_method
Definition: sip_msg.h:100
void pjsip_msg_add_hdr(pjsip_msg *msg, pjsip_hdr *hdr)
Definition: sip_msg.h:980
void * pjsip_msg_find_hdr(const pjsip_msg *msg, pjsip_hdr_e type, const void *start)
void pjsip_tls_setting_wipe_keys(pjsip_tls_setting *opt)
pjsip_transport_state
Definition: sip_transport.h:1441
char * pjsip_rx_data_get_info(pjsip_rx_data *rdata)
pj_status_t pjsip_tx_data_dec_ref(pjsip_tx_data *tdata)
@ PJSIP_TP_STATE_CONNECTED
Definition: sip_transport.h:1442
@ PJSIP_TP_STATE_DISCONNECTED
Definition: sip_transport.h:1445
pjsip_transport_type_e
Definition: sip_types.h:62
struct pjsip_endpoint pjsip_endpoint
Definition: sip_types.h:111
@ PJSIP_ROLE_UAC
Definition: sip_types.h:190
@ PJSIP_TRANSPORT_TCP
Definition: sip_types.h:70
@ PJSIP_TRANSPORT_TLS
Definition: sip_types.h:73
@ PJSIP_TRANSPORT_TLS6
Definition: sip_types.h:100
@ PJSIP_TRANSPORT_UDP
Definition: sip_types.h:67
@ PJSIP_TRANSPORT_UDP6
Definition: sip_types.h:94
@ PJSIP_TRANSPORT_TCP6
Definition: sip_types.h:97
int pjsip_uri_print(pjsip_uri_context_e context, const void *uri, char *buf, pj_size_t size)
Definition: sip_uri.h:300
@ PJSIP_URI_IN_FROMTO_HDR
Definition: sip_uri.h:156
pj_status_t pjsua_acc_set_online_status(pjsua_acc_id acc_id, pj_bool_t is_online)
pj_status_t pjsua_acc_add_local(pjsua_transport_id tid, pj_bool_t is_default, pjsua_acc_id *p_acc_id)
pj_status_t pjsua_acc_modify(pjsua_acc_id acc_id, const pjsua_acc_config *acc_cfg)
pj_status_t pjsua_acc_add(const pjsua_acc_config *acc_cfg, pj_bool_t is_default, pjsua_acc_id *p_acc_id)
pj_status_t pjsua_acc_get_config(pjsua_acc_id acc_id, pj_pool_t *pool, pjsua_acc_config *acc_cfg)
pj_status_t pjsua_acc_get_info(pjsua_acc_id acc_id, pjsua_acc_info *info)
@ PJSUA_IPV6_ENABLED
Definition: pjsua-lib/pjsua.h:3681
int pjsua_acc_id
Definition: pjsua-lib/pjsua.h:265
int pjsua_player_id
Definition: pjsua-lib/pjsua.h:271
pjmedia_endpt * pjsua_get_pjmedia_endpt(void)
pj_status_t pjsua_create(void)
pj_pool_t * pjsua_pool_create(const char *name, pj_size_t init_size, pj_size_t increment)
void pjsua_perror(const char *sender, const char *title, pj_status_t status)
pjsua_ip_change_op
Definition: pjsua-lib/pjsua.h:834
pj_status_t pjsua_init(const pjsua_config *ua_cfg, const pjsua_logging_config *log_cfg, const pjsua_media_config *media_cfg)
pj_status_t pjsua_start(void)
int pjsua_buddy_id
Definition: pjsua-lib/pjsua.h:268
pj_pool_factory * pjsua_get_pool_factory(void)
pj_status_t pjsua_destroy(void)
pjsip_endpoint * pjsua_get_pjsip_endpt(void)
void pjsua_msg_data_init(pjsua_msg_data *msg_data)
int pjsua_call_id
Definition: pjsua-lib/pjsua.h:262
int pjsua_conf_port_id
Definition: pjsua-lib/pjsua.h:277
@ PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS
Definition: pjsua-lib/pjsua.h:863
@ PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT
Definition: pjsua-lib/pjsua.h:853
@ PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS
Definition: pjsua-lib/pjsua.h:858
@ PJSUA_IP_CHANGE_OP_RESTART_LIS
Definition: pjsua-lib/pjsua.h:843
@ PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP
Definition: pjsua-lib/pjsua.h:848
@ PJSUA_IP_CHANGE_OP_COMPLETED
Definition: pjsua-lib/pjsua.h:868
@ PJSUA_DTMF_METHOD_RFC2833
Definition: pjsua-lib/pjsua.h:925
@ PJSUA_DTMF_METHOD_SIP_INFO
Definition: pjsua-lib/pjsua.h:936
@ PJSUA_MED_TP_CLOSE_MEMBER
Definition: pjsua-lib/pjsua.h:747
pj_status_t pjsua_buddy_get_info(pjsua_buddy_id buddy_id, pjsua_buddy_info *info)
pj_status_t pjsua_buddy_add(const pjsua_buddy_config *buddy_cfg, pjsua_buddy_id *p_buddy_id)
pj_status_t pjsua_call_get_info(pjsua_call_id call_id, pjsua_call_info *info)
#define PJSUA_MAX_CALLS
Definition: pjsua-lib/pjsua.h:4947
void pjsua_call_setting_default(pjsua_call_setting *opt)
int pjsua_vid_win_id
Definition: pjsua-lib/pjsua.h:4978
int pjsua_call_get_vid_stream_idx(pjsua_call_id call_id)
pj_status_t pjsua_call_make_call(pjsua_acc_id acc_id, const pj_str_t *dst_uri, const pjsua_call_setting *opt, void *user_data, const pjsua_msg_data *msg_data, pjsua_call_id *p_call_id)
pjsua_conf_port_id pjsua_call_get_conf_port(pjsua_call_id call_id)
unsigned pjsua_call_get_count(void)
pj_bool_t pjsua_call_has_media(pjsua_call_id call_id)
void pjsua_call_hangup_all(void)
pj_status_t pjsua_call_hangup(pjsua_call_id call_id, unsigned code, const pj_str_t *reason, const pjsua_msg_data *msg_data)
pj_status_t pjsua_call_answer2(pjsua_call_id call_id, const pjsua_call_setting *opt, unsigned code, const pj_str_t *reason, const pjsua_msg_data *msg_data)
pj_status_t pjsua_enum_calls(pjsua_call_id ids[], unsigned *count)
@ PJSUA_CALL_MEDIA_ERROR
Definition: pjsua-lib/pjsua.h:5010
@ PJSUA_CALL_MEDIA_REMOTE_HOLD
Definition: pjsua-lib/pjsua.h:5005
@ PJSUA_CALL_MEDIA_ACTIVE
Definition: pjsua-lib/pjsua.h:4995
@ PJSUA_CALL_MEDIA_NONE
Definition: pjsua-lib/pjsua.h:4990
pj_status_t pjsua_player_get_port(pjsua_player_id id, pjmedia_port **p_port)
pj_status_t pjsua_set_null_snd_dev(void)
pjsua_conf_port_id pjsua_recorder_get_conf_port(pjsua_recorder_id id)
pj_status_t pjsua_conf_connect(pjsua_conf_port_id source, pjsua_conf_port_id sink)
pj_status_t pjsua_conf_remove_port(pjsua_conf_port_id port_id)
pjsua_conf_port_id pjsua_player_get_conf_port(pjsua_player_id id)
pj_status_t pjsua_player_set_pos(pjsua_player_id id, pj_uint32_t samples)
pj_status_t pjsua_get_snd_dev(int *capture_dev, int *playback_dev)
pj_status_t pjsua_recorder_create(const pj_str_t *filename, unsigned enc_type, void *enc_param, pj_ssize_t max_size, unsigned options, pjsua_recorder_id *p_id)
pj_status_t pjsua_conf_add_port(pj_pool_t *pool, pjmedia_port *port, pjsua_conf_port_id *p_id)
pj_status_t pjsua_player_destroy(pjsua_player_id id)
pj_status_t pjsua_player_create(const pj_str_t *filename, unsigned options, pjsua_player_id *p_id)
pj_status_t pjsua_set_snd_dev(int capture_dev, int playback_dev)
pj_status_t pjsua_recorder_destroy(pjsua_recorder_id id)
pj_status_t pjsua_conf_disconnect(pjsua_conf_port_id source, pjsua_conf_port_id sink)
pjmedia_port * pjsua_set_no_snd_dev(void)
pj_status_t pjsua_codec_set_priority(const pj_str_t *codec_id, pj_uint8_t priority)
pj_status_t pjsua_transport_create(pjsip_transport_type_e type, const pjsua_transport_config *cfg, pjsua_transport_id *p_id)
int pjsua_transport_id
Definition: pjsua-lib/pjsua.h:3011
pj_status_t pjsua_transport_get_info(pjsua_transport_id id, pjsua_transport_info *info)
pj_status_t pjsua_vid_win_set_size(pjsua_vid_win_id wid, const pjmedia_rect_size *size)
pj_status_t pjsua_vid_win_get_info(pjsua_vid_win_id wid, pjsua_vid_win_info *wi)
pj_status_t pjsua_vid_codec_set_priority(const pj_str_t *codec_id, pj_uint8_t priority)
unsigned char pj_uint8_t
int pj_bool_t
unsigned short pj_uint16_t
int pj_status_t
struct pj_thread_t pj_thread_t
#define PJ_ARRAY_SIZE(a)
struct pj_timer_heap_t pj_timer_heap_t
PJ_SUCCESS
PJ_TRUE
PJ_FALSE
void pj_list_push_back(pj_list_type *list, pj_list_type *node)
#define PJ_LOG(level, arg)
void pj_pool_safe_release(pj_pool_t **ppool)
void pj_pool_release(pj_pool_t *pool)
void * pj_memcpy(void *dst, const void *src, pj_size_t size)
pj_str_t pj_str(char *str)
#define PJ_CHECK_TRUNC_STR(ret, str, len)
pj_str_t * pj_strdup2_with_null(pj_pool_t *pool, pj_str_t *dst, const char *src)
void pj_bzero(void *dst, pj_size_t size)
pj_uint16_t pj_sockaddr_get_port(const pj_sockaddr_t *addr)
pj_uint16_t pj_ntohs(pj_uint16_t netshort)
char * pj_addr_str_print(const pj_str_t *host_str, int port, char *buf, int size, unsigned flag)
const char * pj_ssl_cipher_name(pj_ssl_cipher cipher)
pj_ssize_t pj_ssl_cert_info_dump(const pj_ssl_cert_info *ci, const char *indent, char *buf, pj_size_t buf_size)
pj_status_t pj_ssl_cert_get_verify_status_strings(pj_uint32_t verify_status, const char *error_strings[], unsigned *count)
int pj_thread_get_prio_min(pj_thread_t *thread)
pj_status_t pj_thread_destroy(pj_thread_t *thread)
pj_status_t pj_thread_join(pj_thread_t *thread)
pj_thread_t * pj_thread_this(void)
pj_status_t pj_thread_set_prio(pj_thread_t *thread, int prio)
pj_status_t pj_thread_create(pj_pool_t *pool, const char *thread_name, pj_thread_proc *proc, void *arg, pj_size_t stack_size, unsigned flags, pj_thread_t **thread)
pj_status_t pj_thread_sleep(unsigned msec)
pj_timer_entry * pj_timer_entry_init(pj_timer_entry *entry, int id, void *user_data, pj_timer_heap_callback *cb)
pj_status_t pjmedia_avi_dev_free(pjmedia_vid_dev_index id)
pj_status_t pjmedia_avi_dev_alloc(pjmedia_vid_dev_factory *f, pjmedia_avi_dev_param *param, pjmedia_vid_dev_index *p_id)
void pjmedia_avi_dev_param_default(pjmedia_avi_dev_param *p)
pj_status_t pjmedia_avi_dev_create_factory(pj_pool_factory *pf, unsigned max_dev, pjmedia_vid_dev_factory **p_ret)
#define pj_assert(expr)
#define PJ_UNUSED_ARG(arg)
#define PJ_PERROR(level, arg)
pj_int32_t pjmedia_vid_dev_index
PJMEDIA_VID_INVALID_DEV
pj_uint16_t sin_port
pj_ssize_t slen
char * ptr
int id
pjmedia_avi_streams * avi_streams
pjmedia_event_type type
pj_uint32_t id
pjmedia_format fmt
pjmedia_port_info info
Definition: sip_msg.h:1436
pj_uint32_t expires
Definition: sip_msg.h:1443
Definition: sip_msg.h:1482
pjsip_media_type media
Definition: sip_msg.h:1484
Definition: sip_event.h:81
pjsip_rx_data * rdata
Definition: sip_event.h:107
pjsip_tx_data * tdata
Definition: sip_event.h:108
pjsip_event_id_e type
Definition: sip_event.h:87
struct pjsip_event::@11::@13 tsx_state
union pjsip_event::@11 body
Definition: sip_msg.h:1142
pj_uint32_t ivalue
Definition: sip_msg.h:1146
Definition: sip_msg.h:1070
pj_str_t name
Definition: sip_msg.h:1072
pj_str_t hvalue
Definition: sip_msg.h:1074
Definition: sip_msg.h:324
pjsip_hdr_e type
Definition: sip_msg.h:325
int port
Definition: sip_types.h:226
pj_str_t host
Definition: sip_types.h:225
pj_str_t subtype
Definition: sip_msg.h:593
pj_str_t type
Definition: sip_msg.h:592
Definition: sip_module.h:54
void * data
Definition: sip_msg.h:709
unsigned len
Definition: sip_msg.h:719
Definition: sip_msg.h:857
struct pjsip_request_line req
Definition: sip_msg.h:868
pjsip_msg_body * body
Definition: sip_msg.h:880
union pjsip_msg::@19 line
struct pjsip_status_line status
Definition: sip_msg.h:871
pjsip_hdr hdr
Definition: sip_msg.h:875
pjsip_method method
Definition: sip_msg.h:434
Definition: sip_transport.h:295
struct pjsip_rx_data::@26 msg_info
pjsip_msg * msg
Definition: sip_transport.h:364
pjsip_ctype_hdr * ctype
Definition: sip_transport.h:396
int code
Definition: sip_msg.h:444
pj_str_t reason
Definition: sip_msg.h:445
pj_qos_type qos_type
Definition: sip_transport_tls.h:335
pj_qos_params qos_params
Definition: sip_transport_tls.h:344
Definition: sip_transport_tls.h:400
pj_ssl_sock_info * ssl_sock_info
Definition: sip_transport_tls.h:404
Definition: sip_transport.h:1465
pj_status_t status
Definition: sip_transport.h:1469
void * ext_info
Definition: sip_transport.h:1474
Definition: sip_transport.h:806
char * type_name
Definition: sip_transport.h:821
pjsip_host_port remote_name
Definition: sip_transport.h:828
Definition: sip_transport.h:522
pj_pool_t * pool
Definition: sip_transport.h:527
pjsip_msg * msg
Definition: sip_transport.h:555
Definition: sip_uri.h:223
Definition: pjsua-lib/pjsua.h:3709
pjsua_transport_config rtp_cfg
Definition: pjsua-lib/pjsua.h:4155
pjsua_ipv6_use ipv6_media_use
Definition: pjsua-lib/pjsua.h:4167
Definition: pjsua-lib/pjsua.h:4501
pj_str_t acc_uri
Definition: pjsua-lib/pjsua.h:4515
Definition: pjsua-lib/pjsua.h:6294
unsigned sub_term_code
Definition: pjsua-lib/pjsua.h:6349
const char * sub_state_name
Definition: pjsua-lib/pjsua.h:6340
pj_str_t status_text
Definition: pjsua-lib/pjsua.h:6319
pj_str_t sub_term_reason
Definition: pjsua-lib/pjsua.h:6355
pj_str_t uri
Definition: pjsua-lib/pjsua.h:6303
Definition: pjsua-lib/pjsua.h:5097
unsigned rem_vid_cnt
Definition: pjsua-lib/pjsua.h:5187
pjsip_inv_state state
Definition: pjsua-lib/pjsua.h:5126
pjsua_call_media_info media[PJMEDIA_MAX_SDP_MEDIA]
Definition: pjsua-lib/pjsua.h:5161
pjsip_status_code last_status
Definition: pjsua-lib/pjsua.h:5132
pjsua_call_id id
Definition: pjsua-lib/pjsua.h:5099
pj_str_t last_status_text
Definition: pjsua-lib/pjsua.h:5135
unsigned rem_aud_cnt
Definition: pjsua-lib/pjsua.h:5184
pjsua_call_media_status media_status
Definition: pjsua-lib/pjsua.h:5145
pjsip_role_e role
Definition: pjsua-lib/pjsua.h:5102
pj_str_t state_text
Definition: pjsua-lib/pjsua.h:5129
unsigned media_cnt
Definition: pjsua-lib/pjsua.h:5158
pj_bool_t rem_offerer
Definition: pjsua-lib/pjsua.h:5181
pj_str_t local_info
Definition: pjsua-lib/pjsua.h:5108
pj_str_t remote_info
Definition: pjsua-lib/pjsua.h:5114
struct pjsua_call_media_info::@37::@38 aud
union pjsua_call_media_info::@37 stream
pjsua_vid_win_id win_in
Definition: pjsua-lib/pjsua.h:5067
pjsua_conf_port_id conf_slot
Definition: pjsua-lib/pjsua.h:5058
pjsua_call_media_status status
Definition: pjsua-lib/pjsua.h:5051
pjmedia_dir dir
Definition: pjsua-lib/pjsua.h:5048
struct pjsua_call_media_info::@37::@39 vid
pjmedia_type type
Definition: pjsua-lib/pjsua.h:5045
Definition: pjsua-lib/pjsua.h:1024
unsigned vid_cnt
Definition: pjsua-lib/pjsua.h:1055
unsigned aud_cnt
Definition: pjsua-lib/pjsua.h:1047
Definition: pjsua-lib/pjsua.h:951
unsigned duration
Definition: pjsua-lib/pjsua.h:966
pjsua_dtmf_method method
Definition: pjsua-lib/pjsua.h:955
unsigned digit
Definition: pjsua-lib/pjsua.h:960
Definition: pjsua-lib/pjsua.h:2396
pjsip_hdr hdr_list
Definition: pjsua-lib/pjsua.h:2411
Definition: pjsua-lib/pjsua.h:545
pjsip_rx_data * rdata
Definition: pjsua-lib/pjsua.h:548
Definition: pjsua_internal.h:251
Definition: pjsua-lib/pjsua.h:3021
pj_qos_type qos_type
Definition: pjsua-lib/pjsua.h:3092
pj_qos_params qos_params
Definition: pjsua-lib/pjsua.h:3101
unsigned port
Definition: pjsua-lib/pjsua.h:3028
pjsip_tls_setting tls_setting
Definition: pjsua-lib/pjsua.h:3083
Definition: pjsua-lib/pjsua.h:3139
pj_sockaddr local_addr
Definition: pjsua-lib/pjsua.h:3173
pj_str_t info
Definition: pjsua-lib/pjsua.h:3158
Definition: pjsua-lib/pjsua.h:8366
pjmedia_rect_size size
Definition: pjsua-lib/pjsua.h:8403
Definition: pjsua-lib/pjsua.h:876
int code
Definition: pjsua-lib/pjsua.h:897
struct pjsua_ip_change_op_info::@36 acc_reinvite_calls
struct pjsua_ip_change_op_info::@34 acc_update_contact
struct pjsua_ip_change_op_info::@35 acc_hangup_calls
struct pjsua_ip_change_op_info::@32 lis_restart
struct pjsua_ip_change_op_info::@33 acc_shutdown_tp

 


PJSIP Open Source, high performance, small footprint, and very very portable SIP stack
Copyright (C) 2006-2008 Teluu Inc.