summaryrefslogtreecommitdiff
path: root/pjsip-apps/src/pjsua/pjsua_app_common.c
blob: 0d57da14bd20019abf5aaaa77b8e49f03181c660 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/* $Id$ */
/* 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

#include "pjsua_app_common.h"

#define THIS_FILE	"pjsua_app_common.c"

#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
#   define SOME_BUF_SIZE	(1024 * 10)
#else
#   define SOME_BUF_SIZE	(1024 * 3)
#endif

#ifdef USE_GUI
void displayWindow(pjsua_vid_win_id wid);
#endif

static char some_buf[SOME_BUF_SIZE];

/** Variable definition **/
int		    stdout_refresh = -1;
pj_bool_t	    stdout_refresh_quit = PJ_FALSE;
pjsua_call_id	    current_call = PJSUA_INVALID_ID;
pjsua_app_config    app_config;
pjsua_call_setting  call_opt;
pjsua_msg_data	    msg_data;

int my_atoi(const char *cs)
{
    pj_str_t s;

    pj_cstr(&s, cs);
    if (cs[0] == '-') {
	s.ptr++, s.slen--;
	return 0 - (int)pj_strtoul(&s);
    } else if (cs[0] == '+') {
	s.ptr++, s.slen--;
	return pj_strtoul(&s);
    } else {
	return pj_strtoul(&s);
    }
}

/*
 * Find next call when current call is disconnected or when user
 * press ']'
 */
pj_bool_t find_next_call()
{
    int i, max;

    max = pjsua_call_get_max_count();
    for (i=current_call+1; i<max; ++i) {
	if (pjsua_call_is_active(i)) {
	    current_call = i;
	    return PJ_TRUE;
	}
    }

    for (i=0; i<current_call; ++i) {
	if (pjsua_call_is_active(i)) {
	    current_call = i;
	    return PJ_TRUE;
	}
    }

    current_call = PJSUA_INVALID_ID;
    return PJ_FALSE;
}

pj_bool_t find_prev_call()
{
    int i, max;

    max = pjsua_call_get_max_count();
    for (i=current_call-1; i>=0; --i) {
	if (pjsua_call_is_active(i)) {
	    current_call = i;
	    return PJ_TRUE;
	}
    }

    for (i=max-1; i>current_call; --i) {
	if (pjsua_call_is_active(i)) {
	    current_call = i;
	    return PJ_TRUE;
	}
    }

    current_call = PJSUA_INVALID_ID;
    return PJ_FALSE;
}

/*
 * Send arbitrary request to remote host
 */
void send_request(char *cstr_method, const pj_str_t *dst_uri)
{
    pj_str_t str_method;
    pjsip_method method;
    pjsip_tx_data *tdata;
    pjsip_endpoint *endpt;
    pj_status_t status;

    endpt = pjsua_get_pjsip_endpt();

    str_method = pj_str(cstr_method);
    pjsip_method_init_np(&method, &str_method);

    status = pjsua_acc_create_request(current_acc, &method, dst_uri, &tdata);

    status = pjsip_endpt_send_request(endpt, tdata, -1, NULL, NULL);
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "Unable to send request", status);
	return;
    }
}

/*
 * Print log of call states. Since call states may be too long for logger,
 * printing it is a bit tricky, it should be printed part by part as long 
 * as the logger can accept.
 */
void log_call_dump(int call_id) 
{
    unsigned call_dump_len;
    unsigned part_len;
    unsigned part_idx;
    unsigned log_decor;

    pjsua_call_dump(call_id, PJ_TRUE, some_buf, sizeof(some_buf), "  ");
    call_dump_len = (unsigned)strlen(some_buf);

    log_decor = pj_log_get_decor();
    pj_log_set_decor(log_decor & ~(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_CR));
    PJ_LOG(3,(THIS_FILE, "\n"));
    pj_log_set_decor(0);

    part_idx = 0;
    part_len = PJ_LOG_MAX_SIZE-80;
    while (part_idx < call_dump_len) {
	char p_orig, *p;

	p = &some_buf[part_idx];
	if (part_idx + part_len > call_dump_len)
	    part_len = call_dump_len - part_idx;
	p_orig = p[part_len];
	p[part_len] = '\0';
	PJ_LOG(3,(THIS_FILE, "%s", p));
	p[part_len] = p_orig;
	part_idx += part_len;
    }
    pj_log_set_decor(log_decor);
}

