1 /* $Id$ */
2 /*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "pjsua_app_common.h"
22
23 #define THIS_FILE "pjsua_app_common.c"
24
25 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
26 # define SOME_BUF_SIZE (1024 * 10)
27 #else
28 # define SOME_BUF_SIZE (1024 * 3)
29 #endif
30
31 #ifdef USE_GUI
32 void displayWindow(pjsua_vid_win_id wid);
33 #endif
34
35 static char some_buf[SOME_BUF_SIZE];
36
37 /** Variable definition **/
38 int stdout_refresh = -1;
39 pj_bool_t stdout_refresh_quit = PJ_FALSE;
40 pjsua_call_id current_call = PJSUA_INVALID_ID;
41 pjsua_app_config app_config;
42 pjsua_call_setting call_opt;
43 pjsua_msg_data msg_data;
44
my_atoi(const char * cs)45 int my_atoi(const char *cs)
46 {
47 pj_str_t s;
48 pj_cstr(&s, cs);
49 return my_atoi2(&s);
50 }
51
my_atoi2(const pj_str_t * str)52 int my_atoi2(const pj_str_t *str)
53 {
54 const char *cs = str->ptr;
55 pj_str_t s = *str;
56
57 if (cs[0] == '-') {
58 s.ptr++; s.slen--;
59 return 0 - (int)pj_strtoul(&s);
60 } else if (cs[0] == '+') {
61 s.ptr++; s.slen--;
62 return (int)pj_strtoul(&s);
63 } else {
64 return (int)pj_strtoul(&s);
65 }
66 }
67
68 /*
69 * Find next call when current call is disconnected or when user
70 * press ']'
71 */
find_next_call(void)72 pj_bool_t find_next_call(void)
73 {
74 int i, max;
75
76 max = pjsua_call_get_max_count();
77 for (i=current_call+1; i<max; ++i) {
78 if (pjsua_call_is_active(i)) {
79 current_call = i;
80 return PJ_TRUE;
81 }
82 }
83
84 for (i=0; i<current_call; ++i) {
85 if (pjsua_call_is_active(i)) {
86 current_call = i;
87 return PJ_TRUE;
88 }
89 }
90
91 current_call = PJSUA_INVALID_ID;
92 return PJ_FALSE;
93 }
94
find_prev_call(void)95 pj_bool_t find_prev_call(void)
96 {
97 int i, max;
98
99 max = pjsua_call_get_max_count();
100 for (i=current_call-1; i>=0; --i) {
101 if (pjsua_call_is_active(i)) {
102 current_call = i;
103 return PJ_TRUE;
104 }
105 }
106
107 for (i=max-1; i>current_call; --i) {
108 if (pjsua_call_is_active(i)) {
109 current_call = i;
110 return PJ_TRUE;
111 }
112 }
113
114 current_call = PJSUA_INVALID_ID;
115 return PJ_FALSE;
116 }
117
118 /*
119 * Send arbitrary request to remote host
120 */
send_request(char * cstr_method,const pj_str_t * dst_uri)121 void send_request(char *cstr_method, const pj_str_t *dst_uri)
122 {
123 pj_str_t str_method;
124 pjsip_method method;
125 pjsip_tx_data *tdata;
126 pjsip_endpoint *endpt;
127 pj_status_t status;
128
129 endpt = pjsua_get_pjsip_endpt();
130
131 str_method = pj_str(cstr_method);
132 pjsip_method_init_np(&method, &str_method);
133
134 status = pjsua_acc_create_request(current_acc, &method, dst_uri, &tdata);
135
136 status = pjsip_endpt_send_request(endpt, tdata, -1, NULL, NULL);
137 if (status != PJ_SUCCESS) {
138 pjsua_perror(THIS_FILE, "Unable to send request", status);
139 return;
140 }
141 }
142
143 /*
144 * Print log of call states. Since call states may be too long for logger,
145 * printing it is a bit tricky, it should be printed part by part as long
146 * as the logger can accept.
147 */
log_call_dump(int call_id)148 void log_call_dump(int call_id)
149 {
150 unsigned call_dump_len;
151 unsigned part_len;
152 unsigned part_idx;
153 unsigned log_decor;
154
155 pjsua_call_dump(call_id, PJ_TRUE, some_buf, sizeof(some_buf), " ");
156 call_dump_len = (unsigned)strlen(some_buf);
157
158 log_decor = pj_log_get_decor();
159 pj_log_set_decor(log_decor & ~(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_CR));
160 PJ_LOG(3,(THIS_FILE, "\n"));
161 pj_log_set_decor(0);
162
163 part_idx = 0;
164 part_len = PJ_LOG_MAX_SIZE-80;
165 while (part_idx < call_dump_len) {
166 char p_orig, *p;
167
168 p = &some_buf[part_idx];
169 if (part_idx + part_len > call_dump_len)
170 part_len = call_dump_len - part_idx;
171 p_orig = p[part_len];
172 p[part_len] = '\0';
173 PJ_LOG(3,(THIS_FILE, "%s", p));
174 p[part_len] = p_orig;
175 part_idx += part_len;
176 }
177 pj_log_set_decor(log_decor);
178 }
179
180 #ifdef PJSUA_HAS_VIDEO
app_config_init_video(pjsua_acc_config * acc_cfg)181 void app_config_init_video(pjsua_acc_config *acc_cfg)
182 {
183 acc_cfg->vid_in_auto_show = app_config.vid.in_auto_show;
184 acc_cfg->vid_out_auto_transmit = app_config.vid.out_auto_transmit;
185 /* Note that normally GUI application will prefer a borderless
186 * window.
187 */
188 acc_cfg->vid_wnd_flags = PJMEDIA_VID_DEV_WND_BORDER |
189 PJMEDIA_VID_DEV_WND_RESIZABLE;
190 acc_cfg->vid_cap_dev = app_config.vid.vcapture_dev;
191 acc_cfg->vid_rend_dev = app_config.vid.vrender_dev;
192
193 if (app_config.avi_auto_play &&
194 app_config.avi_def_idx != PJSUA_INVALID_ID &&
195 app_config.avi[app_config.avi_def_idx].dev_id != PJMEDIA_VID_INVALID_DEV)
196 {
197 acc_cfg->vid_cap_dev = app_config.avi[app_config.avi_def_idx].dev_id;
198 }
199 }
200 #else
app_config_init_video(pjsua_acc_config * acc_cfg)201 void app_config_init_video(pjsua_acc_config *acc_cfg)
202 {
203 PJ_UNUSED_ARG(acc_cfg);
204 }
205 #endif
206
207 #ifdef HAVE_MULTIPART_TEST
208 /*
209 * Enable multipart in msg_data and add a dummy body into the
210 * multipart bodies.
211 */
add_multipart(pjsua_msg_data * msg_data)212 void add_multipart(pjsua_msg_data *msg_data)
213 {
214 static pjsip_multipart_part *alt_part;
215
216 if (!alt_part) {
217 pj_str_t type, subtype, content;
218
219 alt_part = pjsip_multipart_create_part(app_config.pool);
220
221 type = pj_str("text");
222 subtype = pj_str("plain");
223 content = pj_str("Sample text body of a multipart bodies");
224 alt_part->body = pjsip_msg_body_create(app_config.pool, &type,
225 &subtype, &content);
226 }
227
228 msg_data->multipart_ctype.type = pj_str("multipart");
229 msg_data->multipart_ctype.subtype = pj_str("mixed");
230 pj_list_push_back(&msg_data->multipart_parts, alt_part);
231 }
232 #endif
233
234 /* arrange windows. arg:
235 * -1: arrange all windows
236 * != -1: arrange only this window id
237 */
arrange_window(pjsua_vid_win_id wid)238 void arrange_window(pjsua_vid_win_id wid)
239 {
240 #if PJSUA_HAS_VIDEO
241 pjmedia_coord pos;
242 int i, last;
243
244 pos.x = 0;
245 pos.y = 10;
246 last = (wid == PJSUA_INVALID_ID) ? PJSUA_MAX_VID_WINS : wid;
247
248 for (i=0; i<last; ++i) {
249 pjsua_vid_win_info wi;
250 pj_status_t status;
251
252 status = pjsua_vid_win_get_info(i, &wi);
253 if (status != PJ_SUCCESS)
254 continue;
255
256 if (wid == PJSUA_INVALID_ID)
257 pjsua_vid_win_set_pos(i, &pos);
258
259 if (wi.show)
260 pos.y += wi.size.h;
261 }
262
263 if (wid != PJSUA_INVALID_ID)
264 pjsua_vid_win_set_pos(wid, &pos);
265
266 #ifdef USE_GUI
267 displayWindow(wid);
268 #endif
269
270 #else
271 PJ_UNUSED_ARG(wid);
272 #endif
273 }
274
275
276 #if PJSUA_HAS_VIDEO
vid_print_dev(int id,const pjmedia_vid_dev_info * vdi,const char * title)277 void vid_print_dev(int id, const pjmedia_vid_dev_info *vdi, const char *title)
278 {
279 char capnames[120];
280 char formats[200];
281 const char *dirname;
282 unsigned i;
283 int st_len;
284
285 if (vdi->dir == PJMEDIA_DIR_CAPTURE_RENDER) {
286 dirname = "capture, render";
287 } else if (vdi->dir == PJMEDIA_DIR_CAPTURE) {
288 dirname = "capture";
289 } else {
290 dirname = "render";
291 }
292
293
294 capnames[0] = '\0';
295 st_len = 0;
296 for (i=0; i<sizeof(int)*8 && (1 << i) < PJMEDIA_VID_DEV_CAP_MAX; ++i) {
297 if (vdi->caps & (1 << i)) {
298 const char *capname = pjmedia_vid_dev_cap_name(1 << i, NULL);
299 if (capname) {
300 int tmp_len = (int)strlen(capname);
301 if ((int)sizeof(capnames) - st_len <= tmp_len)
302 break;
303
304 st_len += (tmp_len + 2);
305 if (*capnames)
306 strcat(capnames, ", ");
307 strcat(capnames, capname);
308 }
309 }
310 }
311
312 formats[0] = '\0';
313 st_len = 0;
314 for (i=0; i<vdi->fmt_cnt; ++i) {
315 const pjmedia_video_format_info *vfi =
316 pjmedia_get_video_format_info(NULL, vdi->fmt[i].id);
317 if (vfi) {
318 int tmp_len = (int)strlen(vfi->name);
319 if ((int)sizeof(formats) - st_len <= tmp_len) {
320 st_len = -1;
321 break;
322 }
323
324 st_len += (tmp_len + 2);
325 if (*formats)
326 strcat(formats, ", ");
327 strcat(formats, vfi->name);
328 }
329 }
330
331 PJ_LOG(3,(THIS_FILE, "%3d %s [%s][%s] %s", id, vdi->name, vdi->driver,
332 dirname, title));
333 PJ_LOG(3,(THIS_FILE, " Supported capabilities: %s", capnames));
334 PJ_LOG(3,(THIS_FILE, " Supported formats: %s%s", formats,
335 (st_len<0? " ..." : "")));
336 }
337
vid_list_devs(void)338 void vid_list_devs(void)
339 {
340 unsigned i, count;
341 pjmedia_vid_dev_info vdi;
342 pj_status_t status;
343
344 PJ_LOG(3,(THIS_FILE, "Video device list:"));
345 count = pjsua_vid_dev_count();
346 if (count == 0) {
347 PJ_LOG(3,(THIS_FILE, " - no device detected -"));
348 return;
349 } else {
350 PJ_LOG(3,(THIS_FILE, "%d device(s) detected:", count));
351 }
352
353 status = pjsua_vid_dev_get_info(PJMEDIA_VID_DEFAULT_RENDER_DEV, &vdi);
354 if (status == PJ_SUCCESS)
355 vid_print_dev(PJMEDIA_VID_DEFAULT_RENDER_DEV, &vdi,
356 "(default renderer device)");
357
358 status = pjsua_vid_dev_get_info(PJMEDIA_VID_DEFAULT_CAPTURE_DEV, &vdi);
359 if (status == PJ_SUCCESS)
360 vid_print_dev(PJMEDIA_VID_DEFAULT_CAPTURE_DEV, &vdi,
361 "(default capture device)");
362
363 for (i=0; i<count; ++i) {
364 status = pjsua_vid_dev_get_info(i, &vdi);
365 if (status == PJ_SUCCESS)
366 vid_print_dev(i, &vdi, "");
367 }
368 }
369
app_config_show_video(int acc_id,const pjsua_acc_config * acc_cfg)370 void app_config_show_video(int acc_id, const pjsua_acc_config *acc_cfg)
371 {
372 PJ_LOG(3,(THIS_FILE,
373 "Account %d:\n"
374 " RX auto show: %d\n"
375 " TX auto transmit: %d\n"
376 " Capture dev: %d\n"
377 " Render dev: %d",
378 acc_id,
379 acc_cfg->vid_in_auto_show,
380 acc_cfg->vid_out_auto_transmit,
381 acc_cfg->vid_cap_dev,
382 acc_cfg->vid_rend_dev));
383 }
384
385
386 #endif
387