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