#ifdef PJSUA_HAS_VIDEO
void app_config_init_video(pjsua_acc_config *acc_cfg)
{
    acc_cfg->vid_in_auto_show = app_config.vid.in_auto_show;
    acc_cfg->vid_out_auto_transmit = app_config.vid.out_auto_transmit;
    /* Note that normally GUI application will prefer a borderless
     * window.
     */
    acc_cfg->vid_wnd_flags = PJMEDIA_VID_DEV_WND_BORDER |
                             PJMEDIA_VID_DEV_WND_RESIZABLE;
    acc_cfg->vid_cap_dev = app_config.vid.vcapture_dev;
    acc_cfg->vid_rend_dev = app_config.vid.vrender_dev;

    if (app_config.avi_auto_play &&
	app_config.avi_def_idx != PJSUA_INVALID_ID &&
	app_config.avi[app_config.avi_def_idx].dev_id != PJMEDIA_VID_INVALID_DEV)
    {
	acc_cfg->vid_cap_dev = app_config.avi[app_config.avi_def_idx].dev_id;
    }
}
#else
void app_config_init_video(pjsua_acc_config *acc_cfg)
{
    PJ_UNUSED_ARG(acc_cfg);
}
#endif

#ifdef HAVE_MULTIPART_TEST
  /*
   * Enable multipart in msg_data and add a dummy body into the
   * multipart bodies.
   */
  void add_multipart(pjsua_msg_data *msg_data)
  {
      static pjsip_multipart_part *alt_part;

      if (!alt_part) {
	  pj_str_t type, subtype, content;

	  alt_part = pjsip_multipart_create_part(app_config.pool);

	  type = pj_str("text");
	  subtype = pj_str("plain");
	  content = pj_str("Sample text body of a multipart bodies");
	  alt_part->body = pjsip_msg_body_create(app_config.pool, &type,
						 &subtype, &content);
      }

      msg_data->multipart_ctype.type = pj_str("multipart");
      msg_data->multipart_ctype.subtype = pj_str("mixed");
      pj_list_push_back(&msg_data->multipart_parts, alt_part);
  }
#endif

/* arrange windows. arg:
 *   -1:    arrange all windows
 *   != -1: arrange only this window id
 */
void arrange_window(pjsua_vid_win_id wid)
{
#if PJSUA_HAS_VIDEO
    pjmedia_coord pos;
    int i, last;

    pos.x = 0;
    pos.y = 10;
    last = (wid == PJSUA_INVALID_ID) ? PJSUA_MAX_VID_WINS : wid;

    for (i=0; i<last; ++i) {
	pjsua_vid_win_info wi;
	pj_status_t status;

	status = pjsua_vid_win_get_info(i, &wi);
	if (status != PJ_SUCCESS)
	    continue;

	if (wid == PJSUA_INVALID_ID)
	    pjsua_vid_win_set_pos(i, &pos);

	if (wi.show)
	    pos.y += wi.size.h;
    }

    if (wid != PJSUA_INVALID_ID)
	pjsua_vid_win_set_pos(wid, &pos);

#ifdef USE_GUI
    displayWindow(wid);
#endif

#else
    PJ_UNUSED_ARG(wid);
#endif
}


