blob: 62b413a0ab093c1a295a0a1ffbbe4174e9087d72 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $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#include <pjsua-lib/pjsua.h>
21#include <pjsua-lib/pjsua_internal.h>
22
23
24#define THIS_FILE "pjsua_media.c"
25
26#define DEFAULT_RTP_PORT 4000
27
28#ifndef PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT
29# define PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT 0
30#endif
31
32static void pjsua_media_config_dup(pj_pool_t *pool,
33 pjsua_media_config *dst,
34 const pjsua_media_config *src)
35{
36 pj_memcpy(dst, src, sizeof(*src));
37 pj_strdup(pool, &dst->turn_server, &src->turn_server);
38 pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred, &src->turn_auth_cred);
39}
40
41
42/**
43 * Init media subsystems.
44 */
45pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg)
46{
47 pj_status_t status;
48
49 pj_log_push_indent();
50
51 /* Specify which audio device settings are save-able */
52 pjsua_var.aud_svmask = 0xFFFFFFFF;
53 /* These are not-settable */
54 pjsua_var.aud_svmask &= ~(PJMEDIA_AUD_DEV_CAP_EXT_FORMAT |
55 PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER |
56 PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER);
57 /* EC settings use different API */
58 pjsua_var.aud_svmask &= ~(PJMEDIA_AUD_DEV_CAP_EC |
59 PJMEDIA_AUD_DEV_CAP_EC_TAIL);
60
61 /* Copy configuration */
62 pjsua_media_config_dup(pjsua_var.pool, &pjsua_var.media_cfg, cfg);
63
64 /* Normalize configuration */
65 if (pjsua_var.media_cfg.snd_clock_rate == 0) {
66 pjsua_var.media_cfg.snd_clock_rate = pjsua_var.media_cfg.clock_rate;
67 }
68
69 if (pjsua_var.media_cfg.has_ioqueue &&
70 pjsua_var.media_cfg.thread_cnt == 0)
71 {
72 pjsua_var.media_cfg.thread_cnt = 1;
73 }
74
75 if (pjsua_var.media_cfg.max_media_ports < pjsua_var.ua_cfg.max_calls) {
76 pjsua_var.media_cfg.max_media_ports = pjsua_var.ua_cfg.max_calls + 2;
77 }
78
79 /* Create media endpoint. */
80 status = pjmedia_endpt_create(&pjsua_var.cp.factory,
81 pjsua_var.media_cfg.has_ioqueue? NULL :
82 pjsip_endpt_get_ioqueue(pjsua_var.endpt),
83 pjsua_var.media_cfg.thread_cnt,
84 &pjsua_var.med_endpt);
85 if (status != PJ_SUCCESS) {
86 pjsua_perror(THIS_FILE,
87 "Media stack initialization has returned error",
88 status);
89 goto on_error;
90 }
91
92 status = pjsua_aud_subsys_init();
93 if (status != PJ_SUCCESS)
94 goto on_error;
95
96#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
97 /* Initialize SRTP library (ticket #788). */
98 status = pjmedia_srtp_init_lib(pjsua_var.med_endpt);
99 if (status != PJ_SUCCESS) {
100 pjsua_perror(THIS_FILE, "Error initializing SRTP library",
101 status);
102 goto on_error;
103 }
104#endif
105
106 /* Video */
107#if PJMEDIA_HAS_VIDEO
108 status = pjsua_vid_subsys_init();
109 if (status != PJ_SUCCESS)
110 goto on_error;
111#endif
112
113 pj_log_pop_indent();
114 return PJ_SUCCESS;
115
116on_error:
117 pj_log_pop_indent();
118 return status;
119}
120
121/*
122 * Start pjsua media subsystem.
123 */
124pj_status_t pjsua_media_subsys_start(void)
125{
126 pj_status_t status;
127
128 pj_log_push_indent();
129
130#if DISABLED_FOR_TICKET_1185
131 /* Create media for calls, if none is specified */
132 if (pjsua_var.calls[0].media[0].tp == NULL) {
133 pjsua_transport_config transport_cfg;
134
135 /* Create default transport config */
136 pjsua_transport_config_default(&transport_cfg);
137 transport_cfg.port = DEFAULT_RTP_PORT;
138
139 status = pjsua_media_transports_create(&transport_cfg);
140 if (status != PJ_SUCCESS) {
141 pj_log_pop_indent();
142 return status;
143 }
144 }
145#endif
146
147 /* Audio */
148 status = pjsua_aud_subsys_start();
149 if (status != PJ_SUCCESS) {
150 pj_log_pop_indent();
151 return status;
152 }
153
154 /* Video */
155#if PJMEDIA_HAS_VIDEO
156 status = pjsua_vid_subsys_start();
157 if (status != PJ_SUCCESS) {
158 pjsua_aud_subsys_destroy();
159 pj_log_pop_indent();
160 return status;
161 }
162#endif
163
164 /* Perform NAT detection */
165 if (pjsua_var.ua_cfg.stun_srv_cnt) {
166 status = pjsua_detect_nat_type();
167 if (status != PJ_SUCCESS) {
168 PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed"));
169 }
170 }
171
172 pj_log_pop_indent();
173 return PJ_SUCCESS;
174}
175
176
177/*
178 * Destroy pjsua media subsystem.
179 */
180pj_status_t pjsua_media_subsys_destroy(unsigned flags)
181{
182 unsigned i;
183
184 PJ_LOG(4,(THIS_FILE, "Shutting down media.."));
185 pj_log_push_indent();
186
187 if (pjsua_var.med_endpt) {
188 /* Wait for media endpoint's worker threads to quit. */
189 pjmedia_endpt_stop_threads(pjsua_var.med_endpt);
190
191 pjsua_aud_subsys_destroy();
192 }
193
194 /* Close media transports */
195 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
196 /* TODO: check if we're not allowed to send to network in the
197 * "flags", and if so do not do TURN allocation...
198 */
199 PJ_UNUSED_ARG(flags);
200 pjsua_media_channel_deinit(i);
201 }
202
203 /* Destroy media endpoint. */
204 if (pjsua_var.med_endpt) {
205
206# if PJMEDIA_HAS_VIDEO
207 pjsua_vid_subsys_destroy();
208# endif
209
210 pjmedia_endpt_destroy(pjsua_var.med_endpt);
211 pjsua_var.med_endpt = NULL;
212
213 /* Deinitialize sound subsystem */
214 // Not necessary, as pjmedia_snd_deinit() should have been called
215 // in pjmedia_endpt_destroy().
216 //pjmedia_snd_deinit();
217 }
218
219 pj_log_pop_indent();
220
221 return PJ_SUCCESS;
222}
223
224/*
225 * Create RTP and RTCP socket pair, and possibly resolve their public
226 * address via STUN.
227 */
228static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
229 const pjsua_transport_config *cfg,
230 pjmedia_sock_info *skinfo)
231{
232 enum {
233 RTP_RETRY = 100
234 };
235 int i;
236 pj_bool_t use_ipv6;
237 int af;
238 pj_sockaddr bound_addr;
239 pj_sockaddr mapped_addr[2];
240 pj_status_t status = PJ_SUCCESS;
241 char addr_buf[PJ_INET6_ADDRSTRLEN+10];
242 pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
243 pj_sock_t sock[2];
244
245 use_ipv6 = (acc->cfg.ipv6_media_use != PJSUA_IPV6_DISABLED);
246 af = use_ipv6 ? pj_AF_INET6() : pj_AF_INET();
247
248 /* Make sure STUN server resolution has completed */
249 if (!use_ipv6 && pjsua_sip_acc_is_using_stun(call_med->call->acc_id)) {
250 status = resolve_stun_server(PJ_TRUE);
251 if (status != PJ_SUCCESS) {
252 pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
253 return status;
254 }
255 }
256
257 if (acc->next_rtp_port == 0)
258 acc->next_rtp_port = (pj_uint16_t)cfg->port;
259
260 if (acc->next_rtp_port == 0)
261 acc->next_rtp_port = (pj_uint16_t)DEFAULT_RTP_PORT;
262
263 for (i=0; i<2; ++i)
264 sock[i] = PJ_INVALID_SOCKET;
265
266 pj_sockaddr_init(af, &bound_addr, NULL, 0);
267 if (cfg->bound_addr.slen) {
268 status = pj_sockaddr_set_str_addr(af, &bound_addr, &cfg->bound_addr);
269 if (status != PJ_SUCCESS) {
270 pjsua_perror(THIS_FILE, "Unable to resolve transport bind address",
271 status);
272 return status;
273 }
274 }
275
276 /* Loop retry to bind RTP and RTCP sockets. */
277 for (i=0; i<RTP_RETRY; ++i, acc->next_rtp_port += 2) {
278
279 if (cfg->port > 0 && cfg->port_range > 0 &&
280 (acc->next_rtp_port > cfg->port + cfg->port_range ||
281 acc->next_rtp_port < cfg->port))
282 {
283 acc->next_rtp_port = (pj_uint16_t)cfg->port;
284 }
285
286 /* Create RTP socket. */
287 status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock[0]);
288 if (status != PJ_SUCCESS) {
289 pjsua_perror(THIS_FILE, "socket() error", status);
290 return status;
291 }
292
293 /* Apply QoS to RTP socket, if specified */
294 status = pj_sock_apply_qos2(sock[0], cfg->qos_type,
295 &cfg->qos_params,
296 2, THIS_FILE, "RTP socket");
297
298 /* Bind RTP socket */
299 pj_sockaddr_set_port(&bound_addr, acc->next_rtp_port);
300 status=pj_sock_bind(sock[0], &bound_addr,
301 pj_sockaddr_get_len(&bound_addr));
302 if (status != PJ_SUCCESS) {
303 pj_sock_close(sock[0]);
304 sock[0] = PJ_INVALID_SOCKET;
305 continue;
306 }
307
308 /* Create RTCP socket. */
309 status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock[1]);
310 if (status != PJ_SUCCESS) {
311 pjsua_perror(THIS_FILE, "socket() error", status);
312 pj_sock_close(sock[0]);
313 return status;
314 }
315
316 /* Apply QoS to RTCP socket, if specified */
317 status = pj_sock_apply_qos2(sock[1], cfg->qos_type,
318 &cfg->qos_params,
319 2, THIS_FILE, "RTCP socket");
320
321 /* Bind RTCP socket */
322 pj_sockaddr_set_port(&bound_addr, (pj_uint16_t)(acc->next_rtp_port+1));
323 status=pj_sock_bind(sock[1], &bound_addr,
324 pj_sockaddr_get_len(&bound_addr));
325 if (status != PJ_SUCCESS) {
326 pj_sock_close(sock[0]);
327 sock[0] = PJ_INVALID_SOCKET;
328
329 pj_sock_close(sock[1]);
330 sock[1] = PJ_INVALID_SOCKET;
331 continue;
332 }
333
334 /*
335 * If we're configured to use STUN, then find out the mapped address,
336 * and make sure that the mapped RTCP port is adjacent with the RTP.
337 */
338 if (!use_ipv6 && pjsua_sip_acc_is_using_stun(call_med->call->acc_id) &&
339 pjsua_var.stun_srv.addr.sa_family != 0)
340 {
341 char ip_addr[32];
342 pj_str_t stun_srv;
343 pj_sockaddr_in resolved_addr[2];
344 pjstun_setting stun_opt;
345
346 pj_ansi_strcpy(ip_addr,
347 pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr));
348 stun_srv = pj_str(ip_addr);
349
350 pj_bzero(&stun_opt, sizeof(stun_opt));
351 stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
352 stun_opt.srv1 = stun_opt.srv2 = stun_srv;
353 stun_opt.port1 = stun_opt.port2 =
354 pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
355 status=pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
356 2, sock, resolved_addr);
357#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
358 PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
359 /* Handle EPIPE (Broken Pipe) error, which happens on UDP socket
360 * after app wakes up from suspended state. In this case, simply
361 * just retry.
362 * P.S.: The magic status is PJ_STATUS_FROM_OS(EPIPE)
363 */
364 if (status == 120032) {
365 PJ_LOG(4,(THIS_FILE, "Got EPIPE error, retrying.."));
366 pj_sock_close(sock[0]);
367 sock[0] = PJ_INVALID_SOCKET;
368
369 pj_sock_close(sock[1]);
370 sock[1] = PJ_INVALID_SOCKET;
371
372 continue;
373 }
374 else
375#endif
376 if (status != PJ_SUCCESS) {
377 pjsua_perror(THIS_FILE, "STUN resolve error", status);
378 goto on_error;
379 }
380
381 pj_sockaddr_cp(&mapped_addr[0], &resolved_addr[0]);
382 pj_sockaddr_cp(&mapped_addr[1], &resolved_addr[1]);
383
384#if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT
385 if (pj_sockaddr_get_port(&mapped_addr[1]) ==
386 pj_sockaddr_get_port(&mapped_addr[0])+1)
387 {
388 /* Success! */
389 break;
390 }
391
392 pj_sock_close(sock[0]);
393 sock[0] = PJ_INVALID_SOCKET;
394
395 pj_sock_close(sock[1]);
396 sock[1] = PJ_INVALID_SOCKET;
397#else
398 if (pj_sockaddr_get_port(&mapped_addr[1]) !=
399 pj_sockaddr_get_port(&mapped_addr[0])+1)
400 {
401 PJ_LOG(4,(THIS_FILE,
402 "Note: STUN mapped RTCP port %d is not adjacent"
403 " to RTP port %d",
404 pj_sockaddr_get_port(&mapped_addr[1]),
405 pj_sockaddr_get_port(&mapped_addr[0])));
406 }
407 /* Success! */
408 break;
409#endif
410
411 } else if (cfg->public_addr.slen) {
412
413 status = pj_sockaddr_init(af, &mapped_addr[0], &cfg->public_addr,
414 (pj_uint16_t)acc->next_rtp_port);
415 if (status != PJ_SUCCESS)
416 goto on_error;
417
418 status = pj_sockaddr_init(af, &mapped_addr[1], &cfg->public_addr,
419 (pj_uint16_t)(acc->next_rtp_port+1));
420 if (status != PJ_SUCCESS)
421 goto on_error;
422
423 break;
424
425 } else {
426 if (acc->cfg.allow_sdp_nat_rewrite && acc->reg_mapped_addr.slen) {
427 pj_status_t status;
428
429 /* Take the address from mapped addr as seen by registrar */
430 status = pj_sockaddr_set_str_addr(af, &bound_addr,
431 &acc->reg_mapped_addr);
432 if (status != PJ_SUCCESS) {
433 /* just leave bound_addr with whatever it was
434 pj_bzero(pj_sockaddr_get_addr(&bound_addr),
435 pj_sockaddr_get_addr_len(&bound_addr));
436 */
437 }
438 }
439
440 if (!pj_sockaddr_has_addr(&bound_addr)) {
441 pj_sockaddr addr;
442
443 /* Get local IP address. */
444 status = pj_gethostip(af, &addr);
445 if (status != PJ_SUCCESS)
446 goto on_error;
447
448 pj_sockaddr_copy_addr(&bound_addr, &addr);
449 }
450
451 for (i=0; i<2; ++i) {
452 pj_sockaddr_init(af, &mapped_addr[i], NULL, 0);
453 pj_sockaddr_copy_addr(&mapped_addr[i], &bound_addr);
454 pj_sockaddr_set_port(&mapped_addr[i],
455 (pj_uint16_t)(acc->next_rtp_port+i));
456 }
457
458 break;
459 }
460 }
461
462 if (sock[0] == PJ_INVALID_SOCKET) {
463 PJ_LOG(1,(THIS_FILE,
464 "Unable to find appropriate RTP/RTCP ports combination"));
465 goto on_error;
466 }
467
468
469 skinfo->rtp_sock = sock[0];
470 pj_sockaddr_cp(&skinfo->rtp_addr_name, &mapped_addr[0]);
471
472 skinfo->rtcp_sock = sock[1];
473 pj_sockaddr_cp(&skinfo->rtcp_addr_name, &mapped_addr[1]);
474
475 PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s",
476 pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf,
477 sizeof(addr_buf), 3)));
478 PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s",
479 pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf,
480 sizeof(addr_buf), 3)));
481
482 acc->next_rtp_port += 2;
483 return PJ_SUCCESS;
484
485on_error:
486 for (i=0; i<2; ++i) {
487 if (sock[i] != PJ_INVALID_SOCKET)
488 pj_sock_close(sock[i]);
489 }
490 return status;
491}
492
493/* Create normal UDP media transports */
494static pj_status_t create_udp_media_transport(const pjsua_transport_config *cfg,
495 pjsua_call_media *call_med)
496{
497 pjmedia_sock_info skinfo;
498 pj_status_t status;
499
500 status = create_rtp_rtcp_sock(call_med, cfg, &skinfo);
501 if (status != PJ_SUCCESS) {
502 pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket",
503 status);
504 goto on_error;
505 }
506
507 status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL,
508 &skinfo, 0, &call_med->tp);
509 if (status != PJ_SUCCESS) {
510 pjsua_perror(THIS_FILE, "Unable to create media transport",
511 status);
512 goto on_error;
513 }
514
515 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
516 pjsua_var.media_cfg.tx_drop_pct);
517
518 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
519 pjsua_var.media_cfg.rx_drop_pct);
520
521 call_med->tp_ready = PJ_SUCCESS;
522
523 return PJ_SUCCESS;
524
525on_error:
526 if (call_med->tp)
527 pjmedia_transport_close(call_med->tp);
528
529 return status;
530}
531
532#if DISABLED_FOR_TICKET_1185
533/* Create normal UDP media transports */
534static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg)
535{
536 unsigned i;
537 pj_status_t status;
538
539 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
540 pjsua_call *call = &pjsua_var.calls[i];
541 unsigned strm_idx;
542
543 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
544 pjsua_call_media *call_med = &call->media[strm_idx];
545
546 status = create_udp_media_transport(cfg, &call_med->tp);
547 if (status != PJ_SUCCESS)
548 goto on_error;
549 }
550 }
551
552 return PJ_SUCCESS;
553
554on_error:
555 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
556 pjsua_call *call = &pjsua_var.calls[i];
557 unsigned strm_idx;
558
559 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
560 pjsua_call_media *call_med = &call->media[strm_idx];
561
562 if (call_med->tp) {
563 pjmedia_transport_close(call_med->tp);
564 call_med->tp = NULL;
565 }
566 }
567 }
568 return status;
569}
570#endif
571
572/* Deferred callback to notify ICE init complete */
573static void ice_init_complete_cb(void *user_data)
574{
575 pjsua_call_media *call_med = (pjsua_call_media*)user_data;
576
577 if (call_med->call == NULL)
578 return;
579
580 /* No need to acquire_call() if we only change the tp_ready flag
581 * (i.e. transport is being created synchronously). Otherwise
582 * calling acquire_call() here may cause deadlock. See
583 * https://trac.pjsip.org/repos/ticket/1578
584 */
585 call_med->tp_ready = call_med->tp_result;
586
587 if (call_med->med_create_cb) {
588 pjsua_call *call = NULL;
589 pjsip_dialog *dlg = NULL;
590
591 if (acquire_call("ice_init_complete_cb", call_med->call->index,
592 &call, &dlg) != PJ_SUCCESS)
593 {
594 /* Call have been terminated */
595 return;
596 }
597
598 (*call_med->med_create_cb)(call_med, call_med->tp_ready,
599 call_med->call->secure_level, NULL);
600
601 if (dlg)
602 pjsip_dlg_dec_lock(dlg);
603 }
604}
605
606/* Deferred callback to notify ICE negotiation failure */
607static void ice_failed_nego_cb(void *user_data)
608{
609 int call_id = (int)(pj_ssize_t)user_data;
610 pjsua_call *call = NULL;
611 pjsip_dialog *dlg = NULL;
612
613 if (acquire_call("ice_failed_nego_cb", call_id,
614 &call, &dlg) != PJ_SUCCESS)
615 {
616 /* Call have been terminated */
617 return;
618 }
619
620 pjsua_var.ua_cfg.cb.on_call_media_state(call_id);
621
622 if (dlg)
623 pjsip_dlg_dec_lock(dlg);
624
625}
626
627/* This callback is called when ICE negotiation completes */
628static void on_ice_complete(pjmedia_transport *tp,
629 pj_ice_strans_op op,
630 pj_status_t result)
631{
632 pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data;
633 pjsua_call *call;
634
635 if (!call_med)
636 return;
637
638 call = call_med->call;
639
640 switch (op) {
641 case PJ_ICE_STRANS_OP_INIT:
642 call_med->tp_result = result;
643 pjsua_schedule_timer2(&ice_init_complete_cb, call_med, 1);
644 break;
645 case PJ_ICE_STRANS_OP_NEGOTIATION:
646 if (result == PJ_SUCCESS) {
647 /* Update RTP address */
648 pjmedia_transport_info tpinfo;
649 pjmedia_transport_info_init(&tpinfo);
650 pjmedia_transport_get_info(call_med->tp, &tpinfo);
651 pj_sockaddr_cp(&call_med->rtp_addr, &tpinfo.sock_info.rtp_addr_name);
652 } else {
653 call_med->state = PJSUA_CALL_MEDIA_ERROR;
654 call_med->dir = PJMEDIA_DIR_NONE;
655 if (call && pjsua_var.ua_cfg.cb.on_call_media_state) {
656 /* Defer the callback to a timer */
657 pjsua_schedule_timer2(&ice_failed_nego_cb,
658 (void*)(pj_ssize_t)call->index, 1);
659 }
660 }
661 /* Check if default ICE transport address is changed */
662 call->reinv_ice_sent = PJ_FALSE;
663 pjsua_call_schedule_reinvite_check(call, 0);
664 break;
665 case PJ_ICE_STRANS_OP_KEEP_ALIVE:
666 if (result != PJ_SUCCESS) {
667 PJ_PERROR(4,(THIS_FILE, result,
668 "ICE keep alive failure for transport %d:%d",
669 call->index, call_med->idx));
670 }
671 if (pjsua_var.ua_cfg.cb.on_call_media_transport_state) {
672 pjsua_med_tp_state_info info;
673
674 pj_bzero(&info, sizeof(info));
675 info.med_idx = call_med->idx;
676 info.state = call_med->tp_st;
677 info.status = result;
678 info.ext_info = &op;
679 (*pjsua_var.ua_cfg.cb.on_call_media_transport_state)(
680 call->index, &info);
681 }
682 if (pjsua_var.ua_cfg.cb.on_ice_transport_error) {
683 pjsua_call_id id = call->index;
684 (*pjsua_var.ua_cfg.cb.on_ice_transport_error)(id, op, result,
685 NULL);
686 }
687 break;
688 }
689}
690
691
692/* Parse "HOST:PORT" format */
693static pj_status_t parse_host_port(const pj_str_t *host_port,
694 pj_str_t *host, pj_uint16_t *port)
695{
696 pj_str_t str_port;
697
698 str_port.ptr = pj_strchr(host_port, ':');
699 if (str_port.ptr != NULL) {
700 int iport;
701
702 host->ptr = host_port->ptr;
703 host->slen = (str_port.ptr - host->ptr);
704 str_port.ptr++;
705 str_port.slen = host_port->slen - host->slen - 1;
706 iport = (int)pj_strtoul(&str_port);
707 if (iport < 1 || iport > 65535)
708 return PJ_EINVAL;
709 *port = (pj_uint16_t)iport;
710 } else {
711 *host = *host_port;
712 *port = 0;
713 }
714
715 return PJ_SUCCESS;
716}
717
718/* Create ICE media transports (when ice is enabled) */
719static pj_status_t create_ice_media_transport(
720 const pjsua_transport_config *cfg,
721 pjsua_call_media *call_med,
722 pj_bool_t async)
723{
724 char stunip[PJ_INET6_ADDRSTRLEN];
725 pjsua_acc_config *acc_cfg;
726 pj_ice_strans_cfg ice_cfg;
727 pjmedia_ice_cb ice_cb;
728 char name[32];
729 unsigned comp_cnt;
730 pj_status_t status;
731
732 acc_cfg = &pjsua_var.acc[call_med->call->acc_id].cfg;
733
734 /* Make sure STUN server resolution has completed */
735 status = resolve_stun_server(PJ_TRUE);
736 if (status != PJ_SUCCESS) {
737 pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
738 return status;
739 }
740
741 /* Create ICE stream transport configuration */
742 pj_ice_strans_cfg_default(&ice_cfg);
743 pj_stun_config_init(&ice_cfg.stun_cfg, &pjsua_var.cp.factory, 0,
744 pjsip_endpt_get_ioqueue(pjsua_var.endpt),
745 pjsip_endpt_get_timer_heap(pjsua_var.endpt));
746
747 ice_cfg.af = pj_AF_INET();
748 ice_cfg.resolver = pjsua_var.resolver;
749
750 ice_cfg.opt = acc_cfg->ice_cfg.ice_opt;
751
752 /* Configure STUN settings */
753 if (pj_sockaddr_has_addr(&pjsua_var.stun_srv)) {
754 pj_sockaddr_print(&pjsua_var.stun_srv, stunip, sizeof(stunip), 0);
755 ice_cfg.stun.server = pj_str(stunip);
756 ice_cfg.stun.port = pj_sockaddr_get_port(&pjsua_var.stun_srv);
757 }
758 if (acc_cfg->ice_cfg.ice_max_host_cands >= 0)
759 ice_cfg.stun.max_host_cands = acc_cfg->ice_cfg.ice_max_host_cands;
760
761 /* Copy binding port setting to STUN setting */
762 pj_sockaddr_init(ice_cfg.af, &ice_cfg.stun.cfg.bound_addr,
763 &cfg->bound_addr, (pj_uint16_t)cfg->port);
764 ice_cfg.stun.cfg.port_range = (pj_uint16_t)cfg->port_range;
765 if (cfg->port != 0 && ice_cfg.stun.cfg.port_range == 0)
766 ice_cfg.stun.cfg.port_range =
767 (pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
768
769 /* Copy QoS setting to STUN setting */
770 ice_cfg.stun.cfg.qos_type = cfg->qos_type;
771 pj_memcpy(&ice_cfg.stun.cfg.qos_params, &cfg->qos_params,
772 sizeof(cfg->qos_params));
773
774 /* Configure TURN settings */
775 if (acc_cfg->turn_cfg.enable_turn) {
776 status = parse_host_port(&acc_cfg->turn_cfg.turn_server,
777 &ice_cfg.turn.server,
778 &ice_cfg.turn.port);
779 if (status != PJ_SUCCESS || ice_cfg.turn.server.slen == 0) {
780 PJ_LOG(1,(THIS_FILE, "Invalid TURN server setting"));
781 return PJ_EINVAL;
782 }
783 if (ice_cfg.turn.port == 0)
784 ice_cfg.turn.port = 3479;
785 ice_cfg.turn.conn_type = acc_cfg->turn_cfg.turn_conn_type;
786 pj_memcpy(&ice_cfg.turn.auth_cred,
787 &acc_cfg->turn_cfg.turn_auth_cred,
788 sizeof(ice_cfg.turn.auth_cred));
789
790 /* Copy QoS setting to TURN setting */
791 ice_cfg.turn.cfg.qos_type = cfg->qos_type;
792 pj_memcpy(&ice_cfg.turn.cfg.qos_params, &cfg->qos_params,
793 sizeof(cfg->qos_params));
794
795 /* Copy binding port setting to TURN setting */
796 pj_sockaddr_init(ice_cfg.af, &ice_cfg.turn.cfg.bound_addr,
797 &cfg->bound_addr, (pj_uint16_t)cfg->port);
798 ice_cfg.turn.cfg.port_range = (pj_uint16_t)cfg->port_range;
799 if (cfg->port != 0 && ice_cfg.turn.cfg.port_range == 0)
800 ice_cfg.turn.cfg.port_range =
801 (pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
802 }
803
804 /* Configure packet size for STUN and TURN sockets */
805 ice_cfg.stun.cfg.max_pkt_size = PJMEDIA_MAX_MRU;
806 ice_cfg.turn.cfg.max_pkt_size = PJMEDIA_MAX_MRU;
807
808 pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb));
809 ice_cb.on_ice_complete = &on_ice_complete;
810 pj_ansi_snprintf(name, sizeof(name), "icetp%02d", call_med->idx);
811 call_med->tp_ready = PJ_EPENDING;
812
813 comp_cnt = 1;
814 if (PJMEDIA_ADVERTISE_RTCP && !acc_cfg->ice_cfg.ice_no_rtcp)
815 ++comp_cnt;
816
817 status = pjmedia_ice_create3(pjsua_var.med_endpt, name, comp_cnt,
818 &ice_cfg, &ice_cb, 0, call_med,
819 &call_med->tp);
820 if (status != PJ_SUCCESS) {
821 pjsua_perror(THIS_FILE, "Unable to create ICE media transport",
822 status);
823 goto on_error;
824 }
825
826 /* Wait until transport is initialized, or time out */
827 if (!async) {
828 pj_bool_t has_pjsua_lock = PJSUA_LOCK_IS_LOCKED();
829 if (has_pjsua_lock)
830 PJSUA_UNLOCK();
831 while (call_med->tp_ready == PJ_EPENDING) {
832 pjsua_handle_events(100);
833 }
834 if (has_pjsua_lock)
835 PJSUA_LOCK();
836 }
837
838 if (async && call_med->tp_ready == PJ_EPENDING) {
839 return PJ_EPENDING;
840 } else if (call_med->tp_ready != PJ_SUCCESS) {
841 pjsua_perror(THIS_FILE, "Error initializing ICE media transport",
842 call_med->tp_ready);
843 status = call_med->tp_ready;
844 goto on_error;
845 }
846
847 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
848 pjsua_var.media_cfg.tx_drop_pct);
849
850 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
851 pjsua_var.media_cfg.rx_drop_pct);
852
853 return PJ_SUCCESS;
854
855on_error:
856 if (call_med->tp != NULL) {
857 pjmedia_transport_close(call_med->tp);
858 call_med->tp = NULL;
859 }
860
861 return status;
862}
863
864#if DISABLED_FOR_TICKET_1185
865/* Create ICE media transports (when ice is enabled) */
866static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
867{
868 unsigned i;
869 pj_status_t status;
870
871 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
872 pjsua_call *call = &pjsua_var.calls[i];
873 unsigned strm_idx;
874
875 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
876 pjsua_call_media *call_med = &call->media[strm_idx];
877
878 status = create_ice_media_transport(cfg, call_med);
879 if (status != PJ_SUCCESS)
880 goto on_error;
881 }
882 }
883
884 return PJ_SUCCESS;
885
886on_error:
887 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
888 pjsua_call *call = &pjsua_var.calls[i];
889 unsigned strm_idx;
890
891 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
892 pjsua_call_media *call_med = &call->media[strm_idx];
893
894 if (call_med->tp) {
895 pjmedia_transport_close(call_med->tp);
896 call_med->tp = NULL;
897 }
898 }
899 }
900 return status;
901}
902#endif
903
904#if DISABLED_FOR_TICKET_1185
905/*
906 * Create media transports for all the calls. This function creates
907 * one UDP media transport for each call.
908 */
909PJ_DEF(pj_status_t) pjsua_media_transports_create(
910 const pjsua_transport_config *app_cfg)
911{
912 pjsua_transport_config cfg;
913 unsigned i;
914 pj_status_t status;
915
916
917 /* Make sure pjsua_init() has been called */
918 PJ_ASSERT_RETURN(pjsua_var.ua_cfg.max_calls>0, PJ_EINVALIDOP);
919
920 PJSUA_LOCK();
921
922 /* Delete existing media transports */
923 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
924 pjsua_call *call = &pjsua_var.calls[i];
925 unsigned strm_idx;
926
927 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
928 pjsua_call_media *call_med = &call->media[strm_idx];
929
930 if (call_med->tp && call_med->tp_auto_del) {
931 pjmedia_transport_close(call_med->tp);
932 call_med->tp = NULL;
933 call_med->tp_orig = NULL;
934 }
935 }
936 }
937
938 /* Copy config */
939 pjsua_transport_config_dup(pjsua_var.pool, &cfg, app_cfg);
940
941 /* Create the transports */
942 if (pjsua_var.ice_cfg.enable_ice) {
943 status = create_ice_media_transports(&cfg);
944 } else {
945 status = create_udp_media_transports(&cfg);
946 }
947
948 /* Set media transport auto_delete to True */
949 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
950 pjsua_call *call = &pjsua_var.calls[i];
951 unsigned strm_idx;
952
953 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
954 pjsua_call_media *call_med = &call->media[strm_idx];
955
956 call_med->tp_auto_del = PJ_TRUE;
957 }
958 }
959
960 PJSUA_UNLOCK();
961
962 return status;
963}
964
965/*
966 * Attach application's created media transports.
967 */
968PJ_DEF(pj_status_t) pjsua_media_transports_attach(pjsua_media_transport tp[],
969 unsigned count,
970 pj_bool_t auto_delete)
971{
972 unsigned i;
973
974 PJ_ASSERT_RETURN(tp && count==pjsua_var.ua_cfg.max_calls, PJ_EINVAL);
975
976 /* Assign the media transports */
977 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
978 pjsua_call *call = &pjsua_var.calls[i];
979 unsigned strm_idx;
980
981 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
982 pjsua_call_media *call_med = &call->media[strm_idx];
983
984 if (call_med->tp && call_med->tp_auto_del) {
985 pjmedia_transport_close(call_med->tp);
986 call_med->tp = NULL;
987 call_med->tp_orig = NULL;
988 }
989 }
990
991 PJ_TODO(remove_pjsua_media_transports_attach);
992
993 call->media[0].tp = tp[i].transport;
994 call->media[0].tp_auto_del = auto_delete;
995 }
996
997 return PJ_SUCCESS;
998}
999#endif
1000
1001/* Go through the list of media in the SDP, find acceptable media, and
1002 * sort them based on the "quality" of the media, and store the indexes
1003 * in the specified array. Media with the best quality will be listed
1004 * first in the array. The quality factors considered currently is
1005 * encryption.
1006 */
1007static void sort_media(const pjmedia_sdp_session *sdp,
1008 const pj_str_t *type,
1009 pjmedia_srtp_use use_srtp,
1010 pj_uint8_t midx[],
1011 unsigned *p_count,
1012 unsigned *p_total_count)
1013{
1014 unsigned i;
1015 unsigned count = 0;
1016 int score[PJSUA_MAX_CALL_MEDIA];
1017
1018 pj_assert(*p_count >= PJSUA_MAX_CALL_MEDIA);
1019 pj_assert(*p_total_count >= PJSUA_MAX_CALL_MEDIA);
1020
1021 *p_count = 0;
1022 *p_total_count = 0;
1023 for (i=0; i<PJSUA_MAX_CALL_MEDIA; ++i)
1024 score[i] = 1;
1025
1026 /* Score each media */
1027 for (i=0; i<sdp->media_count && count<PJSUA_MAX_CALL_MEDIA; ++i) {
1028 const pjmedia_sdp_media *m = sdp->media[i];
1029 const pjmedia_sdp_conn *c;
1030
1031 /* Skip different media */
1032 if (pj_stricmp(&m->desc.media, type) != 0) {
1033 score[count++] = -22000;
1034 continue;
1035 }
1036
1037 c = m->conn? m->conn : sdp->conn;
1038
1039 /* Supported transports */
1040 if (pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) {
1041 switch (use_srtp) {
1042 case PJMEDIA_SRTP_MANDATORY:
1043 case PJMEDIA_SRTP_OPTIONAL:
1044 ++score[i];
1045 break;
1046 case PJMEDIA_SRTP_DISABLED:
1047 //--score[i];
1048 score[i] -= 5;
1049 break;
1050 }
1051 } else if (pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) {
1052 switch (use_srtp) {
1053 case PJMEDIA_SRTP_MANDATORY:
1054 //--score[i];
1055 score[i] -= 5;
1056 break;
1057 case PJMEDIA_SRTP_OPTIONAL:
1058 /* No change in score */
1059 break;
1060 case PJMEDIA_SRTP_DISABLED:
1061 ++score[i];
1062 break;
1063 }
1064 } else {
1065 score[i] -= 10;
1066 }
1067
1068 /* Is media disabled? */
1069 if (m->desc.port == 0)
1070 score[i] -= 10;
1071
1072 /* Is media inactive? */
1073 if (pjmedia_sdp_media_find_attr2(m, "inactive", NULL) ||
1074 pj_strcmp2(&c->addr, "0.0.0.0") == 0)
1075 {
1076 //score[i] -= 10;
1077 score[i] -= 1;
1078 }
1079
1080 ++count;
1081 }
1082
1083 /* Created sorted list based on quality */
1084 for (i=0; i<count; ++i) {
1085 unsigned j;
1086 int best = 0;
1087
1088 for (j=1; j<count; ++j) {
1089 if (score[j] > score[best])
1090 best = j;
1091 }
1092 /* Don't put media with negative score, that media is unacceptable
1093 * for us.
1094 */
1095 midx[i] = (pj_uint8_t)best;
1096 if (score[best] >= 0)
1097 (*p_count)++;
1098 if (score[best] > -22000)
1099 (*p_total_count)++;
1100
1101 score[best] = -22000;
1102
1103 }
1104}
1105
1106/* Callback to receive media events */
1107pj_status_t call_media_on_event(pjmedia_event *event,
1108 void *user_data)
1109{
1110 pjsua_call_media *call_med = (pjsua_call_media*)user_data;
1111 pjsua_call *call = call_med->call;
1112 pj_status_t status = PJ_SUCCESS;
1113
1114 switch(event->type) {
1115 case PJMEDIA_EVENT_KEYFRAME_MISSING:
1116 if (call->opt.req_keyframe_method & PJSUA_VID_REQ_KEYFRAME_SIP_INFO)
1117 {
1118 pj_timestamp now;
1119
1120 pj_get_timestamp(&now);
1121 if (pj_elapsed_msec(&call_med->last_req_keyframe, &now) >=
1122 PJSUA_VID_REQ_KEYFRAME_INTERVAL)
1123 {
1124 pjsua_msg_data msg_data;
1125 const pj_str_t SIP_INFO = {"INFO", 4};
1126 const char *BODY_TYPE = "application/media_control+xml";
1127 const char *BODY =
1128 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1129 "<media_control><vc_primitive><to_encoder>"
1130 "<picture_fast_update/>"
1131 "</to_encoder></vc_primitive></media_control>";
1132
1133 PJ_LOG(4,(THIS_FILE,
1134 "Sending video keyframe request via SIP INFO"));
1135
1136 pjsua_msg_data_init(&msg_data);
1137 pj_cstr(&msg_data.content_type, BODY_TYPE);
1138 pj_cstr(&msg_data.msg_body, BODY);
1139 status = pjsua_call_send_request(call->index, &SIP_INFO,
1140 &msg_data);
1141 if (status != PJ_SUCCESS) {
1142 pj_perror(3, THIS_FILE, status,
1143 "Failed requesting keyframe via SIP INFO");
1144 } else {
1145 call_med->last_req_keyframe = now;
1146 }
1147 }
1148 }
1149 break;
1150
1151 default:
1152 break;
1153 }
1154
1155 if (pjsua_var.ua_cfg.cb.on_call_media_event && call) {
1156 (*pjsua_var.ua_cfg.cb.on_call_media_event)(call->index,
1157 call_med->idx, event);
1158 }
1159
1160 return status;
1161}
1162
1163/* Set media transport state and notify the application via the callback. */
1164void pjsua_set_media_tp_state(pjsua_call_media *call_med,
1165 pjsua_med_tp_st tp_st)
1166{
1167 if (pjsua_var.ua_cfg.cb.on_call_media_transport_state &&
1168 call_med->tp_st != tp_st)
1169 {
1170 pjsua_med_tp_state_info info;
1171
1172 pj_bzero(&info, sizeof(info));
1173 info.med_idx = call_med->idx;
1174 info.state = tp_st;
1175 info.status = call_med->tp_ready;
1176 (*pjsua_var.ua_cfg.cb.on_call_media_transport_state)(
1177 call_med->call->index, &info);
1178 }
1179
1180 call_med->tp_st = tp_st;
1181}
1182
1183/* Callback to resume pjsua_call_media_init() after media transport
1184 * creation is completed.
1185 */
1186static pj_status_t call_media_init_cb(pjsua_call_media *call_med,
1187 pj_status_t status,
1188 int security_level,
1189 int *sip_err_code)
1190{
1191 pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
1192 pjmedia_transport_info tpinfo;
1193 int err_code = 0;
1194
1195 if (status != PJ_SUCCESS)
1196 goto on_return;
1197
1198 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
1199 pjsua_var.media_cfg.tx_drop_pct);
1200
1201 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
1202 pjsua_var.media_cfg.rx_drop_pct);
1203
1204 if (call_med->tp_st == PJSUA_MED_TP_CREATING)
1205 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
1206
1207 if (!call_med->tp_orig &&
1208 pjsua_var.ua_cfg.cb.on_create_media_transport)
1209 {
1210 call_med->use_custom_med_tp = PJ_TRUE;
1211 } else
1212 call_med->use_custom_med_tp = PJ_FALSE;
1213
1214#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
1215 /* This function may be called when SRTP transport already exists
1216 * (e.g: in re-invite, update), don't need to destroy/re-create.
1217 */
1218 if (!call_med->tp_orig) {
1219 pjmedia_srtp_setting srtp_opt;
1220 pjmedia_transport *srtp = NULL;
1221
1222 /* Check if SRTP requires secure signaling */
1223 if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) {
1224 if (security_level < acc->cfg.srtp_secure_signaling) {
1225 err_code = PJSIP_SC_NOT_ACCEPTABLE;
1226 status = PJSIP_ESESSIONINSECURE;
1227 goto on_return;
1228 }
1229 }
1230
1231 /* Always create SRTP adapter */
1232 pjmedia_srtp_setting_default(&srtp_opt);
1233 srtp_opt.close_member_tp = PJ_TRUE;
1234
1235 /* If media session has been ever established, let's use remote's
1236 * preference in SRTP usage policy, especially when it is stricter.
1237 */
1238 if (call_med->rem_srtp_use > acc->cfg.use_srtp)
1239 srtp_opt.use = call_med->rem_srtp_use;
1240 else
1241 srtp_opt.use = acc->cfg.use_srtp;
1242
1243 status = pjmedia_transport_srtp_create(pjsua_var.med_endpt,
1244 call_med->tp,
1245 &srtp_opt, &srtp);
1246 if (status != PJ_SUCCESS) {
1247 err_code = PJSIP_SC_INTERNAL_SERVER_ERROR;
1248 goto on_return;
1249 }
1250
1251 /* Set SRTP as current media transport */
1252 call_med->tp_orig = call_med->tp;
1253 call_med->tp = srtp;
1254 }
1255#else
1256 call_med->tp_orig = call_med->tp;
1257 PJ_UNUSED_ARG(security_level);
1258#endif
1259
1260
1261 pjmedia_transport_info_init(&tpinfo);
1262 pjmedia_transport_get_info(call_med->tp, &tpinfo);
1263
1264 pj_sockaddr_cp(&call_med->rtp_addr, &tpinfo.sock_info.rtp_addr_name);
1265
1266
1267on_return:
1268 if (status != PJ_SUCCESS && call_med->tp) {
1269 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
1270 pjmedia_transport_close(call_med->tp);
1271 call_med->tp = NULL;
1272 }
1273
1274 if (sip_err_code)
1275 *sip_err_code = err_code;
1276
1277 if (call_med->med_init_cb) {
1278 pjsua_med_tp_state_info info;
1279
1280 pj_bzero(&info, sizeof(info));
1281 info.status = status;
1282 info.state = call_med->tp_st;
1283 info.med_idx = call_med->idx;
1284 info.sip_err_code = err_code;
1285 (*call_med->med_init_cb)(call_med->call->index, &info);
1286 }
1287
1288 return status;
1289}
1290
1291/* Initialize the media line */
1292pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
1293 pjmedia_type type,
1294 const pjsua_transport_config *tcfg,
1295 int security_level,
1296 int *sip_err_code,
1297 pj_bool_t async,
1298 pjsua_med_tp_state_cb cb)
1299{
1300 pj_status_t status = PJ_SUCCESS;
1301
1302 /*
1303 * Note: this function may be called when the media already exists
1304 * (e.g. in reinvites, updates, etc.)
1305 */
1306 call_med->type = type;
1307
1308 /* Create the media transport for initial call. Here are the possible
1309 * media transport state and the action needed:
1310 * - PJSUA_MED_TP_NULL or call_med->tp==NULL, create one.
1311 * - PJSUA_MED_TP_RUNNING, do nothing.
1312 * - PJSUA_MED_TP_DISABLED, re-init (media_create(), etc). Currently,
1313 * this won't happen as media_channel_update() will always clean up
1314 * the unused transport of a disabled media.
1315 */
1316 if (call_med->tp == NULL) {
1317#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
1318 /* While in initial call, set default video devices */
1319 if (type == PJMEDIA_TYPE_VIDEO) {
1320 status = pjsua_vid_channel_init(call_med);
1321 if (status != PJ_SUCCESS)
1322 return status;
1323 }
1324#endif
1325
1326 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_CREATING);
1327
1328 if (pjsua_var.acc[call_med->call->acc_id].cfg.ice_cfg.enable_ice) {
1329 status = create_ice_media_transport(tcfg, call_med, async);
1330 if (async && status == PJ_EPENDING) {
1331 /* We will resume call media initialization in the
1332 * on_ice_complete() callback.
1333 */
1334 call_med->med_create_cb = &call_media_init_cb;
1335 call_med->med_init_cb = cb;
1336
1337 return PJ_EPENDING;
1338 }
1339 } else {
1340 status = create_udp_media_transport(tcfg, call_med);
1341 }
1342
1343 if (status != PJ_SUCCESS) {
1344 PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport"));
1345 return status;
1346 }
1347
1348 /* Media transport creation completed immediately, so
1349 * we don't need to call the callback.
1350 */
1351 call_med->med_init_cb = NULL;
1352
1353 } else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) {
1354 /* Media is being reenabled. */
1355 //pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
1356
1357 pj_assert(!"Currently no media transport reuse");
1358 }
1359
1360 return call_media_init_cb(call_med, status, security_level,
1361 sip_err_code);
1362}
1363
1364/* Callback to resume pjsua_media_channel_init() after media transport
1365 * initialization is completed.
1366 */
1367static pj_status_t media_channel_init_cb(pjsua_call_id call_id,
1368 const pjsua_med_tp_state_info *info)
1369{
1370 pjsua_call *call = &pjsua_var.calls[call_id];
1371 pj_status_t status = (info? info->status : PJ_SUCCESS);
1372 unsigned mi;
1373
1374 if (info) {
1375 pj_mutex_lock(call->med_ch_mutex);
1376
1377 /* Set the callback to NULL to indicate that the async operation
1378 * has completed.
1379 */
1380 call->media_prov[info->med_idx].med_init_cb = NULL;
1381
1382 /* In case of failure, save the information to be returned
1383 * by the last media transport to finish.
1384 */
1385 if (info->status != PJ_SUCCESS)
1386 pj_memcpy(&call->med_ch_info, info, sizeof(info));
1387
1388 /* Check whether all the call's medias have finished calling their
1389 * callbacks.
1390 */
1391 for (mi=0; mi < call->med_prov_cnt; ++mi) {
1392 pjsua_call_media *call_med = &call->media_prov[mi];
1393
1394 if (call_med->med_init_cb) {
1395 pj_mutex_unlock(call->med_ch_mutex);
1396 return PJ_SUCCESS;
1397 }
1398
1399 if (call_med->tp_ready != PJ_SUCCESS)
1400 status = call_med->tp_ready;
1401 }
1402
1403 /* OK, we are called by the last media transport finished. */
1404 pj_mutex_unlock(call->med_ch_mutex);
1405 }
1406
1407 if (call->med_ch_mutex) {
1408 pj_mutex_destroy(call->med_ch_mutex);
1409 call->med_ch_mutex = NULL;
1410 }
1411
1412 if (status != PJ_SUCCESS) {
1413 if (call->med_ch_info.status == PJ_SUCCESS) {
1414 call->med_ch_info.status = status;
1415 call->med_ch_info.sip_err_code = PJSIP_SC_TEMPORARILY_UNAVAILABLE;
1416 }
1417 pjsua_media_prov_clean_up(call_id);
1418 goto on_return;
1419 }
1420
1421 /* Tell the media transport of a new offer/answer session */
1422 for (mi=0; mi < call->med_prov_cnt; ++mi) {
1423 pjsua_call_media *call_med = &call->media_prov[mi];
1424
1425 /* Note: tp may be NULL if this media line is disabled */
1426 if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) {
1427 pj_pool_t *tmp_pool = call->async_call.pool_prov;
1428
1429 if (!tmp_pool) {
1430 tmp_pool = (call->inv? call->inv->pool_prov:
1431 call->async_call.dlg->pool);
1432 }
1433
1434 if (call_med->use_custom_med_tp) {
1435 unsigned custom_med_tp_flags = PJSUA_MED_TP_CLOSE_MEMBER;
1436
1437 /* Use custom media transport returned by the application */
1438 call_med->tp =
1439 (*pjsua_var.ua_cfg.cb.on_create_media_transport)
1440 (call_id, mi, call_med->tp,
1441 custom_med_tp_flags);
1442 if (!call_med->tp) {
1443 status =
1444 PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_TEMPORARILY_UNAVAILABLE);
1445 }
1446 }
1447
1448 if (call_med->tp) {
1449 status = pjmedia_transport_media_create(
1450 call_med->tp, tmp_pool,
1451 0, call->async_call.rem_sdp, mi);
1452 }
1453 if (status != PJ_SUCCESS) {
1454 call->med_ch_info.status = status;
1455 call->med_ch_info.med_idx = mi;
1456 call->med_ch_info.state = call_med->tp_st;
1457 call->med_ch_info.sip_err_code = PJSIP_SC_TEMPORARILY_UNAVAILABLE;
1458 pjsua_media_prov_clean_up(call_id);
1459 goto on_return;
1460 }
1461
1462 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_INIT);
1463 }
1464 }
1465
1466 call->med_ch_info.status = PJ_SUCCESS;
1467
1468on_return:
1469 if (call->med_ch_cb)
1470 (*call->med_ch_cb)(call->index, &call->med_ch_info);
1471
1472 return status;
1473}
1474
1475
1476/* Clean up media transports in provisional media that is not used
1477 * by call media.
1478 */
1479static void media_prov_clean_up(pjsua_call_id call_id, int idx)
1480{
1481 pjsua_call *call = &pjsua_var.calls[call_id];
1482 unsigned i;
1483
1484 for (i = idx; i < call->med_prov_cnt; ++i) {
1485 pjsua_call_media *call_med = &call->media_prov[i];
1486 unsigned j;
1487 pj_bool_t used = PJ_FALSE;
1488
1489 if (call_med->tp == NULL)
1490 continue;
1491
1492 for (j = 0; j < call->med_cnt; ++j) {
1493 if (call->media[j].tp == call_med->tp) {
1494 used = PJ_TRUE;
1495 break;
1496 }
1497 }
1498
1499 if (!used) {
1500 if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
1501 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
1502 pjmedia_transport_media_stop(call_med->tp);
1503 }
1504 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
1505 pjmedia_transport_close(call_med->tp);
1506 call_med->tp = call_med->tp_orig = NULL;
1507 }
1508 }
1509}
1510
1511void pjsua_media_prov_clean_up(pjsua_call_id call_id)
1512{
1513 media_prov_clean_up(call_id, 0);
1514}
1515
1516
1517pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
1518 pjsip_role_e role,
1519 int security_level,
1520 pj_pool_t *tmp_pool,
1521 const pjmedia_sdp_session *rem_sdp,
1522 int *sip_err_code,
1523 pj_bool_t async,
1524 pjsua_med_tp_state_cb cb)
1525{
1526 const pj_str_t STR_AUDIO = { "audio", 5 };
1527 const pj_str_t STR_VIDEO = { "video", 5 };
1528 pjsua_call *call = &pjsua_var.calls[call_id];
1529 pjsua_acc *acc = &pjsua_var.acc[call->acc_id];
1530 pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA];
1531 unsigned maudcnt = PJ_ARRAY_SIZE(maudidx);
1532 unsigned mtotaudcnt = PJ_ARRAY_SIZE(maudidx);
1533 pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA];
1534 unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx);
1535 unsigned mtotvidcnt = PJ_ARRAY_SIZE(mvididx);
1536 unsigned mi;
1537 pj_bool_t pending_med_tp = PJ_FALSE;
1538 pj_bool_t reinit = PJ_FALSE;
1539 pj_status_t status;
1540
1541 PJ_UNUSED_ARG(role);
1542
1543 /*
1544 * Note: this function may be called when the media already exists
1545 * (e.g. in reinvites, updates, etc).
1546 */
1547
1548 if (pjsua_get_state() != PJSUA_STATE_RUNNING) {
1549 if (sip_err_code) *sip_err_code = PJSIP_SC_SERVICE_UNAVAILABLE;
1550 return PJ_EBUSY;
1551 }
1552
1553 if (async) {
1554 pj_pool_t *tmppool = (call->inv? call->inv->pool_prov:
1555 call->async_call.dlg->pool);
1556
1557 status = pj_mutex_create_simple(tmppool, NULL, &call->med_ch_mutex);
1558 if (status != PJ_SUCCESS)
1559 return status;
1560 }
1561
1562 if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED)
1563 reinit = PJ_TRUE;
1564
1565 PJ_LOG(4,(THIS_FILE, "Call %d: %sinitializing media..",
1566 call_id, (reinit?"re-":"") ));
1567
1568 pj_log_push_indent();
1569
1570 /* Init provisional media state */
1571 if (call->med_cnt == 0) {
1572 /* New media session, just copy whole from call media state. */
1573 pj_memcpy(call->media_prov, call->media, sizeof(call->media));
1574 } else {
1575 /* Clean up any unused transports. Note that when local SDP reoffer
1576 * is rejected by remote, there may be any initialized transports that
1577 * are not used by call media and currently there is no notification
1578 * from PJSIP level regarding the reoffer rejection.
1579 */
1580 pjsua_media_prov_clean_up(call_id);
1581
1582 /* Updating media session, copy from call media state. */
1583 pj_memcpy(call->media_prov, call->media,
1584 sizeof(call->media[0]) * call->med_cnt);
1585 }
1586 call->med_prov_cnt = call->med_cnt;
1587
1588#if DISABLED_FOR_TICKET_1185
1589 /* Return error if media transport has not been created yet
1590 * (e.g. application is starting)
1591 */
1592 for (i=0; i<call->med_cnt; ++i) {
1593 if (call->media[i].tp == NULL) {
1594 status = PJ_EBUSY;
1595 goto on_error;
1596 }
1597 }
1598#endif
1599
1600 /* Get media count for each media type */
1601 if (rem_sdp) {
1602 sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp,
1603 maudidx, &maudcnt, &mtotaudcnt);
1604 if (maudcnt==0) {
1605 /* Expecting audio in the offer */
1606 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
1607 status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
1608 goto on_error;
1609 }
1610
1611#if PJMEDIA_HAS_VIDEO
1612 sort_media(rem_sdp, &STR_VIDEO, acc->cfg.use_srtp,
1613 mvididx, &mvidcnt, &mtotvidcnt);
1614#else
1615 mvidcnt = mtotvidcnt = 0;
1616 PJ_UNUSED_ARG(STR_VIDEO);
1617#endif
1618
1619 /* Update media count only when remote add any media, this media count
1620 * must never decrease. Also note that we shouldn't apply the media
1621 * count setting (of the call setting) before the SDP negotiation.
1622 */
1623 if (call->med_prov_cnt < rem_sdp->media_count)
1624 call->med_prov_cnt = PJ_MIN(rem_sdp->media_count,
1625 PJSUA_MAX_CALL_MEDIA);
1626
1627 call->rem_offerer = PJ_TRUE;
1628 call->rem_aud_cnt = maudcnt;
1629 call->rem_vid_cnt = mvidcnt;
1630
1631 } else {
1632
1633 /* If call already established, calculate media count from current
1634 * local active SDP and call setting. Otherwise, calculate media
1635 * count from the call setting only.
1636 */
1637 if (reinit) {
1638 const pjmedia_sdp_session *sdp;
1639
1640 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp);
1641 pj_assert(status == PJ_SUCCESS);
1642
1643 sort_media(sdp, &STR_AUDIO, acc->cfg.use_srtp,
1644 maudidx, &maudcnt, &mtotaudcnt);
1645 pj_assert(maudcnt > 0);
1646
1647 sort_media(sdp, &STR_VIDEO, acc->cfg.use_srtp,
1648 mvididx, &mvidcnt, &mtotvidcnt);
1649
1650 /* Call setting may add or remove media. Adding media is done by
1651 * enabling any disabled/port-zeroed media first, then adding new
1652 * media whenever needed. Removing media is done by disabling
1653 * media with the lowest 'quality'.
1654 */
1655
1656 /* Check if we need to add new audio */
1657 if (maudcnt < call->opt.aud_cnt &&
1658 mtotaudcnt < call->opt.aud_cnt)
1659 {
1660 for (mi = 0; mi < call->opt.aud_cnt - mtotaudcnt; ++mi)
1661 maudidx[maudcnt++] = (pj_uint8_t)call->med_prov_cnt++;
1662
1663 mtotaudcnt = call->opt.aud_cnt;
1664 }
1665 maudcnt = call->opt.aud_cnt;
1666
1667 /* Check if we need to add new video */
1668 if (mvidcnt < call->opt.vid_cnt &&
1669 mtotvidcnt < call->opt.vid_cnt)
1670 {
1671 for (mi = 0; mi < call->opt.vid_cnt - mtotvidcnt; ++mi)
1672 mvididx[mvidcnt++] = (pj_uint8_t)call->med_prov_cnt++;
1673
1674 mtotvidcnt = call->opt.vid_cnt;
1675 }
1676 mvidcnt = call->opt.vid_cnt;
1677
1678 } else {
1679
1680 maudcnt = mtotaudcnt = call->opt.aud_cnt;
1681 for (mi=0; mi<maudcnt; ++mi) {
1682 maudidx[mi] = (pj_uint8_t)mi;
1683 }
1684 mvidcnt = mtotvidcnt = call->opt.vid_cnt;
1685 for (mi=0; mi<mvidcnt; ++mi) {
1686 mvididx[mi] = (pj_uint8_t)(maudcnt + mi);
1687 }
1688 call->med_prov_cnt = maudcnt + mvidcnt;
1689
1690 /* Need to publish supported media? */
1691 if (call->opt.flag & PJSUA_CALL_INCLUDE_DISABLED_MEDIA) {
1692 if (mtotaudcnt == 0) {
1693 mtotaudcnt = 1;
1694 maudidx[0] = (pj_uint8_t)call->med_prov_cnt++;
1695 }
1696#if PJMEDIA_HAS_VIDEO
1697 if (mtotvidcnt == 0) {
1698 mtotvidcnt = 1;
1699 mvididx[0] = (pj_uint8_t)call->med_prov_cnt++;
1700 }
1701#endif
1702 }
1703 }
1704
1705 call->rem_offerer = PJ_FALSE;
1706 }
1707
1708 if (call->med_prov_cnt == 0) {
1709 /* Expecting at least one media */
1710 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
1711 status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
1712 goto on_error;
1713 }
1714
1715 if (async) {
1716 call->med_ch_cb = cb;
1717 }
1718
1719 if (rem_sdp) {
1720 call->async_call.rem_sdp =
1721 pjmedia_sdp_session_clone(call->inv->pool_prov, rem_sdp);
1722 } else {
1723 call->async_call.rem_sdp = NULL;
1724 }
1725
1726 call->async_call.pool_prov = tmp_pool;
1727
1728 /* Initialize each media line */
1729 for (mi=0; mi < call->med_prov_cnt; ++mi) {
1730 pjsua_call_media *call_med = &call->media_prov[mi];
1731 pj_bool_t enabled = PJ_FALSE;
1732 pjmedia_type media_type = PJMEDIA_TYPE_UNKNOWN;
1733
1734 if (pj_memchr(maudidx, mi, mtotaudcnt * sizeof(maudidx[0]))) {
1735 media_type = PJMEDIA_TYPE_AUDIO;
1736 if (call->opt.aud_cnt &&
1737 pj_memchr(maudidx, mi, maudcnt * sizeof(maudidx[0])))
1738 {
1739 enabled = PJ_TRUE;
1740 }
1741 } else if (pj_memchr(mvididx, mi, mtotvidcnt * sizeof(mvididx[0]))) {
1742 media_type = PJMEDIA_TYPE_VIDEO;
1743 if (call->opt.vid_cnt &&
1744 pj_memchr(mvididx, mi, mvidcnt * sizeof(mvididx[0])))
1745 {
1746 enabled = PJ_TRUE;
1747 }
1748 }
1749
1750 if (enabled) {
1751 status = pjsua_call_media_init(call_med, media_type,
1752 &acc->cfg.rtp_cfg,
1753 security_level, sip_err_code,
1754 async,
1755 (async? &media_channel_init_cb:
1756 NULL));
1757 if (status == PJ_EPENDING) {
1758 pending_med_tp = PJ_TRUE;
1759 } else if (status != PJ_SUCCESS) {
1760 if (pending_med_tp) {
1761 /* Save failure information. */
1762 call_med->tp_ready = status;
1763 pj_bzero(&call->med_ch_info, sizeof(call->med_ch_info));
1764 call->med_ch_info.status = status;
1765 call->med_ch_info.state = call_med->tp_st;
1766 call->med_ch_info.med_idx = call_med->idx;
1767 if (sip_err_code)
1768 call->med_ch_info.sip_err_code = *sip_err_code;
1769
1770 /* We will return failure in the callback later. */
1771 return PJ_EPENDING;
1772 }
1773
1774 pjsua_media_prov_clean_up(call_id);
1775 goto on_error;
1776 }
1777 } else {
1778 /* By convention, the media is disabled if transport is NULL
1779 * or transport state is PJSUA_MED_TP_DISABLED.
1780 */
1781 if (call_med->tp) {
1782 // Don't close transport here, as SDP negotiation has not been
1783 // done and stream may be still active. Once SDP negotiation
1784 // is done (channel_update() invoked), this transport will be
1785 // closed there.
1786 //pjmedia_transport_close(call_med->tp);
1787 //call_med->tp = NULL;
1788 pj_assert(call_med->tp_st == PJSUA_MED_TP_INIT ||
1789 call_med->tp_st == PJSUA_MED_TP_RUNNING);
1790 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_DISABLED);
1791 }
1792
1793 /* Put media type just for info */
1794 call_med->type = media_type;
1795 }
1796 }
1797
1798 call->audio_idx = maudidx[0];
1799
1800 PJ_LOG(4,(THIS_FILE, "Media index %d selected for audio call %d",
1801 call->audio_idx, call->index));
1802
1803 if (pending_med_tp) {
1804 /* We shouldn't use temporary pool anymore. */
1805 call->async_call.pool_prov = NULL;
1806 /* We have a pending media transport initialization. */
1807 pj_log_pop_indent();
1808 return PJ_EPENDING;
1809 }
1810
1811 /* Media transport initialization completed immediately, so
1812 * we don't need to call the callback.
1813 */
1814 call->med_ch_cb = NULL;
1815
1816 status = media_channel_init_cb(call_id, NULL);
1817 if (status != PJ_SUCCESS && sip_err_code)
1818 *sip_err_code = call->med_ch_info.sip_err_code;
1819
1820 pj_log_pop_indent();
1821 return status;
1822
1823on_error:
1824 if (call->med_ch_mutex) {
1825 pj_mutex_destroy(call->med_ch_mutex);
1826 call->med_ch_mutex = NULL;
1827 }
1828
1829 pj_log_pop_indent();
1830 return status;
1831}
1832
1833
1834/* Create SDP based on the current media channel. Note that, this function
1835 * will not modify the media channel, so when receiving new offer or
1836 * updating media count (via call setting), media channel must be reinit'd
1837 * (using pjsua_media_channel_init()) first before calling this function.
1838 */
1839pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
1840 pj_pool_t *pool,
1841 const pjmedia_sdp_session *rem_sdp,
1842 pjmedia_sdp_session **p_sdp,
1843 int *sip_err_code)
1844{
1845 enum { MAX_MEDIA = PJSUA_MAX_CALL_MEDIA };
1846 pjmedia_sdp_session *sdp;
1847 pj_sockaddr origin;
1848 pjsua_call *call = &pjsua_var.calls[call_id];
1849 pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL;
1850 unsigned mi;
1851 unsigned tot_bandw_tias = 0;
1852 pj_status_t status;
1853
1854 if (pjsua_get_state() != PJSUA_STATE_RUNNING)
1855 return PJ_EBUSY;
1856
1857#if 0
1858 // This function should not really change the media channel.
1859 if (rem_sdp) {
1860 /* If this is a re-offer, let's re-initialize media as remote may
1861 * add or remove media
1862 */
1863 if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
1864 status = pjsua_media_channel_init(call_id, PJSIP_ROLE_UAS,
1865 call->secure_level, pool,
1866 rem_sdp, sip_err_code,
1867 PJ_FALSE, NULL);
1868 if (status != PJ_SUCCESS)
1869 return status;
1870 }
1871 } else {
1872 /* Audio is first in our offer, by convention */
1873 // The audio_idx should not be changed here, as this function may be
1874 // called in generating re-offer and the current active audio index
1875 // can be anywhere.
1876 //call->audio_idx = 0;
1877 }
1878#endif
1879
1880#if 0
1881 // Since r3512, old-style hold should have got transport, created by
1882 // pjsua_media_channel_init() in initial offer/answer or remote reoffer.
1883 /* Create media if it's not created. This could happen when call is
1884 * currently on-hold (with the old style hold)
1885 */
1886 if (call->media[call->audio_idx].tp == NULL) {
1887 pjsip_role_e role;
1888 role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC);
1889 status = pjsua_media_channel_init(call_id, role, call->secure_level,
1890 pool, rem_sdp, sip_err_code);
1891 if (status != PJ_SUCCESS)
1892 return status;
1893 }
1894#endif
1895
1896 /* Get SDP negotiator state */
1897 if (call->inv && call->inv->neg)
1898 sdp_neg_state = pjmedia_sdp_neg_get_state(call->inv->neg);
1899
1900 /* Get one address to use in the origin field */
1901 pj_bzero(&origin, sizeof(origin));
1902 for (mi=0; mi<call->med_prov_cnt; ++mi) {
1903 pjmedia_transport_info tpinfo;
1904
1905 if (call->media_prov[mi].tp == NULL)
1906 continue;
1907
1908 pjmedia_transport_info_init(&tpinfo);
1909 pjmedia_transport_get_info(call->media_prov[mi].tp, &tpinfo);
1910 pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name);
1911 break;
1912 }
1913
1914 /* Create the base (blank) SDP */
1915 status = pjmedia_endpt_create_base_sdp(pjsua_var.med_endpt, pool, NULL,
1916 &origin, &sdp);
1917 if (status != PJ_SUCCESS)
1918 return status;
1919
1920 /* Process each media line */
1921 for (mi=0; mi<call->med_prov_cnt; ++mi) {
1922 pjsua_call_media *call_med = &call->media_prov[mi];
1923 pjmedia_sdp_media *m = NULL;
1924 pjmedia_transport_info tpinfo;
1925 unsigned i;
1926
1927 if (rem_sdp && mi >= rem_sdp->media_count) {
1928 /* Remote might have removed some media lines. */
1929 media_prov_clean_up(call->index, rem_sdp->media_count);
1930 call->med_prov_cnt = rem_sdp->media_count;
1931 break;
1932 }
1933
1934 if (call_med->tp == NULL || call_med->tp_st == PJSUA_MED_TP_DISABLED)
1935 {
1936 /*
1937 * This media is disabled. Just create a valid SDP with zero
1938 * port.
1939 */
1940 if (rem_sdp) {
1941 /* Just clone the remote media and deactivate it */
1942 m = pjmedia_sdp_media_clone_deactivate(pool,
1943 rem_sdp->media[mi]);
1944 } else {
1945 m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
1946 m->desc.transport = pj_str("RTP/AVP");
1947 m->desc.fmt_count = 1;
1948
1949 switch (call_med->type) {
1950 case PJMEDIA_TYPE_AUDIO:
1951 m->desc.media = pj_str("audio");
1952 m->desc.fmt[0] = pj_str("0");
1953 break;
1954 case PJMEDIA_TYPE_VIDEO:
1955 m->desc.media = pj_str("video");
1956 m->desc.fmt[0] = pj_str("31");
1957 break;
1958 default:
1959 /* This must be us generating re-offer, and some unknown
1960 * media may exist, so just clone from active local SDP
1961 * (and it should have been deactivated already).
1962 */
1963 pj_assert(call->inv && call->inv->neg &&
1964 sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE);
1965 {
1966 const pjmedia_sdp_session *s_;
1967 pjmedia_sdp_neg_get_active_local(call->inv->neg, &s_);
1968
1969 pj_assert(mi < s_->media_count);
1970 m = pjmedia_sdp_media_clone(pool, s_->media[mi]);
1971 m->desc.port = 0;
1972 }
1973 break;
1974 }
1975 }
1976
1977 /* Add connection line, if none */
1978 if (m->conn == NULL && sdp->conn == NULL) {
1979 pj_bool_t use_ipv6;
1980
1981 use_ipv6 = (pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
1982 PJSUA_IPV6_DISABLED);
1983
1984 m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
1985 m->conn->net_type = pj_str("IN");
1986 if (use_ipv6) {
1987 m->conn->addr_type = pj_str("IP6");
1988 m->conn->addr = pj_str("::1");
1989 } else {
1990 m->conn->addr_type = pj_str("IP4");
1991 m->conn->addr = pj_str("127.0.0.1");
1992 }
1993 }
1994
1995 sdp->media[sdp->media_count++] = m;
1996 continue;
1997 }
1998
1999 /* Get transport address info */
2000 pjmedia_transport_info_init(&tpinfo);
2001 pjmedia_transport_get_info(call_med->tp, &tpinfo);
2002
2003 /* Ask pjmedia endpoint to create SDP media line */
2004 switch (call_med->type) {
2005 case PJMEDIA_TYPE_AUDIO:
2006 status = pjmedia_endpt_create_audio_sdp(pjsua_var.med_endpt, pool,
2007 &tpinfo.sock_info, 0, &m);
2008 break;
2009#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
2010 case PJMEDIA_TYPE_VIDEO:
2011 status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool,
2012 &tpinfo.sock_info, 0, &m);
2013 break;
2014#endif
2015 default:
2016 pj_assert(!"Invalid call_med media type");
2017 return PJ_EBUG;
2018 }
2019
2020 if (status != PJ_SUCCESS)
2021 return status;
2022
2023 sdp->media[sdp->media_count++] = m;
2024
2025 /* Give to transport */
2026 status = pjmedia_transport_encode_sdp(call_med->tp, pool,
2027 sdp, rem_sdp, mi);
2028 if (status != PJ_SUCCESS) {
2029 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE;
2030 return status;
2031 }
2032
2033#if PJSUA_SDP_SESS_HAS_CONN
2034 /* Copy c= line of the first media to session level,
2035 * if there's none.
2036 */
2037 if (sdp->conn == NULL) {
2038 sdp->conn = pjmedia_sdp_conn_clone(pool, m->conn);
2039 }
2040#endif
2041
2042
2043 /* Find media bandwidth info */
2044 for (i = 0; i < m->bandw_count; ++i) {
2045 const pj_str_t STR_BANDW_MODIFIER_TIAS = { "TIAS", 4 };
2046 if (!pj_stricmp(&m->bandw[i]->modifier, &STR_BANDW_MODIFIER_TIAS))
2047 {
2048 tot_bandw_tias += m->bandw[i]->value;
2049 break;
2050 }
2051 }
2052 }
2053
2054 /* Add NAT info in the SDP */
2055 if (pjsua_var.ua_cfg.nat_type_in_sdp) {
2056 pjmedia_sdp_attr *a;
2057 pj_str_t value;
2058 char nat_info[80];
2059
2060 value.ptr = nat_info;
2061 if (pjsua_var.ua_cfg.nat_type_in_sdp == 1) {
2062 value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
2063 "%d", pjsua_var.nat_type);
2064 } else {
2065 const char *type_name = pj_stun_get_nat_name(pjsua_var.nat_type);
2066 value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
2067 "%d %s",
2068 pjsua_var.nat_type,
2069 type_name);
2070 }
2071
2072 a = pjmedia_sdp_attr_create(pool, "X-nat", &value);
2073
2074 pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a);
2075
2076 }
2077
2078
2079 /* Add bandwidth info in session level using bandwidth modifier "AS". */
2080 if (tot_bandw_tias) {
2081 unsigned bandw;
2082 const pj_str_t STR_BANDW_MODIFIER_AS = { "AS", 2 };
2083 pjmedia_sdp_bandw *b;
2084
2085 /* AS bandwidth = RTP bitrate + RTCP bitrate.
2086 * RTP bitrate = payload bitrate (total TIAS) + overheads (~16kbps).
2087 * RTCP bitrate = est. 5% of RTP bitrate.
2088 * Note that AS bandwidth is in kbps.
2089 */
2090 bandw = tot_bandw_tias + 16000;
2091 bandw += bandw * 5 / 100;
2092 b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
2093 b->modifier = STR_BANDW_MODIFIER_AS;
2094 b->value = bandw / 1000;
2095 sdp->bandw[sdp->bandw_count++] = b;
2096 }
2097
2098
2099#if DISABLED_FOR_TICKET_1185 && defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
2100 /* Check if SRTP is in optional mode and configured to use duplicated
2101 * media, i.e: secured and unsecured version, in the SDP offer.
2102 */
2103 if (!rem_sdp &&
2104 pjsua_var.acc[call->acc_id].cfg.use_srtp == PJMEDIA_SRTP_OPTIONAL &&
2105 pjsua_var.acc[call->acc_id].cfg.srtp_optional_dup_offer)
2106 {
2107 unsigned i;
2108
2109 for (i = 0; i < sdp->media_count; ++i) {
2110 pjmedia_sdp_media *m = sdp->media[i];
2111
2112 /* Check if this media is unsecured but has SDP "crypto"
2113 * attribute.
2114 */
2115 if (pj_stricmp2(&m->desc.transport, "RTP/AVP") == 0 &&
2116 pjmedia_sdp_media_find_attr2(m, "crypto", NULL) != NULL)
2117 {
2118 if (i == (unsigned)call->audio_idx &&
2119 sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE)
2120 {
2121 /* This is a session update, and peer has chosen the
2122 * unsecured version, so let's make this unsecured too.
2123 */
2124 pjmedia_sdp_media_remove_all_attr(m, "crypto");
2125 } else {
2126 /* This is new offer, duplicate media so we'll have
2127 * secured (with "RTP/SAVP" transport) and and unsecured
2128 * versions.
2129 */
2130 pjmedia_sdp_media *new_m;
2131
2132 /* Duplicate this media and apply secured transport */
2133 new_m = pjmedia_sdp_media_clone(pool, m);
2134 pj_strdup2(pool, &new_m->desc.transport, "RTP/SAVP");
2135
2136 /* Remove the "crypto" attribute in the unsecured media */
2137 pjmedia_sdp_media_remove_all_attr(m, "crypto");
2138
2139 /* Insert the new media before the unsecured media */
2140 if (sdp->media_count < PJMEDIA_MAX_SDP_MEDIA) {
2141 pj_array_insert(sdp->media, sizeof(new_m),
2142 sdp->media_count, i, &new_m);
2143 ++sdp->media_count;
2144 ++i;
2145 }
2146 }
2147 }
2148 }
2149 }
2150#endif
2151
2152 call->rem_offerer = (rem_sdp != NULL);
2153
2154 /* Notify application */
2155 if (pjsua_var.ua_cfg.cb.on_call_sdp_created) {
2156 (*pjsua_var.ua_cfg.cb.on_call_sdp_created)(call_id, sdp,
2157 pool, rem_sdp);
2158 }
2159
2160 *p_sdp = sdp;
2161 return PJ_SUCCESS;
2162}
2163
2164
2165static void stop_media_stream(pjsua_call *call, unsigned med_idx)
2166{
2167 pjsua_call_media *call_med = &call->media[med_idx];
2168
2169 /* Check if stream does not exist */
2170 if (med_idx >= call->med_cnt)
2171 return;
2172
2173 pj_log_push_indent();
2174
2175 if (call_med->type == PJMEDIA_TYPE_AUDIO) {
2176 pjsua_aud_stop_stream(call_med);
2177 }
2178
2179#if PJMEDIA_HAS_VIDEO
2180 else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
2181 pjsua_vid_stop_stream(call_med);
2182 }
2183#endif
2184
2185 PJ_LOG(4,(THIS_FILE, "Media stream call%02d:%d is destroyed",
2186 call->index, med_idx));
2187 call_med->prev_state = call_med->state;
2188 call_med->state = PJSUA_CALL_MEDIA_NONE;
2189
2190 /* Try to sync recent changes to provisional media */
2191 if (med_idx < call->med_prov_cnt &&
2192 call->media_prov[med_idx].tp == call_med->tp)
2193 {
2194 pjsua_call_media *prov_med = &call->media_prov[med_idx];
2195
2196 /* Media state */
2197 prov_med->prev_state = call_med->prev_state;
2198 prov_med->state = call_med->state;
2199
2200 /* RTP seq/ts */
2201 prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set;
2202 prov_med->rtp_tx_seq = call_med->rtp_tx_seq;
2203 prov_med->rtp_tx_ts = call_med->rtp_tx_ts;
2204
2205 /* Stream */
2206 if (call_med->type == PJMEDIA_TYPE_AUDIO) {
2207 prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot;
2208 prov_med->strm.a.stream = call_med->strm.a.stream;
2209 }
2210#if PJMEDIA_HAS_VIDEO
2211 else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
2212 prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id;
2213 prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id;
2214 prov_med->strm.v.stream = call_med->strm.v.stream;
2215 }
2216#endif
2217 }
2218
2219 pj_log_pop_indent();
2220}
2221
2222static void stop_media_session(pjsua_call_id call_id)
2223{
2224 pjsua_call *call = &pjsua_var.calls[call_id];
2225 unsigned mi;
2226
2227 for (mi=0; mi<call->med_cnt; ++mi) {
2228 stop_media_stream(call, mi);
2229 }
2230}
2231
2232pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
2233{
2234 pjsua_call *call = &pjsua_var.calls[call_id];
2235 unsigned mi;
2236
2237 for (mi=0; mi<call->med_cnt; ++mi) {
2238 pjsua_call_media *call_med = &call->media[mi];
2239
2240 if (call_med->tp_st == PJSUA_MED_TP_CREATING) {
2241 /* We will do the deinitialization after media transport
2242 * creation is completed.
2243 */
2244 call->async_call.med_ch_deinit = PJ_TRUE;
2245 return PJ_SUCCESS;
2246 }
2247 }
2248
2249 PJ_LOG(4,(THIS_FILE, "Call %d: deinitializing media..", call_id));
2250 pj_log_push_indent();
2251
2252 stop_media_session(call_id);
2253
2254 /* Clean up media transports */
2255 pjsua_media_prov_clean_up(call_id);
2256 call->med_prov_cnt = 0;
2257 for (mi=0; mi<call->med_cnt; ++mi) {
2258 pjsua_call_media *call_med = &call->media[mi];
2259
2260 if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
2261 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
2262 pjmedia_transport_media_stop(call_med->tp);
2263 }
2264
2265 if (call_med->tp) {
2266 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
2267 pjmedia_transport_close(call_med->tp);
2268 call_med->tp = call_med->tp_orig = NULL;
2269 }
2270 call_med->tp_orig = NULL;
2271 }
2272
2273 pj_log_pop_indent();
2274
2275 return PJ_SUCCESS;
2276}
2277
2278
2279/* Match codec fmtp. This will compare the values and the order. */
2280static pj_bool_t match_codec_fmtp(const pjmedia_codec_fmtp *fmtp1,
2281 const pjmedia_codec_fmtp *fmtp2)
2282{
2283 unsigned i;
2284
2285 if (fmtp1->cnt != fmtp2->cnt)
2286 return PJ_FALSE;
2287
2288 for (i = 0; i < fmtp1->cnt; ++i) {
2289 if (pj_stricmp(&fmtp1->param[i].name, &fmtp2->param[i].name))
2290 return PJ_FALSE;
2291 if (pj_stricmp(&fmtp1->param[i].val, &fmtp2->param[i].val))
2292 return PJ_FALSE;
2293 }
2294
2295 return PJ_TRUE;
2296}
2297
2298#if PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO
2299
2300static pj_bool_t is_ice_running(pjmedia_transport *tp)
2301{
2302 pjmedia_transport_info tpinfo;
2303 pjmedia_ice_transport_info *ice_info;
2304
2305 pjmedia_transport_info_init(&tpinfo);
2306 pjmedia_transport_get_info(tp, &tpinfo);
2307 ice_info = (pjmedia_ice_transport_info*)
2308 pjmedia_transport_info_get_spc_info(&tpinfo,
2309 PJMEDIA_TRANSPORT_TYPE_ICE);
2310 return (ice_info && ice_info->sess_state == PJ_ICE_STRANS_STATE_RUNNING);
2311}
2312
2313
2314static pj_bool_t is_media_changed(const pjsua_call *call,
2315 unsigned med_idx,
2316 const pjsua_stream_info *new_si_)
2317{
2318 const pjsua_call_media *call_med = &call->media[med_idx];
2319
2320 /* Check for newly added media */
2321 if (med_idx >= call->med_cnt)
2322 return PJ_TRUE;
2323
2324 /* Compare media type */
2325 if (call_med->type != new_si_->type)
2326 return PJ_TRUE;
2327
2328 /* Audio update checks */
2329 if (call_med->type == PJMEDIA_TYPE_AUDIO) {
2330 pjmedia_stream_info the_old_si;
2331 const pjmedia_stream_info *old_si = NULL;
2332 const pjmedia_stream_info *new_si = &new_si_->info.aud;
2333 const pjmedia_codec_info *old_ci = NULL;
2334 const pjmedia_codec_info *new_ci = &new_si->fmt;
2335 const pjmedia_codec_param *old_cp = NULL;
2336 const pjmedia_codec_param *new_cp = new_si->param;
2337
2338 /* Compare media direction */
2339 if (call_med->dir != new_si->dir)
2340 return PJ_TRUE;
2341
2342 /* Get current active stream info */
2343 if (call_med->strm.a.stream) {
2344 pjmedia_stream_get_info(call_med->strm.a.stream, &the_old_si);
2345 old_si = &the_old_si;
2346 old_ci = &old_si->fmt;
2347 old_cp = old_si->param;
2348 } else {
2349 /* The stream is inactive. */
2350 return (new_si->dir != PJMEDIA_DIR_NONE);
2351 }
2352
2353 /* Compare remote RTP address. If ICE is running, change in default
2354 * address can happen after negotiation, this can be handled
2355 * internally by ICE and does not need to cause media restart.
2356 */
2357 if (!is_ice_running(call_med->tp) &&
2358 pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
2359 {
2360 return PJ_TRUE;
2361 }
2362
2363 /* Compare codec info */
2364 if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) ||
2365 old_ci->clock_rate != new_ci->clock_rate ||
2366 old_ci->channel_cnt != new_ci->channel_cnt ||
2367 old_si->rx_pt != new_si->rx_pt ||
2368 old_si->tx_pt != new_si->tx_pt ||
2369 old_si->rx_event_pt != new_si->tx_event_pt ||
2370 old_si->tx_event_pt != new_si->tx_event_pt)
2371 {
2372 return PJ_TRUE;
2373 }
2374
2375 /* Compare codec param */
2376 if (old_cp->setting.frm_per_pkt != new_cp->setting.frm_per_pkt ||
2377 old_cp->setting.vad != new_cp->setting.vad ||
2378 old_cp->setting.cng != new_cp->setting.cng ||
2379 old_cp->setting.plc != new_cp->setting.plc ||
2380 old_cp->setting.penh != new_cp->setting.penh ||
2381 !match_codec_fmtp(&old_cp->setting.dec_fmtp,
2382 &new_cp->setting.dec_fmtp) ||
2383 !match_codec_fmtp(&old_cp->setting.enc_fmtp,
2384 &new_cp->setting.enc_fmtp))
2385 {
2386 return PJ_TRUE;
2387 }
2388 }
2389
2390#if PJMEDIA_HAS_VIDEO
2391 else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
2392 pjmedia_vid_stream_info the_old_si;
2393 const pjmedia_vid_stream_info *old_si = NULL;
2394 const pjmedia_vid_stream_info *new_si = &new_si_->info.vid;
2395 const pjmedia_vid_codec_info *old_ci = NULL;
2396 const pjmedia_vid_codec_info *new_ci = &new_si->codec_info;
2397 const pjmedia_vid_codec_param *old_cp = NULL;
2398 const pjmedia_vid_codec_param *new_cp = new_si->codec_param;
2399
2400 /* Compare media direction */
2401 if (call_med->dir != new_si->dir)
2402 return PJ_TRUE;
2403
2404 /* Get current active stream info */
2405 if (call_med->strm.v.stream) {
2406 pjmedia_vid_stream_get_info(call_med->strm.v.stream, &the_old_si);
2407 old_si = &the_old_si;
2408 old_ci = &old_si->codec_info;
2409 old_cp = old_si->codec_param;
2410 } else {
2411 /* The stream is inactive. */
2412 return (new_si->dir != PJMEDIA_DIR_NONE);
2413 }
2414
2415 /* Compare remote RTP address. If ICE is running, change in default
2416 * address can happen after negotiation, this can be handled
2417 * internally by ICE and does not need to cause media restart.
2418 */
2419 if (!is_ice_running(call_med->tp) &&
2420 pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
2421 {
2422 return PJ_TRUE;
2423 }
2424
2425 /* Compare codec info */
2426 if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) ||
2427 old_si->rx_pt != new_si->rx_pt ||
2428 old_si->tx_pt != new_si->tx_pt)
2429 {
2430 return PJ_TRUE;
2431 }
2432
2433 /* Compare codec param */
2434 if (/* old_cp->enc_mtu != new_cp->enc_mtu || */
2435 pj_memcmp(&old_cp->enc_fmt.det, &new_cp->enc_fmt.det,
2436 sizeof(pjmedia_video_format_detail)) ||
2437 !match_codec_fmtp(&old_cp->dec_fmtp, &new_cp->dec_fmtp) ||
2438 !match_codec_fmtp(&old_cp->enc_fmtp, &new_cp->enc_fmtp))
2439 {
2440 return PJ_TRUE;
2441 }
2442 }
2443
2444#endif
2445
2446 else {
2447 /* Just return PJ_TRUE for other media type */
2448 return PJ_TRUE;
2449 }
2450
2451 return PJ_FALSE;
2452}
2453
2454#else /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */
2455
2456static pj_bool_t is_media_changed(const pjsua_call *call,
2457 unsigned med_idx,
2458 const pjsua_stream_info *new_si_)
2459{
2460 PJ_UNUSED_ARG(call);
2461 PJ_UNUSED_ARG(med_idx);
2462 PJ_UNUSED_ARG(new_si_);
2463 /* Always assume that media has been changed */
2464 return PJ_TRUE;
2465}
2466
2467#endif /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */
2468
2469
2470pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
2471 const pjmedia_sdp_session *local_sdp,
2472 const pjmedia_sdp_session *remote_sdp)
2473{
2474 pjsua_call *call = &pjsua_var.calls[call_id];
2475 pjsua_acc *acc = &pjsua_var.acc[call->acc_id];
2476 pj_pool_t *tmp_pool = call->inv->pool_prov;
2477 unsigned mi;
2478 pj_bool_t got_media = PJ_FALSE;
2479 pj_status_t status = PJ_SUCCESS;
2480
2481 const pj_str_t STR_AUDIO = { "audio", 5 };
2482 const pj_str_t STR_VIDEO = { "video", 5 };
2483 pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA];
2484 unsigned maudcnt = PJ_ARRAY_SIZE(maudidx);
2485 unsigned mtotaudcnt = PJ_ARRAY_SIZE(maudidx);
2486 pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA];
2487 unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx);
2488 unsigned mtotvidcnt = PJ_ARRAY_SIZE(mvididx);
2489 pj_bool_t need_renego_sdp = PJ_FALSE;
2490
2491 if (pjsua_get_state() != PJSUA_STATE_RUNNING)
2492 return PJ_EBUSY;
2493
2494 PJ_LOG(4,(THIS_FILE, "Call %d: updating media..", call_id));
2495 pj_log_push_indent();
2496
2497 /* Destroy existing media session, if any. */
2498 //stop_media_session(call->index);
2499
2500 /* Call media count must be at least equal to SDP media. Note that
2501 * it may not be equal when remote removed any SDP media line.
2502 */
2503 pj_assert(call->med_prov_cnt >= local_sdp->media_count);
2504
2505 /* Reset audio_idx first */
2506 call->audio_idx = -1;
2507
2508 /* Sort audio/video based on "quality" */
2509 sort_media(local_sdp, &STR_AUDIO, acc->cfg.use_srtp,
2510 maudidx, &maudcnt, &mtotaudcnt);
2511#if PJMEDIA_HAS_VIDEO
2512 sort_media(local_sdp, &STR_VIDEO, acc->cfg.use_srtp,
2513 mvididx, &mvidcnt, &mtotvidcnt);
2514#else
2515 PJ_UNUSED_ARG(STR_VIDEO);
2516 mvidcnt = mtotvidcnt = 0;
2517#endif
2518
2519 /* Applying media count limitation. Note that in generating SDP answer,
2520 * no media count limitation applied, as we didn't know yet which media
2521 * would pass the SDP negotiation.
2522 */
2523 if (maudcnt > call->opt.aud_cnt || mvidcnt > call->opt.vid_cnt)
2524 {
2525 pjmedia_sdp_session *local_sdp2;
2526
2527 maudcnt = PJ_MIN(maudcnt, call->opt.aud_cnt);
2528 mvidcnt = PJ_MIN(mvidcnt, call->opt.vid_cnt);
2529 local_sdp2 = pjmedia_sdp_session_clone(tmp_pool, local_sdp);
2530
2531 for (mi=0; mi < local_sdp2->media_count; ++mi) {
2532 pjmedia_sdp_media *m = local_sdp2->media[mi];
2533
2534 if (m->desc.port == 0 ||
2535 pj_memchr(maudidx, mi, maudcnt*sizeof(maudidx[0])) ||
2536 pj_memchr(mvididx, mi, mvidcnt*sizeof(mvididx[0])))
2537 {
2538 continue;
2539 }
2540
2541 /* Deactivate this media */
2542 pjmedia_sdp_media_deactivate(tmp_pool, m);
2543 }
2544
2545 local_sdp = local_sdp2;
2546 need_renego_sdp = PJ_TRUE;
2547 }
2548
2549 /* Process each media stream */
2550 for (mi=0; mi < call->med_prov_cnt; ++mi) {
2551 pjsua_call_media *call_med = &call->media_prov[mi];
2552 pj_bool_t media_changed = PJ_FALSE;
2553
2554 if (mi >= local_sdp->media_count ||
2555 mi >= remote_sdp->media_count)
2556 {
2557 /* This may happen when remote removed any SDP media lines in
2558 * its re-offer.
2559 */
2560
2561 /* Stop stream */
2562 stop_media_stream(call, mi);
2563
2564 /* Close the media transport */
2565 if (call_med->tp) {
2566 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
2567 pjmedia_transport_close(call_med->tp);
2568 call_med->tp = call_med->tp_orig = NULL;
2569 }
2570 continue;
2571#if 0
2572 /* Something is wrong */
2573 PJ_LOG(1,(THIS_FILE, "Error updating media for call %d: "
2574 "invalid media index %d in SDP", call_id, mi));
2575 status = PJMEDIA_SDP_EINSDP;
2576 goto on_error;
2577#endif
2578 }
2579
2580 /* Apply media update action */
2581 if (call_med->type==PJMEDIA_TYPE_AUDIO) {
2582 pjmedia_stream_info the_si, *si = &the_si;
2583 pjsua_stream_info stream_info;
2584
2585 status = pjmedia_stream_info_from_sdp(
2586 si, tmp_pool, pjsua_var.med_endpt,
2587 local_sdp, remote_sdp, mi);
2588 if (status != PJ_SUCCESS) {
2589 PJ_PERROR(1,(THIS_FILE, status,
2590 "pjmedia_stream_info_from_sdp() failed "
2591 "for call_id %d media %d",
2592 call_id, mi));
2593 continue;
2594 }
2595
2596 /* Codec parameter of stream info (si->param) can be NULL if
2597 * the stream is rejected or disabled.
2598 */
2599 /* Override ptime, if this option is specified. */
2600 if (pjsua_var.media_cfg.ptime != 0 && si->param) {
2601 si->param->setting.frm_per_pkt = (pj_uint8_t)
2602 (pjsua_var.media_cfg.ptime / si->param->info.frm_ptime);
2603 if (si->param->setting.frm_per_pkt == 0)
2604 si->param->setting.frm_per_pkt = 1;
2605 }
2606
2607 /* Disable VAD, if this option is specified. */
2608 if (pjsua_var.media_cfg.no_vad && si->param) {
2609 si->param->setting.vad = 0;
2610 }
2611
2612 /* Check if this media is changed */
2613 stream_info.type = PJMEDIA_TYPE_AUDIO;
2614 stream_info.info.aud = the_si;
2615 if (pjsua_var.media_cfg.no_smart_media_update ||
2616 is_media_changed(call, mi, &stream_info))
2617 {
2618 media_changed = PJ_TRUE;
2619 /* Stop the media */
2620 stop_media_stream(call, mi);
2621 } else {
2622 PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (audio) unchanged.",
2623 call_id, mi));
2624 }
2625
2626 /* Check if no media is active */
2627 if (si->dir == PJMEDIA_DIR_NONE) {
2628
2629 /* Update call media state and direction */
2630 call_med->state = PJSUA_CALL_MEDIA_NONE;
2631 call_med->dir = PJMEDIA_DIR_NONE;
2632
2633 } else {
2634 pjmedia_transport_info tp_info;
2635 pjmedia_srtp_info *srtp_info;
2636
2637 /* Start/restart media transport based on info in SDP */
2638 status = pjmedia_transport_media_start(call_med->tp,
2639 tmp_pool, local_sdp,
2640 remote_sdp, mi);
2641 if (status != PJ_SUCCESS) {
2642 PJ_PERROR(1,(THIS_FILE, status,
2643 "pjmedia_transport_media_start() failed "
2644 "for call_id %d media %d",
2645 call_id, mi));
2646 continue;
2647 }
2648
2649 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_RUNNING);
2650
2651 /* Get remote SRTP usage policy */
2652 pjmedia_transport_info_init(&tp_info);
2653 pjmedia_transport_get_info(call_med->tp, &tp_info);
2654 srtp_info = (pjmedia_srtp_info*)
2655 pjmedia_transport_info_get_spc_info(
2656 &tp_info, PJMEDIA_TRANSPORT_TYPE_SRTP);
2657 if (srtp_info) {
2658 call_med->rem_srtp_use = srtp_info->peer_use;
2659 }
2660
2661 /* Update audio channel */
2662 if (media_changed) {
2663 status = pjsua_aud_channel_update(call_med,
2664 call->inv->pool, si,
2665 local_sdp, remote_sdp);
2666 if (status != PJ_SUCCESS) {
2667 PJ_PERROR(1,(THIS_FILE, status,
2668 "pjsua_aud_channel_update() failed "
2669 "for call_id %d media %d",
2670 call_id, mi));
2671 continue;
2672 }
2673 }
2674
2675 /* Call media direction */
2676 call_med->dir = si->dir;
2677
2678 /* Call media state */
2679 if (call->local_hold)
2680 call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD;
2681 else if (call_med->dir == PJMEDIA_DIR_DECODING)
2682 call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD;
2683 else
2684 call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
2685 }
2686
2687 /* Print info. */
2688 if (status == PJ_SUCCESS) {
2689 char info[80];
2690 int info_len = 0;
2691 int len;
2692 const char *dir;
2693
2694 switch (si->dir) {
2695 case PJMEDIA_DIR_NONE:
2696 dir = "inactive";
2697 break;
2698 case PJMEDIA_DIR_ENCODING:
2699 dir = "sendonly";
2700 break;
2701 case PJMEDIA_DIR_DECODING:
2702 dir = "recvonly";
2703 break;
2704 case PJMEDIA_DIR_ENCODING_DECODING:
2705 dir = "sendrecv";
2706 break;
2707 default:
2708 dir = "unknown";
2709 break;
2710 }
2711 len = pj_ansi_sprintf( info+info_len,
2712 ", stream #%d: %.*s (%s)", mi,
2713 (int)si->fmt.encoding_name.slen,
2714 si->fmt.encoding_name.ptr,
2715 dir);
2716 if (len > 0)
2717 info_len += len;
2718 PJ_LOG(4,(THIS_FILE,"Audio updated%s", info));
2719 }
2720
2721
2722 if (call->audio_idx==-1 && status==PJ_SUCCESS &&
2723 si->dir != PJMEDIA_DIR_NONE)
2724 {
2725 call->audio_idx = mi;
2726 }
2727
2728#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
2729 } else if (call_med->type==PJMEDIA_TYPE_VIDEO) {
2730 pjmedia_vid_stream_info the_si, *si = &the_si;
2731 pjsua_stream_info stream_info;
2732
2733 status = pjmedia_vid_stream_info_from_sdp(
2734 si, tmp_pool, pjsua_var.med_endpt,
2735 local_sdp, remote_sdp, mi);
2736 if (status != PJ_SUCCESS) {
2737 PJ_PERROR(1,(THIS_FILE, status,
2738 "pjmedia_vid_stream_info_from_sdp() failed "
2739 "for call_id %d media %d",
2740 call_id, mi));
2741 continue;
2742 }
2743
2744 /* Check if this media is changed */
2745 stream_info.type = PJMEDIA_TYPE_VIDEO;
2746 stream_info.info.vid = the_si;
2747 if (is_media_changed(call, mi, &stream_info)) {
2748 media_changed = PJ_TRUE;
2749 /* Stop the media */
2750 stop_media_stream(call, mi);
2751 } else {
2752 PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (video) unchanged.",
2753 call_id, mi));
2754 }
2755
2756 /* Check if no media is active */
2757 if (si->dir == PJMEDIA_DIR_NONE) {
2758
2759 /* Update call media state and direction */
2760 call_med->state = PJSUA_CALL_MEDIA_NONE;
2761 call_med->dir = PJMEDIA_DIR_NONE;
2762
2763 } else {
2764 pjmedia_transport_info tp_info;
2765 pjmedia_srtp_info *srtp_info;
2766
2767 /* Start/restart media transport */
2768 status = pjmedia_transport_media_start(call_med->tp,
2769 tmp_pool, local_sdp,
2770 remote_sdp, mi);
2771 if (status != PJ_SUCCESS) {
2772 PJ_PERROR(1,(THIS_FILE, status,
2773 "pjmedia_transport_media_start() failed "
2774 "for call_id %d media %d",
2775 call_id, mi));
2776 continue;
2777 }
2778
2779 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_RUNNING);
2780
2781 /* Get remote SRTP usage policy */
2782 pjmedia_transport_info_init(&tp_info);
2783 pjmedia_transport_get_info(call_med->tp, &tp_info);
2784 srtp_info = (pjmedia_srtp_info*)
2785 pjmedia_transport_info_get_spc_info(
2786 &tp_info, PJMEDIA_TRANSPORT_TYPE_SRTP);
2787 if (srtp_info) {
2788 call_med->rem_srtp_use = srtp_info->peer_use;
2789 }
2790
2791 /* Update audio channel */
2792 if (media_changed) {
2793 status = pjsua_vid_channel_update(call_med,
2794 call->inv->pool, si,
2795 local_sdp, remote_sdp);
2796 if (status != PJ_SUCCESS) {
2797 PJ_PERROR(1,(THIS_FILE, status,
2798 "pjsua_vid_channel_update() failed "
2799 "for call_id %d media %d",
2800 call_id, mi));
2801 continue;
2802 }
2803 }
2804
2805 /* Call media direction */
2806 call_med->dir = si->dir;
2807
2808 /* Call media state */
2809 if (call->local_hold)
2810 call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD;
2811 else if (call_med->dir == PJMEDIA_DIR_DECODING)
2812 call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD;
2813 else
2814 call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
2815 }
2816
2817 /* Print info. */
2818 {
2819 char info[80];
2820 int info_len = 0;
2821 int len;
2822 const char *dir;
2823
2824 switch (si->dir) {
2825 case PJMEDIA_DIR_NONE:
2826 dir = "inactive";
2827 break;
2828 case PJMEDIA_DIR_ENCODING:
2829 dir = "sendonly";
2830 break;
2831 case PJMEDIA_DIR_DECODING:
2832 dir = "recvonly";
2833 break;
2834 case PJMEDIA_DIR_ENCODING_DECODING:
2835 dir = "sendrecv";
2836 break;
2837 default:
2838 dir = "unknown";
2839 break;
2840 }
2841 len = pj_ansi_sprintf( info+info_len,
2842 ", stream #%d: %.*s (%s)", mi,
2843 (int)si->codec_info.encoding_name.slen,
2844 si->codec_info.encoding_name.ptr,
2845 dir);
2846 if (len > 0)
2847 info_len += len;
2848 PJ_LOG(4,(THIS_FILE,"Video updated%s", info));
2849 }
2850
2851#endif
2852 } else {
2853 status = PJMEDIA_EINVALIMEDIATYPE;
2854 }
2855
2856 /* Close the transport of deactivated media, need this here as media
2857 * can be deactivated by the SDP negotiation and the max media count
2858 * (account) setting.
2859 */
2860 if (local_sdp->media[mi]->desc.port==0 && call_med->tp) {
2861 pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
2862 pjmedia_transport_close(call_med->tp);
2863 call_med->tp = call_med->tp_orig = NULL;
2864 }
2865
2866 if (status != PJ_SUCCESS) {
2867 PJ_PERROR(1,(THIS_FILE, status, "Error updating media call%02d:%d",
2868 call_id, mi));
2869 } else {
2870 got_media = PJ_TRUE;
2871 }
2872 }
2873
2874 /* Update call media from provisional media */
2875 call->med_cnt = call->med_prov_cnt;
2876 pj_memcpy(call->media, call->media_prov,
2877 sizeof(call->media_prov[0]) * call->med_prov_cnt);
2878
2879 /* Perform SDP re-negotiation if needed. */
2880 if (got_media && need_renego_sdp) {
2881 pjmedia_sdp_neg *neg = call->inv->neg;
2882
2883 /* This should only happen when we are the answerer. */
2884 PJ_ASSERT_RETURN(neg && !pjmedia_sdp_neg_was_answer_remote(neg),
2885 PJMEDIA_SDPNEG_EINSTATE);
2886
2887 status = pjmedia_sdp_neg_set_remote_offer(tmp_pool, neg, remote_sdp);
2888 if (status != PJ_SUCCESS)
2889 goto on_error;
2890
2891 status = pjmedia_sdp_neg_set_local_answer(tmp_pool, neg, local_sdp);
2892 if (status != PJ_SUCCESS)
2893 goto on_error;
2894
2895 status = pjmedia_sdp_neg_negotiate(tmp_pool, neg, 0);
2896 if (status != PJ_SUCCESS)
2897 goto on_error;
2898 }
2899
2900 pj_log_pop_indent();
2901 return (got_media? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA);
2902
2903on_error:
2904 pj_log_pop_indent();
2905 return status;
2906}
2907
2908/*****************************************************************************
2909 * Codecs.
2910 */
2911
2912/*
2913 * Enum all supported codecs in the system.
2914 */
2915PJ_DEF(pj_status_t) pjsua_enum_codecs( pjsua_codec_info id[],
2916 unsigned *p_count )
2917{
2918 pjmedia_codec_mgr *codec_mgr;
2919 pjmedia_codec_info info[32];
2920 unsigned i, count, prio[32];
2921 pj_status_t status;
2922
2923 codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
2924 count = PJ_ARRAY_SIZE(info);
2925 status = pjmedia_codec_mgr_enum_codecs( codec_mgr, &count, info, prio);
2926 if (status != PJ_SUCCESS) {
2927 *p_count = 0;
2928 return status;
2929 }
2930
2931 if (count > *p_count) count = *p_count;
2932
2933 for (i=0; i<count; ++i) {
2934 pj_bzero(&id[i], sizeof(pjsua_codec_info));
2935
2936 pjmedia_codec_info_to_id(&info[i], id[i].buf_, sizeof(id[i].buf_));
2937 id[i].codec_id = pj_str(id[i].buf_);
2938 id[i].priority = (pj_uint8_t) prio[i];
2939 }
2940
2941 *p_count = count;
2942
2943 return PJ_SUCCESS;
2944}
2945
2946
2947/*
2948 * Change codec priority.
2949 */
2950PJ_DEF(pj_status_t) pjsua_codec_set_priority( const pj_str_t *codec_id,
2951 pj_uint8_t priority )
2952{
2953 const pj_str_t all = { NULL, 0 };
2954 pjmedia_codec_mgr *codec_mgr;
2955
2956 codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
2957
2958 if (codec_id->slen==1 && *codec_id->ptr=='*')
2959 codec_id = &all;
2960
2961 return pjmedia_codec_mgr_set_codec_priority(codec_mgr, codec_id,
2962 priority);
2963}
2964
2965
2966/*
2967 * Get codec parameters.
2968 */
2969PJ_DEF(pj_status_t) pjsua_codec_get_param( const pj_str_t *codec_id,
2970 pjmedia_codec_param *param )
2971{
2972 const pj_str_t all = { NULL, 0 };
2973 const pjmedia_codec_info *info;
2974 pjmedia_codec_mgr *codec_mgr;
2975 unsigned count = 1;
2976 pj_status_t status;
2977
2978 codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
2979
2980 if (codec_id->slen==1 && *codec_id->ptr=='*')
2981 codec_id = &all;
2982
2983 status = pjmedia_codec_mgr_find_codecs_by_id(codec_mgr, codec_id,
2984 &count, &info, NULL);
2985 if (status != PJ_SUCCESS)
2986 return status;
2987
2988 if (count != 1)
2989 return (count > 1? PJ_ETOOMANY : PJ_ENOTFOUND);
2990
2991 status = pjmedia_codec_mgr_get_default_param( codec_mgr, info, param);
2992 return status;
2993}
2994
2995
2996/*
2997 * Set codec parameters.
2998 */
2999PJ_DEF(pj_status_t) pjsua_codec_set_param( const pj_str_t *codec_id,
3000 const pjmedia_codec_param *param)
3001{
3002 const pjmedia_codec_info *info[2];
3003 pjmedia_codec_mgr *codec_mgr;
3004 unsigned count = 2;
3005 pj_status_t status;
3006
3007 codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
3008
3009 status = pjmedia_codec_mgr_find_codecs_by_id(codec_mgr, codec_id,
3010 &count, info, NULL);
3011 if (status != PJ_SUCCESS)
3012 return status;
3013
3014 /* Codec ID should be specific, except for G.722.1 */
3015 if (count > 1 &&
3016 pj_strnicmp2(codec_id, "G7221/16", 8) != 0 &&
3017 pj_strnicmp2(codec_id, "G7221/32", 8) != 0)
3018 {
3019 pj_assert(!"Codec ID is not specific");
3020 return PJ_ETOOMANY;
3021 }
3022
3023 status = pjmedia_codec_mgr_set_default_param(codec_mgr, info[0], param);
3024 return status;
3025}
3026
3027
3028pj_status_t pjsua_media_apply_xml_control(pjsua_call_id call_id,
3029 const pj_str_t *xml_st)
3030{
3031#if PJMEDIA_HAS_VIDEO
3032 pjsua_call *call = &pjsua_var.calls[call_id];
3033 const pj_str_t PICT_FAST_UPDATE = {"picture_fast_update", 19};
3034
3035 if (pj_strstr(xml_st, &PICT_FAST_UPDATE)) {
3036 unsigned i;
3037
3038 PJ_LOG(4,(THIS_FILE, "Received keyframe request via SIP INFO"));
3039
3040 for (i = 0; i < call->med_cnt; ++i) {
3041 pjsua_call_media *cm = &call->media[i];
3042 if (cm->type != PJMEDIA_TYPE_VIDEO || !cm->strm.v.stream)
3043 continue;
3044
3045 pjmedia_vid_stream_send_keyframe(cm->strm.v.stream);
3046 }
3047
3048 return PJ_SUCCESS;
3049 }
3050#endif
3051
3052 /* Just to avoid compiler warning of unused var */
3053 PJ_UNUSED_ARG(call_id);
3054 PJ_UNUSED_ARG(xml_st);
3055
3056 return PJ_ENOTSUP;
3057}
3058