1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <pjsua-lib/pjsua.h>
21 #include <pjsua-lib/pjsua_internal.h>
22 
23 
24 #define THIS_FILE		"pjsua_media.c"
25 
26 #ifndef PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT
27 #   define PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT	0
28 #endif
29 
30 static void stop_media_stream(pjsua_call *call, unsigned med_idx);
31 
pjsua_media_config_dup(pj_pool_t * pool,pjsua_media_config * dst,const pjsua_media_config * src)32 static 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 #if PJ_HAS_SSL_SOCK
40     pj_turn_sock_tls_cfg_dup(pool, &dst->turn_tls_setting,
41 			     &src->turn_tls_setting);
42 #endif
43 }
44 
45 
46 /**
47  * Init media subsystems.
48  */
pjsua_media_subsys_init(const pjsua_media_config * cfg)49 pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg)
50 {
51     pj_status_t status;
52 
53     pj_log_push_indent();
54 
55     /* Specify which audio device settings are save-able */
56     pjsua_var.aud_svmask = 0xFFFFFFFF;
57     /* These are not-settable */
58     pjsua_var.aud_svmask &= ~(PJMEDIA_AUD_DEV_CAP_EXT_FORMAT |
59 			      PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER |
60 			      PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER);
61     /* EC settings use different API */
62     pjsua_var.aud_svmask &= ~(PJMEDIA_AUD_DEV_CAP_EC |
63 			      PJMEDIA_AUD_DEV_CAP_EC_TAIL);
64 
65     /* Copy configuration */
66     pjsua_media_config_dup(pjsua_var.pool, &pjsua_var.media_cfg, cfg);
67 
68     /* Normalize configuration */
69     if (pjsua_var.media_cfg.snd_clock_rate == 0) {
70 	pjsua_var.media_cfg.snd_clock_rate = pjsua_var.media_cfg.clock_rate;
71     }
72 
73     if (pjsua_var.media_cfg.has_ioqueue &&
74 	pjsua_var.media_cfg.thread_cnt == 0)
75     {
76 	pjsua_var.media_cfg.thread_cnt = 1;
77     }
78 
79     if (pjsua_var.media_cfg.max_media_ports < pjsua_var.ua_cfg.max_calls) {
80 	pjsua_var.media_cfg.max_media_ports = pjsua_var.ua_cfg.max_calls + 2;
81     }
82 
83     /* Create media endpoint. */
84     status = pjmedia_endpt_create(&pjsua_var.cp.factory,
85 				  pjsua_var.media_cfg.has_ioqueue? NULL :
86 				     pjsip_endpt_get_ioqueue(pjsua_var.endpt),
87 				  pjsua_var.media_cfg.thread_cnt,
88 				  &pjsua_var.med_endpt);
89     if (status != PJ_SUCCESS) {
90 	pjsua_perror(THIS_FILE,
91 		     "Media stack initialization has returned error",
92 		     status);
93 	goto on_error;
94     }
95 
96     status = pjsua_aud_subsys_init();
97     if (status != PJ_SUCCESS)
98 	goto on_error;
99 
100 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
101     /* Initialize SRTP library (ticket #788). */
102     status = pjmedia_srtp_init_lib(pjsua_var.med_endpt);
103     if (status != PJ_SUCCESS) {
104 	pjsua_perror(THIS_FILE, "Error initializing SRTP library",
105 		     status);
106 	goto on_error;
107     }
108 #endif
109 
110     /* Video */
111 #if PJMEDIA_HAS_VIDEO
112     status = pjsua_vid_subsys_init();
113     if (status != PJ_SUCCESS)
114 	goto on_error;
115 #endif
116 
117     /* Create event manager */
118     if (!pjmedia_event_mgr_instance()) {
119 	status = pjmedia_event_mgr_create(pjsua_var.pool, 0, NULL);
120 	if (status != PJ_SUCCESS) {
121 	    pjsua_perror(THIS_FILE, "Error creating PJMEDIA event manager",
122 			 status);
123 	    goto on_error;
124 	}
125     }
126 
127     pj_log_pop_indent();
128     return PJ_SUCCESS;
129 
130 on_error:
131     pj_log_pop_indent();
132     return status;
133 }
134 
135 /*
136  * Start pjsua media subsystem.
137  */
pjsua_media_subsys_start(void)138 pj_status_t pjsua_media_subsys_start(void)
139 {
140     pj_status_t status;
141 
142     pj_log_push_indent();
143 
144 #if DISABLED_FOR_TICKET_1185
145     /* Create media for calls, if none is specified */
146     if (pjsua_var.calls[0].media[0].tp == NULL) {
147 	pjsua_transport_config transport_cfg;
148 
149 	/* Create default transport config */
150 	pjsua_transport_config_default(&transport_cfg);
151 	transport_cfg.port = DEFAULT_RTP_PORT;
152 
153 	status = pjsua_media_transports_create(&transport_cfg);
154 	if (status != PJ_SUCCESS) {
155 	    pj_log_pop_indent();
156 	    return status;
157 	}
158     }
159 #endif
160 
161     /* Audio */
162     status = pjsua_aud_subsys_start();
163     if (status != PJ_SUCCESS) {
164 	pj_log_pop_indent();
165 	return status;
166     }
167 
168     /* Video */
169 #if PJMEDIA_HAS_VIDEO
170     status = pjsua_vid_subsys_start();
171     if (status != PJ_SUCCESS) {
172 	pjsua_aud_subsys_destroy();
173 	pj_log_pop_indent();
174 	return status;
175     }
176 #endif
177 
178     /* Perform NAT detection */
179     // Performed only when STUN server resolution by pjsua_init() completed
180     // successfully (see ticket #1865).
181     //if (pjsua_var.ua_cfg.stun_srv_cnt) {
182 	//status = pjsua_detect_nat_type();
183 	//if (status != PJ_SUCCESS) {
184 	//    PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed"));
185 	//}
186     //}
187 
188     pj_log_pop_indent();
189     return PJ_SUCCESS;
190 }
191 
192 
193 /*
194  * Destroy pjsua media subsystem.
195  */
pjsua_media_subsys_destroy(unsigned flags)196 pj_status_t pjsua_media_subsys_destroy(unsigned flags)
197 {
198     PJ_UNUSED_ARG(flags);
199 
200     PJ_LOG(4,(THIS_FILE, "Shutting down media.."));
201     pj_log_push_indent();
202 
203     if (pjsua_var.med_endpt) {
204         /* Wait for media endpoint's worker threads to quit. */
205         pjmedia_endpt_stop_threads(pjsua_var.med_endpt);
206 
207 	pjsua_aud_subsys_destroy();
208     }
209 
210 #if 0
211     // This part has been moved out to pjsua_destroy() (see also #1717).
212     /* Close media transports */
213     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
214         /* TODO: check if we're not allowed to send to network in the
215          *       "flags", and if so do not do TURN allocation...
216          */
217 	PJ_UNUSED_ARG(flags);
218 	pjsua_media_channel_deinit(i);
219     }
220 #endif
221 
222     /* Destroy media endpoint. */
223     if (pjsua_var.med_endpt) {
224 
225 #	if PJMEDIA_HAS_VIDEO
226 	    pjsua_vid_subsys_destroy();
227 #	endif
228 
229 	pjmedia_endpt_destroy(pjsua_var.med_endpt);
230 	pjsua_var.med_endpt = NULL;
231 
232 	/* Deinitialize sound subsystem */
233 	// Not necessary, as pjmedia_snd_deinit() should have been called
234 	// in pjmedia_endpt_destroy().
235 	//pjmedia_snd_deinit();
236     }
237 
238     if (pjmedia_event_mgr_instance())
239 	pjmedia_event_mgr_destroy(NULL);
240 
241     pj_log_pop_indent();
242 
243     return PJ_SUCCESS;
244 }
245 
246 /*
247  * Create RTP and RTCP socket pair, and possibly resolve their public
248  * address via STUN.
249  */
create_rtp_rtcp_sock(pjsua_call_media * call_med,const pjsua_transport_config * cfg,pjmedia_sock_info * skinfo)250 static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
251 					const pjsua_transport_config *cfg,
252 					pjmedia_sock_info *skinfo)
253 {
254     enum {
255 	RTP_RETRY = 100
256     };
257     int i;
258     pj_bool_t use_ipv6, use_nat64;
259     int af;
260     pj_sockaddr bound_addr;
261     pj_sockaddr mapped_addr[2];
262     pj_status_t status = PJ_SUCCESS;
263     char addr_buf[PJ_INET6_ADDRSTRLEN+10];
264     pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
265     pj_sock_t sock[2];
266 
267     use_ipv6 = (acc->cfg.ipv6_media_use != PJSUA_IPV6_DISABLED);
268     use_nat64 = (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED);
269     af = (use_ipv6 || use_nat64) ? pj_AF_INET6() : pj_AF_INET();
270 
271     /* Make sure STUN server resolution has completed */
272     if ((!use_ipv6 || use_nat64) &&
273         pjsua_media_acc_is_using_stun(call_med->call->acc_id))
274     {
275 	pj_bool_t retry_stun = (acc->cfg.media_stun_use &
276 				PJSUA_STUN_RETRY_ON_FAILURE) ==
277 				PJSUA_STUN_RETRY_ON_FAILURE;
278 	status = resolve_stun_server(PJ_TRUE, retry_stun,
279 				     (unsigned)acc->cfg.nat64_opt);
280 	if (status != PJ_SUCCESS) {
281 	    pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
282 	    return status;
283 	}
284     }
285 
286     if (acc->next_rtp_port == 0 || cfg->port == 0)
287 	acc->next_rtp_port = (pj_uint16_t)cfg->port;
288 
289     for (i=0; i<2; ++i)
290 	sock[i] = PJ_INVALID_SOCKET;
291 
292     pj_sockaddr_init(af, &bound_addr, NULL, 0);
293     if (cfg->bound_addr.slen) {
294 	status = pj_sockaddr_set_str_addr(af, &bound_addr, &cfg->bound_addr);
295 	if (status != PJ_SUCCESS) {
296 	    pjsua_perror(THIS_FILE, "Unable to resolve transport bind address",
297 			 status);
298 	    return status;
299 	}
300     }
301 
302     /* Loop retry to bind RTP and RTCP sockets. */
303     for (i=0; i<RTP_RETRY; ++i, acc->next_rtp_port += 2) {
304 
305         if (cfg->port > 0 && cfg->port_range > 0 &&
306             (acc->next_rtp_port > cfg->port + cfg->port_range ||
307              acc->next_rtp_port < cfg->port))
308         {
309             acc->next_rtp_port = (pj_uint16_t)cfg->port;
310         }
311 
312 	/* Create RTP socket. */
313 	status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock[0]);
314 	if (status != PJ_SUCCESS) {
315 	    pjsua_perror(THIS_FILE, "socket() error", status);
316 	    return status;
317 	}
318 
319 	/* Apply QoS to RTP socket, if specified */
320 	status = pj_sock_apply_qos2(sock[0], cfg->qos_type,
321 				    &cfg->qos_params,
322 				    2, THIS_FILE, "RTP socket");
323 
324 	/* Apply sockopt, if specified */
325 	if (cfg->sockopt_params.cnt)
326 	    status = pj_sock_setsockopt_params(sock[0], &cfg->sockopt_params);
327 
328 	/* Bind RTP socket */
329 	pj_sockaddr_set_port(&bound_addr, acc->next_rtp_port);
330 	status=pj_sock_bind(sock[0], &bound_addr,
331 	                    pj_sockaddr_get_len(&bound_addr));
332 	if (status != PJ_SUCCESS) {
333 	    pj_sock_close(sock[0]);
334 	    sock[0] = PJ_INVALID_SOCKET;
335 	    continue;
336 	}
337 
338 	/* If bound to random port, find out the port number. */
339 	if (acc->next_rtp_port == 0) {
340 	    pj_sockaddr sock_addr;
341 	    int addr_len = sizeof(pj_sockaddr);
342 
343             status = pj_sock_getsockname(sock[0], &sock_addr, &addr_len);
344 	    if (status != PJ_SUCCESS) {
345 	    	pjsua_perror(THIS_FILE, "getsockname() error", status);
346 	    	pj_sock_close(sock[0]);
347 	    	return status;
348 	    }
349 	    acc->next_rtp_port = pj_sockaddr_get_port(&sock_addr);
350 	}
351 
352 	/* Create RTCP socket. */
353 	status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock[1]);
354 	if (status != PJ_SUCCESS) {
355 	    pjsua_perror(THIS_FILE, "socket() error", status);
356 	    pj_sock_close(sock[0]);
357 	    return status;
358 	}
359 
360 	/* Apply QoS to RTCP socket, if specified */
361 	status = pj_sock_apply_qos2(sock[1], cfg->qos_type,
362 				    &cfg->qos_params,
363 				    2, THIS_FILE, "RTCP socket");
364 
365 	/* Apply sockopt, if specified */
366 	if (cfg->sockopt_params.cnt)
367 	    status = pj_sock_setsockopt_params(sock[1], &cfg->sockopt_params);
368 
369 	/* Bind RTCP socket */
370 	pj_sockaddr_set_port(&bound_addr, (pj_uint16_t)(acc->next_rtp_port+1));
371 	status=pj_sock_bind(sock[1], &bound_addr,
372 	                    pj_sockaddr_get_len(&bound_addr));
373 	if (status != PJ_SUCCESS) {
374 	    pj_sock_close(sock[0]);
375 	    sock[0] = PJ_INVALID_SOCKET;
376 
377 	    pj_sock_close(sock[1]);
378 	    sock[1] = PJ_INVALID_SOCKET;
379 	    continue;
380 	}
381 
382 	/*
383 	 * If we're configured to use STUN, then find out the mapped address,
384 	 * and make sure that the mapped RTCP port is adjacent with the RTP.
385 	 */
386 	if ((!use_ipv6 || use_nat64) &&
387 	    pjsua_media_acc_is_using_stun(call_med->call->acc_id) &&
388 	    pjsua_var.stun_srv.addr.sa_family != 0)
389 	{
390 	    char ip_addr[PJ_INET6_ADDRSTRLEN];
391 	    pj_str_t stun_srv;
392 	    pj_sockaddr_in resolved_addr[2];
393 	    pjstun_setting stun_opt;
394 
395 	    pj_sockaddr_print(&pjsua_var.stun_srv, ip_addr,sizeof(ip_addr),0);
396 	    stun_srv = pj_str(ip_addr);
397 
398 	    pj_bzero(&stun_opt, sizeof(stun_opt));
399 	    stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
400 	    stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
401 	    stun_opt.srv1  = stun_opt.srv2  = stun_srv;
402 	    stun_opt.port1 = stun_opt.port2 =
403 			     pj_sockaddr_get_port(&pjsua_var.stun_srv);
404 	    status=pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
405 					   2, sock, resolved_addr);
406 #if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
407 	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
408 	    /* Handle EPIPE (Broken Pipe) error, which happens on UDP socket
409 	     * after app wakes up from suspended state. In this case, simply
410 	     * just retry.
411 	     * P.S.: The magic status is PJ_STATUS_FROM_OS(EPIPE)
412 	     */
413 	    if (status == 120032) {
414 		PJ_LOG(4,(THIS_FILE, "Got EPIPE error, retrying.."));
415 		pj_sock_close(sock[0]);
416 		sock[0] = PJ_INVALID_SOCKET;
417 
418 		pj_sock_close(sock[1]);
419 		sock[1] = PJ_INVALID_SOCKET;
420 
421 		continue;
422 	    }
423 	    else
424 #endif
425 
426 	    if (status != PJ_SUCCESS && pjsua_var.ua_cfg.stun_srv_cnt > 1 &&
427 	        ((acc->cfg.media_stun_use & PJSUA_STUN_RETRY_ON_FAILURE)==
428 		  PJSUA_STUN_RETRY_ON_FAILURE))
429 	    {
430 		pj_str_t srv =
431 			     pjsua_var.ua_cfg.stun_srv[pjsua_var.stun_srv_idx];
432 
433 		PJ_LOG(4,(THIS_FILE, "Failed to get STUN mapped address, "
434 		       "retrying other STUN servers"));
435 
436 		if (pjsua_var.stun_srv_idx < pjsua_var.ua_cfg.stun_srv_cnt-1) {
437 		    PJSUA_LOCK();
438 		    /* Move the unusable STUN server to the last position
439 		     * as the least prioritize.
440 		     */
441 		    pj_array_erase(pjsua_var.ua_cfg.stun_srv,
442 				   sizeof(pj_str_t),
443 				   pjsua_var.ua_cfg.stun_srv_cnt,
444 				   pjsua_var.stun_srv_idx);
445 
446 		    pj_array_insert(pjsua_var.ua_cfg.stun_srv,
447 				    sizeof(pj_str_t),
448 				    pjsua_var.ua_cfg.stun_srv_cnt-1,
449 				    pjsua_var.ua_cfg.stun_srv_cnt-1,
450 				    &srv);
451 
452 		    PJSUA_UNLOCK();
453 		}
454 	    	status=pjsua_update_stun_servers(pjsua_var.ua_cfg.stun_srv_cnt,
455 	    			   	    	 pjsua_var.ua_cfg.stun_srv,
456 	    			   	    	 PJ_TRUE);
457 	    	if (status == PJ_SUCCESS) {
458 		    if (pjsua_var.stun_srv.addr.sa_family != 0) {
459     			pj_sockaddr_print(&pjsua_var.stun_srv,
460     		     		     	  ip_addr, sizeof(ip_addr), 0);
461 			stun_srv = pj_str(ip_addr);
462 	    	    } else {
463 		    	stun_srv.slen = 0;
464     	            }
465 
466     	            stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
467     	            stun_opt.srv1  = stun_opt.srv2  = stun_srv;
468 	            stun_opt.port1 = stun_opt.port2 =
469 			        pj_sockaddr_get_port(&pjsua_var.stun_srv);
470 	    	    status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory,
471 	    				  	     &stun_opt, 2, sock,
472 	    				    	     resolved_addr);
473 	        }
474 	    }
475 
476 	    if (status != PJ_SUCCESS) {
477 		if (!pjsua_var.ua_cfg.stun_ignore_failure) {
478 		    pjsua_perror(THIS_FILE, "STUN resolve error", status);
479 		    goto on_error;
480 		}
481 
482 		PJ_LOG(4,(THIS_FILE, "Ignoring STUN resolve error %d",
483 		          status));
484 
485 		if (!pj_sockaddr_has_addr(&bound_addr)) {
486 		    pj_sockaddr addr;
487 
488 		    /* Get local IP address. */
489 		    status = pj_gethostip(af, &addr);
490 		    if (status != PJ_SUCCESS)
491 			goto on_error;
492 
493 		    pj_sockaddr_copy_addr(&bound_addr, &addr);
494 		}
495 
496 		for (i=0; i<2; ++i) {
497 		    pj_sockaddr_init(af, &mapped_addr[i], NULL, 0);
498 		    pj_sockaddr_copy_addr(&mapped_addr[i], &bound_addr);
499 		    pj_sockaddr_set_port(&mapped_addr[i],
500 					 (pj_uint16_t)(acc->next_rtp_port+i));
501 		}
502 		break;
503 	    }
504 
505 	    pj_sockaddr_cp(&mapped_addr[0], &resolved_addr[0]);
506 	    pj_sockaddr_cp(&mapped_addr[1], &resolved_addr[1]);
507 
508 #if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT
509 	    if (pj_sockaddr_get_port(&mapped_addr[1]) ==
510 		pj_sockaddr_get_port(&mapped_addr[0])+1)
511 	    {
512 		/* Success! */
513 		break;
514 	    }
515 
516 	    pj_sock_close(sock[0]);
517 	    sock[0] = PJ_INVALID_SOCKET;
518 
519 	    pj_sock_close(sock[1]);
520 	    sock[1] = PJ_INVALID_SOCKET;
521 #else
522 	    if (pj_sockaddr_get_port(&mapped_addr[1]) !=
523 		pj_sockaddr_get_port(&mapped_addr[0])+1)
524 	    {
525 		PJ_LOG(4,(THIS_FILE,
526 			  "Note: STUN mapped RTCP port %d is not adjacent"
527 			  " to RTP port %d",
528 			  pj_sockaddr_get_port(&mapped_addr[1]),
529 			  pj_sockaddr_get_port(&mapped_addr[0])));
530 	    }
531 	    /* Success! */
532 	    break;
533 #endif
534 
535 	} else if (cfg->public_addr.slen) {
536 
537 	    status = pj_sockaddr_init(af, &mapped_addr[0], &cfg->public_addr,
538 				      (pj_uint16_t)acc->next_rtp_port);
539 	    if (status != PJ_SUCCESS)
540 		goto on_error;
541 
542 	    status = pj_sockaddr_init(af, &mapped_addr[1], &cfg->public_addr,
543 				      (pj_uint16_t)(acc->next_rtp_port+1));
544 	    if (status != PJ_SUCCESS)
545 		goto on_error;
546 
547 	    break;
548 
549 	} else {
550 	    if (acc->cfg.allow_sdp_nat_rewrite && acc->reg_mapped_addr.slen) {
551 		pj_status_t status2;
552 
553 		/* Take the address from mapped addr as seen by registrar */
554 		status2 = pj_sockaddr_set_str_addr(af, &bound_addr,
555 		                                   &acc->reg_mapped_addr);
556 		if (status2 != PJ_SUCCESS) {
557 		    /* just leave bound_addr with whatever it was
558 		    pj_bzero(pj_sockaddr_get_addr(&bound_addr),
559 		             pj_sockaddr_get_addr_len(&bound_addr));
560 		     */
561 		}
562 	    }
563 
564 	    if (!pj_sockaddr_has_addr(&bound_addr)) {
565 		pj_sockaddr addr;
566 
567 		/* Get local IP address. */
568 		status = pj_gethostip(af, &addr);
569 		if (status != PJ_SUCCESS)
570 		    goto on_error;
571 
572 		pj_sockaddr_copy_addr(&bound_addr, &addr);
573 	    }
574 
575 	    for (i=0; i<2; ++i) {
576 		pj_sockaddr_init(af, &mapped_addr[i], NULL, 0);
577 		pj_sockaddr_copy_addr(&mapped_addr[i], &bound_addr);
578 		pj_sockaddr_set_port(&mapped_addr[i],
579 		                     (pj_uint16_t)(acc->next_rtp_port+i));
580 	    }
581 
582 	    break;
583 	}
584     }
585 
586     if (sock[0] == PJ_INVALID_SOCKET) {
587 	PJ_LOG(1,(THIS_FILE,
588 		  "Unable to find appropriate RTP/RTCP ports combination"));
589 	goto on_error;
590     }
591 
592 
593     skinfo->rtp_sock = sock[0];
594     pj_sockaddr_cp(&skinfo->rtp_addr_name, &mapped_addr[0]);
595 
596     skinfo->rtcp_sock = sock[1];
597     pj_sockaddr_cp(&skinfo->rtcp_addr_name, &mapped_addr[1]);
598 
599     PJ_LOG(4,(THIS_FILE, "RTP%s socket reachable at %s",
600 	      (call_med->enable_rtcp_mux? " & RTCP": ""),
601 	      pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf,
602 				sizeof(addr_buf), 3)));
603     PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s",
604 	      pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf,
605 				sizeof(addr_buf), 3)));
606 
607     acc->next_rtp_port += 2;
608     return PJ_SUCCESS;
609 
610 on_error:
611     for (i=0; i<2; ++i) {
612 	if (sock[i] != PJ_INVALID_SOCKET)
613 	    pj_sock_close(sock[i]);
614     }
615     return status;
616 }
617 
618 /* Create normal UDP media transports */
create_udp_media_transport(const pjsua_transport_config * cfg,pjsua_call_media * call_med)619 static pj_status_t create_udp_media_transport(const pjsua_transport_config *cfg,
620 					      pjsua_call_media *call_med)
621 {
622     pjmedia_sock_info skinfo;
623     pj_status_t status;
624 
625     status = create_rtp_rtcp_sock(call_med, cfg, &skinfo);
626     if (status != PJ_SUCCESS) {
627 	pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket",
628 		     status);
629 	goto on_error;
630     }
631 
632     status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL,
633 					  &skinfo, 0, &call_med->tp);
634     if (status != PJ_SUCCESS) {
635 	pjsua_perror(THIS_FILE, "Unable to create media transport",
636 		     status);
637 	goto on_error;
638     }
639 
640     pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
641 				    pjsua_var.media_cfg.tx_drop_pct);
642 
643     pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
644 				    pjsua_var.media_cfg.rx_drop_pct);
645 
646     call_med->tp_ready = PJ_SUCCESS;
647 
648     return PJ_SUCCESS;
649 
650 on_error:
651     if (call_med->tp)
652 	pjmedia_transport_close(call_med->tp);
653 
654     return status;
655 }
656 
657 /* Create loop media transport */
create_loop_media_transport(const pjsua_transport_config * cfg,pjsua_call_media * call_med)658 static pj_status_t create_loop_media_transport(
659 		       const pjsua_transport_config *cfg,
660 		       pjsua_call_media *call_med)
661 {
662     pj_status_t status;
663     pjmedia_loop_tp_setting opt;
664     pj_bool_t use_ipv6, use_nat64;
665     int af;
666     pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
667 
668     use_ipv6 = (acc->cfg.ipv6_media_use != PJSUA_IPV6_DISABLED);
669     use_nat64 = (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED);
670     af = (use_ipv6 || use_nat64) ? pj_AF_INET6() : pj_AF_INET();
671 
672     pjmedia_loop_tp_setting_default(&opt);
673     opt.af = af;
674     if (cfg->bound_addr.slen)
675         opt.addr = cfg->bound_addr;
676 
677     if (acc->next_rtp_port == 0 || cfg->port == 0)
678 	acc->next_rtp_port = (pj_uint16_t)cfg->port;
679 
680     if (cfg->port > 0 && cfg->port_range > 0 &&
681         (acc->next_rtp_port > cfg->port + cfg->port_range ||
682          acc->next_rtp_port < cfg->port))
683     {
684         acc->next_rtp_port = (pj_uint16_t)cfg->port;
685     }
686     opt.port = acc->next_rtp_port;
687     acc->next_rtp_port += 2;
688 
689     opt.disable_rx=!pjsua_var.acc[call_med->call->acc_id].cfg.enable_loopback;
690     status = pjmedia_transport_loop_create2(pjsua_var.med_endpt, &opt,
691     					    &call_med->tp);
692     if (status != PJ_SUCCESS) {
693 	pjsua_perror(THIS_FILE, "Unable to create loop media transport",
694 		     status);
695 	goto on_error;
696     }
697 
698     pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
699 				    pjsua_var.media_cfg.tx_drop_pct);
700 
701     pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
702 				    pjsua_var.media_cfg.rx_drop_pct);
703 
704     call_med->tp_ready = PJ_SUCCESS;
705 
706     return PJ_SUCCESS;
707 
708 on_error:
709     if (call_med->tp)
710 	pjmedia_transport_close(call_med->tp);
711 
712     return status;
713 }
714 
715 #if DISABLED_FOR_TICKET_1185
716 /* Create normal UDP media transports */
create_udp_media_transports(pjsua_transport_config * cfg)717 static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg)
718 {
719     unsigned i;
720     pj_status_t status;
721 
722     for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
723 	pjsua_call *call = &pjsua_var.calls[i];
724 	unsigned strm_idx;
725 
726 	for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
727 	    pjsua_call_media *call_med = &call->media[strm_idx];
728 
729 	    status = create_udp_media_transport(cfg, &call_med->tp);
730 	    if (status != PJ_SUCCESS)
731 		goto on_error;
732 	}
733     }
734 
735     return PJ_SUCCESS;
736 
737 on_error:
738     for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
739 	pjsua_call *call = &pjsua_var.calls[i];
740 	unsigned strm_idx;
741 
742 	for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
743 	    pjsua_call_media *call_med = &call->media[strm_idx];
744 
745 	    if (call_med->tp) {
746 		pjmedia_transport_close(call_med->tp);
747 		call_med->tp = NULL;
748 	    }
749 	}
750     }
751     return status;
752 }
753 #endif
754 
755 /* Deferred callback to notify ICE init complete */
ice_init_complete_cb(void * user_data)756 static void ice_init_complete_cb(void *user_data)
757 {
758     pjsua_call_media *call_med = (pjsua_call_media*)user_data;
759 
760     if (call_med->call == NULL || call_med->tp_ready == PJ_SUCCESS)
761 	return;
762 
763     /* No need to acquire_call() if we only change the tp_ready flag
764      * (i.e. transport is being created synchronously). Otherwise
765      * calling acquire_call() here may cause deadlock. See
766      * https://trac.pjsip.org/repos/ticket/1578
767      */
768     call_med->tp_ready = call_med->tp_result;
769 
770     if (call_med->med_create_cb) {
771 	pjsua_call *call = NULL;
772 	pjsip_dialog *dlg = NULL;
773 	pj_status_t status;
774 
775 	status = acquire_call("ice_init_complete_cb", call_med->call->index,
776 			      &call, &dlg);
777 	if (status != PJ_SUCCESS) {
778 	    if (status != PJSIP_ESESSIONTERMINATED) {
779 		/* Retry, if call is still active */
780 		pjsua_schedule_timer2(&ice_init_complete_cb, call_med, 10);
781 	    }
782 	    return;
783 	}
784 
785         (*call_med->med_create_cb)(call_med, call_med->tp_ready,
786                                    call_med->call->secure_level, NULL);
787 
788         if (dlg)
789             pjsip_dlg_dec_lock(dlg);
790     }
791 }
792 
793 /* Deferred callback to notify ICE negotiation failure */
ice_failed_nego_cb(void * user_data)794 static void ice_failed_nego_cb(void *user_data)
795 {
796     int call_id = (int)(pj_ssize_t)user_data;
797     pjsua_call *call = NULL;
798     pjsip_dialog *dlg = NULL;
799     pj_status_t status;
800 
801     status = acquire_call("ice_failed_nego_cb", call_id, &call, &dlg);
802     if (status != PJ_SUCCESS) {
803 	if (status != PJSIP_ESESSIONTERMINATED) {
804 	    /* Retry, if call is still active */
805 	    pjsua_schedule_timer2(&ice_failed_nego_cb,
806 				  (void*)(pj_ssize_t)call_id, 10);
807 	}
808 	return;
809     }
810 
811     if (!call->hanging_up)
812     	pjsua_var.ua_cfg.cb.on_call_media_state(call_id);
813 
814     if (dlg)
815         pjsip_dlg_dec_lock(dlg);
816 
817 }
818 
819 /* This callback is called when ICE negotiation completes */
on_ice_complete(pjmedia_transport * tp,pj_ice_strans_op op,pj_status_t result)820 static void on_ice_complete(pjmedia_transport *tp,
821 			    pj_ice_strans_op op,
822 			    pj_status_t result)
823 {
824     pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data;
825     pjsua_call *call;
826 
827     if (!call_med)
828 	return;
829 
830     call = call_med->call;
831 
832     switch (op) {
833     case PJ_ICE_STRANS_OP_INIT:
834         call_med->tp_result = result;
835         pjsua_schedule_timer2(&ice_init_complete_cb, call_med, 1);
836 	break;
837     case PJ_ICE_STRANS_OP_NEGOTIATION:
838 	if (result == PJ_SUCCESS) {
839             /* Update RTP address */
840             pjmedia_transport_info tpinfo;
841             pjmedia_transport_info_init(&tpinfo);
842             pjmedia_transport_get_info(call_med->tp, &tpinfo);
843             pj_sockaddr_cp(&call_med->rtp_addr, &tpinfo.sock_info.rtp_addr_name);
844         } else {
845 	    call_med->state = PJSUA_CALL_MEDIA_ERROR;
846 	    call_med->dir = PJMEDIA_DIR_NONE;
847 	    if (call && !call->hanging_up &&
848 	        pjsua_var.ua_cfg.cb.on_call_media_state)
849 	    {
850 		/* Defer the callback to a timer */
851 		pjsua_schedule_timer2(&ice_failed_nego_cb,
852 				      (void*)(pj_ssize_t)call->index, 1);
853 	    }
854         }
855 
856 	/* Stop trickling */
857 	if (call->trickle_ice.trickling < PJSUA_OP_STATE_DONE) {
858 	    call->trickle_ice.trickling = PJSUA_OP_STATE_DONE;
859 	    pjsua_cancel_timer(&call->trickle_ice.timer);
860 	    PJ_LOG(4,(THIS_FILE, "Call %d: ICE trickle stopped trickling as "
861 		      "ICE nego completed",
862 		      call->index));
863 	}
864 
865 	/* Check if default ICE transport address is changed */
866         call->reinv_ice_sent = PJ_FALSE;
867 	pjsua_call_schedule_reinvite_check(call, 0);
868 	break;
869     case PJ_ICE_STRANS_OP_KEEP_ALIVE:
870     case PJ_ICE_STRANS_OP_ADDR_CHANGE:
871 	if (result != PJ_SUCCESS) {
872 	    PJ_PERROR(4,(THIS_FILE, result,
873 		         "ICE keep alive failure for transport %d:%d",
874 		         call->index, call_med->idx));
875 	}
876         if (!call->hanging_up &&
877             pjsua_var.ua_cfg.cb.on_call_media_transport_state)
878         {
879             pjsua_med_tp_state_info info;
880 
881             pj_bzero(&info, sizeof(info));
882             info.med_idx = call_med->idx;
883             info.state = call_med->tp_st;
884             info.status = result;
885             info.ext_info = &op;
886 	    (*pjsua_var.ua_cfg.cb.on_call_media_transport_state)(
887                 call->index, &info);
888         }
889 	if (pjsua_var.ua_cfg.cb.on_ice_transport_error &&
890 	    op == PJ_ICE_STRANS_OP_KEEP_ALIVE)
891 	{
892 	    pjsua_call_id id = call->index;
893 	    (*pjsua_var.ua_cfg.cb.on_ice_transport_error)(id, op, result,
894 							  NULL);
895 	}
896 	break;
897     }
898 }
899 
900 
901 /* Parse "HOST:PORT" format */
parse_host_port(const pj_str_t * host_port,pj_str_t * host,pj_uint16_t * port)902 static pj_status_t parse_host_port(const pj_str_t *host_port,
903 				   pj_str_t *host, pj_uint16_t *port)
904 {
905     pj_str_t str_port;
906 
907     str_port.ptr = pj_strchr(host_port, ':');
908     if (str_port.ptr != NULL) {
909 	int iport;
910 
911 	host->ptr = host_port->ptr;
912 	host->slen = (str_port.ptr - host->ptr);
913 	str_port.ptr++;
914 	str_port.slen = host_port->slen - host->slen - 1;
915 	iport = (int)pj_strtoul(&str_port);
916 	if (iport < 1 || iport > 65535)
917 	    return PJ_EINVAL;
918 	*port = (pj_uint16_t)iport;
919     } else {
920 	*host = *host_port;
921 	*port = 0;
922     }
923 
924     return PJ_SUCCESS;
925 }
926 
927 /* Create ICE media transports (when ice is enabled) */
create_ice_media_transport(const pjsua_transport_config * cfg,pjsua_call_media * call_med,pj_bool_t async)928 static pj_status_t create_ice_media_transport(
929 				const pjsua_transport_config *cfg,
930 				pjsua_call_media *call_med,
931                                 pj_bool_t async)
932 {
933     char stunip[PJ_INET6_ADDRSTRLEN];
934     pjsua_acc_config *acc_cfg;
935     pj_ice_strans_cfg ice_cfg;
936     pjmedia_ice_cb ice_cb;
937     char name[32];
938     unsigned comp_cnt;
939     pj_status_t status;
940     pj_bool_t use_ipv6, use_nat64;
941     pj_bool_t trickle = PJ_FALSE;
942     pjmedia_sdp_session *rem_sdp;
943 
944     acc_cfg = &pjsua_var.acc[call_med->call->acc_id].cfg;
945     use_ipv6 = (acc_cfg->ipv6_media_use != PJSUA_IPV6_DISABLED);
946     use_nat64 = (acc_cfg->nat64_opt != PJSUA_NAT64_DISABLED);
947 
948     /* Make sure STUN server resolution has completed */
949     if (pjsua_media_acc_is_using_stun(call_med->call->acc_id)) {
950 	pj_bool_t retry_stun = (acc_cfg->media_stun_use &
951 				PJSUA_STUN_RETRY_ON_FAILURE) ==
952 				PJSUA_STUN_RETRY_ON_FAILURE;
953 	status = resolve_stun_server(PJ_TRUE, retry_stun,
954 				     (unsigned)acc_cfg->nat64_opt);
955 	if (status != PJ_SUCCESS) {
956 	    pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
957 	    return status;
958 	}
959     }
960 
961     /* Create ICE stream transport configuration */
962     pj_ice_strans_cfg_default(&ice_cfg);
963     pj_bzero(&ice_cfg.stun, sizeof(ice_cfg.stun));
964     pj_bzero(&ice_cfg.turn, sizeof(ice_cfg.turn));
965     pj_stun_config_init(&ice_cfg.stun_cfg, &pjsua_var.cp.factory, 0,
966 		        pjsip_endpt_get_ioqueue(pjsua_var.endpt),
967 			pjsip_endpt_get_timer_heap(pjsua_var.endpt));
968 
969     ice_cfg.resolver = pjsua_var.resolver;
970 
971     ice_cfg.opt = acc_cfg->ice_cfg.ice_opt;
972     rem_sdp = call_med->call->async_call.rem_sdp;
973 
974     if (rem_sdp) {
975     	/* Match the default address family according to the offer */
976         const pj_str_t ID_IP6 = { "IP6", 3};
977     	const pjmedia_sdp_media *m;
978 	const pjmedia_sdp_conn *c;
979 
980 	m = rem_sdp->media[call_med->idx];
981 	c = m->conn? m->conn : rem_sdp->conn;
982 
983 	if (pj_stricmp(&c->addr_type, &ID_IP6) == 0)
984 	    ice_cfg.af = pj_AF_INET6();
985     } else if (use_ipv6 || use_nat64) {
986     	ice_cfg.af = pj_AF_INET6();
987     }
988 
989     /* Should not wait for ICE STUN/TURN ready when trickle ICE is enabled */
990     if (ice_cfg.opt.trickle != PJ_ICE_SESS_TRICKLE_DISABLED &&
991 	(call_med->call->inv == NULL ||
992 	 call_med->call->inv->state < PJSIP_INV_STATE_CONFIRMED))
993     {
994 	if (rem_sdp) {
995 	    /* As answerer: and when remote signals trickle ICE in SDP */
996 	    trickle = pjmedia_ice_sdp_has_trickle(rem_sdp, call_med->idx);
997 	    if (trickle) {
998 		call_med->call->trickle_ice.remote_sup = PJ_TRUE;
999 		call_med->call->trickle_ice.enabled = PJ_TRUE;
1000 	    }
1001 	} else {
1002 	    /* As offerer: and when trickle ICE mode is full */
1003 	    trickle = (ice_cfg.opt.trickle==PJ_ICE_SESS_TRICKLE_FULL);
1004 	    call_med->call->trickle_ice.enabled = PJ_TRUE;
1005 	}
1006 
1007 	/* Check if trickle ICE can start trickling/sending SIP INFO */
1008 	pjsua_ice_check_start_trickling(call_med->call, PJ_FALSE, NULL);
1009     } else {
1010 	/* For non-initial INVITE, always use regular ICE */
1011 	ice_cfg.opt.trickle = PJ_ICE_SESS_TRICKLE_DISABLED;
1012     }
1013 
1014     /* If STUN transport is configured, initialize STUN transport settings */
1015     if ((pj_sockaddr_has_addr(&pjsua_var.stun_srv) &&
1016 	 pjsua_media_acc_is_using_stun(call_med->call->acc_id)) ||
1017 	acc_cfg->ice_cfg.ice_max_host_cands != 0)
1018     {
1019 	ice_cfg.stun_tp_cnt = 1;
1020 	pj_ice_strans_stun_cfg_default(&ice_cfg.stun_tp[0]);
1021 	if (use_nat64) {
1022 	    ice_cfg.stun_tp[0].af = pj_AF_INET6();
1023 	} else if (use_ipv6 && PJ_ICE_MAX_STUN >= 2) {
1024 	    ice_cfg.stun_tp_cnt = 2;
1025 	    pj_ice_strans_stun_cfg_default(&ice_cfg.stun_tp[1]);
1026 	    ice_cfg.stun_tp[1].af = pj_AF_INET6();
1027 	}
1028     }
1029 
1030     /* Configure STUN transport settings */
1031     if (ice_cfg.stun_tp_cnt) {
1032 	unsigned i;
1033 
1034 	if (pj_sockaddr_has_addr(&pjsua_var.stun_srv)) {
1035 	    pj_sockaddr_print(&pjsua_var.stun_srv, stunip,
1036 			      sizeof(stunip), 0);
1037 	}
1038 
1039 	for (i = 0; i < ice_cfg.stun_tp_cnt; ++i) {
1040 	    pj_str_t IN6_ADDR_ANY = {"0", 1};
1041 
1042 	    /* Configure STUN server */
1043 	    if (pjsua_media_acc_is_using_stun(call_med->call->acc_id) &&
1044 		pj_sockaddr_has_addr(&pjsua_var.stun_srv) &&
1045 		pjsua_var.stun_srv.addr.sa_family == ice_cfg.stun_tp[i].af)
1046 	    {
1047 	    	ice_cfg.stun_tp[i].server = pj_str(stunip);
1048 	    	ice_cfg.stun_tp[i].port = pj_sockaddr_get_port(
1049 	    				      &pjsua_var.stun_srv);
1050 	    }
1051 
1052 	    /* Configure max host candidates */
1053 	    if (acc_cfg->ice_cfg.ice_max_host_cands >= 0) {
1054 		ice_cfg.stun_tp[i].max_host_cands =
1055 				acc_cfg->ice_cfg.ice_max_host_cands;
1056 	    }
1057 
1058 	    /* Configure binding address */
1059 	    pj_sockaddr_init(ice_cfg.stun_tp[i].af,
1060 			     &ice_cfg.stun_tp[i].cfg.bound_addr,
1061 			     (ice_cfg.stun_tp[i].af == pj_AF_INET()?
1062 			     &cfg->bound_addr: &IN6_ADDR_ANY),
1063 			     (pj_uint16_t)cfg->port);
1064 	    ice_cfg.stun_tp[i].cfg.port_range = (pj_uint16_t)cfg->port_range;
1065 	    if (cfg->port != 0 && ice_cfg.stun_tp[i].cfg.port_range == 0) {
1066 	    	ice_cfg.stun_tp[i].cfg.port_range =
1067 			    (pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
1068 	    }
1069 
1070 	    /* Configure QoS setting */
1071 	    ice_cfg.stun_tp[i].cfg.qos_type = cfg->qos_type;
1072 	    pj_memcpy(&ice_cfg.stun_tp[i].cfg.qos_params, &cfg->qos_params,
1073 		      sizeof(cfg->qos_params));
1074 
1075 	    /* Configure max packet size */
1076 	    ice_cfg.stun_tp[i].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
1077 	}
1078     }
1079 
1080     /* Configure TURN settings */
1081     if (acc_cfg->turn_cfg.enable_turn) {
1082         unsigned i, idx = 0;
1083 
1084         if (use_ipv6 && !use_nat64 && PJ_ICE_MAX_TURN >= 3) {
1085             ice_cfg.turn_tp_cnt = 3;
1086             idx = 1;
1087         } else {
1088 	    ice_cfg.turn_tp_cnt = 1;
1089 	}
1090 
1091 	for (i = 0; i < ice_cfg.turn_tp_cnt; i++)
1092 	    pj_ice_strans_turn_cfg_default(&ice_cfg.turn_tp[i]);
1093 
1094 	if (use_ipv6 || use_nat64) {
1095 	    if (!use_nat64)
1096 	        ice_cfg.turn_tp[idx++].af = pj_AF_INET6();
1097 
1098 	    /* Additional candidate: IPv4 relay via IPv6 TURN server */
1099 	    ice_cfg.turn_tp[idx].af = pj_AF_INET6();
1100 	    ice_cfg.turn_tp[idx].alloc_param.af = pj_AF_INET();
1101 	}
1102 
1103 	/* Configure TURN server */
1104 	status = parse_host_port(&acc_cfg->turn_cfg.turn_server,
1105 				 &ice_cfg.turn_tp[0].server,
1106 				 &ice_cfg.turn_tp[0].port);
1107 	if (status != PJ_SUCCESS || ice_cfg.turn_tp[0].server.slen == 0) {
1108 	    PJ_LOG(1,(THIS_FILE, "Invalid TURN server setting"));
1109 	    return PJ_EINVAL;
1110 	}
1111 
1112 	if (ice_cfg.turn_tp[0].port == 0)
1113 	    ice_cfg.turn_tp[0].port = 3479;
1114 
1115 	for (i = 0; i < ice_cfg.turn_tp_cnt; i++) {
1116 	    pj_str_t IN6_ADDR_ANY = {"0", 1};
1117 
1118 	    /* Configure TURN connection settings and credential */
1119 	    ice_cfg.turn_tp[i].server    = ice_cfg.turn_tp[0].server;
1120 	    ice_cfg.turn_tp[i].port      = ice_cfg.turn_tp[0].port;
1121 	    ice_cfg.turn_tp[i].conn_type = acc_cfg->turn_cfg.turn_conn_type;
1122 	    pj_memcpy(&ice_cfg.turn_tp[i].auth_cred,
1123 		      &acc_cfg->turn_cfg.turn_auth_cred,
1124 		      sizeof(ice_cfg.turn_tp[i].auth_cred));
1125 
1126 	    /* Configure QoS setting */
1127 	    ice_cfg.turn_tp[i].cfg.qos_type = cfg->qos_type;
1128 	    pj_memcpy(&ice_cfg.turn_tp[i].cfg.qos_params, &cfg->qos_params,
1129 		      sizeof(cfg->qos_params));
1130 
1131 	    /* Configure binding address */
1132 	    pj_sockaddr_init(ice_cfg.turn_tp[i].af,
1133 	    		     &ice_cfg.turn_tp[i].cfg.bound_addr,
1134 			     (ice_cfg.turn_tp[i].af == pj_AF_INET()?
1135 			     &cfg->bound_addr: &IN6_ADDR_ANY),
1136 			     (pj_uint16_t)cfg->port);
1137 	    ice_cfg.turn_tp[i].cfg.port_range = (pj_uint16_t)cfg->port_range;
1138 	    if (cfg->port != 0 && ice_cfg.turn_tp[i].cfg.port_range == 0)
1139 	        ice_cfg.turn_tp[i].cfg.port_range =
1140 				 (pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
1141 
1142 	    /* Configure max packet size */
1143 	    ice_cfg.turn_tp[i].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
1144 
1145 #if PJ_HAS_SSL_SOCK
1146 	    if (ice_cfg.turn_tp[i].conn_type == PJ_TURN_TP_TLS) {
1147 		pj_memcpy(&ice_cfg.turn_tp[i].cfg.tls_cfg,
1148 			  &acc_cfg->turn_cfg.turn_tls_setting,
1149 			  sizeof(ice_cfg.turn_tp[i].cfg.tls_cfg));
1150 	    }
1151 #endif
1152 	}
1153     }
1154 
1155     pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb));
1156     ice_cb.on_ice_complete = &on_ice_complete;
1157     pj_ansi_snprintf(name, sizeof(name), "icetp%02d", call_med->idx);
1158     call_med->tp_ready = trickle? PJ_SUCCESS : PJ_EPENDING;
1159 
1160     comp_cnt = 1;
1161     if (PJMEDIA_ADVERTISE_RTCP && !acc_cfg->ice_cfg.ice_no_rtcp)
1162 	++comp_cnt;
1163 
1164     status = pjmedia_ice_create3(pjsua_var.med_endpt, name, comp_cnt,
1165 				 &ice_cfg, &ice_cb, PJSUA_ICE_TRANSPORT_OPTION,
1166                                  call_med, &call_med->tp);
1167     if (status != PJ_SUCCESS) {
1168 	pjsua_perror(THIS_FILE, "Unable to create ICE media transport",
1169 		     status);
1170 	goto on_error;
1171     }
1172 
1173     /* Wait until transport is initialized, or time out */
1174     if (!async && !trickle) {
1175 	pj_bool_t has_pjsua_lock = PJSUA_LOCK_IS_LOCKED();
1176 	pjsip_dialog *dlg = call_med->call->inv ?
1177 				call_med->call->inv->dlg : NULL;
1178         if (has_pjsua_lock)
1179 	    PJSUA_UNLOCK();
1180         if (dlg) {
1181             /* Don't lock otherwise deadlock:
1182              * https://trac.pjsip.org/repos/ticket/1737
1183              */
1184 	    pjsip_dlg_inc_session(dlg, &pjsua_var.mod);
1185             pjsip_dlg_dec_lock(dlg);
1186         }
1187         while (call_med->tp_ready == PJ_EPENDING) {
1188 	    pjsua_handle_events(100);
1189         }
1190         if (dlg) {
1191             pjsip_dlg_inc_lock(dlg);
1192 	    pjsip_dlg_dec_session(dlg, &pjsua_var.mod);
1193         }
1194 	if (has_pjsua_lock)
1195 	    PJSUA_LOCK();
1196     }
1197 
1198     if (!call_med->tp) {
1199 	/* Call has been disconnected, and media transports have been cleared
1200 	 * (see ticket #1759).
1201 	 */
1202 	PJ_LOG(4,(THIS_FILE, "Media transport initialization cancelled "
1203 		             "because call has been disconnected"));
1204 	status = PJ_ECANCELLED;
1205 	goto on_error;
1206     } else if (async && call_med->tp_ready == PJ_EPENDING) {
1207         return PJ_EPENDING;
1208     } else if (call_med->tp_ready != PJ_SUCCESS) {
1209 	pjsua_perror(THIS_FILE, "Error initializing ICE media transport",
1210 		     call_med->tp_ready);
1211 	status = call_med->tp_ready;
1212 	goto on_error;
1213     }
1214 
1215     pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
1216 				    pjsua_var.media_cfg.tx_drop_pct);
1217 
1218     pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
1219 				    pjsua_var.media_cfg.rx_drop_pct);
1220 
1221     return PJ_SUCCESS;
1222 
1223 on_error:
1224     if (call_med->tp != NULL) {
1225 	pjmedia_transport_close(call_med->tp);
1226 	call_med->tp = NULL;
1227     }
1228 
1229     return status;
1230 }
1231 
1232 #if DISABLED_FOR_TICKET_1185
1233 /* Create ICE media transports (when ice is enabled) */
create_ice_media_transports(pjsua_transport_config * cfg)1234 static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
1235 {
1236     unsigned i;
1237     pj_status_t status;
1238 
1239     for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
1240 	pjsua_call *call = &pjsua_var.calls[i];
1241 	unsigned strm_idx;
1242 
1243 	for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
1244 	    pjsua_call_media *call_med = &call->media[strm_idx];
1245 
1246 	    status = create_ice_media_transport(cfg, call_med);
1247 	    if (status != PJ_SUCCESS)
1248 		goto on_error;
1249 	}
1250     }
1251 
1252     return PJ_SUCCESS;
1253 
1254 on_error:
1255     for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
1256 	pjsua_call *call = &pjsua_var.calls[i];
1257 	unsigned strm_idx;
1258 
1259 	for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
1260 	    pjsua_call_media *call_med = &call->media[strm_idx];
1261 
1262 	    if (call_med->tp) {
1263 		pjmedia_transport_close(call_med->tp);
1264 		call_med->tp = NULL;
1265 	    }
1266 	}
1267     }
1268     return status;
1269 }
1270 #endif
1271 
1272 #if DISABLED_FOR_TICKET_1185
1273 /*
1274  * Create media transports for all the calls. This function creates
1275  * one UDP media transport for each call.
1276  */
pjsua_media_transports_create(const pjsua_transport_config * app_cfg)1277 PJ_DEF(pj_status_t) pjsua_media_transports_create(
1278 			const pjsua_transport_config *app_cfg)
1279 {
1280     pjsua_transport_config cfg;
1281     unsigned i;
1282     pj_status_t status;
1283 
1284 
1285     /* Make sure pjsua_init() has been called */
1286     PJ_ASSERT_RETURN(pjsua_var.ua_cfg.max_calls>0, PJ_EINVALIDOP);
1287 
1288     PJSUA_LOCK();
1289 
1290     /* Delete existing media transports */
1291     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
1292 	pjsua_call *call = &pjsua_var.calls[i];
1293 	unsigned strm_idx;
1294 
1295 	for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
1296 	    pjsua_call_media *call_med = &call->media[strm_idx];
1297 
1298 	    if (call_med->tp && call_med->tp_auto_del) {
1299 		pjmedia_transport_close(call_med->tp);
1300 		call_med->tp = NULL;
1301 		call_med->tp_orig = NULL;
1302 	    }
1303 	}
1304     }
1305 
1306     /* Copy config */
1307     pjsua_transport_config_dup(pjsua_var.pool, &cfg, app_cfg);
1308 
1309     /* Create the transports */
1310     if (pjsua_var.ice_cfg.enable_ice) {
1311 	status = create_ice_media_transports(&cfg);
1312     } else {
1313 	status = create_udp_media_transports(&cfg);
1314     }
1315 
1316     /* Set media transport auto_delete to True */
1317     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
1318 	pjsua_call *call = &pjsua_var.calls[i];
1319 	unsigned strm_idx;
1320 
1321 	for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
1322 	    pjsua_call_media *call_med = &call->media[strm_idx];
1323 
1324 	    call_med->tp_auto_del = PJ_TRUE;
1325 	}
1326     }
1327 
1328     PJSUA_UNLOCK();
1329 
1330     return status;
1331 }
1332 
1333 /*
1334  * Attach application's created media transports.
1335  */
pjsua_media_transports_attach(pjsua_media_transport tp[],unsigned count,pj_bool_t auto_delete)1336 PJ_DEF(pj_status_t) pjsua_media_transports_attach(pjsua_media_transport tp[],
1337 						  unsigned count,
1338 						  pj_bool_t auto_delete)
1339 {
1340     unsigned i;
1341 
1342     PJ_ASSERT_RETURN(tp && count==pjsua_var.ua_cfg.max_calls, PJ_EINVAL);
1343 
1344     /* Assign the media transports */
1345     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
1346 	pjsua_call *call = &pjsua_var.calls[i];
1347 	unsigned strm_idx;
1348 
1349 	for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
1350 	    pjsua_call_media *call_med = &call->media[strm_idx];
1351 
1352 	    if (call_med->tp && call_med->tp_auto_del) {
1353 		pjmedia_transport_close(call_med->tp);
1354 		call_med->tp = NULL;
1355 		call_med->tp_orig = NULL;
1356 	    }
1357 	}
1358 
1359 	PJ_TODO(remove_pjsua_media_transports_attach);
1360 
1361 	call->media[0].tp = tp[i].transport;
1362 	call->media[0].tp_auto_del = auto_delete;
1363     }
1364 
1365     return PJ_SUCCESS;
1366 }
1367 #endif
1368 
1369 /* Go through the list of media in the SDP, find acceptable media, and
1370  * sort them based on the below criteria, and store the indexes
1371  * in the specified array. The criteria is as follows:
1372  * 1. enabled, i.e: SDP media port not zero
1373  * 2. transport protocol in the SDP matching account config's
1374  *    secure media transport usage (\a use_srtp field).
1375  * 3. active, i.e: SDP media direction is not "inactive"
1376  * 4. media order (according to the SDP).
1377  */
sort_media(const pjmedia_sdp_session * sdp,const pj_str_t * type,pjmedia_srtp_use use_srtp,pj_uint8_t midx[],unsigned * p_count,unsigned * p_total_count)1378 static void sort_media(const pjmedia_sdp_session *sdp,
1379 		       const pj_str_t *type,
1380 		       pjmedia_srtp_use	use_srtp,
1381 		       pj_uint8_t midx[],
1382 		       unsigned *p_count,
1383 		       unsigned *p_total_count)
1384 {
1385     unsigned i;
1386     unsigned count = 0;
1387     int score[PJSUA_MAX_CALL_MEDIA];
1388 
1389     pj_assert(*p_count >= PJSUA_MAX_CALL_MEDIA);
1390     pj_assert(*p_total_count >= PJSUA_MAX_CALL_MEDIA);
1391 
1392     *p_count = 0;
1393     *p_total_count = 0;
1394     for (i=0; i<PJSUA_MAX_CALL_MEDIA; ++i)
1395 	score[i] = 1;
1396 
1397     /* Score each media */
1398     for (i=0; i<sdp->media_count && count<PJSUA_MAX_CALL_MEDIA; ++i) {
1399 	const pjmedia_sdp_media *m = sdp->media[i];
1400 	const pjmedia_sdp_conn *c;
1401 	pj_uint32_t proto;
1402 
1403 	/* Skip different media */
1404 	if (pj_stricmp(&m->desc.media, type) != 0) {
1405 	    score[count++] = -22000;
1406 	    continue;
1407 	}
1408 
1409 	c = m->conn? m->conn : sdp->conn;
1410 
1411 	/* Supported transports */
1412 	proto = pjmedia_sdp_transport_get_proto(&m->desc.transport);
1413 	if (PJMEDIA_TP_PROTO_HAS_FLAG(proto, PJMEDIA_TP_PROTO_RTP_SAVP))
1414 	{
1415 	    switch (use_srtp) {
1416 	    case PJMEDIA_SRTP_MANDATORY:
1417 	    case PJMEDIA_SRTP_OPTIONAL:
1418 		++score[i];
1419 		break;
1420 	    case PJMEDIA_SRTP_DISABLED:
1421 		//--score[i];
1422 		score[i] -= 5;
1423 		break;
1424 	    }
1425 	} else if (PJMEDIA_TP_PROTO_HAS_FLAG(proto, PJMEDIA_TP_PROTO_RTP_AVP))
1426 	{
1427 	    switch (use_srtp) {
1428 	    case PJMEDIA_SRTP_MANDATORY:
1429 		//--score[i];
1430 		score[i] -= 5;
1431 		break;
1432 	    case PJMEDIA_SRTP_OPTIONAL:
1433 		/* No change in score */
1434 		break;
1435 	    case PJMEDIA_SRTP_DISABLED:
1436 		++score[i];
1437 		break;
1438 	    }
1439 	} else {
1440 	    score[i] -= 10;
1441 	}
1442 
1443 	/* Is media disabled? */
1444 	if (m->desc.port == 0)
1445 	    score[i] -= 10;
1446 
1447 	/* Is media inactive? */
1448 	if (pjmedia_sdp_media_find_attr2(m, "inactive", NULL) ||
1449 	    pj_strcmp2(&c->addr, "0.0.0.0") == 0)
1450 	{
1451 	    //score[i] -= 10;
1452 	    score[i] -= 1;
1453 	}
1454 
1455 	++count;
1456     }
1457 
1458     /* Created sorted list based on quality */
1459     for (i=0; i<count; ++i) {
1460 	unsigned j;
1461 	int best = 0;
1462 
1463 	for (j=1; j<count; ++j) {
1464 	    if (score[j] > score[best])
1465 		best = j;
1466 	}
1467 	/* Don't put media with negative score, that media is unacceptable
1468 	 * for us.
1469 	 */
1470 	midx[i] = (pj_uint8_t)best;
1471 	if (score[best] >= 0)
1472 	    (*p_count)++;
1473 	if (score[best] > -22000)
1474 	    (*p_total_count)++;
1475 
1476 	score[best] = -22000;
1477 
1478     }
1479 }
1480 
1481 
1482 /* Go through the list of media in the call, find acceptable media, and
1483  * sort them based on the "quality" of the media, and store the indexes
1484  * in the specified array. Media with the best quality will be listed
1485  * first in the array.
1486  */
sort_media2(const pjsua_call_media * call_med,pj_bool_t check_tp,unsigned call_med_cnt,pjmedia_type type,pj_uint8_t midx[],unsigned * p_count,unsigned * p_total_count)1487 static void sort_media2(const pjsua_call_media *call_med,
1488 			pj_bool_t check_tp,
1489 			unsigned call_med_cnt,
1490 			pjmedia_type type,
1491 			pj_uint8_t midx[],
1492 			unsigned *p_count,
1493 			unsigned *p_total_count)
1494 {
1495     unsigned i;
1496     unsigned count = 0;
1497     int score[PJSUA_MAX_CALL_MEDIA];
1498 
1499     pj_assert(*p_count >= PJSUA_MAX_CALL_MEDIA);
1500     pj_assert(*p_total_count >= PJSUA_MAX_CALL_MEDIA);
1501 
1502     *p_count = 0;
1503     *p_total_count = 0;
1504     for (i=0; i<PJSUA_MAX_CALL_MEDIA; ++i)
1505 	score[i] = 1;
1506 
1507     /* Score each media */
1508     for (i=0; i<call_med_cnt && count<PJSUA_MAX_CALL_MEDIA; ++i) {
1509 
1510 	/* Skip different media */
1511 	if (call_med[i].type != type) {
1512 	    score[count++] = -22000;
1513 	    continue;
1514 	}
1515 
1516 	/* Is it active? */
1517 	if (check_tp && !call_med[i].tp) {
1518 	    score[i] -= 10;
1519 	}
1520 
1521 	++count;
1522     }
1523 
1524     /* Created sorted list based on quality */
1525     for (i=0; i<count; ++i) {
1526 	unsigned j;
1527 	int best = 0;
1528 
1529 	for (j=1; j<count; ++j) {
1530 	    if (score[j] > score[best])
1531 		best = j;
1532 	}
1533 	/* Don't put media with negative score, that media is unacceptable
1534 	 * for us.
1535 	 */
1536 	midx[i] = (pj_uint8_t)best;
1537 	if (score[best] >= 0)
1538 	    (*p_count)++;
1539 	if (score[best] > -22000)
1540 	    (*p_total_count)++;
1541 
1542 	score[best] = -22000;
1543 
1544     }
1545 }
1546 
1547 /* Callback to receive global media events */
on_media_event(pjmedia_event * event,void * user_data)1548 pj_status_t on_media_event(pjmedia_event *event, void *user_data)
1549 {
1550     char ev_name[5];
1551     pj_status_t status = PJ_SUCCESS;
1552 
1553     PJ_UNUSED_ARG(user_data);
1554 
1555     pjmedia_fourcc_name(event->type, ev_name);
1556     PJ_LOG(4,(THIS_FILE, "Received media event type=%s, src=%p, epub=%p",
1557 			 ev_name, event->src, event->epub));
1558 
1559     /* Forward the event */
1560     if (pjsua_var.ua_cfg.cb.on_media_event) {
1561 	(*pjsua_var.ua_cfg.cb.on_media_event)(event);
1562     }
1563 
1564     return status;
1565 }
1566 
1567 /* Call on_call_media_event() callback using timer */
call_med_event_cb(void * user_data)1568 void call_med_event_cb(void *user_data)
1569 {
1570     pjsua_event_list *eve = (pjsua_event_list *)user_data;
1571 
1572     (*pjsua_var.ua_cfg.cb.on_call_media_event)(eve->call_id,
1573 					       eve->med_idx,
1574 					       &eve->event);
1575 
1576     pj_mutex_lock(pjsua_var.timer_mutex);
1577     pj_list_push_back(&pjsua_var.event_list, eve);
1578     pj_mutex_unlock(pjsua_var.timer_mutex);
1579 }
1580 
1581 /* Callback to receive media events of a call */
call_media_on_event(pjmedia_event * event,void * user_data)1582 pj_status_t call_media_on_event(pjmedia_event *event,
1583                                 void *user_data)
1584 {
1585     pjsua_call_media *call_med = (pjsua_call_media*)user_data;
1586     pjsua_call *call = call_med? call_med->call : NULL;
1587     char ev_name[5];
1588     pj_status_t status = PJ_SUCCESS;
1589 
1590     pjmedia_fourcc_name(event->type, ev_name);
1591     PJ_LOG(5,(THIS_FILE, "Call %d: Media %d: Received media event, type=%s, "
1592 			 "src=%p, epub=%p",
1593 			 call->index, call_med->idx, ev_name,
1594 			 event->src, event->epub));
1595 
1596     switch(event->type) {
1597 	case PJMEDIA_EVENT_KEYFRAME_MISSING:
1598 	    if (call->opt.req_keyframe_method & PJSUA_VID_REQ_KEYFRAME_SIP_INFO)
1599 	    {
1600 		pj_timestamp now;
1601 
1602 		pj_get_timestamp(&now);
1603 		if (pj_elapsed_msec(&call_med->last_req_keyframe, &now) >=
1604 		    PJSUA_VID_REQ_KEYFRAME_INTERVAL)
1605 		{
1606 		    pjsua_msg_data msg_data;
1607 		    const pj_str_t SIP_INFO = {"INFO", 4};
1608 		    const char *BODY_TYPE = "application/media_control+xml";
1609 		    const char *BODY =
1610 			"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1611 			"<media_control><vc_primitive><to_encoder>"
1612 			"<picture_fast_update/>"
1613 			"</to_encoder></vc_primitive></media_control>";
1614 
1615 		    PJ_LOG(4,(THIS_FILE,
1616 			      "Sending video keyframe request via SIP INFO"));
1617 
1618 		    pjsua_msg_data_init(&msg_data);
1619 		    pj_cstr(&msg_data.content_type, BODY_TYPE);
1620 		    pj_cstr(&msg_data.msg_body, BODY);
1621 		    status = pjsua_call_send_request(call->index, &SIP_INFO,
1622 						     &msg_data);
1623 		    if (status != PJ_SUCCESS) {
1624 			PJ_PERROR(3,(THIS_FILE, status,
1625 				  "Failed requesting keyframe via SIP INFO"));
1626 		    } else {
1627 			call_med->last_req_keyframe = now;
1628 		    }
1629 		}
1630 	    }
1631 	    break;
1632 
1633 #if PJSUA_HAS_VIDEO
1634 	case PJMEDIA_EVENT_FMT_CHANGED:
1635 	    if (call_med->strm.v.rdr_win_id != PJSUA_INVALID_ID) {
1636 		pjsua_vid_win *w = &pjsua_var.win[call_med->strm.v.rdr_win_id];
1637 		if (event->epub == w->vp_rend) {
1638 		    /* Renderer just changed format, reconnect stream */
1639 		    pjsua_vid_conf_disconnect(call_med->strm.v.strm_dec_slot,
1640 					      w->rend_slot);
1641 		    pjsua_vid_conf_connect(call_med->strm.v.strm_dec_slot,
1642 					   w->rend_slot, NULL);
1643 		}
1644 	    }
1645 
1646 	    if (call_med->strm.v.strm_dec_slot != PJSUA_INVALID_ID) {
1647 		/* Stream decoder changed format, update all conf listeners
1648 		 * by reconnecting.
1649 		 */
1650 		pjsua_conf_port_id dec_pid = call_med->strm.v.strm_dec_slot;
1651 		pjmedia_port *strm_dec;
1652 		pjsua_vid_conf_port_info pi;
1653 		unsigned i;
1654 
1655 		status = pjmedia_vid_stream_get_port(call_med->strm.v.stream,
1656 						     PJMEDIA_DIR_DECODING,
1657 						     &strm_dec);
1658 		if (status != PJ_SUCCESS)
1659 		    break;
1660 
1661 		/* Verify that the publisher is the stream decoder */
1662 		if (event->epub != strm_dec)
1663 		    break;
1664 
1665 		status = pjsua_vid_conf_get_port_info(dec_pid, &pi);
1666 		if (status != PJ_SUCCESS)
1667 		    break;
1668 
1669 		for (i = 0; i < pi.listener_cnt; i++) {
1670 		    pjsua_vid_conf_disconnect(dec_pid, pi.listeners[i]);
1671 		    pjsua_vid_conf_connect(dec_pid, pi.listeners[i], NULL);
1672 		}
1673 	    }
1674 	    break;
1675 
1676 	case PJMEDIA_EVENT_VID_DEV_ERROR:
1677 	    {
1678 		PJ_PERROR(3,(THIS_FILE, event->data.vid_dev_err.status,
1679 			     "Video device id=%d error for call %d",
1680 			     event->data.vid_dev_err.id,
1681 			     call->index));
1682 	    }
1683 	    break;
1684 #endif
1685 
1686 	default:
1687 	    break;
1688     }
1689 
1690     if (pjsua_var.ua_cfg.cb.on_call_media_event) {
1691 	pjsua_event_list *eve = NULL;
1692 
1693     	pj_mutex_lock(pjsua_var.timer_mutex);
1694 
1695     	if (pj_list_empty(&pjsua_var.event_list)) {
1696             eve = PJ_POOL_ALLOC_T(pjsua_var.timer_pool, pjsua_event_list);
1697     	} else {
1698             eve = pjsua_var.event_list.next;
1699             pj_list_erase(eve);
1700     	}
1701 
1702     	pj_mutex_unlock(pjsua_var.timer_mutex);
1703 
1704     	if (call) {
1705     	    if (call->hanging_up)
1706     	    	return status;
1707 
1708     	    eve->call_id = call->index;
1709     	    eve->med_idx = call_med->idx;
1710     	} else {
1711 	    /* Also deliver non call events such as audio device error */
1712     	    eve->call_id = PJSUA_INVALID_ID;
1713     	    eve->med_idx = 0;
1714     	}
1715     	pj_memcpy(&eve->event, event, sizeof(pjmedia_event));
1716     	pjsua_schedule_timer2(&call_med_event_cb, eve, 1);
1717     }
1718 
1719     return status;
1720 }
1721 
1722 /* Set media transport state and notify the application via the callback. */
pjsua_set_media_tp_state(pjsua_call_media * call_med,pjsua_med_tp_st tp_st)1723 void pjsua_set_media_tp_state(pjsua_call_media *call_med,
1724                               pjsua_med_tp_st tp_st)
1725 {
1726     if (!call_med->call->hanging_up &&
1727         pjsua_var.ua_cfg.cb.on_call_media_transport_state &&
1728         call_med->tp_st != tp_st)
1729     {
1730         pjsua_med_tp_state_info info;
1731 
1732         pj_bzero(&info, sizeof(info));
1733         info.med_idx = call_med->idx;
1734         info.state = tp_st;
1735         info.status = call_med->tp_ready;
1736 	(*pjsua_var.ua_cfg.cb.on_call_media_transport_state)(
1737             call_med->call->index, &info);
1738     }
1739 
1740     call_med->tp_st = tp_st;
1741 }
1742 
1743 
1744 /* This callback is called when SRTP negotiation completes */
on_srtp_nego_complete(pjmedia_transport * tp,pj_status_t result)1745 static void on_srtp_nego_complete(pjmedia_transport *tp,
1746 				  pj_status_t result)
1747 {
1748     pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data;
1749     pjsua_call *call;
1750 
1751     if (!call_med)
1752 	return;
1753 
1754     call = call_med->call;
1755     PJ_PERROR(4,(THIS_FILE, result,
1756 		 "Call %d: Media %d: SRTP negotiation completes",
1757 	         call->index, call_med->idx));
1758 
1759     if (result != PJ_SUCCESS) {
1760 	call_med->state = PJSUA_CALL_MEDIA_ERROR;
1761 	call_med->dir = PJMEDIA_DIR_NONE;
1762 	if (call && !call->hanging_up &&
1763 	    pjsua_var.ua_cfg.cb.on_call_media_state)
1764 	{
1765 	    /* Defer the callback to a timer */
1766 	    pjsua_schedule_timer2(&ice_failed_nego_cb,
1767 				  (void*)(pj_ssize_t)call->index, 1);
1768 	}
1769     }
1770 }
1771 
1772 
1773 /* Callback to resume pjsua_call_media_init() after media transport
1774  * creation is completed.
1775  */
call_media_init_cb(pjsua_call_media * call_med,pj_status_t status,int security_level,int * sip_err_code)1776 static pj_status_t call_media_init_cb(pjsua_call_media *call_med,
1777                                       pj_status_t status,
1778                                       int security_level,
1779                                       int *sip_err_code)
1780 {
1781     pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
1782     pjmedia_transport_info tpinfo;
1783     int err_code = 0;
1784 
1785     if (status != PJ_SUCCESS) {
1786 	err_code = PJSIP_SC_TEMPORARILY_UNAVAILABLE;
1787         goto on_return;
1788     }
1789 
1790     pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
1791 				    pjsua_var.media_cfg.tx_drop_pct);
1792 
1793     pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
1794 				    pjsua_var.media_cfg.rx_drop_pct);
1795 
1796     if (call_med->tp_st == PJSUA_MED_TP_CREATING)
1797         pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
1798 
1799     if (!call_med->tp_orig &&
1800         pjsua_var.ua_cfg.cb.on_create_media_transport)
1801     {
1802         call_med->use_custom_med_tp = PJ_TRUE;
1803     } else
1804         call_med->use_custom_med_tp = PJ_FALSE;
1805 
1806 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
1807     /* This function may be called when SRTP transport already exists
1808      * (e.g: in re-invite, update), don't need to destroy/re-create.
1809      */
1810     if (!call_med->tp_orig) {
1811 	pjmedia_srtp_setting srtp_opt;
1812 	pjsua_srtp_opt *acc_srtp_opt = &acc->cfg.srtp_opt;
1813 	pjmedia_transport *srtp = NULL;
1814 	unsigned i;
1815 
1816 	/* Check if SRTP requires secure signaling */
1817 	if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) {
1818 	    if (security_level < acc->cfg.srtp_secure_signaling) {
1819 		err_code = PJSIP_SC_NOT_ACCEPTABLE;
1820 		status = PJSIP_ESESSIONINSECURE;
1821 		goto on_return;
1822 	    }
1823 	}
1824 
1825 	/* Always create SRTP adapter */
1826 	pjmedia_srtp_setting_default(&srtp_opt);
1827 	srtp_opt.close_member_tp = PJ_TRUE;
1828 	srtp_opt.cb.on_srtp_nego_complete = &on_srtp_nego_complete;
1829 	srtp_opt.user_data = call_med;
1830 
1831 	/* Get crypto and keying settings from account settings */
1832 	srtp_opt.crypto_count = acc_srtp_opt->crypto_count;
1833 	for (i = 0; i < srtp_opt.crypto_count; ++i)
1834 	    srtp_opt.crypto[i] = acc_srtp_opt->crypto[i];
1835 	srtp_opt.keying_count = acc_srtp_opt->keying_count;
1836 	for (i = 0; i < srtp_opt.keying_count; ++i)
1837 	    srtp_opt.keying[i] = acc_srtp_opt->keying[i];
1838 
1839 	/* If media session has been ever established, let's use remote's
1840 	 * preference in SRTP usage policy, especially when it is stricter.
1841 	 */
1842 	if (call_med->rem_srtp_use > acc->cfg.use_srtp)
1843 	    srtp_opt.use = call_med->rem_srtp_use;
1844 	else
1845 	    srtp_opt.use = acc->cfg.use_srtp;
1846 
1847 	if (pjsua_var.ua_cfg.cb.on_create_media_transport_srtp) {
1848 	    pjmedia_srtp_setting srtp_opt2 = srtp_opt;
1849 	    pjsua_call *call = call_med->call;
1850 
1851 	    /* Warn that this callback is deprecated (see also #2100) */
1852 	    PJ_LOG(1,(THIS_FILE, "Warning: on_create_media_transport_srtp "
1853 				 "is deprecated and will be removed in the "
1854 				 "future release"));
1855 
1856 	    (*pjsua_var.ua_cfg.cb.on_create_media_transport_srtp)
1857 		(call->index, call_med->idx, &srtp_opt2);
1858 
1859 	    /* Only apply SRTP usage policy if this is initial INVITE */
1860 	    if (call->inv && call->inv->state < PJSIP_INV_STATE_CONFIRMED) {
1861 		srtp_opt.use = srtp_opt2.use;
1862 	    }
1863 
1864 	    /* Apply crypto and keying settings from callback */
1865 	    srtp_opt.crypto_count = srtp_opt2.crypto_count;
1866 	    for (i = 0; i < srtp_opt.crypto_count; ++i)
1867 		srtp_opt.crypto[i] = srtp_opt2.crypto[i];
1868 	    srtp_opt.keying_count = srtp_opt2.keying_count;
1869 	    for (i = 0; i < srtp_opt.keying_count; ++i)
1870 		srtp_opt.keying[i] = srtp_opt2.keying[i];
1871     	}
1872 
1873 	status = pjmedia_transport_srtp_create(pjsua_var.med_endpt,
1874 					       call_med->tp,
1875 					       &srtp_opt, &srtp);
1876 	if (status != PJ_SUCCESS) {
1877 	    err_code = PJSIP_SC_INTERNAL_SERVER_ERROR;
1878 	    goto on_return;
1879 	}
1880 
1881 	/* Set SRTP as current media transport */
1882 	call_med->tp_orig = call_med->tp;
1883 	call_med->tp = srtp;
1884     }
1885 #else
1886     call_med->tp_orig = call_med->tp;
1887     PJ_UNUSED_ARG(security_level);
1888 #endif
1889 
1890 
1891     pjmedia_transport_info_init(&tpinfo);
1892     pjmedia_transport_get_info(call_med->tp, &tpinfo);
1893 
1894     pj_sockaddr_cp(&call_med->rtp_addr, &tpinfo.sock_info.rtp_addr_name);
1895 
1896 
1897 on_return:
1898     if (status != PJ_SUCCESS) {
1899 	if (call_med->tp) {
1900 	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
1901 	    pjmedia_transport_close(call_med->tp);
1902 	    call_med->tp = NULL;
1903 	}
1904 
1905 	if (err_code == 0)
1906 	    err_code = PJSIP_ERRNO_TO_SIP_STATUS(status);
1907 
1908 	if (sip_err_code)
1909 	    *sip_err_code = err_code;
1910     }
1911 
1912     if (call_med->med_init_cb) {
1913         pjsua_med_tp_state_info info;
1914 
1915         pj_bzero(&info, sizeof(info));
1916         info.status = status;
1917         info.state = call_med->tp_st;
1918         info.med_idx = call_med->idx;
1919         info.sip_err_code = err_code;
1920         (*call_med->med_init_cb)(call_med->call->index, &info);
1921     }
1922 
1923     return status;
1924 }
1925 
1926 /* Determine if call's media is being changed, for example when video is being
1927  * added. Then we can reject incoming re-INVITE, for example. This is the
1928  * solution for https://trac.pjsip.org/repos/ticket/1738
1929  */
pjsua_call_media_is_changing(pjsua_call * call)1930 pj_bool_t  pjsua_call_media_is_changing(pjsua_call *call)
1931 {
1932     /* The problem in #1738 occurs because we do handle_events() loop while
1933      * adding media, which could cause incoming re-INVITE to be processed and
1934      * cause havoc. Since the handle_events() loop only happens while adding
1935      * media, it is sufficient to only check if "prov > cnt" for now.
1936      */
1937     return call->med_prov_cnt > call->med_cnt;
1938 }
1939 
1940 /* Initialize the media line */
pjsua_call_media_init(pjsua_call_media * call_med,pjmedia_type type,const pjsua_transport_config * tcfg,int security_level,int * sip_err_code,pj_bool_t async,pjsua_med_tp_state_cb cb)1941 pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
1942                                   pjmedia_type type,
1943 				  const pjsua_transport_config *tcfg,
1944 				  int security_level,
1945 				  int *sip_err_code,
1946                                   pj_bool_t async,
1947                                   pjsua_med_tp_state_cb cb)
1948 {
1949     pj_status_t status = PJ_SUCCESS;
1950 
1951     /*
1952      * Note: this function may be called when the media already exists
1953      * (e.g. in reinvites, updates, etc.)
1954      */
1955     call_med->type = type;
1956 
1957     /* Create the media transport for initial call. Here are the possible
1958      * media transport state and the action needed:
1959      * - PJSUA_MED_TP_NULL or call_med->tp==NULL, create one.
1960      * - PJSUA_MED_TP_RUNNING, do nothing.
1961      * - PJSUA_MED_TP_DISABLED, re-init (media_create(), etc). Currently,
1962      *   this won't happen as media_channel_update() will always clean up
1963      *   the unused transport of a disabled media.
1964      */
1965     if (call_med->tp == NULL) {
1966     	pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
1967 
1968         /* Initializations. If media transport creation completes immediately,
1969          * we don't need to call the callbacks.
1970          */
1971         call_med->med_init_cb = NULL;
1972         call_med->med_create_cb = NULL;
1973 
1974 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
1975 	/* While in initial call, set default video devices */
1976 	if (type == PJMEDIA_TYPE_VIDEO) {
1977 	    status = pjsua_vid_channel_init(call_med);
1978 	    if (status != PJ_SUCCESS)
1979 		return status;
1980 	}
1981 #endif
1982 
1983         pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_CREATING);
1984 
1985 	if (acc->cfg.use_loop_med_tp) {
1986 	    status = create_loop_media_transport(tcfg, call_med);
1987 	} else if (acc->cfg.ice_cfg.enable_ice) {
1988 	    status = create_ice_media_transport(tcfg, call_med, async);
1989             if (async && status == PJ_EPENDING) {
1990 	        /* We will resume call media initialization in the
1991 	         * on_ice_complete() callback.
1992 	         */
1993                 call_med->med_create_cb = &call_media_init_cb;
1994                 call_med->med_init_cb = cb;
1995 
1996 	        return PJ_EPENDING;
1997 	    }
1998 	} else {
1999 	    status = create_udp_media_transport(tcfg, call_med);
2000 	}
2001 
2002         if (status != PJ_SUCCESS) {
2003 	    if (sip_err_code)
2004 		*sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR;
2005 	    call_med->tp_ready = status;
2006 	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
2007 	    pjsua_perror(THIS_FILE, "Error creating media transport", status);
2008 	    return status;
2009 	}
2010 
2011     } else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) {
2012 	/* Media is being reenabled. */
2013 	//pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
2014 
2015 	pj_assert(!"Currently no media transport reuse");
2016     }
2017 
2018     return call_media_init_cb(call_med, status, security_level,
2019                               sip_err_code);
2020 }
2021 
2022 /* Callback to resume pjsua_media_channel_init() after media transport
2023  * initialization is completed.
2024  */
media_channel_init_cb(pjsua_call_id call_id,const pjsua_med_tp_state_info * info)2025 static pj_status_t media_channel_init_cb(pjsua_call_id call_id,
2026                                          const pjsua_med_tp_state_info *info)
2027 {
2028     pjsua_call *call = &pjsua_var.calls[call_id];
2029     pj_status_t status = (info? info->status : PJ_SUCCESS);
2030     unsigned mi;
2031 
2032     if (info) {
2033         pj_mutex_lock(call->med_ch_mutex);
2034 
2035         /* Set the callback to NULL to indicate that the async operation
2036          * has completed.
2037          */
2038         call->media_prov[info->med_idx].med_init_cb = NULL;
2039 
2040         /* In case of failure, save the information to be returned
2041          * by the last media transport to finish.
2042          */
2043         if (info->status != PJ_SUCCESS)
2044             pj_memcpy(&call->med_ch_info, info, sizeof(*info));
2045 
2046         /* Check whether all the call's medias have finished calling their
2047          * callbacks.
2048          */
2049         for (mi=0; mi < call->med_prov_cnt; ++mi) {
2050             pjsua_call_media *call_med = &call->media_prov[mi];
2051 
2052             if (call_med->med_init_cb) {
2053                 pj_mutex_unlock(call->med_ch_mutex);
2054                 return PJ_SUCCESS;
2055             }
2056 
2057             if (call_med->tp_ready != PJ_SUCCESS)
2058                 status = call_med->tp_ready;
2059         }
2060 
2061         /* OK, we are called by the last media transport finished. */
2062         pj_mutex_unlock(call->med_ch_mutex);
2063     }
2064 
2065     if (call->med_ch_mutex) {
2066         pj_mutex_destroy(call->med_ch_mutex);
2067         call->med_ch_mutex = NULL;
2068     }
2069 
2070     PJ_PERROR(5,(THIS_FILE, status,
2071 		 "Call %d: media transport initialization complete", call_id));
2072 
2073     if (status != PJ_SUCCESS) {
2074 	if (call->med_ch_info.status == PJ_SUCCESS) {
2075 	    call->med_ch_info.status = status;
2076 	    call->med_ch_info.sip_err_code = PJSIP_SC_TEMPORARILY_UNAVAILABLE;
2077 	}
2078 
2079 	/* Revert back provisional media. */
2080 	pjsua_media_prov_revert(call_id);
2081 
2082 	goto on_return;
2083     }
2084 
2085     /* Tell the media transport of a new offer/answer session */
2086     for (mi=0; mi < call->med_prov_cnt; ++mi) {
2087 	pjsua_call_media *call_med = &call->media_prov[mi];
2088 
2089 	/* Note: tp may be NULL if this media line is disabled */
2090 	if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) {
2091             pj_pool_t *tmp_pool = call->async_call.pool_prov;
2092 
2093             if (!tmp_pool) {
2094                 tmp_pool = (call->inv? call->inv->pool_prov:
2095                             call->async_call.dlg->pool);
2096             }
2097 
2098             if (call_med->use_custom_med_tp) {
2099                 unsigned custom_med_tp_flags = PJSUA_MED_TP_CLOSE_MEMBER;
2100 
2101                 /* Use custom media transport returned by the application */
2102                 call_med->tp =
2103                     (*pjsua_var.ua_cfg.cb.on_create_media_transport)
2104                         (call_id, mi, call_med->tp,
2105                          custom_med_tp_flags);
2106                 if (!call_med->tp) {
2107                     status =
2108                         PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_TEMPORARILY_UNAVAILABLE);
2109                 }
2110             }
2111 
2112             if (call_med->tp) {
2113             	unsigned options = (call_med->enable_rtcp_mux?
2114             			    PJMEDIA_TPMED_RTCP_MUX: 0);
2115                 status = pjmedia_transport_media_create(
2116                              call_med->tp, tmp_pool,
2117                              options, call->async_call.rem_sdp, mi);
2118             }
2119 	    if (status != PJ_SUCCESS) {
2120                 call->med_ch_info.status = status;
2121                 call->med_ch_info.med_idx = mi;
2122                 call->med_ch_info.state = call_med->tp_st;
2123                 call->med_ch_info.sip_err_code = PJSIP_SC_TEMPORARILY_UNAVAILABLE;
2124 
2125 		/* Revert back provisional media. */
2126 		pjsua_media_prov_revert(call_id);
2127 
2128 		goto on_return;
2129 	    }
2130 
2131 	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_INIT);
2132 	}
2133     }
2134 
2135     call->med_ch_info.status = PJ_SUCCESS;
2136 
2137 on_return:
2138     if (call->med_ch_cb)
2139         (*call->med_ch_cb)(call->index, &call->med_ch_info);
2140 
2141     return status;
2142 }
2143 
2144 
2145 /* Clean up media transports in provisional media that is not used by
2146  * call media.
2147  */
pjsua_media_prov_clean_up(pjsua_call_id call_id)2148 void pjsua_media_prov_clean_up(pjsua_call_id call_id)
2149 {
2150     pjsua_call *call = &pjsua_var.calls[call_id];
2151     unsigned i;
2152 
2153     if (call->med_prov_cnt > call->med_cnt) {
2154         PJ_LOG(4,(THIS_FILE, "Call %d: cleaning up provisional media, "
2155         		     "prov_med_cnt=%d, med_cnt=%d",
2156 			     call_id, call->med_prov_cnt, call->med_cnt));
2157     }
2158 
2159     for (i = 0; i < call->med_prov_cnt; ++i) {
2160 	pjsua_call_media *call_med = &call->media_prov[i];
2161 	unsigned j;
2162 	pj_bool_t used = PJ_FALSE;
2163 
2164 	if (call_med->tp == NULL)
2165 	    continue;
2166 
2167 	for (j = 0; j < call->med_cnt; ++j) {
2168 	    if (call->media[j].tp == call_med->tp) {
2169 		used = PJ_TRUE;
2170 		break;
2171 	    }
2172 	}
2173 
2174 	if (!used) {
2175 	    if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
2176 		pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
2177 		pjmedia_transport_media_stop(call_med->tp);
2178 	    }
2179 	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
2180 	    pjmedia_transport_close(call_med->tp);
2181 	    call_med->tp = call_med->tp_orig = NULL;
2182 	}
2183     }
2184 
2185     // Cleaning up unused media transports should not change provisional
2186     // media count.
2187     //call->med_prov_cnt = 0;
2188 }
2189 
2190 
2191 /* Revert back provisional media. */
pjsua_media_prov_revert(pjsua_call_id call_id)2192 void pjsua_media_prov_revert(pjsua_call_id call_id)
2193 {
2194     pjsua_call *call = &pjsua_var.calls[call_id];
2195 
2196     /* Clean up unused media transport */
2197     pjsua_media_prov_clean_up(call_id);
2198 
2199     /* Copy provisional media from active media */
2200     pj_memcpy(call->media_prov, call->media,
2201 	      sizeof(call->media[0]) * call->med_cnt);
2202     call->med_prov_cnt = call->med_cnt;
2203 }
2204 
2205 
pjsua_media_channel_init(pjsua_call_id call_id,pjsip_role_e role,int security_level,pj_pool_t * tmp_pool,const pjmedia_sdp_session * rem_sdp,int * sip_err_code,pj_bool_t async,pjsua_med_tp_state_cb cb)2206 pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
2207 				     pjsip_role_e role,
2208 				     int security_level,
2209 				     pj_pool_t *tmp_pool,
2210 				     const pjmedia_sdp_session *rem_sdp,
2211 				     int *sip_err_code,
2212                                      pj_bool_t async,
2213                                      pjsua_med_tp_state_cb cb)
2214 {
2215     const pj_str_t STR_AUDIO = { "audio", 5 };
2216     const pj_str_t STR_VIDEO = { "video", 5 };
2217     pjsua_call *call = &pjsua_var.calls[call_id];
2218     pjsua_acc *acc = &pjsua_var.acc[call->acc_id];
2219     pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA];
2220     unsigned maudcnt = PJ_ARRAY_SIZE(maudidx);
2221     unsigned mtotaudcnt = PJ_ARRAY_SIZE(maudidx);
2222     pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA];
2223     unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx);
2224     unsigned mtotvidcnt = PJ_ARRAY_SIZE(mvididx);
2225     unsigned mi;
2226     pj_bool_t pending_med_tp = PJ_FALSE;
2227     pj_bool_t reinit = PJ_FALSE;
2228     pj_status_t status;
2229 
2230     PJ_UNUSED_ARG(role);
2231 
2232     /*
2233      * Note: this function may be called when the media already exists
2234      * (e.g. in reinvites, updates, etc).
2235      */
2236 
2237     if (pjsua_get_state() != PJSUA_STATE_RUNNING) {
2238         if (sip_err_code)
2239 	    *sip_err_code = PJSIP_SC_SERVICE_UNAVAILABLE;
2240 	return PJ_EBUSY;
2241     }
2242 
2243     if (async) {
2244         pj_pool_t *tmppool = (call->inv? call->inv->pool_prov:
2245                               call->async_call.dlg->pool);
2246 
2247         status = pj_mutex_create_simple(tmppool, NULL, &call->med_ch_mutex);
2248 	if (status != PJ_SUCCESS) {
2249 	    if (sip_err_code)
2250 		*sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR;
2251             return status;
2252 	}
2253     }
2254 
2255     if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED)
2256 	reinit = PJ_TRUE;
2257 
2258     PJ_LOG(4,(THIS_FILE, "Call %d: %sinitializing media..",
2259 			 call_id, (reinit?"re-":"") ));
2260 
2261     pj_log_push_indent();
2262 
2263     /* Init provisional media state */
2264     if (call->med_cnt == 0) {
2265 	/* New media session, just copy whole from call media state. */
2266 	pj_memcpy(call->media_prov, call->media, sizeof(call->media));
2267     } else {
2268 	/* Clean up any unused transports. Note that when local SDP reoffer
2269 	 * is rejected by remote, there may be any initialized transports that
2270 	 * are not used by call media and currently there is no notification
2271 	 * from PJSIP level regarding the reoffer rejection.
2272 	 */
2273 	pjsua_media_prov_clean_up(call_id);
2274 
2275 	/* Updating media session, copy from call media state. */
2276 	pj_memcpy(call->media_prov, call->media,
2277 		  sizeof(call->media[0]) * call->med_cnt);
2278     }
2279     call->med_prov_cnt = call->med_cnt;
2280 
2281 #if DISABLED_FOR_TICKET_1185
2282     /* Return error if media transport has not been created yet
2283      * (e.g. application is starting)
2284      */
2285     for (i=0; i<call->med_cnt; ++i) {
2286 	if (call->media[i].tp == NULL) {
2287 	    status = PJ_EBUSY;
2288 	    goto on_error;
2289 	}
2290     }
2291 #endif
2292 
2293     /* Get media count for each media type */
2294     if (rem_sdp) {
2295 
2296 	/* We are sending answer, check media count for each media type
2297 	 * from the remote SDP.
2298 	 */
2299 	sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp,
2300 		   maudidx, &maudcnt, &mtotaudcnt);
2301 
2302 #if PJMEDIA_HAS_VIDEO
2303 	sort_media(rem_sdp, &STR_VIDEO, acc->cfg.use_srtp,
2304 		   mvididx, &mvidcnt, &mtotvidcnt);
2305 #else
2306 	mvidcnt = mtotvidcnt = 0;
2307 	PJ_UNUSED_ARG(STR_VIDEO);
2308 #endif
2309 
2310 	if (maudcnt + mvidcnt == 0) {
2311 	    /* Expecting audio or video in the offer */
2312 	    if (sip_err_code)
2313 		*sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
2314 	    status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
2315 	    goto on_error;
2316 	}
2317 
2318 	/* Update media count only when remote add any media, this media count
2319 	 * must never decrease. Also note that we shouldn't apply the media
2320 	 * count setting (of the call setting) before the SDP negotiation.
2321 	 */
2322 	if (call->med_prov_cnt < rem_sdp->media_count)
2323 	    call->med_prov_cnt = PJ_MIN(rem_sdp->media_count,
2324 					PJSUA_MAX_CALL_MEDIA);
2325 
2326 	call->rem_offerer = PJ_TRUE;
2327 	call->rem_aud_cnt = maudcnt;
2328 	call->rem_vid_cnt = mvidcnt;
2329 
2330     } else {
2331 
2332 	/* If call is already established, adjust the existing call media list
2333 	 * to media count setting in call setting, e.g: re-enable/disable/add
2334 	 * media from existing media.
2335 	 * Otherwise, apply media count from the call setting directly.
2336 	 */
2337 	if (reinit) {
2338 	    pj_bool_t sort_check_tp;
2339 
2340 	    /* Media sorting below will check transport, i.e: media without
2341 	     * transport will have lower priority. If PJSUA_CALL_REINIT_MEDIA
2342 	     * is set, we must not check transport.
2343 	     */
2344 	    sort_check_tp = !(call->opt.flag & PJSUA_CALL_REINIT_MEDIA);
2345 
2346 	    /* We are sending reoffer, check media count for each media type
2347 	     * from the existing call media list.
2348 	     */
2349 	    sort_media2(call->media_prov, sort_check_tp, call->med_prov_cnt,
2350 			PJMEDIA_TYPE_AUDIO, maudidx, &maudcnt, &mtotaudcnt);
2351 
2352 	    /* No need to assert if there's no media. */
2353 	    //pj_assert(maudcnt > 0);
2354 
2355 	    sort_media2(call->media_prov, sort_check_tp, call->med_prov_cnt,
2356 			PJMEDIA_TYPE_VIDEO, mvididx, &mvidcnt, &mtotvidcnt);
2357 
2358 	    /* Call setting may add or remove media. Adding media is done by
2359 	     * enabling any disabled/port-zeroed media first, then adding new
2360 	     * media whenever needed. Removing media is done by disabling
2361 	     * media with the lowest 'quality'.
2362 	     */
2363 
2364 	    /* Check if we need to add new audio */
2365 	    if (maudcnt < call->opt.aud_cnt &&
2366 		mtotaudcnt < call->opt.aud_cnt)
2367 	    {
2368 		for (mi = 0; mi < call->opt.aud_cnt - mtotaudcnt; ++mi)
2369 		    maudidx[maudcnt++] = (pj_uint8_t)call->med_prov_cnt++;
2370 
2371 		mtotaudcnt = call->opt.aud_cnt;
2372 	    }
2373 	    maudcnt = call->opt.aud_cnt;
2374 
2375 	    /* Check if we need to add new video */
2376 	    if (mvidcnt < call->opt.vid_cnt &&
2377 		mtotvidcnt < call->opt.vid_cnt)
2378 	    {
2379 		for (mi = 0; mi < call->opt.vid_cnt - mtotvidcnt; ++mi)
2380 		    mvididx[mvidcnt++] = (pj_uint8_t)call->med_prov_cnt++;
2381 
2382 		mtotvidcnt = call->opt.vid_cnt;
2383 	    }
2384 	    mvidcnt = call->opt.vid_cnt;
2385 
2386 	    /* In case of media reinit, 'med_prov_cnt' may be decreased
2387 	     * because the new call->opt says so. As media count should
2388 	     * never decrease, we should verify 'med_prov_cnt' to be
2389 	     * at least equal to 'med_cnt' (see also #1987).
2390 	     */
2391 	    if ((call->opt.flag & PJSUA_CALL_REINIT_MEDIA) &&
2392 		call->med_prov_cnt < call->med_cnt)
2393 	    {
2394 		call->med_prov_cnt = call->med_cnt;
2395 	    }
2396 
2397 	} else {
2398 
2399 	    maudcnt = mtotaudcnt = call->opt.aud_cnt;
2400 	    for (mi=0; mi<maudcnt; ++mi) {
2401 		maudidx[mi] = (pj_uint8_t)mi;
2402 	    }
2403 	    mvidcnt = mtotvidcnt = call->opt.vid_cnt;
2404 	    for (mi=0; mi<mvidcnt; ++mi) {
2405 		mvididx[mi] = (pj_uint8_t)(maudcnt + mi);
2406 	    }
2407 	    call->med_prov_cnt = maudcnt + mvidcnt;
2408 
2409 	    /* Need to publish supported media? */
2410 	    if (call->opt.flag & PJSUA_CALL_INCLUDE_DISABLED_MEDIA) {
2411 		if (mtotaudcnt == 0) {
2412 		    mtotaudcnt = 1;
2413 		    maudidx[0] = (pj_uint8_t)call->med_prov_cnt++;
2414 		}
2415 #if PJMEDIA_HAS_VIDEO
2416 		if (mtotvidcnt == 0) {
2417 		    mtotvidcnt = 1;
2418 		    mvididx[0] = (pj_uint8_t)call->med_prov_cnt++;
2419 		}
2420 #endif
2421 	    }
2422 	}
2423 
2424 	call->rem_offerer = PJ_FALSE;
2425     }
2426 
2427     if (call->med_prov_cnt == 0) {
2428 	/* Expecting at least one media */
2429 	if (sip_err_code)
2430 	    *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
2431 	status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
2432 	goto on_error;
2433     }
2434 
2435     if (async) {
2436         call->med_ch_cb = cb;
2437     }
2438 
2439     if (rem_sdp) {
2440         call->async_call.rem_sdp =
2441             pjmedia_sdp_session_clone(call->inv->pool_prov, rem_sdp);
2442     } else {
2443 	call->async_call.rem_sdp = NULL;
2444     }
2445 
2446     call->async_call.pool_prov = tmp_pool;
2447 
2448     /* Initialize each media line */
2449     for (mi=0; mi < call->med_prov_cnt; ++mi) {
2450 	pjsua_call_media *call_med = &call->media_prov[mi];
2451 	pj_bool_t enabled = PJ_FALSE;
2452 	pjmedia_type media_type = PJMEDIA_TYPE_UNKNOWN;
2453 
2454 	if (pj_memchr(maudidx, mi, mtotaudcnt * sizeof(maudidx[0]))) {
2455 	    media_type = PJMEDIA_TYPE_AUDIO;
2456 	    if (call->opt.aud_cnt &&
2457 		pj_memchr(maudidx, mi, maudcnt * sizeof(maudidx[0])))
2458 	    {
2459 		enabled = PJ_TRUE;
2460 	    }
2461 	} else if (pj_memchr(mvididx, mi, mtotvidcnt * sizeof(mvididx[0]))) {
2462 	    media_type = PJMEDIA_TYPE_VIDEO;
2463 	    if (call->opt.vid_cnt &&
2464 		pj_memchr(mvididx, mi, mvidcnt * sizeof(mvididx[0])))
2465 	    {
2466 		enabled = PJ_TRUE;
2467 	    }
2468 	}
2469 
2470 	if (enabled) {
2471 	    call_med->enable_rtcp_mux = acc->cfg.enable_rtcp_mux;
2472 
2473 	    status = pjsua_call_media_init(call_med, media_type,
2474 	                                   &acc->cfg.rtp_cfg,
2475 					   security_level, sip_err_code,
2476                                            async,
2477                                            (async? &media_channel_init_cb:
2478                                             NULL));
2479             if (status == PJ_EPENDING) {
2480                 pending_med_tp = PJ_TRUE;
2481             } else if (status != PJ_SUCCESS) {
2482                 if (pending_med_tp) {
2483                     /* Save failure information. */
2484                     call_med->tp_ready = status;
2485                     pj_bzero(&call->med_ch_info, sizeof(call->med_ch_info));
2486                     call->med_ch_info.status = status;
2487                     call->med_ch_info.state = call_med->tp_st;
2488                     call->med_ch_info.med_idx = call_med->idx;
2489                     if (sip_err_code)
2490                         call->med_ch_info.sip_err_code = *sip_err_code;
2491 
2492                     /* We will return failure in the callback later. */
2493                     return PJ_EPENDING;
2494                 }
2495 
2496 		/* Revert back provisional media. */
2497 		pjsua_media_prov_revert(call_id);
2498 
2499 		goto on_error;
2500 	    }
2501 
2502 	    /* Find and save "a=mid". Currently this is for trickle ICE.
2503 	     * Trickle ICE match media in SDP of SIP INFO by comparing this
2504 	     * attribute, so remote SDP must be received first before remote
2505 	     * SDP in SIP INFO can be processed.
2506 	     */
2507 	    if (rem_sdp && call_med->rem_mid.slen == 0) {
2508 		const pjmedia_sdp_media *m = rem_sdp->media[mi];
2509 		pjmedia_sdp_attr *a;
2510 
2511 		a = pjmedia_sdp_media_find_attr2(m, "mid", NULL);
2512 		if (a)
2513 		    call_med->rem_mid = a->value;
2514 	    }
2515 
2516 	} else {
2517 	    /* By convention, the media is disabled if transport is NULL
2518 	     * or transport state is PJSUA_MED_TP_DISABLED.
2519 	     */
2520 	    if (call_med->tp) {
2521 		// Don't close transport here, as SDP negotiation has not been
2522 		// done and stream may be still active. Once SDP negotiation
2523 		// is done (channel_update() invoked), this transport will be
2524 		// closed there.
2525 		//pjmedia_transport_close(call_med->tp);
2526 		//call_med->tp = NULL;
2527 		pj_assert(call_med->tp_st == PJSUA_MED_TP_INIT ||
2528 			  call_med->tp_st == PJSUA_MED_TP_RUNNING);
2529 		pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_DISABLED);
2530 	    }
2531 
2532 	    /* Put media type just for info if not yet defined */
2533 	    if (call_med->type == PJMEDIA_TYPE_NONE)
2534 		call_med->type = media_type;
2535 	}
2536     }
2537 
2538     if (maudcnt > 0) {
2539     	call->audio_idx = maudidx[0];
2540 
2541     	PJ_LOG(4,(THIS_FILE, "Media index %d selected for audio call %d",
2542 	      	  call->audio_idx, call->index));
2543     } else {
2544     	call->audio_idx = -1;
2545     }
2546 
2547     if (pending_med_tp) {
2548         /* We shouldn't use temporary pool anymore. */
2549         call->async_call.pool_prov = NULL;
2550         /* We have a pending media transport initialization. */
2551         pj_log_pop_indent();
2552         return PJ_EPENDING;
2553     }
2554 
2555     /* Media transport initialization completed immediately, so
2556      * we don't need to call the callback.
2557      */
2558     call->med_ch_cb = NULL;
2559 
2560     status = media_channel_init_cb(call_id, NULL);
2561     if (status != PJ_SUCCESS && sip_err_code) {
2562 	if (call->med_ch_info.sip_err_code)
2563 	    *sip_err_code = call->med_ch_info.sip_err_code;
2564 	else
2565 	    *sip_err_code = PJSIP_ERRNO_TO_SIP_STATUS(status);
2566     }
2567 
2568     pj_log_pop_indent();
2569     return status;
2570 
2571 on_error:
2572     if (call->med_ch_mutex) {
2573         pj_mutex_destroy(call->med_ch_mutex);
2574         call->med_ch_mutex = NULL;
2575     }
2576 
2577     if (sip_err_code && *sip_err_code == 0)
2578 	*sip_err_code = PJSIP_ERRNO_TO_SIP_STATUS(status);
2579 
2580     pj_log_pop_indent();
2581     return status;
2582 }
2583 
2584 
2585 /* Create SDP based on the current media channel. Note that, this function
2586  * will not modify the media channel, so when receiving new offer or
2587  * updating media count (via call setting), media channel must be reinit'd
2588  * (using pjsua_media_channel_init()) first before calling this function.
2589  */
pjsua_media_channel_create_sdp(pjsua_call_id call_id,pj_pool_t * pool,const pjmedia_sdp_session * rem_sdp,pjmedia_sdp_session ** p_sdp,int * sip_err_code)2590 pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
2591 					   pj_pool_t *pool,
2592 					   const pjmedia_sdp_session *rem_sdp,
2593 					   pjmedia_sdp_session **p_sdp,
2594 					   int *sip_err_code)
2595 {
2596     enum { MAX_MEDIA = PJSUA_MAX_CALL_MEDIA };
2597     pjmedia_sdp_session *sdp;
2598     pj_sockaddr origin;
2599     pjsua_call *call = &pjsua_var.calls[call_id];
2600     pjsua_acc *acc = &pjsua_var.acc[call->acc_id];
2601     pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL;
2602     unsigned mi;
2603     unsigned tot_bandw_tias = 0;
2604     pj_status_t status;
2605 
2606     if (pjsua_get_state() != PJSUA_STATE_RUNNING) {
2607 	status = PJ_EBUSY;
2608 	goto on_error;
2609     }
2610 
2611 #if 0
2612     // This function should not really change the media channel.
2613     if (rem_sdp) {
2614 	/* If this is a re-offer, let's re-initialize media as remote may
2615 	 * add or remove media
2616 	 */
2617 	if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
2618 	    status = pjsua_media_channel_init(call_id, PJSIP_ROLE_UAS,
2619 					      call->secure_level, pool,
2620 					      rem_sdp, sip_err_code,
2621                                               PJ_FALSE, NULL);
2622 	    if (status != PJ_SUCCESS)
2623 		return status;
2624 	}
2625     } else {
2626 	/* Audio is first in our offer, by convention */
2627 	// The audio_idx should not be changed here, as this function may be
2628 	// called in generating re-offer and the current active audio index
2629 	// can be anywhere.
2630 	//call->audio_idx = 0;
2631     }
2632 #endif
2633 
2634 #if 0
2635     // Since r3512, old-style hold should have got transport, created by
2636     // pjsua_media_channel_init() in initial offer/answer or remote reoffer.
2637     /* Create media if it's not created. This could happen when call is
2638      * currently on-hold (with the old style hold)
2639      */
2640     if (call->media[call->audio_idx].tp == NULL) {
2641 	pjsip_role_e role;
2642 	role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC);
2643 	status = pjsua_media_channel_init(call_id, role, call->secure_level,
2644 					  pool, rem_sdp, sip_err_code);
2645 	if (status != PJ_SUCCESS)
2646 	    return status;
2647     }
2648 #endif
2649 
2650     /* Get SDP negotiator state */
2651     if (call->inv && call->inv->neg)
2652 	sdp_neg_state = pjmedia_sdp_neg_get_state(call->inv->neg);
2653 
2654     PJ_UNUSED_ARG(sdp_neg_state);
2655 
2656     /* Get one address to use in the origin field */
2657     pj_bzero(&origin, sizeof(origin));
2658     for (mi=0; mi<call->med_prov_cnt; ++mi) {
2659 	pjmedia_transport_info tpinfo;
2660 
2661 	if (call->media_prov[mi].tp == NULL)
2662 	    continue;
2663 
2664 	pjmedia_transport_info_init(&tpinfo);
2665 	pjmedia_transport_get_info(call->media_prov[mi].tp, &tpinfo);
2666 	pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name);
2667 	break;
2668     }
2669 
2670     /* Create the base (blank) SDP */
2671     status = pjmedia_endpt_create_base_sdp(pjsua_var.med_endpt, pool, NULL,
2672                                            &origin, &sdp);
2673     if (status != PJ_SUCCESS)
2674 	goto on_error;
2675 
2676     /* Process each media line */
2677     for (mi=0; mi<call->med_prov_cnt; ++mi) {
2678 	pjsua_call_media *call_med = &call->media_prov[mi];
2679 	pjmedia_sdp_media *m = NULL;
2680 	pjmedia_transport_info tpinfo;
2681 	unsigned i;
2682 
2683 	if (rem_sdp && mi >= rem_sdp->media_count) {
2684 	    /* Remote might have removed some media lines. */
2685 	    /* Note that we must not modify the current active media
2686 	     * (e.g: stop stream, close/cleanup media transport), as if
2687 	     * SDP nego fails, the current active media should be maintained.
2688 	     * Also note that our media count should never decrease, even when
2689 	     * remote removed some media lines.
2690 	     */
2691 	    break;
2692 	}
2693 
2694 	if (call_med->tp == NULL || call_med->tp_st == PJSUA_MED_TP_DISABLED)
2695 	{
2696 	    /*
2697 	     * This media is disabled. Just create a valid SDP with zero
2698 	     * port.
2699 	     */
2700 	    if (rem_sdp) {
2701 		/* Just clone the remote media and deactivate it */
2702 		m = pjmedia_sdp_media_clone_deactivate(pool,
2703 						       rem_sdp->media[mi]);
2704 	    } else {
2705 		m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
2706 		m->desc.transport = pj_str("RTP/AVP");
2707 		m->desc.fmt_count = 1;
2708 
2709 		switch (call_med->type) {
2710 		case PJMEDIA_TYPE_AUDIO:
2711 		    m->desc.media = pj_str("audio");
2712 		    m->desc.fmt[0] = pj_str("0");
2713 		    break;
2714 		case PJMEDIA_TYPE_VIDEO:
2715 		    m->desc.media = pj_str("video");
2716 		    m->desc.fmt[0] = pj_str("31");
2717 		    break;
2718 		default:
2719 		    /* This must be us generating re-offer, and some unknown
2720 		     * media may exist, so just clone from active local SDP
2721 		     * (and it should have been deactivated already).
2722 		     */
2723 		    pj_assert(call->inv && call->inv->neg &&
2724 			      sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE);
2725 		    {
2726 			const pjmedia_sdp_session *s_;
2727 			pjmedia_sdp_neg_get_active_local(call->inv->neg, &s_);
2728 
2729 			if (mi < s_->media_count) {
2730 			    m = pjmedia_sdp_media_clone(pool, s_->media[mi]);
2731 			    m->desc.port = 0;
2732 			} else {
2733 			    /* Remote may have removed some media lines in
2734 			     * previous negotiations. However, since our
2735 			     * media count may never decrease (as per
2736 			     * the RFC), we'll just offer unknown media here.
2737 			     */
2738 		    	    m->desc.media = pj_str("unknown");
2739 		            m->desc.fmt[0] = pj_str("0");
2740 			}
2741 		    }
2742 		    break;
2743 		}
2744 	    }
2745 
2746 	    /* Add connection line, if none */
2747 	    if (m->conn == NULL && sdp->conn == NULL) {
2748 		pj_bool_t use_ipv6;
2749 		pj_bool_t use_nat64;
2750 
2751 		use_ipv6 = (pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
2752 			    PJSUA_IPV6_DISABLED);
2753 		use_nat64 = (pjsua_var.acc[call->acc_id].cfg.nat64_opt !=
2754 			     PJSUA_NAT64_DISABLED);
2755 
2756 		m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
2757 		m->conn->net_type = pj_str("IN");
2758 		if (use_ipv6 && !use_nat64) {
2759 		    m->conn->addr_type = pj_str("IP6");
2760 		    m->conn->addr = pj_str("::1");
2761 		} else {
2762 		    m->conn->addr_type = pj_str("IP4");
2763 		    m->conn->addr = pj_str("127.0.0.1");
2764 		}
2765 	    }
2766 
2767 	    sdp->media[sdp->media_count++] = m;
2768 	    continue;
2769 	}
2770 
2771 	/* Get transport address info */
2772 	pjmedia_transport_info_init(&tpinfo);
2773 	pjmedia_transport_get_info(call_med->tp, &tpinfo);
2774 
2775 	/* Ask pjmedia endpoint to create SDP media line */
2776 	switch (call_med->type) {
2777 	case PJMEDIA_TYPE_AUDIO:
2778 	    status = pjmedia_endpt_create_audio_sdp(pjsua_var.med_endpt, pool,
2779                                                     &tpinfo.sock_info, 0, &m);
2780 	    break;
2781 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
2782 	case PJMEDIA_TYPE_VIDEO:
2783 	    status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool,
2784 	                                            &tpinfo.sock_info, 0, &m);
2785 	    break;
2786 #endif
2787 	default:
2788 	    pj_assert(!"Invalid call_med media type");
2789 	    status = PJ_EBUG;
2790 	}
2791 
2792 	if (status != PJ_SUCCESS)
2793 	    goto on_error;
2794 
2795 	/* Add generated media to SDP session */
2796 	sdp->media[sdp->media_count++] = m;
2797 
2798 	/* Disable media if it has zero format/codec */
2799 	if (m->desc.fmt_count == 0) {
2800 	    m->desc.fmt[m->desc.fmt_count++] = pj_str("0");
2801 	    pjmedia_sdp_media_deactivate(pool, m);
2802 	    PJ_LOG(3,(THIS_FILE,
2803 		      "Call %d media %d: Disabled due to no active codec",
2804 		      call_id, mi));
2805 	    continue;
2806 	}
2807 
2808     	/* Add ssrc and cname attribute */
2809     	m->attr[m->attr_count++] = pjmedia_sdp_attr_create_ssrc(pool,
2810     								call_med->ssrc,
2811     								&call->cname);
2812 
2813 	/* Give to transport */
2814 	status = pjmedia_transport_encode_sdp(call_med->tp, pool,
2815 					      sdp, rem_sdp, mi);
2816 	if (status != PJ_SUCCESS) {
2817 	    if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE;
2818 	    goto on_error;
2819 	}
2820 
2821 #if PJSUA_SDP_SESS_HAS_CONN
2822 	/* Copy c= line of the first media to session level,
2823 	 * if there's none.
2824 	 */
2825 	if (sdp->conn == NULL) {
2826 	    sdp->conn = pjmedia_sdp_conn_clone(pool, m->conn);
2827 	}
2828 #endif
2829 
2830 
2831 	/* Find media bandwidth info */
2832 	for (i = 0; i < m->bandw_count; ++i) {
2833 	    const pj_str_t STR_BANDW_MODIFIER_TIAS = { "TIAS", 4 };
2834 	    if (!pj_stricmp(&m->bandw[i]->modifier, &STR_BANDW_MODIFIER_TIAS))
2835 	    {
2836 		tot_bandw_tias += m->bandw[i]->value;
2837 		break;
2838 	    }
2839 	}
2840 
2841 	/* Setup RTCP-FB */
2842 	{
2843 	    pjmedia_rtcp_fb_setting rtcp_cfg;
2844 	    pjmedia_rtcp_fb_setting_default(&rtcp_cfg);
2845 
2846 	    /* Add RTCP-FB PLI if PJSUA_VID_REQ_KEYFRAME_RTCP_PLI is set */
2847 	    if (call_med->type == PJMEDIA_TYPE_VIDEO &&
2848 		(call->opt.req_keyframe_method &
2849 		 PJSUA_VID_REQ_KEYFRAME_RTCP_PLI))
2850 	    {
2851 		rtcp_cfg.cap_count = 1;
2852 		pj_strset2(&rtcp_cfg.caps[0].codec_id, (char*)"*");
2853 		rtcp_cfg.caps[0].type = PJMEDIA_RTCP_FB_NACK;
2854 		pj_strset2(&rtcp_cfg.caps[0].param, (char*)"pli");
2855 	    }
2856 
2857 	    /* Should we put "RTP/AVPF" in SDP?*/
2858 	    if (rem_sdp) {
2859 		/* For answer, match remote offer */
2860 		unsigned rem_proto = 0;
2861 		rem_proto = pjmedia_sdp_transport_get_proto(
2862 					&rem_sdp->media[mi]->desc.transport);
2863 		rtcp_cfg.dont_use_avpf =
2864 			!PJMEDIA_TP_PROTO_HAS_FLAG(rem_proto,
2865 						PJMEDIA_TP_PROFILE_RTCP_FB);
2866 	    } else {
2867 		/* For offer, check account setting */
2868 		rtcp_cfg.dont_use_avpf = acc->cfg.rtcp_fb_cfg.dont_use_avpf ||
2869 					 (acc->cfg.rtcp_fb_cfg.cap_count == 0
2870 					  && rtcp_cfg.cap_count == 0);
2871 	    }
2872 
2873 	    status = pjmedia_rtcp_fb_encode_sdp(pool, pjsua_var.med_endpt,
2874 						&rtcp_cfg, sdp,
2875 						mi, rem_sdp);
2876 	    if (status != PJ_SUCCESS) {
2877 		PJ_PERROR(3,(THIS_FILE, status,
2878 			     "Call %d media %d: Failed to encode RTCP-FB PLI "
2879 			     "setting to SDP",
2880 			     call_id, mi));
2881 	    }
2882 
2883 	    /* Add any other RTCP-FB setting configured in account setting */
2884 	    if (acc->cfg.rtcp_fb_cfg.cap_count) {
2885 		pj_bool_t tmp = rtcp_cfg.dont_use_avpf;
2886 		rtcp_cfg = acc->cfg.rtcp_fb_cfg;
2887 		rtcp_cfg.dont_use_avpf = tmp;
2888 		status = pjmedia_rtcp_fb_encode_sdp(pool, pjsua_var.med_endpt,
2889 						    &rtcp_cfg, sdp,
2890 						    mi, rem_sdp);
2891 		if (status != PJ_SUCCESS) {
2892 		    PJ_PERROR(3,(THIS_FILE, status,
2893 				 "Call %d media %d: Failed to encode account "
2894 				 "RTCP-FB setting to SDP",
2895 				 call_id, mi));
2896 		}
2897 	    }
2898 	}
2899 
2900 	/* Find and save "a=mid". Currently this is for trickle ICE. Trickle
2901 	 * ICE match media in SDP of SIP INFO by comparing this attribute,
2902 	 * so remote SDP must be received first before remote SDP in SIP INFO
2903 	 * can be processed.
2904 	 */
2905 	if (call_med->rem_mid.slen == 0) {
2906 	    pjmedia_sdp_attr *a;
2907 
2908 	    a = pjmedia_sdp_media_find_attr2(m, "mid", NULL);
2909 	    if (a)
2910 		call_med->rem_mid = a->value;
2911 	}
2912     }
2913 
2914     /* Add NAT info in the SDP */
2915     if (pjsua_var.ua_cfg.nat_type_in_sdp) {
2916 	pjmedia_sdp_attr *a;
2917 	pj_str_t value;
2918 	char nat_info[80];
2919 
2920 	value.ptr = nat_info;
2921 	if (pjsua_var.ua_cfg.nat_type_in_sdp == 1) {
2922 	    value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
2923 					  "%d", pjsua_var.nat_type);
2924 	} else {
2925 	    const char *type_name = pj_stun_get_nat_name(pjsua_var.nat_type);
2926 	    value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
2927 					  "%d %s",
2928 					  pjsua_var.nat_type,
2929 					  type_name);
2930 	}
2931 
2932 	a = pjmedia_sdp_attr_create(pool, "X-nat", &value);
2933 
2934 	pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a);
2935 
2936     }
2937 
2938 
2939     /* Add bandwidth info in session level using bandwidth modifier "AS". */
2940     if (tot_bandw_tias) {
2941 	unsigned bandw;
2942 	const pj_str_t STR_BANDW_MODIFIER_AS = { "AS", 2 };
2943 	pjmedia_sdp_bandw *b;
2944 
2945 	/* AS bandwidth = RTP bitrate + RTCP bitrate.
2946 	 * RTP bitrate  = payload bitrate (total TIAS) + overheads (~16kbps).
2947 	 * RTCP bitrate = est. 5% of RTP bitrate.
2948 	 * Note that AS bandwidth is in kbps.
2949 	 */
2950 	bandw = tot_bandw_tias + 16000;
2951 	bandw += bandw * 5 / 100;
2952 	b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
2953 	b->modifier = STR_BANDW_MODIFIER_AS;
2954 	b->value = bandw / 1000;
2955 	sdp->bandw[sdp->bandw_count++] = b;
2956     }
2957 
2958 #if DISABLED_FOR_TICKET_1185 && defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
2959     /* Check if SRTP is in optional mode and configured to use duplicated
2960      * media, i.e: secured and unsecured version, in the SDP offer.
2961      */
2962     if (!rem_sdp &&
2963 	pjsua_var.acc[call->acc_id].cfg.use_srtp == PJMEDIA_SRTP_OPTIONAL &&
2964 	pjsua_var.acc[call->acc_id].cfg.srtp_optional_dup_offer)
2965     {
2966 	unsigned i;
2967 
2968 	for (i = 0; i < sdp->media_count; ++i) {
2969 	    pjmedia_sdp_media *m = sdp->media[i];
2970 
2971 	    /* Check if this media is unsecured but has SDP "crypto"
2972 	     * attribute.
2973 	     */
2974 	    if (pj_stricmp2(&m->desc.transport, "RTP/AVP") == 0 &&
2975 		pjmedia_sdp_media_find_attr2(m, "crypto", NULL) != NULL)
2976 	    {
2977 		if (i == (unsigned)call->audio_idx &&
2978 		    sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE)
2979 		{
2980 		    /* This is a session update, and peer has chosen the
2981 		     * unsecured version, so let's make this unsecured too.
2982 		     */
2983 		    pjmedia_sdp_media_remove_all_attr(m, "crypto");
2984 		} else {
2985 		    /* This is new offer, duplicate media so we'll have
2986 		     * secured (with "RTP/SAVP" transport) and and unsecured
2987 		     * versions.
2988 		     */
2989 		    pjmedia_sdp_media *new_m;
2990 
2991 		    /* Duplicate this media and apply secured transport */
2992 		    new_m = pjmedia_sdp_media_clone(pool, m);
2993 		    pj_strdup2(pool, &new_m->desc.transport, "RTP/SAVP");
2994 
2995 		    /* Remove the "crypto" attribute in the unsecured media */
2996 		    pjmedia_sdp_media_remove_all_attr(m, "crypto");
2997 
2998 		    /* Insert the new media before the unsecured media */
2999 		    if (sdp->media_count < PJMEDIA_MAX_SDP_MEDIA) {
3000 			pj_array_insert(sdp->media, sizeof(new_m),
3001 					sdp->media_count, i, &new_m);
3002 			++sdp->media_count;
3003 			++i;
3004 		    }
3005 		}
3006 	    }
3007 	}
3008     }
3009 #endif
3010 
3011     call->rem_offerer = (rem_sdp != NULL);
3012 
3013     /* Notify application */
3014     if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_call_sdp_created) {
3015 	(*pjsua_var.ua_cfg.cb.on_call_sdp_created)(call_id, sdp,
3016 						   pool, rem_sdp);
3017     }
3018 
3019     *p_sdp = sdp;
3020     return PJ_SUCCESS;
3021 
3022 on_error:
3023     if (sip_err_code && *sip_err_code == 0)
3024 	*sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR;
3025 
3026     return status;
3027 }
3028 
3029 
stop_media_stream(pjsua_call * call,unsigned med_idx)3030 static void stop_media_stream(pjsua_call *call, unsigned med_idx)
3031 {
3032     pjsua_call_media *call_med;
3033 
3034     if (pjsua_call_media_is_changing(call)) {
3035     	call_med = &call->media_prov[med_idx];
3036     	if (med_idx >= call->med_prov_cnt)
3037 	    return;
3038     } else {
3039     	call_med = &call->media[med_idx];
3040         if (med_idx >= call->med_cnt)
3041 	    return;
3042     }
3043 
3044     pj_log_push_indent();
3045 
3046     if (call_med->type == PJMEDIA_TYPE_AUDIO) {
3047 	pjsua_aud_stop_stream(call_med);
3048     }
3049 
3050 #if PJMEDIA_HAS_VIDEO
3051     else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
3052 	pjsua_vid_stop_stream(call_med);
3053     }
3054 #endif
3055 
3056     PJ_LOG(4,(THIS_FILE, "Media stream call%02d:%d is destroyed",
3057 			 call->index, med_idx));
3058     call_med->prev_state = call_med->state;
3059     call_med->state = PJSUA_CALL_MEDIA_NONE;
3060 
3061     /* Try to sync recent changes to provisional media */
3062     if (med_idx < call->med_prov_cnt &&
3063 	call->media_prov[med_idx].tp == call_med->tp)
3064     {
3065 	pjsua_call_media *prov_med = &call->media_prov[med_idx];
3066 
3067 	/* Media state */
3068 	prov_med->prev_state = call_med->prev_state;
3069 	prov_med->state	     = call_med->state;
3070 
3071 	/* RTP seq/ts */
3072 	prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set;
3073 	prov_med->rtp_tx_seq	    = call_med->rtp_tx_seq;
3074 	prov_med->rtp_tx_ts	    = call_med->rtp_tx_ts;
3075 
3076 	/* Stream */
3077 	if (call_med->type == PJMEDIA_TYPE_AUDIO) {
3078 	    prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot;
3079 	    prov_med->strm.a.stream    = call_med->strm.a.stream;
3080 	}
3081 #if PJMEDIA_HAS_VIDEO
3082 	else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
3083 	    prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id;
3084 	    prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id;
3085 	    prov_med->strm.v.stream	= call_med->strm.v.stream;
3086 	}
3087 #endif
3088     }
3089 
3090     pj_log_pop_indent();
3091 }
3092 
stop_media_session(pjsua_call_id call_id)3093 static void stop_media_session(pjsua_call_id call_id)
3094 {
3095     pjsua_call *call = &pjsua_var.calls[call_id];
3096     unsigned mi;
3097 
3098     for (mi=0; mi<call->med_cnt; ++mi) {
3099 	stop_media_stream(call, mi);
3100     }
3101 }
3102 
pjsua_media_channel_deinit(pjsua_call_id call_id)3103 pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
3104 {
3105     pjsua_call *call = &pjsua_var.calls[call_id];
3106     unsigned mi;
3107 
3108     for (mi=0; mi<call->med_cnt; ++mi) {
3109 	pjsua_call_media *call_med = &call->media[mi];
3110 
3111         if (call_med->tp_st == PJSUA_MED_TP_CREATING) {
3112             /* We will do the deinitialization after media transport
3113              * creation is completed.
3114              */
3115             call->async_call.med_ch_deinit = PJ_TRUE;
3116             return PJ_SUCCESS;
3117         }
3118     }
3119 
3120     PJ_LOG(4,(THIS_FILE, "Call %d: deinitializing media..", call_id));
3121     pj_log_push_indent();
3122 
3123     stop_media_session(call_id);
3124 
3125     /* Stop trickle ICE timer */
3126     if (call->trickle_ice.trickling > PJSUA_OP_STATE_NULL) {
3127 	call->trickle_ice.trickling = PJSUA_OP_STATE_NULL;
3128 	pjsua_cancel_timer(&call->trickle_ice.timer);
3129     }
3130     call->trickle_ice.enabled = PJ_FALSE;
3131     call->trickle_ice.pending_info = PJ_FALSE;
3132     call->trickle_ice.remote_sup = PJ_FALSE;
3133     call->trickle_ice.retrans18x_count = 0;
3134 
3135     /* Clean up media transports */
3136     pjsua_media_prov_clean_up(call_id);
3137     call->med_prov_cnt = 0;
3138     for (mi=0; mi<call->med_cnt; ++mi) {
3139 	pjsua_call_media *call_med = &call->media[mi];
3140 
3141         if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
3142 	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
3143 	    pjmedia_transport_media_stop(call_med->tp);
3144 	}
3145 
3146 	if (call_med->tp) {
3147 	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
3148 	    pjmedia_transport_close(call_med->tp);
3149 	    call_med->tp = call_med->tp_orig = NULL;
3150 	}
3151         call_med->tp_orig = NULL;
3152         call_med->rem_srtp_use = PJMEDIA_SRTP_UNKNOWN;
3153     }
3154 
3155     pj_log_pop_indent();
3156 
3157     return PJ_SUCCESS;
3158 }
3159 
3160 
3161 /* Match codec fmtp. This will compare the values and the order. */
match_codec_fmtp(const pjmedia_codec_fmtp * fmtp1,const pjmedia_codec_fmtp * fmtp2)3162 static pj_bool_t match_codec_fmtp(const pjmedia_codec_fmtp *fmtp1,
3163 				  const pjmedia_codec_fmtp *fmtp2)
3164 {
3165     unsigned i;
3166 
3167     if (fmtp1->cnt != fmtp2->cnt)
3168 	return PJ_FALSE;
3169 
3170     for (i = 0; i < fmtp1->cnt; ++i) {
3171 	if (pj_stricmp(&fmtp1->param[i].name, &fmtp2->param[i].name))
3172 	    return PJ_FALSE;
3173 	if (pj_stricmp(&fmtp1->param[i].val, &fmtp2->param[i].val))
3174 	    return PJ_FALSE;
3175     }
3176 
3177     return PJ_TRUE;
3178 }
3179 
3180 #if PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO
3181 
is_ice_running(pjmedia_transport * tp)3182 static pj_bool_t is_ice_running(pjmedia_transport *tp)
3183 {
3184     pjmedia_transport_info tpinfo;
3185     pjmedia_ice_transport_info *ice_info;
3186 
3187     pjmedia_transport_info_init(&tpinfo);
3188     pjmedia_transport_get_info(tp, &tpinfo);
3189     ice_info = (pjmedia_ice_transport_info*)
3190 	       pjmedia_transport_info_get_spc_info(&tpinfo,
3191 						   PJMEDIA_TRANSPORT_TYPE_ICE);
3192     return (ice_info && ice_info->sess_state == PJ_ICE_STRANS_STATE_RUNNING);
3193 }
3194 
3195 
is_media_changed(const pjsua_call * call,unsigned med_idx,const pjsua_stream_info * new_si_)3196 static pj_bool_t is_media_changed(const pjsua_call *call,
3197 				  unsigned med_idx,
3198 				  const pjsua_stream_info *new_si_)
3199 {
3200     const pjsua_call_media *call_med = &call->media[med_idx];
3201 
3202     /* Check for newly added media */
3203     if (med_idx >= call->med_cnt)
3204 	return PJ_TRUE;
3205 
3206     /* Compare media type */
3207     if (call_med->type != new_si_->type)
3208 	return PJ_TRUE;
3209 
3210     /* Audio update checks */
3211     if (call_med->type == PJMEDIA_TYPE_AUDIO) {
3212 	pjmedia_stream_info the_old_si;
3213 	const pjmedia_stream_info *old_si = NULL;
3214 	const pjmedia_stream_info *new_si = &new_si_->info.aud;
3215 	const pjmedia_codec_info *old_ci = NULL;
3216 	const pjmedia_codec_info *new_ci = &new_si->fmt;
3217 	const pjmedia_codec_param *old_cp = NULL;
3218 	const pjmedia_codec_param *new_cp = new_si->param;
3219 
3220 	/* Compare media direction */
3221 	if (call_med->dir != new_si->dir)
3222 	    return PJ_TRUE;
3223 
3224 	/* Get current active stream info */
3225 	if (call_med->strm.a.stream) {
3226 	    pjmedia_stream_get_info(call_med->strm.a.stream, &the_old_si);
3227 	    old_si = &the_old_si;
3228 	    old_ci = &old_si->fmt;
3229 	    old_cp = old_si->param;
3230 	} else {
3231 	    /* The stream is inactive. */
3232 	    return (new_si->dir != PJMEDIA_DIR_NONE);
3233 	}
3234 
3235 	/* Compare remote RTP address. If ICE is running, change in default
3236 	 * address can happen after negotiation, this can be handled
3237 	 * internally by ICE and does not need to cause media restart.
3238 	 */
3239 	if (old_si->rtcp_mux != new_si->rtcp_mux)
3240 	    return PJ_TRUE;
3241 	if (!is_ice_running(call_med->tp) &&
3242 	    pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
3243 	{
3244 	    return PJ_TRUE;
3245 	}
3246 
3247 	/* Compare codec info */
3248 	if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) ||
3249 	    old_ci->clock_rate != new_ci->clock_rate ||
3250 	    old_ci->channel_cnt != new_ci->channel_cnt ||
3251 	    old_si->rx_pt != new_si->rx_pt ||
3252 	    old_si->tx_pt != new_si->tx_pt ||
3253 	    old_si->rx_event_pt != new_si->tx_event_pt ||
3254 	    old_si->tx_event_pt != new_si->tx_event_pt)
3255 	{
3256 	    return PJ_TRUE;
3257 	}
3258 
3259 	/* Compare codec param */
3260 	if (old_cp->setting.frm_per_pkt != new_cp->setting.frm_per_pkt ||
3261 	    old_cp->setting.vad != new_cp->setting.vad ||
3262 	    old_cp->setting.cng != new_cp->setting.cng ||
3263 	    old_cp->setting.plc != new_cp->setting.plc ||
3264 	    old_cp->setting.penh != new_cp->setting.penh ||
3265 	    !match_codec_fmtp(&old_cp->setting.dec_fmtp,
3266 			      &new_cp->setting.dec_fmtp) ||
3267 	    !match_codec_fmtp(&old_cp->setting.enc_fmtp,
3268 			      &new_cp->setting.enc_fmtp))
3269 	{
3270 	    return PJ_TRUE;
3271 	}
3272     }
3273 
3274 #if PJMEDIA_HAS_VIDEO
3275     else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
3276 	pjmedia_vid_stream_info the_old_si;
3277 	const pjmedia_vid_stream_info *old_si = NULL;
3278 	const pjmedia_vid_stream_info *new_si = &new_si_->info.vid;
3279 	const pjmedia_vid_codec_info *old_ci = NULL;
3280 	const pjmedia_vid_codec_info *new_ci = &new_si->codec_info;
3281 	const pjmedia_vid_codec_param *old_cp = NULL;
3282 	const pjmedia_vid_codec_param *new_cp = new_si->codec_param;
3283 
3284 	/* Compare media direction */
3285 	if (call_med->dir != new_si->dir)
3286 	    return PJ_TRUE;
3287 
3288 	/* Get current active stream info */
3289 	if (call_med->strm.v.stream) {
3290 	    pjmedia_vid_stream_get_info(call_med->strm.v.stream, &the_old_si);
3291 	    old_si = &the_old_si;
3292 	    old_ci = &old_si->codec_info;
3293 	    old_cp = old_si->codec_param;
3294 	} else {
3295 	    /* The stream is inactive. */
3296 	    return (new_si->dir != PJMEDIA_DIR_NONE);
3297 	}
3298 
3299 	/* Compare remote RTP address. If ICE is running, change in default
3300 	 * address can happen after negotiation, this can be handled
3301 	 * internally by ICE and does not need to cause media restart.
3302 	 */
3303 	if (old_si->rtcp_mux != new_si->rtcp_mux)
3304 	    return PJ_TRUE;
3305 	if (!is_ice_running(call_med->tp) &&
3306 	    pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
3307 	{
3308 	    return PJ_TRUE;
3309 	}
3310 
3311 	/* Compare codec info */
3312 	if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) ||
3313 	    old_si->rx_pt != new_si->rx_pt ||
3314 	    old_si->tx_pt != new_si->tx_pt)
3315 	{
3316 	    return PJ_TRUE;
3317 	}
3318 
3319 	/* Compare codec param */
3320 	if (/* old_cp->enc_mtu != new_cp->enc_mtu || */
3321 	    pj_memcmp(&old_cp->enc_fmt.det, &new_cp->enc_fmt.det,
3322 		      sizeof(pjmedia_video_format_detail)) ||
3323 	    !match_codec_fmtp(&old_cp->dec_fmtp, &new_cp->dec_fmtp) ||
3324 	    !match_codec_fmtp(&old_cp->enc_fmtp, &new_cp->enc_fmtp))
3325 	{
3326 	    return PJ_TRUE;
3327 	}
3328     }
3329 
3330 #endif
3331 
3332     else {
3333 	/* Just return PJ_TRUE for other media type */
3334 	return PJ_TRUE;
3335     }
3336 
3337     return PJ_FALSE;
3338 }
3339 
3340 #else /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */
3341 
is_media_changed(const pjsua_call * call,unsigned med_idx,const pjsua_stream_info * new_si_)3342 static pj_bool_t is_media_changed(const pjsua_call *call,
3343 				  unsigned med_idx,
3344 				  const pjsua_stream_info *new_si_)
3345 {
3346     PJ_UNUSED_ARG(call);
3347     PJ_UNUSED_ARG(med_idx);
3348     PJ_UNUSED_ARG(new_si_);
3349     /* Always assume that media has been changed */
3350     return PJ_TRUE;
3351 }
3352 
3353 #endif /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */
3354 
3355 
pjsua_media_channel_update(pjsua_call_id call_id,const pjmedia_sdp_session * local_sdp,const pjmedia_sdp_session * remote_sdp)3356 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
3357 				       const pjmedia_sdp_session *local_sdp,
3358 				       const pjmedia_sdp_session *remote_sdp)
3359 {
3360     pjsua_call *call = &pjsua_var.calls[call_id];
3361     pjsua_acc *acc = &pjsua_var.acc[call->acc_id];
3362     pj_pool_t *tmp_pool = call->inv->pool_prov;
3363     unsigned mi;
3364     pj_bool_t got_media = PJ_FALSE;
3365     pj_status_t status = PJ_SUCCESS;
3366 
3367     const pj_str_t STR_AUDIO = { "audio", 5 };
3368     const pj_str_t STR_VIDEO = { "video", 5 };
3369     pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA];
3370     unsigned maudcnt = PJ_ARRAY_SIZE(maudidx);
3371     unsigned mtotaudcnt = PJ_ARRAY_SIZE(maudidx);
3372     pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA];
3373     unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx);
3374     unsigned mtotvidcnt = PJ_ARRAY_SIZE(mvididx);
3375     pj_bool_t need_renego_sdp = PJ_FALSE;
3376 
3377     if (pjsua_get_state() != PJSUA_STATE_RUNNING)
3378 	return PJ_EBUSY;
3379 
3380     PJ_LOG(4,(THIS_FILE, "Call %d: updating media..", call_id));
3381     pj_log_push_indent();
3382 
3383     /* Destroy existing media session, if any. */
3384     //stop_media_session(call->index);
3385 
3386     /* Call media count must be at least equal to SDP media. Note that
3387      * it may not be equal when remote removed any SDP media line.
3388      */
3389     pj_assert(call->med_prov_cnt >= local_sdp->media_count);
3390 
3391     /* Reset audio_idx first */
3392     call->audio_idx = -1;
3393 
3394     /* Sort audio/video based on "quality" */
3395     sort_media(local_sdp, &STR_AUDIO, acc->cfg.use_srtp,
3396 	       maudidx, &maudcnt, &mtotaudcnt);
3397 #if PJMEDIA_HAS_VIDEO
3398     sort_media(local_sdp, &STR_VIDEO, acc->cfg.use_srtp,
3399 	       mvididx, &mvidcnt, &mtotvidcnt);
3400 #else
3401     PJ_UNUSED_ARG(STR_VIDEO);
3402     mvidcnt = mtotvidcnt = 0;
3403 #endif
3404 
3405     /* We need to re-nego SDP or modify our answer when:
3406      * - media count exceeds the configured limit,
3407      * - RTCP-FB is enabled (so a=rtcp-fb will only be printed for negotiated
3408      *   codecs)
3409      */
3410     if (!pjmedia_sdp_neg_was_answer_remote(call->inv->neg) &&
3411 	((maudcnt > call->opt.aud_cnt || mvidcnt > call->opt.vid_cnt) ||
3412 	(acc->cfg.rtcp_fb_cfg.cap_count)))
3413     {
3414 	pjmedia_sdp_session *local_sdp_renego = NULL;
3415 
3416 	local_sdp_renego = pjmedia_sdp_session_clone(tmp_pool, local_sdp);
3417 	local_sdp = local_sdp_renego;
3418 	need_renego_sdp = PJ_TRUE;
3419 
3420 	/* Add RTCP-FB info into local SDP answer */
3421 	if (acc->cfg.rtcp_fb_cfg.cap_count) {
3422 	    for (mi=0; mi < local_sdp_renego->media_count; ++mi) {
3423 		status = pjmedia_rtcp_fb_encode_sdp(
3424 					tmp_pool, pjsua_var.med_endpt,
3425 					&acc->cfg.rtcp_fb_cfg,
3426 					local_sdp_renego, mi, remote_sdp);
3427 		if (status != PJ_SUCCESS) {
3428 		    PJ_PERROR(3,(THIS_FILE, status,
3429 				 "Call %d media %d: Failed to encode RTCP-FB "
3430 				 "setting to SDP",
3431 				 call_id, mi));
3432 		}
3433 	    }
3434 	}
3435 
3436 	/* Applying media count limitation. Note that in generating SDP
3437 	 * answer, no media count limitation applied as we didn't know yet
3438 	 * which media would pass the SDP negotiation.
3439 	 */
3440 	if (maudcnt > call->opt.aud_cnt || mvidcnt > call->opt.vid_cnt)
3441 	{
3442 	    maudcnt = PJ_MIN(maudcnt, call->opt.aud_cnt);
3443 	    mvidcnt = PJ_MIN(mvidcnt, call->opt.vid_cnt);
3444 
3445 	    for (mi=0; mi < local_sdp_renego->media_count; ++mi) {
3446 		pjmedia_sdp_media *m = local_sdp_renego->media[mi];
3447 
3448 		if (m->desc.port == 0 ||
3449 		    pj_memchr(maudidx, mi, maudcnt*sizeof(maudidx[0])) ||
3450 		    pj_memchr(mvididx, mi, mvidcnt*sizeof(mvididx[0])))
3451 		{
3452 		    continue;
3453 		}
3454 
3455 		/* Deactivate this excess media */
3456 		pjmedia_sdp_media_deactivate(tmp_pool, m);
3457 	    }
3458 	}
3459     }
3460 
3461     /* Update call media from provisional media */
3462     call->med_cnt = call->med_prov_cnt;
3463     pj_memcpy(call->media, call->media_prov,
3464 	      sizeof(call->media_prov[0]) * call->med_prov_cnt);
3465 
3466     /* Process each media stream */
3467     for (mi=0; mi < call->med_cnt; ++mi) {
3468 	pjsua_call_media *call_med = &call->media[mi];
3469 	pj_bool_t media_changed = PJ_FALSE;
3470 
3471 	if (mi >= local_sdp->media_count ||
3472 	    mi >= remote_sdp->media_count)
3473 	{
3474 	    /* This may happen when remote removed any SDP media lines in
3475 	     * its re-offer.
3476 	     */
3477 
3478 	    /* Stop stream */
3479 	    stop_media_stream(call, mi);
3480 
3481 	    /* Close the media transport */
3482 	    if (call_med->tp) {
3483 		pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
3484 		pjmedia_transport_close(call_med->tp);
3485 		call_med->tp = call_med->tp_orig = NULL;
3486 	    }
3487 	    continue;
3488 #if 0
3489 	    /* Something is wrong */
3490 	    PJ_LOG(1,(THIS_FILE, "Error updating media for call %d: "
3491 		      "invalid media index %d in SDP", call_id, mi));
3492 	    status = PJMEDIA_SDP_EINSDP;
3493 	    goto on_error;
3494 #endif
3495 	}
3496 
3497 	/* Apply media update action */
3498 	if (call_med->type==PJMEDIA_TYPE_AUDIO) {
3499 	    pjmedia_stream_info the_si, *si = &the_si;
3500 	    pjsua_stream_info stream_info;
3501 
3502 	    status = pjmedia_stream_info_from_sdp(
3503 					si, tmp_pool, pjsua_var.med_endpt,
3504 	                                local_sdp, remote_sdp, mi);
3505 	    if (status != PJ_SUCCESS) {
3506 		PJ_PERROR(1,(THIS_FILE, status,
3507 			     "pjmedia_stream_info_from_sdp() failed "
3508 			         "for call_id %d media %d",
3509 			     call_id, mi));
3510 		goto on_check_med_status;
3511 	    }
3512 
3513 	    /* Check if remote wants RTP and RTCP multiplexing,
3514 	     * but we don't enable it.
3515 	     */
3516 	    if (si->rtcp_mux && !call_med->enable_rtcp_mux) {
3517 	        si->rtcp_mux = PJ_FALSE;
3518 	    }
3519 
3520             /* Codec parameter of stream info (si->param) can be NULL if
3521              * the stream is rejected or disabled.
3522              */
3523 	    /* Override ptime, if this option is specified. */
3524 	    if (pjsua_var.media_cfg.ptime != 0 && si->param) {
3525 	        si->param->setting.frm_per_pkt = (pj_uint8_t)
3526 		    (pjsua_var.media_cfg.ptime / si->param->info.frm_ptime);
3527 	        if (si->param->setting.frm_per_pkt == 0)
3528 		    si->param->setting.frm_per_pkt = 1;
3529 	    }
3530 
3531 	    /* Disable VAD, if this option is specified. */
3532 	    if (pjsua_var.media_cfg.no_vad && si->param) {
3533 	        si->param->setting.vad = 0;
3534 	    }
3535 
3536 	    /* Check if this media is changed */
3537 	    stream_info.type = PJMEDIA_TYPE_AUDIO;
3538 	    stream_info.info.aud = the_si;
3539 	    if (pjsua_var.media_cfg.no_smart_media_update ||
3540 		is_media_changed(call, mi, &stream_info))
3541 	    {
3542 		media_changed = PJ_TRUE;
3543 		/* Stop the media */
3544 		stop_media_stream(call, mi);
3545 	    } else {
3546 		PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (audio) unchanged.",
3547 			  call_id, mi));
3548 	    }
3549 
3550 	    /* Check if no media is active */
3551 	    if (local_sdp->media[mi]->desc.port == 0) {
3552 
3553 		/* Update call media state and direction */
3554 		call_med->state = PJSUA_CALL_MEDIA_NONE;
3555 		call_med->dir = PJMEDIA_DIR_NONE;
3556 
3557 	    } else if (call_med->tp) {
3558 		pjmedia_transport_info tp_info;
3559 		pjmedia_srtp_info *srtp_info;
3560 
3561 		/* Call media direction */
3562 		call_med->dir = si->dir;
3563 
3564 		/* Call media state */
3565 		if (call->local_hold)
3566 		    call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD;
3567 		else if (call_med->dir == PJMEDIA_DIR_DECODING)
3568 		    call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD;
3569 		else
3570 		    call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
3571 
3572 		if (call->inv->following_fork) {
3573 		    unsigned options = (call_med->enable_rtcp_mux?
3574             			        PJMEDIA_TPMED_RTCP_MUX: 0);
3575 		    /* Normally media transport will automatically restart
3576 		     * itself (if needed, based on info from the SDP) in
3577 		     * pjmedia_transport_media_start(), however in "following
3578 		     * forked media" case (see #1644), we need to explicitly
3579 		     * restart it as it cannot detect fork scenario from
3580 		     * the SDP only.
3581 		     */
3582 		    status = pjmedia_transport_media_stop(call_med->tp);
3583 		    if (status != PJ_SUCCESS) {
3584 			PJ_PERROR(1,(THIS_FILE, status,
3585 				     "pjmedia_transport_media_stop() failed "
3586 				     "for call_id %d media %d",
3587 				     call_id, mi));
3588 			goto on_check_med_status;
3589 		    }
3590 		    status = pjmedia_transport_media_create(call_med->tp,
3591 							    tmp_pool,
3592 							    options, NULL, mi);
3593 		    if (status != PJ_SUCCESS) {
3594 			PJ_PERROR(1,(THIS_FILE, status,
3595 				     "pjmedia_transport_media_create() failed "
3596 				     "for call_id %d media %d",
3597 				     call_id, mi));
3598 			goto on_check_med_status;
3599 		    }
3600 		}
3601 
3602 		/* Start/restart media transport based on info in SDP */
3603 		status = pjmedia_transport_media_start(call_med->tp,
3604 						       tmp_pool, local_sdp,
3605 						       remote_sdp, mi);
3606 		if (status != PJ_SUCCESS) {
3607 		    PJ_PERROR(1,(THIS_FILE, status,
3608 				 "pjmedia_transport_media_start() failed "
3609 				     "for call_id %d media %d",
3610 				 call_id, mi));
3611 		    goto on_check_med_status;
3612 		}
3613 
3614 		pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_RUNNING);
3615 
3616 		/* Get remote SRTP usage policy */
3617 		pjmedia_transport_info_init(&tp_info);
3618 		pjmedia_transport_get_info(call_med->tp, &tp_info);
3619 		srtp_info = (pjmedia_srtp_info*)
3620 			    pjmedia_transport_info_get_spc_info(
3621 				    &tp_info, PJMEDIA_TRANSPORT_TYPE_SRTP);
3622 		if (srtp_info) {
3623 		    call_med->rem_srtp_use = srtp_info->peer_use;
3624 		}
3625 
3626 		/* Update audio channel */
3627 		if (media_changed) {
3628 		    status = pjsua_aud_channel_update(call_med,
3629 						      call->inv->pool, si,
3630 						      local_sdp, remote_sdp);
3631 		    if (status != PJ_SUCCESS) {
3632 			PJ_PERROR(1,(THIS_FILE, status,
3633 				     "pjsua_aud_channel_update() failed "
3634 					 "for call_id %d media %d",
3635 				     call_id, mi));
3636 			goto on_check_med_status;
3637 		    }
3638 
3639 		    if (pjmedia_transport_info_get_spc_info(
3640 				    &tp_info, PJMEDIA_TRANSPORT_TYPE_LOOP))
3641 		    {
3642 			pjmedia_transport_loop_disable_rx(
3643 				call_med->tp, call_med->strm.a.stream,
3644 				!acc->cfg.enable_loopback);
3645 		    }
3646 		}
3647 	    }
3648 
3649 	    /* Print info. */
3650 	    if (status == PJ_SUCCESS) {
3651 		char info[80];
3652 		int info_len = 0;
3653 		int len;
3654 		const char *dir;
3655 
3656 		switch (si->dir) {
3657 		case PJMEDIA_DIR_NONE:
3658 		    dir = "inactive";
3659 		    break;
3660 		case PJMEDIA_DIR_ENCODING:
3661 		    dir = "sendonly";
3662 		    break;
3663 		case PJMEDIA_DIR_DECODING:
3664 		    dir = "recvonly";
3665 		    break;
3666 		case PJMEDIA_DIR_ENCODING_DECODING:
3667 		    dir = "sendrecv";
3668 		    break;
3669 		default:
3670 		    dir = "unknown";
3671 		    break;
3672 		}
3673 		len = pj_ansi_sprintf( info+info_len,
3674 				       ", stream #%d: %.*s (%s)", mi,
3675 				       (int)si->fmt.encoding_name.slen,
3676 				       si->fmt.encoding_name.ptr,
3677 				       dir);
3678 		if (len > 0)
3679 		    info_len += len;
3680 		PJ_LOG(4,(THIS_FILE,"Audio updated%s", info));
3681 	    }
3682 
3683 
3684 	    if (call->audio_idx==-1 && status==PJ_SUCCESS &&
3685 		si->dir != PJMEDIA_DIR_NONE)
3686 	    {
3687 		call->audio_idx = mi;
3688 	    }
3689 
3690 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
3691 	} else if (call_med->type==PJMEDIA_TYPE_VIDEO) {
3692 	    pjmedia_vid_stream_info the_si, *si = &the_si;
3693 	    pjsua_stream_info stream_info;
3694 
3695 	    status = pjmedia_vid_stream_info_from_sdp(
3696 					si, tmp_pool, pjsua_var.med_endpt,
3697 					local_sdp, remote_sdp, mi);
3698 	    if (status != PJ_SUCCESS) {
3699 		PJ_PERROR(1,(THIS_FILE, status,
3700 			     "pjmedia_vid_stream_info_from_sdp() failed "
3701 			         "for call_id %d media %d",
3702 			     call_id, mi));
3703 		goto on_check_med_status;
3704 	    }
3705 
3706 	    /* Check if remote wants RTP and RTCP multiplexing,
3707 	     * but we don't enable it.
3708 	     */
3709 	    if (si->rtcp_mux && !call_med->enable_rtcp_mux) {
3710 	        si->rtcp_mux = PJ_FALSE;
3711 	    }
3712 
3713 	    /* Check if this media is changed */
3714 	    stream_info.type = PJMEDIA_TYPE_VIDEO;
3715 	    stream_info.info.vid = the_si;
3716 	    if (is_media_changed(call, mi, &stream_info)) {
3717 		media_changed = PJ_TRUE;
3718 		/* Stop the media */
3719 		stop_media_stream(call, mi);
3720 	    } else {
3721 		PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (video) unchanged.",
3722 			  call_id, mi));
3723 	    }
3724 
3725 	    /* Check if no media is active */
3726 	    if (si->dir == PJMEDIA_DIR_NONE) {
3727 
3728 		/* Update call media state and direction */
3729 		call_med->state = PJSUA_CALL_MEDIA_NONE;
3730 		call_med->dir = PJMEDIA_DIR_NONE;
3731 
3732 	    } else if (call_med->tp) {
3733 		pjmedia_transport_info tp_info;
3734 		pjmedia_srtp_info *srtp_info;
3735 
3736 		/* Call media direction */
3737 		call_med->dir = si->dir;
3738 
3739 		/* Call media state */
3740 		if (call->local_hold)
3741 		    call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD;
3742 		else if (call_med->dir == PJMEDIA_DIR_DECODING)
3743 		    call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD;
3744 		else
3745 		    call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
3746 
3747 		/* Start/restart media transport */
3748 		status = pjmedia_transport_media_start(call_med->tp,
3749 						       tmp_pool, local_sdp,
3750 						       remote_sdp, mi);
3751 		if (status != PJ_SUCCESS) {
3752 		    PJ_PERROR(1,(THIS_FILE, status,
3753 				 "pjmedia_transport_media_start() failed "
3754 				     "for call_id %d media %d",
3755 				 call_id, mi));
3756 		    goto on_check_med_status;
3757 		}
3758 
3759 		pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_RUNNING);
3760 
3761 		/* Get remote SRTP usage policy */
3762 		pjmedia_transport_info_init(&tp_info);
3763 		pjmedia_transport_get_info(call_med->tp, &tp_info);
3764 		srtp_info = (pjmedia_srtp_info*)
3765 			    pjmedia_transport_info_get_spc_info(
3766 				    &tp_info, PJMEDIA_TRANSPORT_TYPE_SRTP);
3767 		if (srtp_info) {
3768 		    call_med->rem_srtp_use = srtp_info->peer_use;
3769 		}
3770 
3771 		/* Update audio channel */
3772 		if (media_changed) {
3773 		    status = pjsua_vid_channel_update(call_med,
3774 						      call->inv->pool, si,
3775 						      local_sdp, remote_sdp);
3776 		    if (status != PJ_SUCCESS) {
3777 			PJ_PERROR(1,(THIS_FILE, status,
3778 				     "pjsua_vid_channel_update() failed "
3779 					 "for call_id %d media %d",
3780 				     call_id, mi));
3781 			goto on_check_med_status;
3782 		    }
3783 		}
3784 	    }
3785 
3786 	    /* Print info. */
3787 	    {
3788 		char info[80];
3789 		int info_len = 0;
3790 		int len;
3791 		const char *dir;
3792 
3793 		switch (si->dir) {
3794 		case PJMEDIA_DIR_NONE:
3795 		    dir = "inactive";
3796 		    break;
3797 		case PJMEDIA_DIR_ENCODING:
3798 		    dir = "sendonly";
3799 		    break;
3800 		case PJMEDIA_DIR_DECODING:
3801 		    dir = "recvonly";
3802 		    break;
3803 		case PJMEDIA_DIR_ENCODING_DECODING:
3804 		    dir = "sendrecv";
3805 		    break;
3806 		default:
3807 		    dir = "unknown";
3808 		    break;
3809 		}
3810 		len = pj_ansi_sprintf( info+info_len,
3811 				       ", stream #%d: %.*s (%s)", mi,
3812 				       (int)si->codec_info.encoding_name.slen,
3813 				       si->codec_info.encoding_name.ptr,
3814 				       dir);
3815 		if (len > 0)
3816 		    info_len += len;
3817 		PJ_LOG(4,(THIS_FILE,"Video updated%s", info));
3818 	    }
3819 
3820 #endif
3821 	} else {
3822 	    status = PJMEDIA_EUNSUPMEDIATYPE;
3823 	}
3824 
3825 	/* Close the transport of deactivated media, need this here as media
3826 	 * can be deactivated by the SDP negotiation and the max media count
3827 	 * (account) setting.
3828 	 */
3829 	if (local_sdp->media[mi]->desc.port==0 && call_med->tp) {
3830 	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
3831 	    pjmedia_transport_close(call_med->tp);
3832 	    call_med->tp = call_med->tp_orig = NULL;
3833 	}
3834 
3835 on_check_med_status:
3836 	if (status != PJ_SUCCESS) {
3837 	    /* Stop stream */
3838 	    stop_media_stream(call, mi);
3839 
3840 	    /* Close the media transport */
3841 	    if (call_med->tp) {
3842 		pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
3843 		pjmedia_transport_close(call_med->tp);
3844 		call_med->tp = call_med->tp_orig = NULL;
3845 	    }
3846 
3847 	    /* Update media states */
3848 	    call_med->state = PJSUA_CALL_MEDIA_ERROR;
3849 	    call_med->dir = PJMEDIA_DIR_NONE;
3850 
3851 	    if (status != PJMEDIA_EUNSUPMEDIATYPE) {
3852 		PJ_PERROR(1, (THIS_FILE, status, "Error updating media "
3853 		              "call%02d:%d", call_id, mi));
3854 	    } else {
3855 		PJ_PERROR(3, (THIS_FILE, status, "Skipped updating media "
3856 		              "call%02d:%d (media type=%s)", call_id, mi,
3857 			      pjmedia_type_name(call_med->type)));
3858 	    }
3859 
3860 	} else {
3861 	    /* Only set 'got_media' flag if this media is not disabled */
3862 	    if (local_sdp->media[mi]->desc.port != 0)
3863 		got_media = PJ_TRUE;
3864 	}
3865     }
3866 
3867     /* Sync provisional media to call media */
3868     call->med_prov_cnt = call->med_cnt;
3869     pj_memcpy(call->media_prov, call->media,
3870 	      sizeof(call->media[0]) * call->med_cnt);
3871 
3872     /* Perform SDP re-negotiation. */
3873     if (got_media && need_renego_sdp) {
3874 	pjmedia_sdp_neg *neg = call->inv->neg;
3875 
3876 	status = pjmedia_sdp_neg_set_remote_offer(tmp_pool, neg, remote_sdp);
3877 	if (status != PJ_SUCCESS)
3878 	    goto on_error;
3879 
3880 	status = pjmedia_sdp_neg_set_local_answer(tmp_pool, neg, local_sdp);
3881 	if (status != PJ_SUCCESS)
3882 	    goto on_error;
3883 
3884 	status = pjmedia_sdp_neg_negotiate(tmp_pool, neg, 0);
3885 	if (status != PJ_SUCCESS)
3886 	    goto on_error;
3887     }
3888 
3889     pj_log_pop_indent();
3890     return (got_media? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA);
3891 
3892 on_error:
3893     pj_log_pop_indent();
3894     return status;
3895 }
3896 
3897 /*****************************************************************************
3898  * Codecs.
3899  */
3900 
3901 /*
3902  * Enum all supported codecs in the system.
3903  */
pjsua_enum_codecs(pjsua_codec_info id[],unsigned * p_count)3904 PJ_DEF(pj_status_t) pjsua_enum_codecs( pjsua_codec_info id[],
3905 				       unsigned *p_count )
3906 {
3907     pjmedia_codec_mgr *codec_mgr;
3908     pjmedia_codec_info info[32];
3909     unsigned i, count, prio[32];
3910     pj_status_t status;
3911 
3912     codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
3913     count = PJ_ARRAY_SIZE(info);
3914     status = pjmedia_codec_mgr_enum_codecs( codec_mgr, &count, info, prio);
3915     if (status != PJ_SUCCESS) {
3916 	*p_count = 0;
3917 	return status;
3918     }
3919 
3920     if (count > *p_count) count = *p_count;
3921 
3922     for (i=0; i<count; ++i) {
3923 	pj_bzero(&id[i], sizeof(pjsua_codec_info));
3924 
3925 	pjmedia_codec_info_to_id(&info[i], id[i].buf_, sizeof(id[i].buf_));
3926 	id[i].codec_id = pj_str(id[i].buf_);
3927 	id[i].priority = (pj_uint8_t) prio[i];
3928     }
3929 
3930     *p_count = count;
3931 
3932     return PJ_SUCCESS;
3933 }
3934 
3935 
3936 /*
3937  * Change codec priority.
3938  */
pjsua_codec_set_priority(const pj_str_t * codec_id,pj_uint8_t priority)3939 PJ_DEF(pj_status_t) pjsua_codec_set_priority( const pj_str_t *codec_id,
3940 					      pj_uint8_t priority )
3941 {
3942     const pj_str_t all = { NULL, 0 };
3943     pjmedia_codec_mgr *codec_mgr;
3944 
3945     codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
3946 
3947     if (codec_id->slen==1 && *codec_id->ptr=='*')
3948 	codec_id = &all;
3949 
3950     return pjmedia_codec_mgr_set_codec_priority(codec_mgr, codec_id,
3951 					        priority);
3952 }
3953 
3954 
3955 /*
3956  * Get codec parameters.
3957  */
pjsua_codec_get_param(const pj_str_t * codec_id,pjmedia_codec_param * param)3958 PJ_DEF(pj_status_t) pjsua_codec_get_param( const pj_str_t *codec_id,
3959 					   pjmedia_codec_param *param )
3960 {
3961     const pj_str_t all = { NULL, 0 };
3962     const pjmedia_codec_info *info;
3963     pjmedia_codec_mgr *codec_mgr;
3964     unsigned count = 1;
3965     pj_status_t status;
3966 
3967     codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
3968 
3969     if (codec_id->slen==1 && *codec_id->ptr=='*')
3970 	codec_id = &all;
3971 
3972     status = pjmedia_codec_mgr_find_codecs_by_id(codec_mgr, codec_id,
3973 						 &count, &info, NULL);
3974     if (status != PJ_SUCCESS)
3975 	return status;
3976 
3977     if (count != 1)
3978 	return (count > 1? PJ_ETOOMANY : PJ_ENOTFOUND);
3979 
3980     status = pjmedia_codec_mgr_get_default_param( codec_mgr, info, param);
3981     return status;
3982 }
3983 
3984 
3985 /*
3986  * Set codec parameters.
3987  */
pjsua_codec_set_param(const pj_str_t * codec_id,const pjmedia_codec_param * param)3988 PJ_DEF(pj_status_t) pjsua_codec_set_param( const pj_str_t *codec_id,
3989 					   const pjmedia_codec_param *param)
3990 {
3991     const pjmedia_codec_info *info[2];
3992     pjmedia_codec_mgr *codec_mgr;
3993     unsigned count = 2;
3994     pj_status_t status;
3995 
3996     codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
3997 
3998     status = pjmedia_codec_mgr_find_codecs_by_id(codec_mgr, codec_id,
3999 						 &count, info, NULL);
4000     if (status != PJ_SUCCESS)
4001 	return status;
4002 
4003     /* Codec ID should be specific, except for G.722.1 */
4004     if (count > 1 &&
4005 	pj_strnicmp2(codec_id, "G7221/16", 8) != 0 &&
4006 	pj_strnicmp2(codec_id, "G7221/32", 8) != 0)
4007     {
4008 	pj_assert(!"Codec ID is not specific");
4009 	return PJ_ETOOMANY;
4010     }
4011 
4012     status = pjmedia_codec_mgr_set_default_param(codec_mgr, info[0], param);
4013     return status;
4014 }
4015 
4016 
pjsua_media_apply_xml_control(pjsua_call_id call_id,const pj_str_t * xml_st)4017 pj_status_t pjsua_media_apply_xml_control(pjsua_call_id call_id,
4018 					  const pj_str_t *xml_st)
4019 {
4020 #if PJMEDIA_HAS_VIDEO
4021     pjsua_call *call = &pjsua_var.calls[call_id];
4022     const pj_str_t PICT_FAST_UPDATE = {"picture_fast_update", 19};
4023 
4024     if (pj_strstr(xml_st, &PICT_FAST_UPDATE)) {
4025 	unsigned i;
4026 
4027 	PJ_LOG(4,(THIS_FILE, "Received keyframe request via SIP INFO"));
4028 
4029 	for (i = 0; i < call->med_cnt; ++i) {
4030 	    pjsua_call_media *cm = &call->media[i];
4031 	    if (cm->type != PJMEDIA_TYPE_VIDEO || !cm->strm.v.stream)
4032 		continue;
4033 
4034 	    pjmedia_vid_stream_send_keyframe(cm->strm.v.stream);
4035 	}
4036 
4037 	return PJ_SUCCESS;
4038     }
4039 #endif
4040 
4041     /* Just to avoid compiler warning of unused var */
4042     PJ_UNUSED_ARG(call_id);
4043     PJ_UNUSED_ARG(xml_st);
4044 
4045     return PJ_ENOTSUP;
4046 }
4047 
4048