#if PJSUA_HAS_VIDEO
void vid_print_dev(int id, const pjmedia_vid_dev_info *vdi, const char *title)
{
    char capnames[120];
    char formats[200];
    const char *dirname;
    unsigned i;
    int st_len;

    if (vdi->dir == PJMEDIA_DIR_CAPTURE_RENDER) {
	dirname = "capture, render";
    } else if (vdi->dir == PJMEDIA_DIR_CAPTURE) {
	dirname = "capture";
    } else {
	dirname = "render";
    }


    capnames[0] = '\0';
    st_len = 0;
    for (i=0; i<sizeof(int)*8 && (1 << i) < PJMEDIA_VID_DEV_CAP_MAX; ++i) {
	if (vdi->caps & (1 << i)) {
	    const char *capname = pjmedia_vid_dev_cap_name(1 << i, NULL);
	    if (capname) {
		int tmp_len = strlen(capname);
		if ((int)sizeof(capnames) - st_len <= tmp_len)
		    break;

		st_len += (tmp_len + 2);
		if (*capnames)
		    strcat(capnames, ", ");
		strcat(capnames, capname);
	    }
	}
    }

    formats[0] = '\0';
    st_len = 0;
    for (i=0; i<vdi->fmt_cnt; ++i) {
	const pjmedia_video_format_info *vfi =
		pjmedia_get_video_format_info(NULL, vdi->fmt[i].id);
	if (vfi) {
	    int tmp_len = strlen(vfi->name);
	    if ((int)sizeof(formats) - st_len <= tmp_len) {
		st_len = -1;
		break;
	    }

	    st_len += (tmp_len + 2);
	    if (*formats)
		strcat(formats, ", ");
	    strcat(formats, vfi->name);
	}
    }

    PJ_LOG(3,(THIS_FILE, "%3d %s [%s][%s] %s", id, vdi->name, vdi->driver,
	      dirname, title));
    PJ_LOG(3,(THIS_FILE, "    Supported capabilities: %s", capnames));
    PJ_LOG(3,(THIS_FILE, "    Supported formats: %s%s", formats,
			      (st_len<0? " ..." : "")));
}

void vid_list_devs()
{
    unsigned i, count;
    pjmedia_vid_dev_info vdi;
    pj_status_t status;

    PJ_LOG(3,(THIS_FILE, "Video device list:"));
    count = pjsua_vid_dev_count();
    if (count == 0) {
	PJ_LOG(3,(THIS_FILE, " - no device detected -"));
	return;
    } else {
	PJ_LOG(3,(THIS_FILE, "%d device(s) detected:", count));
    }

    status = pjsua_vid_dev_get_info(PJMEDIA_VID_DEFAULT_RENDER_DEV, &vdi);
    if (status == PJ_SUCCESS)
	vid_print_dev(PJMEDIA_VID_DEFAULT_RENDER_DEV, &vdi,
	              "(default renderer device)");

    status = pjsua_vid_dev_get_info(PJMEDIA_VID_DEFAULT_CAPTURE_DEV, &vdi);
    if (status == PJ_SUCCESS)
	vid_print_dev(PJMEDIA_VID_DEFAULT_CAPTURE_DEV, &vdi,
	              "(default capture device)");

    for (i=0; i<count; ++i) {
	status = pjsua_vid_dev_get_info(i, &vdi);
	if (status == PJ_SUCCESS)
	    vid_print_dev(i, &vdi, "");
    }
}

void app_config_show_video(int acc_id, const pjsua_acc_config *acc_cfg)
{
    PJ_LOG(3,(THIS_FILE,
	      "Account %d:\n"
	      "  RX auto show:     %d\n"
	      "  TX auto transmit: %d\n"
	      "  Capture dev:      %d\n"
	      "  Render dev:       %d",
	      acc_id,
	      acc_cfg->vid_in_auto_show,
	      acc_cfg->vid_out_auto_transmit,
	      acc_cfg->vid_cap_dev,
	      acc_cfg->vid_rend_dev));
}


#endif