1 /*! \file    ice.c
2  * \author   Lorenzo Miniero <lorenzo@meetecho.com>
3  * \copyright GNU General Public License v3
4  * \brief    ICE/STUN/TURN processing
5  * \details  Implementation (based on libnice) of the ICE process. The
6  * code handles the whole ICE process, from the gathering of candidates
7  * to the final setup of a virtual channel RTP and RTCP can be transported
8  * on. Incoming RTP and RTCP packets from peers are relayed to the associated
9  * plugins by means of the incoming_rtp and incoming_rtcp callbacks. Packets
10  * to be sent to peers are relayed by peers invoking the relay_rtp and
11  * relay_rtcp core callbacks instead.
12  *
13  * \ingroup protocols
14  * \ref protocols
15  */
16 
17 #include <ifaddrs.h>
18 #include <poll.h>
19 #include <net/if.h>
20 #include <sys/socket.h>
21 #include <sys/time.h>
22 #include <netdb.h>
23 #include <fcntl.h>
24 #include <stun/usages/bind.h>
25 #include <nice/debug.h>
26 
27 #include "janus.h"
28 #include "debug.h"
29 #include "ice.h"
30 #include "turnrest.h"
31 #include "sdp.h"
32 #include "rtpsrtp.h"
33 #include "rtcp.h"
34 #include "apierror.h"
35 #include "ip-utils.h"
36 #include "events.h"
37 
38 /* STUN server/port, if any */
39 static char *janus_stun_server = NULL;
40 static uint16_t janus_stun_port = 0;
41 
janus_ice_get_stun_server(void)42 char *janus_ice_get_stun_server(void) {
43 	return janus_stun_server;
44 }
janus_ice_get_stun_port(void)45 uint16_t janus_ice_get_stun_port(void) {
46 	return janus_stun_port;
47 }
48 
49 
50 /* TURN server/port and credentials, if any */
51 static char *janus_turn_server = NULL;
52 static uint16_t janus_turn_port = 0;
53 static char *janus_turn_user = NULL, *janus_turn_pwd = NULL;
54 static NiceRelayType janus_turn_type = NICE_RELAY_TYPE_TURN_UDP;
55 
janus_ice_get_turn_server(void)56 char *janus_ice_get_turn_server(void) {
57 	return janus_turn_server;
58 }
janus_ice_get_turn_port(void)59 uint16_t janus_ice_get_turn_port(void) {
60 	return janus_turn_port;
61 }
62 
63 
64 /* TURN REST API support, if any */
janus_ice_get_turn_rest_api(void)65 char *janus_ice_get_turn_rest_api(void) {
66 #ifndef HAVE_TURNRESTAPI
67 	return NULL;
68 #else
69 	return (char *)janus_turnrest_get_backend();
70 #endif
71 }
72 
73 /* Force relay settings */
74 static gboolean force_relay_allowed = FALSE;
janus_ice_allow_force_relay(void)75 void janus_ice_allow_force_relay(void) {
76 	force_relay_allowed = TRUE;
77 }
janus_ice_is_force_relay_allowed(void)78 gboolean janus_ice_is_force_relay_allowed(void) {
79 	return force_relay_allowed;
80 }
81 
82 /* ICE-Lite status */
83 static gboolean janus_ice_lite_enabled;
janus_ice_is_ice_lite_enabled(void)84 gboolean janus_ice_is_ice_lite_enabled(void) {
85 	return janus_ice_lite_enabled;
86 }
87 
88 /* ICE-TCP support (only libnice >= 0.1.8, currently broken) */
89 static gboolean janus_ice_tcp_enabled;
janus_ice_is_ice_tcp_enabled(void)90 gboolean janus_ice_is_ice_tcp_enabled(void) {
91 	return janus_ice_tcp_enabled;
92 }
93 
94 /* Full-trickle support */
95 static gboolean janus_full_trickle_enabled;
janus_ice_is_full_trickle_enabled(void)96 gboolean janus_ice_is_full_trickle_enabled(void) {
97 	return janus_full_trickle_enabled;
98 }
99 
100 /* mDNS resolution support */
101 static gboolean janus_mdns_enabled;
janus_ice_is_mdns_enabled(void)102 gboolean janus_ice_is_mdns_enabled(void) {
103 	return janus_mdns_enabled;
104 }
105 
106 /* IPv6 support */
107 static gboolean janus_ipv6_enabled;
108 static gboolean janus_ipv6_linklocal_enabled;
janus_ice_is_ipv6_enabled(void)109 gboolean janus_ice_is_ipv6_enabled(void) {
110 	return janus_ipv6_enabled;
111 }
112 static gboolean janus_ipv6_linklocal_enabled;
janus_ice_is_ipv6_linklocal_enabled(void)113 gboolean janus_ice_is_ipv6_linklocal_enabled(void) {
114 	return janus_ipv6_linklocal_enabled;
115 }
116 
117 #ifdef HAVE_ICE_NOMINATION
118 /* Since libnice 0.1.15, we can configure the ICE nomination mode: it was
119  * always "aggressive" before, so we set it to "aggressive" by default as well */
120 static NiceNominationMode janus_ice_nomination = NICE_NOMINATION_MODE_AGGRESSIVE;
janus_ice_set_nomination_mode(const char * nomination)121 void janus_ice_set_nomination_mode(const char *nomination) {
122 	if(nomination == NULL) {
123 		JANUS_LOG(LOG_WARN, "Invalid ICE nomination mode, falling back to 'aggressive'\n");
124 	} else if(!strcasecmp(nomination, "regular")) {
125 		JANUS_LOG(LOG_INFO, "Configuring Janus to use ICE regular nomination\n");
126 		janus_ice_nomination = NICE_NOMINATION_MODE_REGULAR;
127 	} else if(!strcasecmp(nomination, "aggressive")) {
128 		JANUS_LOG(LOG_INFO, "Configuring Janus to use ICE aggressive nomination\n");
129 		janus_ice_nomination = NICE_NOMINATION_MODE_AGGRESSIVE;
130 	} else {
131 		JANUS_LOG(LOG_WARN, "Unsupported ICE nomination mode '%s', falling back to 'aggressive'\n", nomination);
132 	}
133 }
janus_ice_get_nomination_mode(void)134 const char *janus_ice_get_nomination_mode(void) {
135 	return (janus_ice_nomination == NICE_NOMINATION_MODE_REGULAR ? "regular" : "aggressive");
136 }
137 #endif
138 
139 /* Keepalive via connectivity checks */
140 static gboolean janus_ice_keepalive_connchecks = FALSE;
janus_ice_set_keepalive_conncheck_enabled(gboolean enabled)141 void janus_ice_set_keepalive_conncheck_enabled(gboolean enabled) {
142 	janus_ice_keepalive_connchecks = enabled;
143 	if(janus_ice_keepalive_connchecks) {
144 		JANUS_LOG(LOG_INFO, "Using connectivity checks as PeerConnection keep-alives\n");
145 		JANUS_LOG(LOG_WARN, "Notice that the current libnice master is breaking connections after 50s when keepalive-conncheck enabled. As such, better to stick to 0.1.18 until the issue is addressed upstream\n");
146 	}
147 }
janus_ice_is_keepalive_conncheck_enabled(void)148 gboolean janus_ice_is_keepalive_conncheck_enabled(void) {
149 	return janus_ice_keepalive_connchecks;
150 }
151 
152 /* Opaque IDs set by applications are by default only passed to event handlers
153  * for correlation purposes, but not sent back to the user or application in
154  * the related Janus API responses or events, unless configured otherwise */
155 static gboolean opaqueid_in_api = FALSE;
janus_enable_opaqueid_in_api(void)156 void janus_enable_opaqueid_in_api(void) {
157 	opaqueid_in_api = TRUE;
158 }
janus_is_opaqueid_in_api_enabled(void)159 gboolean janus_is_opaqueid_in_api_enabled(void) {
160 	return opaqueid_in_api;
161 }
162 
163 /* Only needed in case we're using static event loops spawned at startup (disabled by default) */
164 typedef struct janus_ice_static_event_loop {
165 	int id;
166 	GMainContext *mainctx;
167 	GMainLoop *mainloop;
168 	GThread *thread;
169 } janus_ice_static_event_loop;
170 static int static_event_loops = 0;
171 static gboolean allow_loop_indication = FALSE;
172 static GSList *event_loops = NULL, *current_loop = NULL;
173 static janus_mutex event_loops_mutex = JANUS_MUTEX_INITIALIZER;
janus_ice_static_event_loop_thread(void * data)174 static void *janus_ice_static_event_loop_thread(void *data) {
175 	janus_ice_static_event_loop *loop = data;
176 	JANUS_LOG(LOG_VERB, "[loop#%d] Event loop thread started\n", loop->id);
177 	if(loop->mainloop == NULL) {
178 		JANUS_LOG(LOG_ERR, "[loop#%d] Invalid loop...\n", loop->id);
179 		g_thread_unref(g_thread_self());
180 		return NULL;
181 	}
182 	JANUS_LOG(LOG_DBG, "[loop#%d] Looping...\n", loop->id);
183 	g_main_loop_run(loop->mainloop);
184 	/* When the loop quits, we can unref it */
185 	g_main_loop_unref(loop->mainloop);
186 	g_main_context_unref(loop->mainctx);
187 	JANUS_LOG(LOG_VERB, "[loop#%d] Event loop thread ended!\n", loop->id);
188 	return NULL;
189 }
janus_ice_get_static_event_loops(void)190 int janus_ice_get_static_event_loops(void) {
191 	return static_event_loops;
192 }
janus_ice_is_loop_indication_allowed(void)193 gboolean janus_ice_is_loop_indication_allowed(void) {
194 	return allow_loop_indication;
195 }
janus_ice_set_static_event_loops(int loops,gboolean allow_api)196 void janus_ice_set_static_event_loops(int loops, gboolean allow_api) {
197 	if(loops == 0)
198 		return;
199 	else if(loops < 1) {
200 		JANUS_LOG(LOG_WARN, "Invalid number of static event loops (%d), disabling\n", loops);
201 		return;
202 	}
203 	/* Create a pool of new event loops */
204 	int i = 0;
205 	for(i=0; i<loops; i++) {
206 		janus_ice_static_event_loop *loop = g_malloc0(sizeof(janus_ice_static_event_loop));
207 		loop->id = static_event_loops;
208 		loop->mainctx = g_main_context_new();
209 		loop->mainloop = g_main_loop_new(loop->mainctx, FALSE);
210 		/* Now spawn a thread for this loop */
211 		GError *error = NULL;
212 		char tname[16];
213 		g_snprintf(tname, sizeof(tname), "hloop %d", loop->id);
214 		loop->thread = g_thread_try_new(tname, &janus_ice_static_event_loop_thread, loop, &error);
215 		if(error != NULL) {
216 			g_main_loop_unref(loop->mainloop);
217 			g_main_context_unref(loop->mainctx);
218 			g_free(loop);
219 			JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch a new event loop thread...\n",
220 				error->code, error->message ? error->message : "??");
221 			g_error_free(error);
222 		} else {
223 			event_loops = g_slist_append(event_loops, loop);
224 			static_event_loops++;
225 		}
226 	}
227 	current_loop = event_loops;
228 	JANUS_LOG(LOG_INFO, "Spawned %d static event loops (handles won't have a dedicated loop)\n", static_event_loops);
229 	allow_loop_indication = allow_api;
230 	JANUS_LOG(LOG_INFO, "  -- Janus API %s be able to drive the loop choice for new handles\n",
231 		allow_loop_indication ? "will" : "will NOT");
232 	return;
233 }
janus_ice_stop_static_event_loops(void)234 void janus_ice_stop_static_event_loops(void) {
235 	if(static_event_loops < 1)
236 		return;
237 	/* Quit all the static loops and wait for the threads to leave */
238 	janus_mutex_lock(&event_loops_mutex);
239 	GSList *l = event_loops;
240 	while(l) {
241 		janus_ice_static_event_loop *loop = (janus_ice_static_event_loop *)l->data;
242 		if(loop->mainloop != NULL && g_main_loop_is_running(loop->mainloop))
243 			g_main_loop_quit(loop->mainloop);
244 		g_thread_join(loop->thread);
245 		l = l->next;
246 	}
247 	g_slist_free_full(event_loops, (GDestroyNotify)g_free);
248 	janus_mutex_unlock(&event_loops_mutex);
249 }
250 
251 /* libnice debugging */
252 static gboolean janus_ice_debugging_enabled;
janus_ice_is_ice_debugging_enabled(void)253 gboolean janus_ice_is_ice_debugging_enabled(void) {
254 	return janus_ice_debugging_enabled;
255 }
janus_ice_debugging_enable(void)256 void janus_ice_debugging_enable(void) {
257 	JANUS_LOG(LOG_VERB, "Enabling libnice debugging...\n");
258 	if(g_getenv("NICE_DEBUG") == NULL) {
259 		JANUS_LOG(LOG_WARN, "No NICE_DEBUG environment variable set, setting maximum debug\n");
260 		g_setenv("NICE_DEBUG", "all", TRUE);
261 	}
262 	if(g_getenv("G_MESSAGES_DEBUG") == NULL) {
263 		JANUS_LOG(LOG_WARN, "No G_MESSAGES_DEBUG environment variable set, setting maximum debug\n");
264 		g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
265 	}
266 	JANUS_LOG(LOG_VERB, "Debugging NICE_DEBUG=%s G_MESSAGES_DEBUG=%s\n",
267 		g_getenv("NICE_DEBUG"), g_getenv("G_MESSAGES_DEBUG"));
268 	janus_ice_debugging_enabled = TRUE;
269 	nice_debug_enable(strstr(g_getenv("NICE_DEBUG"), "all") || strstr(g_getenv("NICE_DEBUG"), "stun"));
270 }
janus_ice_debugging_disable(void)271 void janus_ice_debugging_disable(void) {
272 	JANUS_LOG(LOG_VERB, "Disabling libnice debugging...\n");
273 	janus_ice_debugging_enabled = FALSE;
274 	nice_debug_disable(TRUE);
275 }
276 
277 
278 /* NAT 1:1 stuff */
279 static gboolean nat_1_1_enabled = FALSE;
280 static gboolean keep_private_host = FALSE;
janus_ice_enable_nat_1_1(gboolean kph)281 void janus_ice_enable_nat_1_1(gboolean kph) {
282 	nat_1_1_enabled = TRUE;
283 	keep_private_host = kph;
284 }
285 
286 /* Interface/IP enforce/ignore lists */
287 GList *janus_ice_enforce_list = NULL, *janus_ice_ignore_list = NULL;
288 janus_mutex ice_list_mutex;
289 
janus_ice_enforce_interface(const char * ip)290 void janus_ice_enforce_interface(const char *ip) {
291 	if(ip == NULL)
292 		return;
293 	/* Is this an IP or an interface? */
294 	janus_mutex_lock(&ice_list_mutex);
295 	janus_ice_enforce_list = g_list_append(janus_ice_enforce_list, (gpointer)ip);
296 	janus_mutex_unlock(&ice_list_mutex);
297 }
janus_ice_is_enforced(const char * ip)298 gboolean janus_ice_is_enforced(const char *ip) {
299 	if(ip == NULL || janus_ice_enforce_list == NULL)
300 		return false;
301 	janus_mutex_lock(&ice_list_mutex);
302 	GList *temp = janus_ice_enforce_list;
303 	while(temp) {
304 		const char *enforced = (const char *)temp->data;
305 		if(enforced != NULL && strstr(ip, enforced) == ip) {
306 			janus_mutex_unlock(&ice_list_mutex);
307 			return true;
308 		}
309 		temp = temp->next;
310 	}
311 	janus_mutex_unlock(&ice_list_mutex);
312 	return false;
313 }
314 
janus_ice_ignore_interface(const char * ip)315 void janus_ice_ignore_interface(const char *ip) {
316 	if(ip == NULL)
317 		return;
318 	/* Is this an IP or an interface? */
319 	janus_mutex_lock(&ice_list_mutex);
320 	janus_ice_ignore_list = g_list_append(janus_ice_ignore_list, (gpointer)ip);
321 	if(janus_ice_enforce_list != NULL) {
322 		JANUS_LOG(LOG_WARN, "Added %s to the ICE ignore list, but the ICE enforce list is not empty: the ICE ignore list will not be used\n", ip);
323 	}
324 	janus_mutex_unlock(&ice_list_mutex);
325 }
janus_ice_is_ignored(const char * ip)326 gboolean janus_ice_is_ignored(const char *ip) {
327 	if(ip == NULL || janus_ice_ignore_list == NULL)
328 		return false;
329 	janus_mutex_lock(&ice_list_mutex);
330 	GList *temp = janus_ice_ignore_list;
331 	while(temp) {
332 		const char *ignored = (const char *)temp->data;
333 		if(ignored != NULL && strstr(ip, ignored) == ip) {
334 			janus_mutex_unlock(&ice_list_mutex);
335 			return true;
336 		}
337 		temp = temp->next;
338 	}
339 	janus_mutex_unlock(&ice_list_mutex);
340 	return false;
341 }
342 
343 
344 /* Frequency of statistics via event handlers (one second by default) */
345 static int janus_ice_event_stats_period = 1;
janus_ice_set_event_stats_period(int period)346 void janus_ice_set_event_stats_period(int period) {
347 	janus_ice_event_stats_period = period;
348 }
janus_ice_get_event_stats_period(void)349 int janus_ice_get_event_stats_period(void) {
350 	return janus_ice_event_stats_period;
351 }
352 
353 /* How to handle media statistic events (one per media or one per peerConnection) */
354 static gboolean janus_ice_event_combine_media_stats = false;
janus_ice_event_set_combine_media_stats(gboolean combine_media_stats_to_one_event)355 void janus_ice_event_set_combine_media_stats(gboolean combine_media_stats_to_one_event) {
356 	janus_ice_event_combine_media_stats = combine_media_stats_to_one_event;
357 }
janus_ice_event_get_combine_media_stats(void)358 gboolean janus_ice_event_get_combine_media_stats(void) {
359 	return janus_ice_event_combine_media_stats;
360 }
361 
362 /* RTP/RTCP port range */
363 uint16_t rtp_range_min = 0;
364 uint16_t rtp_range_max = 0;
365 
366 
367 #define JANUS_ICE_PACKET_AUDIO	0
368 #define JANUS_ICE_PACKET_VIDEO	1
369 #define JANUS_ICE_PACKET_TEXT	2
370 #define JANUS_ICE_PACKET_BINARY	3
371 #define JANUS_ICE_PACKET_SCTP	4
372 /* Janus enqueued (S)RTP/(S)RTCP packet to send */
373 typedef struct janus_ice_queued_packet {
374 	char *data;
375 	char *label;
376 	char *protocol;
377 	gint length;
378 	gint type;
379 	gboolean control;
380 	gboolean retransmission;
381 	gboolean encrypted;
382 	gint64 added;
383 } janus_ice_queued_packet;
384 /* A few static, fake, messages we use as a trigger: e.g., to start a
385  * new DTLS handshake, hangup a PeerConnection or close a handle */
386 static janus_ice_queued_packet
387 	janus_ice_start_gathering,
388 	janus_ice_add_candidates,
389 	janus_ice_dtls_handshake,
390 	janus_ice_media_stopped,
391 	janus_ice_hangup_peerconnection,
392 	janus_ice_detach_handle,
393 	janus_ice_data_ready;
394 
395 /* Janus NACKed packet we're tracking (to avoid duplicates) */
396 typedef struct janus_ice_nacked_packet {
397 	janus_ice_handle *handle;
398 	int vindex;
399 	guint16 seq_number;
400 	guint source_id;
401 } janus_ice_nacked_packet;
janus_ice_nacked_packet_cleanup(gpointer user_data)402 static gboolean janus_ice_nacked_packet_cleanup(gpointer user_data) {
403 	janus_ice_nacked_packet *pkt = (janus_ice_nacked_packet *)user_data;
404 
405 	if(pkt->handle->stream){
406 		JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Cleaning up NACKed packet %"SCNu16" (SSRC %"SCNu32", vindex %d)...\n",
407 			pkt->handle->handle_id, pkt->seq_number, pkt->handle->stream->video_ssrc_peer[pkt->vindex], pkt->vindex);
408 		g_hash_table_remove(pkt->handle->stream->rtx_nacked[pkt->vindex], GUINT_TO_POINTER(pkt->seq_number));
409 		g_hash_table_remove(pkt->handle->stream->pending_nacked_cleanup, GUINT_TO_POINTER(pkt->source_id));
410 	}
411 
412 	return G_SOURCE_REMOVE;
413 }
414 
415 /* Deallocation helpers for handles and related structs */
416 static void janus_ice_handle_free(const janus_refcount *handle_ref);
417 static void janus_ice_webrtc_free(janus_ice_handle *handle);
418 static void janus_ice_plugin_session_free(const janus_refcount *app_handle_ref);
419 static void janus_ice_stream_free(const janus_refcount *handle_ref);
420 static void janus_ice_component_free(const janus_refcount *handle_ref);
421 
422 /* Custom GSource for outgoing traffic */
423 typedef struct janus_ice_outgoing_traffic {
424 	GSource parent;
425 	janus_ice_handle *handle;
426 	GDestroyNotify destroy;
427 } janus_ice_outgoing_traffic;
428 static gboolean janus_ice_outgoing_rtcp_handle(gpointer user_data);
429 static gboolean janus_ice_outgoing_stats_handle(gpointer user_data);
430 static gboolean janus_ice_outgoing_traffic_handle(janus_ice_handle *handle, janus_ice_queued_packet *pkt);
janus_ice_outgoing_traffic_prepare(GSource * source,gint * timeout)431 static gboolean janus_ice_outgoing_traffic_prepare(GSource *source, gint *timeout) {
432 	janus_ice_outgoing_traffic *t = (janus_ice_outgoing_traffic *)source;
433 	return (g_async_queue_length(t->handle->queued_packets) > 0);
434 }
janus_ice_outgoing_traffic_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)435 static gboolean janus_ice_outgoing_traffic_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
436 	janus_ice_outgoing_traffic *t = (janus_ice_outgoing_traffic *)source;
437 	int ret = G_SOURCE_CONTINUE;
438 	janus_ice_queued_packet *pkt = NULL;
439 	while((pkt = g_async_queue_try_pop(t->handle->queued_packets)) != NULL) {
440 		if(janus_ice_outgoing_traffic_handle(t->handle, pkt) == G_SOURCE_REMOVE)
441 			ret = G_SOURCE_REMOVE;
442 	}
443 	return ret;
444 }
janus_ice_outgoing_traffic_finalize(GSource * source)445 static void janus_ice_outgoing_traffic_finalize(GSource *source) {
446 	janus_ice_outgoing_traffic *t = (janus_ice_outgoing_traffic *)source;
447 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Finalizing loop source\n", t->handle->handle_id);
448 	if(static_event_loops > 0) {
449 		/* This handle was sharing an event loop with others */
450 		janus_ice_webrtc_free(t->handle);
451 		janus_refcount_decrease(&t->handle->ref);
452 	} else if(t->handle->mainloop != NULL && g_main_loop_is_running(t->handle->mainloop)) {
453 		/* This handle had a dedicated event loop, quit it */
454 		g_main_loop_quit(t->handle->mainloop);
455 	}
456 	janus_refcount_decrease(&t->handle->ref);
457 }
458 static GSourceFuncs janus_ice_outgoing_traffic_funcs = {
459 	janus_ice_outgoing_traffic_prepare,
460 	NULL,	/* We don't need check */
461 	janus_ice_outgoing_traffic_dispatch,
462 	janus_ice_outgoing_traffic_finalize,
463 	NULL, NULL
464 };
janus_ice_outgoing_traffic_create(janus_ice_handle * handle,GDestroyNotify destroy)465 static GSource *janus_ice_outgoing_traffic_create(janus_ice_handle *handle, GDestroyNotify destroy) {
466 	GSource *source = g_source_new(&janus_ice_outgoing_traffic_funcs, sizeof(janus_ice_outgoing_traffic));
467 	janus_ice_outgoing_traffic *t = (janus_ice_outgoing_traffic *)source;
468 	char name[255];
469 	g_snprintf(name, sizeof(name), "source-%"SCNu64, handle->handle_id);
470 	g_source_set_name(source, name);
471 	janus_refcount_increase(&handle->ref);
472 	t->handle = handle;
473 	t->destroy = destroy;
474 	return source;
475 }
476 
477 /* Time, in seconds, that should pass with no media (audio or video) being
478  * received before Janus notifies you about this with a receiving=false */
479 #define DEFAULT_NO_MEDIA_TIMER	1
480 static uint no_media_timer = DEFAULT_NO_MEDIA_TIMER;
janus_set_no_media_timer(uint timer)481 void janus_set_no_media_timer(uint timer) {
482 	no_media_timer = timer;
483 	if(no_media_timer == 0)
484 		JANUS_LOG(LOG_VERB, "Disabling no-media timer\n");
485 	else
486 		JANUS_LOG(LOG_VERB, "Setting no-media timer to %us\n", no_media_timer);
487 }
janus_get_no_media_timer(void)488 uint janus_get_no_media_timer(void) {
489 	return no_media_timer;
490 }
491 
492 /* Number of lost packets per seconds on a media stream (uplink or downlink,
493  * audio or video), that should result in a slow-link event to the user.
494  * By default the feature is disabled (threshold=0), as it can be quite
495  * verbose and is often redundant information, since the same info on lost
496  * packets (in and out) can already be retrieved via client-side stats */
497 #define DEFAULT_SLOWLINK_THRESHOLD	0
498 static uint slowlink_threshold = DEFAULT_SLOWLINK_THRESHOLD;
janus_set_slowlink_threshold(uint packets)499 void janus_set_slowlink_threshold(uint packets) {
500 	slowlink_threshold = packets;
501 	if(slowlink_threshold == 0)
502 		JANUS_LOG(LOG_VERB, "Disabling slow-link events\n");
503 	else
504 		JANUS_LOG(LOG_VERB, "Setting slowlink-threshold to %u packets\n", slowlink_threshold);
505 }
janus_get_slowlink_threshold(void)506 uint janus_get_slowlink_threshold(void) {
507 	return slowlink_threshold;
508 }
509 
510 /* Period, in milliseconds, to refer to for sending TWCC feedback */
511 #define DEFAULT_TWCC_PERIOD		200
512 static uint twcc_period = DEFAULT_TWCC_PERIOD;
janus_set_twcc_period(uint period)513 void janus_set_twcc_period(uint period) {
514 	twcc_period = period;
515 	if(twcc_period == 0) {
516 		JANUS_LOG(LOG_WARN, "Invalid TWCC period, falling back to default\n");
517 		twcc_period = DEFAULT_TWCC_PERIOD;
518 	} else {
519 		JANUS_LOG(LOG_VERB, "Setting TWCC period to %ds\n", twcc_period);
520 	}
521 }
janus_get_twcc_period(void)522 uint janus_get_twcc_period(void) {
523 	return twcc_period;
524 }
525 
526 /* DSCP value, which we can set via libnice: it's disabled by default */
527 static int dscp_ef = 0;
janus_set_dscp(int dscp)528 void janus_set_dscp(int dscp) {
529 	dscp_ef = dscp;
530 	if(dscp_ef > 0) {
531 		JANUS_LOG(LOG_VERB, "Setting DSCP EF to %d\n", dscp_ef);
532 	}
533 }
janus_get_dscp(void)534 int janus_get_dscp(void) {
535 	return dscp_ef;
536 }
537 
538 
janus_ice_free_rtp_packet(janus_rtp_packet * pkt)539 static inline void janus_ice_free_rtp_packet(janus_rtp_packet *pkt) {
540 	if(pkt == NULL) {
541 		return;
542 	}
543 
544 	g_free(pkt->data);
545 	g_free(pkt);
546 }
547 
janus_ice_free_queued_packet(janus_ice_queued_packet * pkt)548 static void janus_ice_free_queued_packet(janus_ice_queued_packet *pkt) {
549 	if(pkt == NULL || pkt == &janus_ice_start_gathering ||
550 			pkt == &janus_ice_add_candidates ||
551 			pkt == &janus_ice_dtls_handshake ||
552 			pkt == &janus_ice_media_stopped ||
553 			pkt == &janus_ice_hangup_peerconnection ||
554 			pkt == &janus_ice_detach_handle ||
555 			pkt == &janus_ice_data_ready) {
556 		return;
557 	}
558 	g_free(pkt->data);
559 	g_free(pkt->label);
560 	g_free(pkt->protocol);
561 	g_free(pkt);
562 }
563 
564 /* Minimum and maximum value, in milliseconds, for the NACK queue/retransmissions (default=200ms/1000ms) */
565 #define DEFAULT_MIN_NACK_QUEUE	200
566 #define DEFAULT_MAX_NACK_QUEUE	1000
567 /* Maximum ignore count after retransmission (200ms) */
568 #define MAX_NACK_IGNORE			200000
569 
570 static gboolean nack_optimizations = FALSE;
janus_set_nack_optimizations_enabled(gboolean optimize)571 void janus_set_nack_optimizations_enabled(gboolean optimize) {
572 	nack_optimizations = optimize;
573 }
janus_is_nack_optimizations_enabled(void)574 gboolean janus_is_nack_optimizations_enabled(void) {
575 	return nack_optimizations;
576 }
577 
578 static uint16_t min_nack_queue = DEFAULT_MIN_NACK_QUEUE;
janus_set_min_nack_queue(uint16_t mnq)579 void janus_set_min_nack_queue(uint16_t mnq) {
580 	min_nack_queue = mnq < DEFAULT_MAX_NACK_QUEUE ? mnq : DEFAULT_MAX_NACK_QUEUE;
581 	if(min_nack_queue == 0)
582 		JANUS_LOG(LOG_VERB, "Disabling NACK queue\n");
583 	else
584 		JANUS_LOG(LOG_VERB, "Setting min NACK queue to %dms\n", min_nack_queue);
585 }
janus_get_min_nack_queue(void)586 uint16_t janus_get_min_nack_queue(void) {
587 	return min_nack_queue;
588 }
589 /* Helper to clean old NACK packets in the buffer when they exceed the queue time limit */
janus_cleanup_nack_buffer(gint64 now,janus_ice_stream * stream,gboolean audio,gboolean video)590 static void janus_cleanup_nack_buffer(gint64 now, janus_ice_stream *stream, gboolean audio, gboolean video) {
591 	if(stream && stream->component) {
592 		janus_ice_component *component = stream->component;
593 		if(audio && component->audio_retransmit_buffer) {
594 			janus_rtp_packet *p = (janus_rtp_packet *)g_queue_peek_head(component->audio_retransmit_buffer);
595 			while(p && (!now || (now - p->created >= (gint64)stream->nack_queue_ms*1000))) {
596 				/* Packet is too old, get rid of it */
597 				g_queue_pop_head(component->audio_retransmit_buffer);
598 				/* Remove from hashtable too */
599 				janus_rtp_header *header = (janus_rtp_header *)p->data;
600 				guint16 seq = ntohs(header->seq_number);
601 				g_hash_table_remove(component->audio_retransmit_seqs, GUINT_TO_POINTER(seq));
602 				/* Free the packet */
603 				janus_ice_free_rtp_packet(p);
604 				p = (janus_rtp_packet *)g_queue_peek_head(component->audio_retransmit_buffer);
605 			}
606 		}
607 		if(video && component->video_retransmit_buffer) {
608 			janus_rtp_packet *p = (janus_rtp_packet *)g_queue_peek_head(component->video_retransmit_buffer);
609 			while(p && (!now || (now - p->created >= (gint64)stream->nack_queue_ms*1000))) {
610 				/* Packet is too old, get rid of it */
611 				g_queue_pop_head(component->video_retransmit_buffer);
612 				/* Remove from hashtable too */
613 				janus_rtp_header *header = (janus_rtp_header *)p->data;
614 				guint16 seq = ntohs(header->seq_number);
615 				g_hash_table_remove(component->video_retransmit_seqs, GUINT_TO_POINTER(seq));
616 				/* Free the packet */
617 				janus_ice_free_rtp_packet(p);
618 				p = (janus_rtp_packet *)g_queue_peek_head(component->video_retransmit_buffer);
619 			}
620 		}
621 	}
622 }
623 
624 
625 #define SEQ_MISSING_WAIT 12000 /*  12ms */
626 #define SEQ_NACKED_WAIT 155000 /* 155ms */
627 /* janus_seq_info list functions */
janus_seq_append(janus_seq_info ** head,janus_seq_info * new_seq)628 static void janus_seq_append(janus_seq_info **head, janus_seq_info *new_seq) {
629 	if(*head == NULL) {
630 		new_seq->prev = new_seq;
631 		new_seq->next = new_seq;
632 		*head = new_seq;
633 	} else {
634 		janus_seq_info *last_seq = (*head)->prev;
635 		new_seq->prev = last_seq;
636 		new_seq->next = *head;
637 		(*head)->prev = new_seq;
638 		last_seq->next = new_seq;
639 	}
640 }
janus_seq_pop_head(janus_seq_info ** head)641 static janus_seq_info *janus_seq_pop_head(janus_seq_info **head) {
642 	janus_seq_info *pop_seq = *head;
643 	if(pop_seq) {
644 		janus_seq_info *new_head = pop_seq->next;
645 		if(pop_seq == new_head || new_head == NULL) {
646 			*head = NULL;
647 		} else {
648 			*head = new_head;
649 			new_head->prev = pop_seq->prev;
650 			new_head->prev->next = new_head;
651 		}
652 	}
653 	return pop_seq;
654 }
janus_seq_list_free(janus_seq_info ** head)655 void janus_seq_list_free(janus_seq_info **head) {
656 	if(!*head)
657 		return;
658 	janus_seq_info *cur = *head;
659 	do {
660 		janus_seq_info *next = cur->next;
661 		g_free(cur);
662 		cur = next;
663 	} while(cur != *head);
664 	*head = NULL;
665 }
janus_seq_in_range(guint16 seqn,guint16 start,guint16 len)666 static int janus_seq_in_range(guint16 seqn, guint16 start, guint16 len) {
667 	/* Supports wrapping sequence (easier with int range) */
668 	int n = seqn;
669 	int nh = (1<<16) + n;
670 	int s = start;
671 	int e = s + len;
672 	return (s <= n && n < e) || (s <= nh && nh < e);
673 }
674 
675 
676 /* Internal method for relaying RTCP messages, optionally filtering them in case they come from plugins */
677 void janus_ice_relay_rtcp_internal(janus_ice_handle *handle, janus_plugin_rtcp *packet, gboolean filter_rtcp);
678 
679 
680 /* Map of active plugin sessions */
681 static GHashTable *plugin_sessions;
682 static janus_mutex plugin_sessions_mutex;
janus_plugin_session_is_alive(janus_plugin_session * plugin_session)683 gboolean janus_plugin_session_is_alive(janus_plugin_session *plugin_session) {
684 	if(plugin_session == NULL || plugin_session < (janus_plugin_session *)0x1000 ||
685 			g_atomic_int_get(&plugin_session->stopped))
686 		return FALSE;
687 	/* Make sure this plugin session is still alive */
688 	janus_mutex_lock_nodebug(&plugin_sessions_mutex);
689 	janus_plugin_session *result = g_hash_table_lookup(plugin_sessions, plugin_session);
690 	janus_mutex_unlock_nodebug(&plugin_sessions_mutex);
691 	if(result == NULL) {
692 		JANUS_LOG(LOG_ERR, "Invalid plugin session (%p)\n", plugin_session);
693 	}
694 	return (result != NULL);
695 }
janus_plugin_session_dereference(janus_plugin_session * plugin_session)696 static void janus_plugin_session_dereference(janus_plugin_session *plugin_session) {
697 	if(plugin_session)
698 		janus_refcount_decrease(&plugin_session->ref);
699 }
700 
701 
janus_ice_clear_queued_candidates(janus_ice_handle * handle)702 static void janus_ice_clear_queued_candidates(janus_ice_handle *handle) {
703 	if(handle == NULL || handle->queued_candidates == NULL) {
704 		return;
705 	}
706 	while(g_async_queue_length(handle->queued_candidates) > 0) {
707 		(void)g_async_queue_try_pop(handle->queued_candidates);
708 	}
709 }
710 
janus_ice_clear_queued_packets(janus_ice_handle * handle)711 static void janus_ice_clear_queued_packets(janus_ice_handle *handle) {
712 	if(handle == NULL || handle->queued_packets == NULL) {
713 		return;
714 	}
715 	janus_ice_queued_packet *pkt = NULL;
716 	while(g_async_queue_length(handle->queued_packets) > 0) {
717 		pkt = g_async_queue_try_pop(handle->queued_packets);
718 		janus_ice_free_queued_packet(pkt);
719 	}
720 }
721 
722 
janus_ice_notify_trickle(janus_ice_handle * handle,char * buffer)723 static void janus_ice_notify_trickle(janus_ice_handle *handle, char *buffer) {
724 	if(handle == NULL)
725 		return;
726 	char cbuffer[200];
727 	if(buffer != NULL)
728 		g_snprintf(cbuffer, sizeof(cbuffer), "candidate:%s", buffer);
729 	/* Send a "trickle" event to the browser */
730 	janus_session *session = (janus_session *)handle->session;
731 	if(session == NULL)
732 		return;
733 	json_t *event = json_object();
734 	json_object_set_new(event, "janus", json_string("trickle"));
735 	json_object_set_new(event, "session_id", json_integer(session->session_id));
736 	json_object_set_new(event, "sender", json_integer(handle->handle_id));
737 	if(opaqueid_in_api && handle->opaque_id != NULL)
738 		json_object_set_new(event, "opaque_id", json_string(handle->opaque_id));
739 	json_t *candidate = json_object();
740 	if(buffer != NULL) {
741 		json_object_set_new(candidate, "sdpMid", json_string(handle->stream_mid));
742 		json_object_set_new(candidate, "sdpMLineIndex", json_integer(0));
743 		json_object_set_new(candidate, "candidate", json_string(cbuffer));
744 	} else {
745 		json_object_set_new(candidate, "completed", json_true());
746 	}
747 	json_object_set_new(event, "candidate", candidate);
748 	/* Send the event */
749 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending trickle event (%s) to transport...\n",
750 		handle->handle_id, buffer ? "candidate" : "end-of-candidates");
751 	janus_session_notify_event(session, event);
752 }
753 
janus_ice_notify_media(janus_ice_handle * handle,gboolean video,int substream,gboolean up)754 static void janus_ice_notify_media(janus_ice_handle *handle, gboolean video, int substream, gboolean up) {
755 	if(handle == NULL)
756 		return;
757 	/* Prepare JSON event to notify user/application */
758 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Notifying that we %s receiving %s\n",
759 		handle->handle_id, up ? "are" : "are NOT", video ? "video" : "audio");
760 	janus_session *session = (janus_session *)handle->session;
761 	if(session == NULL)
762 		return;
763 	json_t *event = json_object();
764 	json_object_set_new(event, "janus", json_string("media"));
765 	json_object_set_new(event, "session_id", json_integer(session->session_id));
766 	json_object_set_new(event, "sender", json_integer(handle->handle_id));
767 	if(opaqueid_in_api && handle->opaque_id != NULL)
768 		json_object_set_new(event, "opaque_id", json_string(handle->opaque_id));
769 	json_object_set_new(event, "type", json_string(video ? "video" : "audio"));
770 	if(video && handle->stream && handle->stream->video_rtcp_ctx[1] != NULL)
771 		json_object_set_new(event, "substream", json_integer(substream));
772 	json_object_set_new(event, "receiving", up ? json_true() : json_false());
773 	if(!up && no_media_timer > 1)
774 		json_object_set_new(event, "seconds", json_integer(no_media_timer));
775 	/* Send the event */
776 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
777 	janus_session_notify_event(session, event);
778 	/* Notify event handlers as well */
779 	if(janus_events_is_enabled()) {
780 		json_t *info = json_object();
781 		json_object_set_new(info, "media", json_string(video ? "video" : "audio"));
782 		if(video && handle->stream && handle->stream->video_rtcp_ctx[1] != NULL)
783 			json_object_set_new(info, "substream", json_integer(substream));
784 		json_object_set_new(info, "receiving", up ? json_true() : json_false());
785 		if(!up && no_media_timer > 1)
786 			json_object_set_new(info, "seconds", json_integer(no_media_timer));
787 		janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, JANUS_EVENT_SUBTYPE_MEDIA_STATE,
788 			session->session_id, handle->handle_id, handle->opaque_id, info);
789 	}
790 }
791 
janus_ice_notify_hangup(janus_ice_handle * handle,const char * reason)792 void janus_ice_notify_hangup(janus_ice_handle *handle, const char *reason) {
793 	if(handle == NULL)
794 		return;
795 	/* Prepare JSON event to notify user/application */
796 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Notifying WebRTC hangup; %p\n", handle->handle_id, handle);
797 	janus_session *session = (janus_session *)handle->session;
798 	if(session == NULL)
799 		return;
800 	json_t *event = json_object();
801 	json_object_set_new(event, "janus", json_string("hangup"));
802 	json_object_set_new(event, "session_id", json_integer(session->session_id));
803 	json_object_set_new(event, "sender", json_integer(handle->handle_id));
804 	if(opaqueid_in_api && handle->opaque_id != NULL)
805 		json_object_set_new(event, "opaque_id", json_string(handle->opaque_id));
806 	if(reason != NULL)
807 		json_object_set_new(event, "reason", json_string(reason));
808 	/* Send the event */
809 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...; %p\n", handle->handle_id, handle);
810 	janus_session_notify_event(session, event);
811 	/* Notify event handlers as well */
812 	if(janus_events_is_enabled()) {
813 		json_t *info = json_object();
814 		json_object_set_new(info, "connection", json_string("hangup"));
815 		if(reason != NULL)
816 			json_object_set_new(info, "reason", json_string(reason));
817 		janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, JANUS_EVENT_SUBTYPE_WEBRTC_STATE,
818 			session->session_id, handle->handle_id, handle->opaque_id, info);
819 	}
820 }
821 
822 
823 /* Trickle helpers */
janus_ice_trickle_new(const char * transaction,json_t * candidate)824 janus_ice_trickle *janus_ice_trickle_new(const char *transaction, json_t *candidate) {
825 	if(transaction == NULL || candidate == NULL)
826 		return NULL;
827 	janus_ice_trickle *trickle = g_malloc(sizeof(janus_ice_trickle));
828 	trickle->handle = NULL;
829 	trickle->received = janus_get_monotonic_time();
830 	trickle->transaction = g_strdup(transaction);
831 	trickle->candidate = json_deep_copy(candidate);
832 	return trickle;
833 }
834 
janus_ice_trickle_parse(janus_ice_handle * handle,json_t * candidate,const char ** error)835 gint janus_ice_trickle_parse(janus_ice_handle *handle, json_t *candidate, const char **error) {
836 	const char *ignore_error = NULL;
837 	if(error == NULL) {
838 		error = &ignore_error;
839 	}
840 	if(handle == NULL) {
841 		*error = "Invalid handle";
842 		return JANUS_ERROR_HANDLE_NOT_FOUND;
843 	}
844 	/* Parse trickle candidate */
845 	if(!json_is_object(candidate) || json_object_get(candidate, "completed") != NULL) {
846 		JANUS_LOG(LOG_VERB, "No more remote candidates for handle %"SCNu64"!\n", handle->handle_id);
847 		janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES);
848 	} else {
849 		/* Handle remote candidate */
850 		json_t *mid = json_object_get(candidate, "sdpMid");
851 		if(mid && !json_is_string(mid)) {
852 			*error = "Trickle error: invalid element type (sdpMid should be a string)";
853 			return JANUS_ERROR_INVALID_ELEMENT_TYPE;
854 		}
855 		json_t *mline = json_object_get(candidate, "sdpMLineIndex");
856 		if(mline && (!json_is_integer(mline) || json_integer_value(mline) < 0)) {
857 			*error = "Trickle error: invalid element type (sdpMLineIndex should be a positive integer)";
858 			return JANUS_ERROR_INVALID_ELEMENT_TYPE;
859 		}
860 		if(!mid && !mline) {
861 			*error = "Trickle error: missing mandatory element (sdpMid or sdpMLineIndex)";
862 			return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
863 		}
864 		json_t *rc = json_object_get(candidate, "candidate");
865 		if(!rc) {
866 			*error = "Trickle error: missing mandatory element (candidate)";
867 			return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
868 		}
869 		if(!json_is_string(rc)) {
870 			*error = "Trickle error: invalid element type (candidate should be a string)";
871 			return JANUS_ERROR_INVALID_ELEMENT_TYPE;
872 		}
873 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Trickle candidate (%s): %s\n", handle->handle_id, json_string_value(mid), json_string_value(rc));
874 		/* Parse it */
875 		int sdpMLineIndex = mline ? json_integer_value(mline) : -1;
876 		const char *sdpMid = json_string_value(mid);
877 		if(sdpMLineIndex > 0 || (handle->stream_mid && sdpMid && strcmp(handle->stream_mid, sdpMid))) {
878 			/* FIXME We bundle everything, so we ignore candidates for anything beyond the first m-line */
879 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got a mid='%s' candidate (index %d) but we're bundling, ignoring...\n",
880 				handle->handle_id, json_string_value(mid), sdpMLineIndex);
881 			return 0;
882 		}
883 		janus_ice_stream *stream = handle->stream;
884 		if(stream == NULL) {
885 			*error = "Trickle error: invalid element type (no such stream)";
886 			return JANUS_ERROR_TRICKE_INVALID_STREAM;
887 		}
888 		int res = janus_sdp_parse_candidate(stream, json_string_value(rc), 1);
889 		if(res != 0) {
890 			JANUS_LOG(LOG_ERR, "[%"SCNu64"] Failed to parse candidate... (%d)\n", handle->handle_id, res);
891 			/* FIXME Should we return an error? */
892 		}
893 	}
894 	return 0;
895 }
896 
janus_ice_trickle_destroy(janus_ice_trickle * trickle)897 void janus_ice_trickle_destroy(janus_ice_trickle *trickle) {
898 	if(trickle == NULL)
899 		return;
900 	g_free(trickle->transaction);
901 	trickle->transaction = NULL;
902 	if(trickle->candidate)
903 		json_decref(trickle->candidate);
904 	trickle->candidate = NULL;
905 	g_free(trickle);
906 }
907 
908 
909 /* libnice initialization */
janus_ice_init(gboolean ice_lite,gboolean ice_tcp,gboolean full_trickle,gboolean ignore_mdns,gboolean ipv6,gboolean ipv6_linklocal,uint16_t rtp_min_port,uint16_t rtp_max_port)910 void janus_ice_init(gboolean ice_lite, gboolean ice_tcp, gboolean full_trickle, gboolean ignore_mdns,
911 		gboolean ipv6, gboolean ipv6_linklocal, uint16_t rtp_min_port, uint16_t rtp_max_port) {
912 	janus_ice_lite_enabled = ice_lite;
913 	janus_ice_tcp_enabled = ice_tcp;
914 	janus_full_trickle_enabled = full_trickle;
915 	janus_mdns_enabled = !ignore_mdns;
916 	janus_ipv6_enabled = ipv6;
917 	if(ipv6)
918 		janus_ipv6_linklocal_enabled = ipv6_linklocal;
919 	JANUS_LOG(LOG_INFO, "Initializing ICE stuff (%s mode, ICE-TCP candidates %s, %s-trickle, IPv6 support %s)\n",
920 		janus_ice_lite_enabled ? "Lite" : "Full",
921 		janus_ice_tcp_enabled ? "enabled" : "disabled",
922 		janus_full_trickle_enabled ? "full" : "half",
923 		janus_ipv6_enabled ? "enabled" : "disabled");
924 	if(janus_ice_tcp_enabled) {
925 #ifndef HAVE_LIBNICE_TCP
926 		JANUS_LOG(LOG_WARN, "libnice version < 0.1.8, disabling ICE-TCP support\n");
927 		janus_ice_tcp_enabled = FALSE;
928 #else
929 		if(!janus_ice_lite_enabled) {
930 			JANUS_LOG(LOG_WARN, "You may experience problems when having ICE-TCP enabled without having ICE Lite enabled too in libnice\n");
931 		}
932 #endif
933 	}
934 	/* libnice debugging is disabled unless explicitly stated */
935 	nice_debug_disable(TRUE);
936 
937 	/*! \note The RTP/RTCP port range configuration may be just a placeholder: for
938 	 * instance, libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails
939 	 * when linking with an undefined reference to \c nice_agent_set_port_range
940 	 * so this is checked by the install.sh script in advance. */
941 	rtp_range_min = rtp_min_port;
942 	rtp_range_max = rtp_max_port;
943 	if(rtp_range_max < rtp_range_min) {
944 		JANUS_LOG(LOG_WARN, "Invalid ICE port range: %"SCNu16" > %"SCNu16"\n", rtp_range_min, rtp_range_max);
945 	} else if(rtp_range_min > 0 || rtp_range_max > 0) {
946 #ifndef HAVE_PORTRANGE
947 		JANUS_LOG(LOG_WARN, "nice_agent_set_port_range unavailable, port range disabled\n");
948 #else
949 		JANUS_LOG(LOG_INFO, "ICE port range: %"SCNu16"-%"SCNu16"\n", rtp_range_min, rtp_range_max);
950 #endif
951 	}
952 	if(!janus_mdns_enabled)
953 		JANUS_LOG(LOG_WARN, "mDNS resolution disabled, .local candidates will be ignored\n");
954 
955 	/* We keep track of plugin sessions to avoid problems */
956 	plugin_sessions = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)janus_plugin_session_dereference);
957 	janus_mutex_init(&plugin_sessions_mutex);
958 
959 #ifdef HAVE_TURNRESTAPI
960 	/* Initialize the TURN REST API client stack, whether we're going to use it or not */
961 	janus_turnrest_init();
962 #endif
963 
964 }
965 
janus_ice_deinit(void)966 void janus_ice_deinit(void) {
967 #ifdef HAVE_TURNRESTAPI
968 	janus_turnrest_deinit();
969 #endif
970 }
971 
janus_ice_test_stun_server(janus_network_address * addr,uint16_t port,uint16_t local_port,janus_network_address * public_addr,uint16_t * public_port)972 int janus_ice_test_stun_server(janus_network_address *addr, uint16_t port,
973 		uint16_t local_port, janus_network_address *public_addr, uint16_t *public_port) {
974 	if(!addr || !public_addr)
975 		return -1;
976 	/* Test the STUN server */
977 	StunAgent stun;
978 	stun_agent_init (&stun, STUN_ALL_KNOWN_ATTRIBUTES, STUN_COMPATIBILITY_RFC5389, 0);
979 	StunMessage msg;
980 	uint8_t buf[1500];
981 	size_t len = stun_usage_bind_create(&stun, &msg, buf, 1500);
982 	JANUS_LOG(LOG_INFO, "Testing STUN server: message is of %zu bytes\n", len);
983 	/* Use the janus_network_address info to drive the socket creation */
984 	int fd = socket(addr->family, SOCK_DGRAM, 0);
985 	if(fd < 0) {
986 		JANUS_LOG(LOG_FATAL, "Error creating socket for STUN BINDING test\n");
987 		return -1;
988 	}
989 	struct sockaddr *address = NULL, *remote = NULL;
990 	struct sockaddr_in address4 = { 0 }, remote4 = { 0 };
991 	struct sockaddr_in6 address6 = { 0 }, remote6 = { 0 };
992 	socklen_t addrlen = 0;
993 	if(addr->family == AF_INET) {
994 		memset(&address4, 0, sizeof(address4));
995 		address4.sin_family = AF_INET;
996 		address4.sin_port = htons(local_port);
997 		address4.sin_addr.s_addr = INADDR_ANY;
998 		memset(&remote4, 0, sizeof(remote4));
999 		remote4.sin_family = AF_INET;
1000 		remote4.sin_port = htons(port);
1001 		memcpy(&remote4.sin_addr, &addr->ipv4, sizeof(addr->ipv4));
1002 		address = (struct sockaddr *)(&address4);
1003 		remote = (struct sockaddr *)(&remote4);
1004 		addrlen = sizeof(remote4);
1005 	} else if(addr->family == AF_INET6) {
1006 		memset(&address6, 0, sizeof(address6));
1007 		address6.sin6_family = AF_INET6;
1008 		address6.sin6_port = htons(local_port);
1009 		address6.sin6_addr = in6addr_any;
1010 		memset(&remote6, 0, sizeof(remote6));
1011 		remote6.sin6_family = AF_INET6;
1012 		remote6.sin6_port = htons(port);
1013 		memcpy(&remote6.sin6_addr, &addr->ipv6, sizeof(addr->ipv6));
1014 		remote6.sin6_addr = addr->ipv6;
1015 		address = (struct sockaddr *)(&address6);
1016 		remote = (struct sockaddr *)(&remote6);
1017 		addrlen = sizeof(remote6);
1018 	}
1019 	if(bind(fd, address, addrlen) < 0) {
1020 		JANUS_LOG(LOG_FATAL, "Bind failed for STUN BINDING test: %d (%s)\n", errno, g_strerror(errno));
1021 		close(fd);
1022 		return -1;
1023 	}
1024 	int bytes = sendto(fd, buf, len, 0, remote, addrlen);
1025 	if(bytes < 0) {
1026 		JANUS_LOG(LOG_FATAL, "Error sending STUN BINDING test\n");
1027 		close(fd);
1028 		return -1;
1029 	}
1030 	JANUS_LOG(LOG_VERB, "  >> Sent %d bytes, waiting for reply...\n", bytes);
1031 	struct timeval timeout;
1032 	fd_set readfds;
1033 	FD_ZERO(&readfds);
1034 	FD_SET(fd, &readfds);
1035 	timeout.tv_sec = 5;	/* FIXME Don't wait forever */
1036 	timeout.tv_usec = 0;
1037 	int err = select(fd+1, &readfds, NULL, NULL, &timeout);
1038 	if(err < 0) {
1039 		JANUS_LOG(LOG_FATAL, "Error waiting for a response to our STUN BINDING test: %d (%s)\n", errno, g_strerror(errno));
1040 		close(fd);
1041 		return -1;
1042 	}
1043 	if(!FD_ISSET(fd, &readfds)) {
1044 		JANUS_LOG(LOG_FATAL, "No response to our STUN BINDING test\n");
1045 		close(fd);
1046 		return -1;
1047 	}
1048 	bytes = recvfrom(fd, buf, 1500, 0, remote, &addrlen);
1049 	JANUS_LOG(LOG_VERB, "  >> Got %d bytes...\n", bytes);
1050 	close(fd);
1051 	if(bytes < 0) {
1052 		JANUS_LOG(LOG_FATAL, "Failed to receive STUN\n");
1053 		return -1;
1054 	}
1055 	if(stun_agent_validate (&stun, &msg, buf, bytes, NULL, NULL) != STUN_VALIDATION_SUCCESS) {
1056 		JANUS_LOG(LOG_FATAL, "Failed to validate STUN BINDING response\n");
1057 		return -1;
1058 	}
1059 	StunClass class = stun_message_get_class(&msg);
1060 	StunMethod method = stun_message_get_method(&msg);
1061 	if(class != STUN_RESPONSE || method != STUN_BINDING) {
1062 		JANUS_LOG(LOG_FATAL, "Unexpected STUN response: %d/%d\n", class, method);
1063 		return -1;
1064 	}
1065 	StunMessageReturn ret = stun_message_find_xor_addr(&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, (struct sockaddr_storage *)address, &addrlen);
1066 	JANUS_LOG(LOG_VERB, "  >> XOR-MAPPED-ADDRESS: %d\n", ret);
1067 	if(ret == STUN_MESSAGE_RETURN_SUCCESS) {
1068 		if(janus_network_address_from_sockaddr(address, public_addr) != 0) {
1069 			JANUS_LOG(LOG_ERR, "Could not resolve XOR-MAPPED-ADDRESS...\n");
1070 			return -1;
1071 		}
1072 		if(public_port != NULL) {
1073 			if(address->sa_family == AF_INET) {
1074 				struct sockaddr_in *addr = (struct sockaddr_in *)address;
1075 				*public_port = ntohs(addr->sin_port);
1076 			} else if(address->sa_family == AF_INET6) {
1077 				struct sockaddr_in6 *addr = (struct sockaddr_in6 *)address;
1078 				*public_port = ntohs(addr->sin6_port);
1079 			}
1080 		}
1081 		return 0;
1082 	}
1083 	ret = stun_message_find_addr(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, (struct sockaddr_storage *)address, &addrlen);
1084 	JANUS_LOG(LOG_VERB, "  >> MAPPED-ADDRESS: %d\n", ret);
1085 	if(ret == STUN_MESSAGE_RETURN_SUCCESS) {
1086 		if(janus_network_address_from_sockaddr(address, public_addr) != 0) {
1087 			JANUS_LOG(LOG_ERR, "Could not resolve MAPPED-ADDRESS...\n");
1088 			return -1;
1089 		}
1090 		if(public_port != NULL) {
1091 			if(address->sa_family == AF_INET) {
1092 				struct sockaddr_in *addr = (struct sockaddr_in *)address;
1093 				*public_port = ntohs(addr->sin_port);
1094 			} else if(address->sa_family == AF_INET6) {
1095 				struct sockaddr_in6 *addr = (struct sockaddr_in6 *)address;
1096 				*public_port = ntohs(addr->sin6_port);
1097 			}
1098 		}
1099 		return 0;
1100 	}
1101 	/* No usable attribute? */
1102 	JANUS_LOG(LOG_ERR, "No XOR-MAPPED-ADDRESS or MAPPED-ADDRESS...\n");
1103 	return -1;
1104 }
1105 
janus_ice_set_stun_server(gchar * stun_server,uint16_t stun_port)1106 int janus_ice_set_stun_server(gchar *stun_server, uint16_t stun_port) {
1107 	if(stun_server == NULL)
1108 		return 0;	/* No initialization needed */
1109 	if(stun_port == 0)
1110 		stun_port = 3478;
1111 	JANUS_LOG(LOG_INFO, "STUN server to use: %s:%u\n", stun_server, stun_port);
1112 	/* Resolve address to get an IP */
1113 	struct addrinfo *res = NULL;
1114 	janus_network_address addr;
1115 	janus_network_address_string_buffer addr_buf;
1116 	if(getaddrinfo(stun_server, NULL, NULL, &res) != 0 ||
1117 			janus_network_address_from_sockaddr(res->ai_addr, &addr) != 0 ||
1118 			janus_network_address_to_string_buffer(&addr, &addr_buf) != 0) {
1119 		JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", stun_server);
1120 		if(res)
1121 			freeaddrinfo(res);
1122 		return -1;
1123 	}
1124 	freeaddrinfo(res);
1125 	janus_stun_server = g_strdup(janus_network_address_string_from_buffer(&addr_buf));
1126 	if(janus_stun_server == NULL) {
1127 		JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", stun_server);
1128 		return -1;
1129 	}
1130 	janus_stun_port = stun_port;
1131 	JANUS_LOG(LOG_INFO, "  >> %s:%u (%s)\n", janus_stun_server, janus_stun_port, addr.family == AF_INET ? "IPv4" : "IPv6");
1132 
1133 	/* Test the STUN server */
1134 	janus_network_address public_addr = { 0 };
1135 	if(janus_ice_test_stun_server(&addr, janus_stun_port, 0, &public_addr, NULL) < 0) {
1136 		g_free(janus_stun_server);
1137 		janus_stun_server = NULL;
1138 		return -1;
1139 	}
1140 	if(janus_network_address_to_string_buffer(&public_addr, &addr_buf) != 0) {
1141 		JANUS_LOG(LOG_ERR, "Could not resolve public address...\n");
1142 		g_free(janus_stun_server);
1143 		janus_stun_server = NULL;
1144 		return -1;
1145 	}
1146 	const char *public_ip = janus_network_address_string_from_buffer(&addr_buf);
1147 	JANUS_LOG(LOG_INFO, "  >> Our public address is %s\n", public_ip);
1148 	janus_add_public_ip(public_ip);
1149 	return 0;
1150 }
1151 
janus_ice_set_turn_server(gchar * turn_server,uint16_t turn_port,gchar * turn_type,gchar * turn_user,gchar * turn_pwd)1152 int janus_ice_set_turn_server(gchar *turn_server, uint16_t turn_port, gchar *turn_type, gchar *turn_user, gchar *turn_pwd) {
1153 	if(turn_server == NULL)
1154 		return 0;	/* No initialization needed */
1155 	if(turn_type == NULL)
1156 		turn_type = (char *)"udp";
1157 	if(turn_port == 0)
1158 		turn_port = 3478;
1159 	JANUS_LOG(LOG_INFO, "TURN server to use: %s:%u (%s)\n", turn_server, turn_port, turn_type);
1160 	if(!strcasecmp(turn_type, "udp")) {
1161 		janus_turn_type = NICE_RELAY_TYPE_TURN_UDP;
1162 	} else if(!strcasecmp(turn_type, "tcp")) {
1163 		janus_turn_type = NICE_RELAY_TYPE_TURN_TCP;
1164 	} else if(!strcasecmp(turn_type, "tls")) {
1165 		janus_turn_type = NICE_RELAY_TYPE_TURN_TLS;
1166 	} else {
1167 		JANUS_LOG(LOG_ERR, "Unsupported relay type '%s'...\n", turn_type);
1168 		return -1;
1169 	}
1170 	/* Resolve address to get an IP */
1171 	struct addrinfo *res = NULL;
1172 	janus_network_address addr;
1173 	janus_network_address_string_buffer addr_buf;
1174 	if(getaddrinfo(turn_server, NULL, NULL, &res) != 0 ||
1175 			janus_network_address_from_sockaddr(res->ai_addr, &addr) != 0 ||
1176 			janus_network_address_to_string_buffer(&addr, &addr_buf) != 0) {
1177 		JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", turn_server);
1178 		if(res)
1179 			freeaddrinfo(res);
1180 		return -1;
1181 	}
1182 	freeaddrinfo(res);
1183 	g_free(janus_turn_server);
1184 	janus_turn_server = g_strdup(janus_network_address_string_from_buffer(&addr_buf));
1185 	if(janus_turn_server == NULL) {
1186 		JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", turn_server);
1187 		return -1;
1188 	}
1189 	janus_turn_port = turn_port;
1190 	JANUS_LOG(LOG_VERB, "  >> %s:%u\n", janus_turn_server, janus_turn_port);
1191 	g_free(janus_turn_user);
1192 	janus_turn_user = NULL;
1193 	if(turn_user)
1194 		janus_turn_user = g_strdup(turn_user);
1195 	g_free(janus_turn_pwd);
1196 	janus_turn_pwd = NULL;
1197 	if(turn_pwd)
1198 		janus_turn_pwd = g_strdup(turn_pwd);
1199 	return 0;
1200 }
1201 
janus_ice_set_turn_rest_api(gchar * api_server,gchar * api_key,gchar * api_method,uint api_timeout)1202 int janus_ice_set_turn_rest_api(gchar *api_server, gchar *api_key, gchar *api_method, uint api_timeout) {
1203 #ifndef HAVE_TURNRESTAPI
1204 	JANUS_LOG(LOG_ERR, "Janus has been built with no libcurl support, TURN REST API unavailable\n");
1205 	return -1;
1206 #else
1207 	if(api_server != NULL &&
1208 			(strstr(api_server, "http://") != api_server && strstr(api_server, "https://") != api_server)) {
1209 		JANUS_LOG(LOG_ERR, "Invalid TURN REST API backend: not an HTTP address\n");
1210 		return -1;
1211 	}
1212 	janus_turnrest_set_backend(api_server, api_key, api_method, api_timeout);
1213 	JANUS_LOG(LOG_INFO, "TURN REST API backend: %s\n", api_server ? api_server : "(disabled)");
1214 #endif
1215 	return 0;
1216 }
1217 
1218 
1219 /* ICE stuff */
1220 static const gchar *janus_ice_state_name[] =
1221 {
1222 	"disconnected",
1223 	"gathering",
1224 	"connecting",
1225 	"connected",
1226 	"ready",
1227 	"failed"
1228 };
janus_get_ice_state_name(gint state)1229 const gchar *janus_get_ice_state_name(gint state) {
1230 	if(state < 0 || state > 5)
1231 		return NULL;
1232 	return janus_ice_state_name[state];
1233 }
1234 
1235 
1236 /* Thread to take care of the handle loop */
janus_ice_handle_thread(void * data)1237 static void *janus_ice_handle_thread(void *data) {
1238 	janus_ice_handle *handle = data;
1239 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Handle thread started; %p\n", handle->handle_id, handle);
1240 	if(handle->mainloop == NULL) {
1241 		JANUS_LOG(LOG_ERR, "[%"SCNu64"] Invalid loop...\n", handle->handle_id);
1242 		janus_refcount_decrease(&handle->ref);
1243 		g_thread_unref(g_thread_self());
1244 		return NULL;
1245 	}
1246 	JANUS_LOG(LOG_DBG, "[%"SCNu64"] Looping...\n", handle->handle_id);
1247 	g_main_loop_run(handle->mainloop);
1248 	janus_ice_webrtc_free(handle);
1249 	handle->thread = NULL;
1250 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Handle thread ended! %p\n", handle->handle_id, handle);
1251 	/* Unref the handle */
1252 	janus_refcount_decrease(&handle->ref);
1253 	g_thread_unref(g_thread_self());
1254 	return NULL;
1255 }
1256 
janus_ice_handle_create(void * core_session,const char * opaque_id,const char * token)1257 janus_ice_handle *janus_ice_handle_create(void *core_session, const char *opaque_id, const char *token) {
1258 	if(core_session == NULL)
1259 		return NULL;
1260 	janus_session *session = (janus_session *)core_session;
1261 	janus_ice_handle *handle = NULL;
1262 	guint64 handle_id = 0;
1263 	while(handle_id == 0) {
1264 		handle_id = janus_random_uint64();
1265 		handle = janus_session_handles_find(session, handle_id);
1266 		if(handle != NULL) {
1267 			/* Handle ID already taken, try another one */
1268 			janus_refcount_decrease(&handle->ref);	/* janus_session_handles_find increases it */
1269 			handle_id = 0;
1270 		}
1271 	}
1272 	handle = (janus_ice_handle *)g_malloc0(sizeof(janus_ice_handle));
1273 	JANUS_LOG(LOG_INFO, "Creating new handle in session %"SCNu64": %"SCNu64"; %p %p\n", session->session_id, handle_id, core_session, handle);
1274 	janus_refcount_init(&handle->ref, janus_ice_handle_free);
1275 	janus_refcount_increase(&session->ref);
1276 	handle->session = core_session;
1277 	if(opaque_id)
1278 		handle->opaque_id = g_strdup(opaque_id);
1279 	if(token)
1280 		handle->token = g_strdup(token);
1281 	handle->created = janus_get_monotonic_time();
1282 	handle->handle_id = handle_id;
1283 	handle->app = NULL;
1284 	handle->app_handle = NULL;
1285 	handle->queued_candidates = g_async_queue_new();
1286 	handle->queued_packets = g_async_queue_new();
1287 	janus_mutex_init(&handle->mutex);
1288 	janus_session_handles_insert(session, handle);
1289 	return handle;
1290 }
1291 
janus_ice_handle_attach_plugin(void * core_session,janus_ice_handle * handle,janus_plugin * plugin,int loop_index)1292 gint janus_ice_handle_attach_plugin(void *core_session, janus_ice_handle *handle, janus_plugin *plugin, int loop_index) {
1293 	if(core_session == NULL)
1294 		return JANUS_ERROR_SESSION_NOT_FOUND;
1295 	janus_session *session = (janus_session *)core_session;
1296 	if(plugin == NULL)
1297 		return JANUS_ERROR_PLUGIN_NOT_FOUND;
1298 	if(handle == NULL)
1299 		return JANUS_ERROR_HANDLE_NOT_FOUND;
1300 	if(handle->app != NULL) {
1301 		/* This handle is already attached to a plugin */
1302 		return JANUS_ERROR_PLUGIN_ATTACH;
1303 	}
1304 	int error = 0;
1305 	janus_plugin_session *session_handle = g_malloc(sizeof(janus_plugin_session));
1306 	session_handle->gateway_handle = handle;
1307 	session_handle->plugin_handle = NULL;
1308 	g_atomic_int_set(&session_handle->stopped, 0);
1309 	plugin->create_session(session_handle, &error);
1310 	if(error) {
1311 		/* TODO Make error struct to pass verbose information */
1312 		g_free(session_handle);
1313 		return error;
1314 	}
1315 	janus_refcount_init(&session_handle->ref, janus_ice_plugin_session_free);
1316 	/* Handle and plugin session reference each other */
1317 	janus_refcount_increase(&session_handle->ref);
1318 	janus_refcount_increase(&handle->ref);
1319 	handle->app = plugin;
1320 	handle->app_handle = session_handle;
1321 	/* Add this plugin session to active sessions map */
1322 	janus_mutex_lock(&plugin_sessions_mutex);
1323 	g_hash_table_insert(plugin_sessions, session_handle, session_handle);
1324 	janus_mutex_unlock(&plugin_sessions_mutex);
1325 	/* Create a new context, loop, and source */
1326 	if(static_event_loops == 0) {
1327 		handle->mainctx = g_main_context_new();
1328 		handle->mainloop = g_main_loop_new(handle->mainctx, FALSE);
1329 	} else {
1330 		/* We're actually using static event loops, pick one from the list */
1331 		if(!allow_loop_indication && loop_index > -1) {
1332 			JANUS_LOG(LOG_WARN, "[%"SCNu64"] Manual allocation of event loops forbidden, ignoring provided loop index %d\n", handle->handle_id, loop_index);
1333 		}
1334 		janus_refcount_increase(&handle->ref);
1335 		janus_mutex_lock(&event_loops_mutex);
1336 		gboolean automatic_selection = TRUE;
1337 		if(allow_loop_indication && loop_index != -1) {
1338 			/* The API can drive the selection and an index was provided, check if it exists */
1339 			janus_ice_static_event_loop *loop = g_slist_nth_data(event_loops, loop_index);
1340 			if(loop == NULL) {
1341 				JANUS_LOG(LOG_WARN, "[%"SCNu64"] Invalid loop index %d, picking event loop automatically\n", handle->handle_id, loop_index);
1342 			} else {
1343 				automatic_selection = FALSE;
1344 				handle->mainctx = loop->mainctx;
1345 				handle->mainloop = loop->mainloop;
1346 				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Manually added handle to loop #%d\n", handle->handle_id, loop->id);
1347 			}
1348 		}
1349 		if(automatic_selection) {
1350 			/* Pick an available loop automatically (round robin) */
1351 			janus_ice_static_event_loop *loop = (janus_ice_static_event_loop *)current_loop->data;
1352 			handle->mainctx = loop->mainctx;
1353 			handle->mainloop = loop->mainloop;
1354 			current_loop = current_loop->next;
1355 			if(current_loop == NULL)
1356 				current_loop = event_loops;
1357 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Automatically added handle to loop #%d\n", handle->handle_id, loop->id);
1358 		}
1359 		janus_mutex_unlock(&event_loops_mutex);
1360 	}
1361 	handle->rtp_source = janus_ice_outgoing_traffic_create(handle, (GDestroyNotify)g_free);
1362 	g_source_set_priority(handle->rtp_source, G_PRIORITY_DEFAULT);
1363 	g_source_attach(handle->rtp_source, handle->mainctx);
1364 	if(static_event_loops == 0) {
1365 		/* Now spawn a thread for this loop */
1366 		GError *terror = NULL;
1367 		char tname[16];
1368 		g_snprintf(tname, sizeof(tname), "hloop %"SCNu64, handle->handle_id);
1369 		janus_refcount_increase(&handle->ref);
1370 		handle->thread = g_thread_try_new(tname, &janus_ice_handle_thread, handle, &terror);
1371 		if(terror != NULL) {
1372 			/* FIXME We should clear some resources... */
1373 			JANUS_LOG(LOG_ERR, "[%"SCNu64"] Got error %d (%s) trying to launch the handle thread...\n",
1374 				handle->handle_id, terror->code, terror->message ? terror->message : "??");
1375 			g_error_free(terror);
1376 			janus_refcount_decrease(&handle->ref);	/* This is for the thread reference we just added */
1377 			janus_ice_handle_destroy(session, handle);
1378 			return -1;
1379 		}
1380 	}
1381 	/* Notify event handlers */
1382 	if(janus_events_is_enabled())
1383 		janus_events_notify_handlers(JANUS_EVENT_TYPE_HANDLE, JANUS_EVENT_SUBTYPE_NONE,
1384 			session->session_id, handle->handle_id, "attached", plugin->get_package(), handle->opaque_id, handle->token);
1385 	return 0;
1386 }
1387 
janus_ice_handle_destroy(void * core_session,janus_ice_handle * handle)1388 gint janus_ice_handle_destroy(void *core_session, janus_ice_handle *handle) {
1389 	/* session->mutex has to be locked when calling this function */
1390 	janus_session *session = (janus_session *)core_session;
1391 	if(session == NULL)
1392 		return JANUS_ERROR_SESSION_NOT_FOUND;
1393 	if(handle == NULL)
1394 		return JANUS_ERROR_HANDLE_NOT_FOUND;
1395 	if(!g_atomic_int_compare_and_exchange(&handle->destroyed, 0, 1))
1396 		return 0;
1397 	/* First of all, hangup the PeerConnection, if any */
1398 	janus_ice_webrtc_hangup(handle, "Detach");
1399 	janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
1400 	/* Remove the session from active sessions map */
1401 	janus_mutex_lock(&plugin_sessions_mutex);
1402 	gboolean found = g_hash_table_remove(plugin_sessions, handle->app_handle);
1403 	if(!found) {
1404 		janus_mutex_unlock(&plugin_sessions_mutex);
1405 		return JANUS_ERROR_HANDLE_NOT_FOUND;
1406 	}
1407 	janus_mutex_unlock(&plugin_sessions_mutex);
1408 	janus_plugin *plugin_t = (janus_plugin *)handle->app;
1409 	if(plugin_t == NULL) {
1410 		/* There was no plugin attached, probably something went wrong there */
1411 		janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1412 		janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
1413 		if(handle->mainloop != NULL) {
1414 			if(static_event_loops == 0 && handle->mainloop != NULL && g_main_loop_is_running(handle->mainloop)) {
1415 				g_main_loop_quit(handle->mainloop);
1416 			}
1417 		}
1418 		janus_refcount_decrease(&handle->ref);
1419 		return 0;
1420 	}
1421 	JANUS_LOG(LOG_INFO, "Detaching handle from %s; %p %p %p %p\n", plugin_t->get_name(), handle, handle->app_handle, handle->app_handle->gateway_handle, handle->app_handle->plugin_handle);
1422 	/* Actually detach handle... */
1423 	if(g_atomic_int_compare_and_exchange(&handle->app_handle->stopped, 0, 1)) {
1424 		/* Notify the plugin that the session's over (the plugin will
1425 		 * remove the other reference to the plugin session handle) */
1426 		g_async_queue_push(handle->queued_packets, &janus_ice_detach_handle);
1427 		g_main_context_wakeup(handle->mainctx);
1428 	}
1429 	/* Get rid of the handle now */
1430 	if(g_atomic_int_compare_and_exchange(&handle->dump_packets, 1, 0)) {
1431 		janus_text2pcap_close(handle->text2pcap);
1432 		g_clear_pointer(&handle->text2pcap, janus_text2pcap_free);
1433 	}
1434 	/* We only actually destroy the handle later */
1435 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Handle detached, scheduling destruction\n", handle->handle_id);
1436 	/* Unref the handle: we only unref the session too when actually freeing the handle, so that it is freed before that */
1437 	janus_refcount_decrease(&handle->ref);
1438 	return 0;
1439 }
1440 
janus_ice_handle_free(const janus_refcount * handle_ref)1441 static void janus_ice_handle_free(const janus_refcount *handle_ref) {
1442 	janus_ice_handle *handle = janus_refcount_containerof(handle_ref, janus_ice_handle, ref);
1443 	/* This stack can be destroyed, free all the resources */
1444 	janus_mutex_lock(&handle->mutex);
1445 	if(handle->queued_candidates != NULL) {
1446 		janus_ice_clear_queued_candidates(handle);
1447 		g_async_queue_unref(handle->queued_candidates);
1448 	}
1449 	if(handle->queued_packets != NULL) {
1450 		janus_ice_clear_queued_packets(handle);
1451 		g_async_queue_unref(handle->queued_packets);
1452 	}
1453 	if(static_event_loops == 0 && handle->mainloop != NULL) {
1454 		g_main_loop_unref(handle->mainloop);
1455 		handle->mainloop = NULL;
1456 	}
1457 	if(static_event_loops == 0 && handle->mainctx != NULL) {
1458 		g_main_context_unref(handle->mainctx);
1459 		handle->mainctx = NULL;
1460 	}
1461 	janus_mutex_unlock(&handle->mutex);
1462 	janus_ice_webrtc_free(handle);
1463 	JANUS_LOG(LOG_INFO, "[%"SCNu64"] Handle and related resources freed; %p %p\n", handle->handle_id, handle, handle->session);
1464 	/* Finally, unref the session and free the handle */
1465 	if(handle->session != NULL) {
1466 		janus_session *session = (janus_session *)handle->session;
1467 		janus_refcount_decrease(&session->ref);
1468 	}
1469 	g_free(handle->opaque_id);
1470 	g_free(handle->token);
1471 	g_free(handle);
1472 }
1473 
1474 #ifdef HAVE_CLOSE_ASYNC
janus_ice_cb_agent_closed(GObject * src,GAsyncResult * result,gpointer data)1475 static void janus_ice_cb_agent_closed(GObject *src, GAsyncResult *result, gpointer data) {
1476 	janus_ice_outgoing_traffic *t = (janus_ice_outgoing_traffic *)data;
1477 	janus_ice_handle *handle = t->handle;
1478 
1479 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Disposing nice agent %p\n", handle->handle_id, handle->agent);
1480 	g_object_unref(handle->agent);
1481 	handle->agent = NULL;
1482 	g_source_unref((GSource *)t);
1483 	janus_refcount_decrease(&handle->ref);
1484 }
1485 #endif
1486 
janus_ice_plugin_session_free(const janus_refcount * app_handle_ref)1487 static void janus_ice_plugin_session_free(const janus_refcount *app_handle_ref) {
1488 	janus_plugin_session *app_handle = janus_refcount_containerof(app_handle_ref, janus_plugin_session, ref);
1489 	/* This app handle can be destroyed, free all the resources */
1490 	if(app_handle->gateway_handle != NULL) {
1491 		janus_ice_handle *handle = (janus_ice_handle *)app_handle->gateway_handle;
1492 		app_handle->gateway_handle = NULL;
1493 		handle->app_handle = NULL;
1494 		janus_refcount_decrease(&handle->ref);
1495 	}
1496 	g_free(app_handle);
1497 }
1498 
janus_ice_webrtc_hangup(janus_ice_handle * handle,const char * reason)1499 void janus_ice_webrtc_hangup(janus_ice_handle *handle, const char *reason) {
1500 	if(handle == NULL)
1501 		return;
1502 	g_atomic_int_set(&handle->closepc, 0);
1503 	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT))
1504 		return;
1505 	janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1506 	janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
1507 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_GOT_OFFER);
1508 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_GOT_ANSWER);
1509 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_NEGOTIATED);
1510 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
1511 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
1512 	/* User will be notified only after the actual hangup */
1513 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Hanging up PeerConnection because of a %s\n",
1514 		handle->handle_id, reason);
1515 	handle->hangup_reason = reason;
1516 	/* Let's message the loop, we'll notify the plugin from there */
1517 	if(handle->queued_packets != NULL) {
1518 #if GLIB_CHECK_VERSION(2, 46, 0)
1519 		g_async_queue_push_front(handle->queued_packets, &janus_ice_hangup_peerconnection);
1520 #else
1521 		g_async_queue_push(handle->queued_packets, &janus_ice_hangup_peerconnection);
1522 #endif
1523 		g_main_context_wakeup(handle->mainctx);
1524 	}
1525 }
1526 
janus_ice_webrtc_free(janus_ice_handle * handle)1527 static void janus_ice_webrtc_free(janus_ice_handle *handle) {
1528 	if(handle == NULL)
1529 		return;
1530 	janus_mutex_lock(&handle->mutex);
1531 	if(!handle->agent_created) {
1532 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_NEW_DATACHAN_SDP);
1533 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
1534 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
1535 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AGENT);
1536 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_E2EE);
1537 		janus_mutex_unlock(&handle->mutex);
1538 		return;
1539 	}
1540 	handle->agent_created = 0;
1541 	if(handle->stream != NULL) {
1542 		janus_ice_stream_destroy(handle->stream);
1543 		handle->stream = NULL;
1544 	}
1545 	if(handle->agent != NULL) {
1546 #ifdef HAVE_CLOSE_ASYNC
1547 		if(G_IS_OBJECT(handle->agent)) {
1548 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Removing stream %d from agent %p\n",
1549 				handle->handle_id, handle->stream_id, handle->agent);
1550 			nice_agent_remove_stream(handle->agent, handle->stream_id);
1551 			handle->stream_id = 0;
1552 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Closing nice agent %p\n", handle->handle_id, handle->agent);
1553 			janus_refcount_increase(&handle->ref);
1554 			if(handle->rtp_source != NULL) {
1555 				/* Destroy the agent asynchronously */
1556 				g_source_ref(handle->rtp_source);
1557 				nice_agent_close_async(handle->agent, janus_ice_cb_agent_closed, handle->rtp_source);
1558 			} else {
1559 				/* No traffic source, destroy it right away */
1560 				if(G_IS_OBJECT(handle->agent))
1561 					g_object_unref(handle->agent);
1562 				handle->agent = NULL;
1563 				janus_refcount_decrease(&handle->ref);
1564 			}
1565 		}
1566 #else
1567 		if(G_IS_OBJECT(handle->agent))
1568 			g_object_unref(handle->agent);
1569 		handle->agent = NULL;
1570 #endif
1571 	}
1572 	if(handle->pending_trickles) {
1573 		while(handle->pending_trickles) {
1574 			GList *temp = g_list_first(handle->pending_trickles);
1575 			handle->pending_trickles = g_list_remove_link(handle->pending_trickles, temp);
1576 			janus_ice_trickle *trickle = (janus_ice_trickle *)temp->data;
1577 			g_list_free(temp);
1578 			janus_ice_trickle_destroy(trickle);
1579 		}
1580 	}
1581 	handle->pending_trickles = NULL;
1582 	janus_ice_clear_queued_candidates(handle);
1583 	g_free(handle->rtp_profile);
1584 	handle->rtp_profile = NULL;
1585 	g_free(handle->local_sdp);
1586 	handle->local_sdp = NULL;
1587 	g_free(handle->remote_sdp);
1588 	handle->remote_sdp = NULL;
1589 	handle->stream_mid = NULL;
1590 	g_free(handle->audio_mid);
1591 	handle->audio_mid = NULL;
1592 	g_free(handle->video_mid);
1593 	handle->video_mid = NULL;
1594 	g_free(handle->data_mid);
1595 	handle->data_mid = NULL;
1596 	handle->thread = NULL;
1597 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_NEW_DATACHAN_SDP);
1598 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
1599 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
1600 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AGENT);
1601 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_E2EE);
1602 	if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP) && handle->hangup_reason) {
1603 		janus_ice_notify_hangup(handle, handle->hangup_reason);
1604 	}
1605 	handle->hangup_reason = NULL;
1606 	janus_mutex_unlock(&handle->mutex);
1607 	JANUS_LOG(LOG_INFO, "[%"SCNu64"] WebRTC resources freed; %p %p\n", handle->handle_id, handle, handle->session);
1608 }
1609 
janus_ice_stream_destroy(janus_ice_stream * stream)1610 void janus_ice_stream_destroy(janus_ice_stream *stream) {
1611 	if(stream == NULL)
1612 		return;
1613 	if(stream->component != NULL) {
1614 		janus_ice_component_destroy(stream->component);
1615 		stream->component = NULL;
1616 	}
1617 	if(stream->pending_nacked_cleanup && g_hash_table_size(stream->pending_nacked_cleanup) > 0) {
1618 		GHashTableIter iter;
1619 		gpointer val;
1620 		g_hash_table_iter_init(&iter, stream->pending_nacked_cleanup);
1621 		while(g_hash_table_iter_next(&iter, NULL, &val)) {
1622 			GSource *source = val;
1623 			g_source_destroy(source);
1624 		}
1625 		g_hash_table_destroy(stream->pending_nacked_cleanup);
1626 	}
1627 	stream->pending_nacked_cleanup = NULL;
1628 	janus_ice_handle *handle = stream->handle;
1629 	if(handle != NULL) {
1630 		janus_refcount_decrease(&handle->ref);
1631 		stream->handle = NULL;
1632 	}
1633 	janus_refcount_decrease(&stream->ref);
1634 }
1635 
janus_ice_stream_free(const janus_refcount * stream_ref)1636 static void janus_ice_stream_free(const janus_refcount *stream_ref) {
1637 	janus_ice_stream *stream = janus_refcount_containerof(stream_ref, janus_ice_stream, ref);
1638 	/* This stream can be destroyed, free all the resources */
1639 	stream->handle = NULL;
1640 	g_free(stream->remote_hashing);
1641 	stream->remote_hashing = NULL;
1642 	g_free(stream->remote_fingerprint);
1643 	stream->remote_fingerprint = NULL;
1644 	g_free(stream->ruser);
1645 	stream->ruser = NULL;
1646 	g_free(stream->rpass);
1647 	stream->rpass = NULL;
1648 	g_free(stream->rid[0]);
1649 	stream->rid[0] = NULL;
1650 	g_free(stream->rid[1]);
1651 	stream->rid[1] = NULL;
1652 	g_free(stream->rid[2]);
1653 	stream->rid[2] = NULL;
1654 	g_list_free(stream->audio_payload_types);
1655 	stream->audio_payload_types = NULL;
1656 	g_list_free(stream->video_payload_types);
1657 	stream->video_payload_types = NULL;
1658 	if(stream->rtx_payload_types != NULL)
1659 		g_hash_table_destroy(stream->rtx_payload_types);
1660 	stream->rtx_payload_types = NULL;
1661 	if(stream->clock_rates != NULL)
1662 		g_hash_table_destroy(stream->clock_rates);
1663 	stream->clock_rates = NULL;
1664 	g_free(stream->audio_codec);
1665 	stream->audio_codec = NULL;
1666 	g_free(stream->video_codec);
1667 	stream->video_codec = NULL;
1668 	g_free(stream->audio_rtcp_ctx);
1669 	stream->audio_rtcp_ctx = NULL;
1670 	g_free(stream->video_rtcp_ctx[0]);
1671 	stream->video_rtcp_ctx[0] = NULL;
1672 	g_free(stream->video_rtcp_ctx[1]);
1673 	stream->video_rtcp_ctx[1] = NULL;
1674 	g_free(stream->video_rtcp_ctx[2]);
1675 	stream->video_rtcp_ctx[2] = NULL;
1676 	if(stream->rtx_nacked[0])
1677 		g_hash_table_destroy(stream->rtx_nacked[0]);
1678 	stream->rtx_nacked[0] = NULL;
1679 	if(stream->rtx_nacked[1])
1680 		g_hash_table_destroy(stream->rtx_nacked[1]);
1681 	stream->rtx_nacked[1] = NULL;
1682 	if(stream->rtx_nacked[2])
1683 		g_hash_table_destroy(stream->rtx_nacked[2]);
1684 	stream->rtx_nacked[2] = NULL;
1685 	g_slist_free_full(stream->transport_wide_received_seq_nums, (GDestroyNotify)g_free);
1686 	stream->transport_wide_received_seq_nums = NULL;
1687 	stream->audio_first_ntp_ts = 0;
1688 	stream->audio_first_rtp_ts = 0;
1689 	stream->video_first_ntp_ts[0] = 0;
1690 	stream->video_first_ntp_ts[1] = 0;
1691 	stream->video_first_ntp_ts[2] = 0;
1692 	stream->video_first_rtp_ts[0] = 0;
1693 	stream->video_first_rtp_ts[1] = 0;
1694 	stream->video_first_rtp_ts[2] = 0;
1695 	stream->audio_last_rtp_ts = 0;
1696 	stream->audio_last_ntp_ts = 0;
1697 	stream->video_last_rtp_ts = 0;
1698 	stream->video_last_ntp_ts = 0;
1699 	g_free(stream);
1700 	stream = NULL;
1701 }
1702 
janus_ice_component_destroy(janus_ice_component * component)1703 void janus_ice_component_destroy(janus_ice_component *component) {
1704 	if(component == NULL)
1705 		return;
1706 	janus_ice_stream *stream = component->stream;
1707 	if(stream != NULL) {
1708 		janus_refcount_decrease(&stream->ref);
1709 		component->stream = NULL;
1710 	}
1711 	janus_dtls_srtp_destroy(component->dtls);
1712 	janus_refcount_decrease(&component->ref);
1713 }
1714 
janus_ice_component_free(const janus_refcount * component_ref)1715 static void janus_ice_component_free(const janus_refcount *component_ref) {
1716 	janus_ice_component *component = janus_refcount_containerof(component_ref, janus_ice_component, ref);
1717 	if(component->icestate_source != NULL) {
1718 		g_source_destroy(component->icestate_source);
1719 		g_source_unref(component->icestate_source);
1720 		component->icestate_source = NULL;
1721 	}
1722 	if(component->dtlsrt_source != NULL) {
1723 		g_source_destroy(component->dtlsrt_source);
1724 		g_source_unref(component->dtlsrt_source);
1725 		component->dtlsrt_source = NULL;
1726 	}
1727 	if(component->dtls != NULL) {
1728 		janus_dtls_srtp_destroy(component->dtls);
1729 		janus_refcount_decrease(&component->dtls->ref);
1730 		component->dtls = NULL;
1731 	}
1732 	if(component->audio_retransmit_buffer != NULL) {
1733 		janus_rtp_packet *p = NULL;
1734 		while((p = (janus_rtp_packet *)g_queue_pop_head(component->audio_retransmit_buffer)) != NULL) {
1735 			/* Remove from hashtable too */
1736 			janus_rtp_header *header = (janus_rtp_header *)p->data;
1737 			guint16 seq = ntohs(header->seq_number);
1738 			g_hash_table_remove(component->audio_retransmit_seqs, GUINT_TO_POINTER(seq));
1739 			/* Free the packet */
1740 			janus_ice_free_rtp_packet(p);
1741 		}
1742 		g_queue_free(component->audio_retransmit_buffer);
1743 		g_hash_table_destroy(component->audio_retransmit_seqs);
1744 	}
1745 	if(component->video_retransmit_buffer != NULL) {
1746 		janus_rtp_packet *p = NULL;
1747 		while((p = (janus_rtp_packet *)g_queue_pop_head(component->video_retransmit_buffer)) != NULL) {
1748 			/* Remove from hashtable too */
1749 			janus_rtp_header *header = (janus_rtp_header *)p->data;
1750 			guint16 seq = ntohs(header->seq_number);
1751 			g_hash_table_remove(component->video_retransmit_seqs, GUINT_TO_POINTER(seq));
1752 			/* Free the packet */
1753 			janus_ice_free_rtp_packet(p);
1754 		}
1755 		g_queue_free(component->video_retransmit_buffer);
1756 		g_hash_table_destroy(component->video_retransmit_seqs);
1757 	}
1758 	if(component->candidates != NULL) {
1759 		GSList *i = NULL, *candidates = component->candidates;
1760 		for(i = candidates; i; i = i->next) {
1761 			NiceCandidate *c = (NiceCandidate *) i->data;
1762 			if(c != NULL) {
1763 				nice_candidate_free(c);
1764 				c = NULL;
1765 			}
1766 		}
1767 		g_slist_free(candidates);
1768 		candidates = NULL;
1769 	}
1770 	component->candidates = NULL;
1771 	if(component->local_candidates != NULL) {
1772 		GSList *i = NULL, *candidates = component->local_candidates;
1773 		for(i = candidates; i; i = i->next) {
1774 			gchar *c = (gchar *) i->data;
1775 			g_free(c);
1776 		}
1777 		g_slist_free(candidates);
1778 		candidates = NULL;
1779 	}
1780 	component->local_candidates = NULL;
1781 	if(component->remote_candidates != NULL) {
1782 		GSList *i = NULL, *candidates = component->remote_candidates;
1783 		for(i = candidates; i; i = i->next) {
1784 			gchar *c = (gchar *) i->data;
1785 			g_free(c);
1786 		}
1787 		g_slist_free(candidates);
1788 		candidates = NULL;
1789 	}
1790 	component->remote_candidates = NULL;
1791 	g_free(component->selected_pair);
1792 	component->selected_pair = NULL;
1793 	if(component->last_seqs_audio)
1794 		janus_seq_list_free(&component->last_seqs_audio);
1795 	if(component->last_seqs_video[0])
1796 		janus_seq_list_free(&component->last_seqs_video[0]);
1797 	if(component->last_seqs_video[1])
1798 		janus_seq_list_free(&component->last_seqs_video[1]);
1799 	if(component->last_seqs_video[2])
1800 		janus_seq_list_free(&component->last_seqs_video[2]);
1801 	g_free(component);
1802 	//~ janus_mutex_unlock(&handle->mutex);
1803 }
1804 
1805 /* Call plugin slow_link callback if a minimum of lost packets are detected within a second */
1806 static void
janus_slow_link_update(janus_ice_component * component,janus_ice_handle * handle,gboolean video,gboolean uplink,guint lost)1807 janus_slow_link_update(janus_ice_component *component, janus_ice_handle *handle,
1808 		gboolean video, gboolean uplink, guint lost) {
1809 	/* We keep the counters in different janus_ice_stats objects, depending on the direction */
1810 	guint sl_lost_last_count = uplink ?
1811 		(video ? component->in_stats.sl_lost_count_video : component->in_stats.sl_lost_count_audio) :
1812 		(video ? component->out_stats.sl_lost_count_video : component->out_stats.sl_lost_count_audio);
1813 	guint sl_lost_recently = (lost >= sl_lost_last_count) ? (lost - sl_lost_last_count) : 0;
1814 	if(slowlink_threshold > 0 && sl_lost_recently >= slowlink_threshold) {
1815 		/* Tell the plugin */
1816 		janus_plugin *plugin = (janus_plugin *)handle->app;
1817 		if(plugin && plugin->slow_link && janus_plugin_session_is_alive(handle->app_handle) &&
1818 				!g_atomic_int_get(&handle->destroyed))
1819 			plugin->slow_link(handle->app_handle, uplink, video);
1820 		/* Notify the user/application too */
1821 		janus_session *session = (janus_session *)handle->session;
1822 		if(session != NULL) {
1823 			json_t *event = json_object();
1824 			json_object_set_new(event, "janus", json_string("slowlink"));
1825 			json_object_set_new(event, "session_id", json_integer(session->session_id));
1826 			json_object_set_new(event, "sender", json_integer(handle->handle_id));
1827 			if(opaqueid_in_api && handle->opaque_id != NULL)
1828 				json_object_set_new(event, "opaque_id", json_string(handle->opaque_id));
1829 			json_object_set_new(event, "media", json_string(video ? "video" : "audio"));
1830 			json_object_set_new(event, "uplink", uplink ? json_true() : json_false());
1831 			json_object_set_new(event, "lost", json_integer(sl_lost_recently));
1832 			/* Send the event */
1833 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...; %p\n", handle->handle_id, handle);
1834 			janus_session_notify_event(session, event);
1835 			/* Finally, notify event handlers */
1836 			if(janus_events_is_enabled()) {
1837 				json_t *info = json_object();
1838 				json_object_set_new(info, "media", json_string(video ? "video" : "audio"));
1839 				json_object_set_new(info, "slow_link", json_string(uplink ? "uplink" : "downlink"));
1840 				json_object_set_new(info, "lost_lastsec", json_integer(sl_lost_recently));
1841 				janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, JANUS_EVENT_SUBTYPE_MEDIA_SLOWLINK,
1842 					session->session_id, handle->handle_id, handle->opaque_id, info);
1843 			}
1844 		}
1845 	}
1846 	/* Update the counter */
1847 	if(uplink) {
1848 		if(video)
1849 			component->in_stats.sl_lost_count_video = lost;
1850 		else
1851 			component->in_stats.sl_lost_count_audio = lost;
1852 	} else {
1853 		if(video)
1854 			component->out_stats.sl_lost_count_video = lost;
1855 		else
1856 			component->out_stats.sl_lost_count_audio = lost;
1857 	}
1858 }
1859 
1860 
1861 /* ICE state check timer (needed to check if a failed really is definitive or if things can still improve) */
janus_ice_check_failed(gpointer data)1862 static gboolean janus_ice_check_failed(gpointer data) {
1863 	janus_ice_component *component = (janus_ice_component *)data;
1864 	if(component == NULL)
1865 		return FALSE;
1866 	janus_ice_stream *stream = component->stream;
1867 	if(!stream)
1868 		goto stoptimer;
1869 	janus_ice_handle *handle = stream->handle;
1870 	if(!handle)
1871 		goto stoptimer;
1872 	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP) ||
1873 			janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT))
1874 		goto stoptimer;
1875 	if(component->state == NICE_COMPONENT_STATE_CONNECTED || component->state == NICE_COMPONENT_STATE_READY) {
1876 		/* ICE succeeded in the meanwhile, get rid of this timer */
1877 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE succeeded, disabling ICE state check timer!\n", handle->handle_id);
1878 		goto stoptimer;
1879 	}
1880 	/* Still in the failed state, how much time passed since we first detected it? */
1881 	if(janus_get_monotonic_time() - component->icefailed_detected < 5*G_USEC_PER_SEC) {
1882 		/* Let's wait a little longer */
1883 		return TRUE;
1884 	}
1885 	/* If we got here it means the timer expired, and we should check if this is a failure */
1886 	gboolean trickle_recv = (!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE) || janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES));
1887 	gboolean answer_recv = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_GOT_ANSWER);
1888 	gboolean alert_set = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1889 	/* We may still be waiting for something... but we don't wait forever */
1890 	gboolean do_wait = TRUE;
1891 	if(janus_get_monotonic_time() - component->icefailed_detected >= 15*G_USEC_PER_SEC) {
1892 		do_wait = FALSE;
1893 	}
1894 	if(!do_wait || (handle && trickle_recv && answer_recv && !alert_set)) {
1895 		/* FIXME Should we really give up for what may be a failure in only one of the media? */
1896 		JANUS_LOG(LOG_ERR, "[%"SCNu64"] ICE failed for component %d in stream %d...\n",
1897 			handle->handle_id, component->component_id, stream->stream_id);
1898 		janus_ice_webrtc_hangup(handle, "ICE failed");
1899 		goto stoptimer;
1900 	}
1901 	/* Let's wait a little longer */
1902 	JANUS_LOG(LOG_WARN, "[%"SCNu64"] ICE failed for component %d in stream %d, but we're still waiting for some info so we don't care... (trickle %s, answer %s, alert %s)\n",
1903 		handle->handle_id, component->component_id, stream->stream_id,
1904 		trickle_recv ? "received" : "pending",
1905 		answer_recv ? "received" : "pending",
1906 		alert_set ? "set" : "not set");
1907 	return TRUE;
1908 
1909 stoptimer:
1910 	if(component->icestate_source != NULL) {
1911 		g_source_destroy(component->icestate_source);
1912 		g_source_unref(component->icestate_source);
1913 		component->icestate_source = NULL;
1914 	}
1915 	return FALSE;
1916 }
1917 
1918 /* Callbacks */
janus_ice_cb_candidate_gathering_done(NiceAgent * agent,guint stream_id,gpointer user_data)1919 static void janus_ice_cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer user_data) {
1920 	janus_ice_handle *handle = (janus_ice_handle *)user_data;
1921 	if(!handle)
1922 		return;
1923 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Gathering done for stream %d\n", handle->handle_id, stream_id);
1924 	handle->cdone++;
1925 	janus_ice_stream *stream = handle->stream;
1926 	if(!stream || stream->stream_id != stream_id) {
1927 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]  No stream %d??\n", handle->handle_id, stream_id);
1928 		return;
1929 	}
1930 	stream->cdone = 1;
1931 	/* If we're doing full-trickle, send an event to the user too */
1932 	if(janus_full_trickle_enabled) {
1933 		/* Send a "trickle" event with completed:true to the browser */
1934 		janus_ice_notify_trickle(handle, NULL);
1935 	}
1936 }
1937 
janus_ice_cb_component_state_changed(NiceAgent * agent,guint stream_id,guint component_id,guint state,gpointer ice)1938 static void janus_ice_cb_component_state_changed(NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer ice) {
1939 	janus_ice_handle *handle = (janus_ice_handle *)ice;
1940 	if(!handle)
1941 		return;
1942 	if(component_id > 1) {
1943 		/* State changed for a component we don't need anymore (rtcp-mux) */
1944 		return;
1945 	}
1946 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Component state changed for component %d in stream %d: %d (%s)\n",
1947 		handle->handle_id, component_id, stream_id, state, janus_get_ice_state_name(state));
1948 	janus_ice_stream *stream = handle->stream;
1949 	if(!stream || stream->stream_id != stream_id) {
1950 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
1951 		return;
1952 	}
1953 	janus_ice_component *component = stream->component;
1954 	if(!component || component->component_id != component_id) {
1955 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
1956 		return;
1957 	}
1958 	component->state = state;
1959 	/* Notify event handlers */
1960 	if(janus_events_is_enabled()) {
1961 		janus_session *session = (janus_session *)handle->session;
1962 		json_t *info = json_object();
1963 		json_object_set_new(info, "ice", json_string(janus_get_ice_state_name(state)));
1964 		json_object_set_new(info, "stream_id", json_integer(stream_id));
1965 		json_object_set_new(info, "component_id", json_integer(component_id));
1966 		janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, JANUS_EVENT_SUBTYPE_WEBRTC_ICE,
1967 			session->session_id, handle->handle_id, handle->opaque_id, info);
1968 	}
1969 	/* FIXME Even in case the state is 'connected', we wait for the 'new-selected-pair' callback to do anything */
1970 	if(state == NICE_COMPONENT_STATE_FAILED) {
1971 		/* Failed doesn't mean necessarily we need to give up: we may be trickling */
1972 		gboolean alert_set = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1973 		if(alert_set)
1974 			return;
1975 		gboolean trickle_recv = (!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE) || janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES));
1976 		gboolean answer_recv = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_GOT_ANSWER);
1977 		JANUS_LOG(LOG_WARN, "[%"SCNu64"] ICE failed for component %d in stream %d, but let's give it some time... (trickle %s, answer %s, alert %s)\n",
1978 			handle->handle_id, component_id, stream_id,
1979 			trickle_recv ? "received" : "pending",
1980 			answer_recv ? "received" : "pending",
1981 			alert_set ? "set" : "not set");
1982 		/* In case we haven't started a timer yet, let's do it now */
1983 		if(component->icestate_source == NULL && component->icefailed_detected == 0) {
1984 			component->icefailed_detected = janus_get_monotonic_time();
1985 			component->icestate_source = g_timeout_source_new(500);
1986 			g_source_set_callback(component->icestate_source, janus_ice_check_failed, component, NULL);
1987 			guint id = g_source_attach(component->icestate_source, handle->mainctx);
1988 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Creating ICE state check timer with ID %u\n", handle->handle_id, id);
1989 		}
1990 	}
1991 }
1992 
1993 #ifndef HAVE_LIBNICE_TCP
janus_ice_cb_new_selected_pair(NiceAgent * agent,guint stream_id,guint component_id,gchar * local,gchar * remote,gpointer ice)1994 static void janus_ice_cb_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, gchar *local, gchar *remote, gpointer ice) {
1995 #else
1996 static void janus_ice_cb_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, NiceCandidate *local, NiceCandidate *remote, gpointer ice) {
1997 #endif
1998 	janus_ice_handle *handle = (janus_ice_handle *)ice;
1999 	if(!handle)
2000 		return;
2001 	if(component_id > 1) {
2002 		/* New selected pair for a component we don't need anymore (rtcp-mux) */
2003 		return;
2004 	}
2005 #ifndef HAVE_LIBNICE_TCP
2006 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] New selected pair for component %d in stream %d: %s <-> %s\n", handle ? handle->handle_id : 0, component_id, stream_id, local, remote);
2007 #else
2008 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] New selected pair for component %d in stream %d: %s <-> %s\n", handle ? handle->handle_id : 0, component_id, stream_id, local->foundation, remote->foundation);
2009 #endif
2010 	janus_ice_stream *stream = handle->stream;
2011 	if(!stream || stream->stream_id != stream_id) {
2012 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
2013 		return;
2014 	}
2015 	janus_ice_component *component = stream->component;
2016 	if(!component || component->component_id != component_id) {
2017 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
2018 		return;
2019 	}
2020 	char sp[200];
2021 #ifndef HAVE_LIBNICE_TCP
2022 	g_snprintf(sp, 200, "%s <-> %s", local, remote);
2023 #else
2024 	gchar laddress[NICE_ADDRESS_STRING_LEN], raddress[NICE_ADDRESS_STRING_LEN];
2025 	gint lport = 0, rport = 0;
2026 	nice_address_to_string(&(local->addr), (gchar *)&laddress);
2027 	nice_address_to_string(&(remote->addr), (gchar *)&raddress);
2028 	lport = nice_address_get_port(&(local->addr));
2029 	rport = nice_address_get_port(&(remote->addr));
2030 	const char *ltype = NULL, *rtype = NULL;
2031 	switch(local->type) {
2032 		case NICE_CANDIDATE_TYPE_HOST:
2033 			ltype = "host";
2034 			break;
2035 		case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
2036 			ltype = "srflx";
2037 			break;
2038 		case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
2039 			ltype = "prflx";
2040 			break;
2041 		case NICE_CANDIDATE_TYPE_RELAYED:
2042 			ltype = "relay";
2043 			break;
2044 		default:
2045 			break;
2046 	}
2047 	switch(remote->type) {
2048 		case NICE_CANDIDATE_TYPE_HOST:
2049 			rtype = "host";
2050 			break;
2051 		case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
2052 			rtype = "srflx";
2053 			break;
2054 		case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
2055 			rtype = "prflx";
2056 			break;
2057 		case NICE_CANDIDATE_TYPE_RELAYED:
2058 			rtype = "relay";
2059 			break;
2060 		default:
2061 			break;
2062 	}
2063 	g_snprintf(sp, sizeof(sp), "%s:%d [%s,%s] <-> %s:%d [%s,%s]",
2064 		laddress, lport, ltype, local->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "udp" : "tcp",
2065 		raddress, rport, rtype, remote->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "udp" : "tcp");
2066 #endif
2067 	gboolean newpair = FALSE;
2068 	if(component->selected_pair == NULL || strcmp(sp, component->selected_pair)) {
2069 		newpair = TRUE;
2070 		gchar *prev_selected_pair = component->selected_pair;
2071 		component->selected_pair = g_strdup(sp);
2072 		g_clear_pointer(&prev_selected_pair, g_free);
2073 	}
2074 	/* Notify event handlers */
2075 	if(newpair && janus_events_is_enabled()) {
2076 		janus_session *session = (janus_session *)handle->session;
2077 		json_t *info = json_object();
2078 		json_object_set_new(info, "selected-pair", json_string(sp));
2079 #ifdef HAVE_LIBNICE_TCP
2080 		json_t *candidates = json_object();
2081 		json_t *lcand = json_object();
2082 		json_object_set_new(lcand, "address", json_string(laddress));
2083 		json_object_set_new(lcand, "port", json_integer(lport));
2084 		json_object_set_new(lcand, "type", json_string(ltype));
2085 		json_object_set_new(lcand, "transport", json_string(local->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "udp" : "tcp"));
2086 		json_object_set_new(lcand, "family", json_integer(nice_address_ip_version(&local->addr)));
2087 		json_object_set_new(candidates, "local", lcand);
2088 		json_t *rcand = json_object();
2089 		json_object_set_new(rcand, "address", json_string(raddress));
2090 		json_object_set_new(rcand, "port", json_integer(rport));
2091 		json_object_set_new(rcand, "type", json_string(rtype));
2092 		json_object_set_new(rcand, "transport", json_string(remote->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "udp" : "tcp"));
2093 		json_object_set_new(rcand, "family", json_integer(nice_address_ip_version(&remote->addr)));
2094 		json_object_set_new(candidates, "remote", rcand);
2095 		json_object_set_new(info, "candidates", candidates);
2096 #endif
2097 		json_object_set_new(info, "stream_id", json_integer(stream_id));
2098 		json_object_set_new(info, "component_id", json_integer(component_id));
2099 		janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, JANUS_EVENT_SUBTYPE_WEBRTC_PAIR,
2100 			session->session_id, handle->handle_id, handle->opaque_id, info);
2101 	}
2102 	/* Have we been here before? (might happen, when trickling) */
2103 	if(component->component_connected > 0)
2104 		return;
2105 	/* FIXME Clear the queue */
2106 	janus_ice_clear_queued_packets(handle);
2107 	/* Now we can start the DTLS handshake (FIXME This was on the 'connected' state notification, before) */
2108 	JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Component is ready enough, starting DTLS handshake...\n", handle->handle_id);
2109 	component->component_connected = janus_get_monotonic_time();
2110 	/* Start the DTLS handshake, at last */
2111 #if GLIB_CHECK_VERSION(2, 46, 0)
2112 	g_async_queue_push_front(handle->queued_packets, &janus_ice_dtls_handshake);
2113 #else
2114 	g_async_queue_push(handle->queued_packets, &janus_ice_dtls_handshake);
2115 #endif
2116 	g_main_context_wakeup(handle->mainctx);
2117 }
2118 
2119 /* Candidates management */
2120 static int janus_ice_candidate_to_string(janus_ice_handle *handle, NiceCandidate *c, char *buffer, int buflen, gboolean log_candidate, gboolean force_private, guint public_ip_index);
2121 #ifndef HAVE_LIBNICE_TCP
2122 static void janus_ice_cb_new_local_candidate (NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation, gpointer ice) {
2123 #else
2124 static void janus_ice_cb_new_local_candidate (NiceAgent *agent, NiceCandidate *candidate, gpointer ice) {
2125 #endif
2126 	if(!janus_full_trickle_enabled) {
2127 		/* Ignore if we're not full-trickling: for half-trickle
2128 		 * janus_ice_candidates_to_sdp() is used instead */
2129 		return;
2130 	}
2131 	janus_ice_handle *handle = (janus_ice_handle *)ice;
2132 	if(!handle)
2133 		return;
2134 #ifndef HAVE_LIBNICE_TCP
2135 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Discovered new local candidate for component %d in stream %d: foundation=%s\n", handle ? handle->handle_id : 0, component_id, stream_id, foundation);
2136 #else
2137 	const char *ctype = NULL;
2138 	switch(candidate->type) {
2139 		case NICE_CANDIDATE_TYPE_HOST:
2140 			ctype = "host";
2141 			break;
2142 		case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
2143 			ctype = "srflx";
2144 			break;
2145 		case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
2146 			ctype = "prflx";
2147 			break;
2148 		case NICE_CANDIDATE_TYPE_RELAYED:
2149 			ctype = "relay";
2150 			break;
2151 		default:
2152 			break;
2153 	}
2154 	guint stream_id = candidate->stream_id;
2155 	guint component_id = candidate->component_id;
2156 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Discovered new local candidate for component %d in stream %d: type=%s\n", handle ? handle->handle_id : 0, component_id, stream_id, ctype);
2157 #endif
2158 	if(component_id > 1) {
2159 		/* New remote candidate for a component we don't need anymore (rtcp-mux) */
2160 		return;
2161 	}
2162 	janus_ice_stream *stream = handle->stream;
2163 	if(!stream || stream->stream_id != stream_id) {
2164 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
2165 		return;
2166 	}
2167 	janus_ice_component *component = stream->component;
2168 	if(!component || component->component_id != component_id) {
2169 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
2170 		return;
2171 	}
2172 #ifndef HAVE_LIBNICE_TCP
2173 	/* Get local candidates and look for the related foundation */
2174 	NiceCandidate *candidate = NULL;
2175 	GSList *candidates = nice_agent_get_local_candidates(agent, component_id, stream_id), *tmp = candidates;
2176 	while(tmp) {
2177 		NiceCandidate *c = (NiceCandidate *)tmp->data;
2178 		/* Check if this is what we're looking for */
2179 		if(!candidate && !strcasecmp(c->foundation, foundation)) {
2180 			/* It is! */
2181 			candidate = c;
2182 		} else {
2183 			nice_candidate_free(c);
2184 		}
2185 		tmp = tmp->next;
2186 	}
2187 	g_slist_free(candidates);
2188 	if(candidate == NULL) {
2189 		JANUS_LOG(LOG_WARN, "Candidate with foundation %s not found?\n", foundation);
2190 		return;
2191 	}
2192 #endif
2193 	char buffer[200];
2194 	guint public_ip_index = 0;
2195 	gboolean ipv6 = (nice_address_ip_version(&candidate->addr) == 6);
2196 	gboolean same_family = (!ipv6 && janus_has_public_ipv4_ip()) || (ipv6 && janus_has_public_ipv6_ip());
2197 	do {
2198 		if(janus_ice_candidate_to_string(handle, candidate, buffer, sizeof(buffer), TRUE, FALSE, public_ip_index) == 0) {
2199 			/* Candidate encoded, send a "trickle" event to the browser (but only if it's not a 'prflx') */
2200 			if(candidate->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
2201 				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping prflx candidate...\n", handle->handle_id);
2202 			} else {
2203 				if(strlen(buffer) > 0)
2204 					janus_ice_notify_trickle(handle, buffer);
2205 				/* If nat-1-1 is enabled but we want to keep the private host, add another candidate */
2206 				if(nat_1_1_enabled && public_ip_index == 0 && (keep_private_host || !same_family) &&
2207 						janus_ice_candidate_to_string(handle, candidate, buffer, sizeof(buffer), TRUE, TRUE, public_ip_index) == 0) {
2208 					if(candidate->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
2209 						JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping prflx candidate...\n", handle->handle_id);
2210 					} else if(strlen(buffer) > 0) {
2211 						janus_ice_notify_trickle(handle, buffer);
2212 					}
2213 				}
2214 			}
2215 		}
2216 		public_ip_index++;
2217 		if(!same_family) {
2218 			/* We don't have any nat-1-1 address of the same family as this candidate, we're done */
2219 			break;
2220 		}
2221 	} while (public_ip_index < janus_get_public_ip_count());
2222 
2223 #ifndef HAVE_LIBNICE_TCP
2224 	nice_candidate_free(candidate);
2225 #endif
2226 }
2227 
2228 #ifndef HAVE_LIBNICE_TCP
2229 static void janus_ice_cb_new_remote_candidate (NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation, gpointer ice) {
2230 #else
2231 static void janus_ice_cb_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate, gpointer ice) {
2232 #endif
2233 	janus_ice_handle *handle = (janus_ice_handle *)ice;
2234 	if(!handle)
2235 		return;
2236 #ifndef HAVE_LIBNICE_TCP
2237 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Discovered new remote candidate for component %d in stream %d: foundation=%s\n", handle ? handle->handle_id : 0, component_id, stream_id, foundation);
2238 #else
2239 	const char *ctype = NULL;
2240 	switch(candidate->type) {
2241 		case NICE_CANDIDATE_TYPE_HOST:
2242 			ctype = "host";
2243 			break;
2244 		case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
2245 			ctype = "srflx";
2246 			break;
2247 		case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
2248 			ctype = "prflx";
2249 			break;
2250 		case NICE_CANDIDATE_TYPE_RELAYED:
2251 			ctype = "relay";
2252 			break;
2253 		default:
2254 			break;
2255 	}
2256 	guint stream_id = candidate->stream_id;
2257 	guint component_id = candidate->component_id;
2258 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Discovered new remote candidate for component %d in stream %d: type=%s\n", handle ? handle->handle_id : 0, component_id, stream_id, ctype);
2259 #endif
2260 	if(component_id > 1) {
2261 		/* New remote candidate for a component we don't need anymore (rtcp-mux) */
2262 		return;
2263 	}
2264 	janus_ice_stream *stream = handle->stream;
2265 	if(!stream || stream->stream_id != stream_id) {
2266 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
2267 		return;
2268 	}
2269 	janus_ice_component *component = stream->component;
2270 	if(!component || component->component_id != component_id) {
2271 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
2272 		return;
2273 	}
2274 #ifndef HAVE_LIBNICE_TCP
2275 	/* Get remote candidates and look for the related foundation */
2276 	NiceCandidate *candidate = NULL;
2277 	GSList *candidates = nice_agent_get_remote_candidates(agent, component_id, stream_id), *tmp = candidates;
2278 	while(tmp) {
2279 		NiceCandidate *c = (NiceCandidate *)tmp->data;
2280 		if(candidate == NULL) {
2281 			/* Check if this is what we're looking for */
2282 			if(!strcasecmp(c->foundation, foundation)) {
2283 				/* It is! */
2284 				candidate = c;
2285 				tmp = tmp->next;
2286 				continue;
2287 			}
2288 		}
2289 		nice_candidate_free(c);
2290 		tmp = tmp->next;
2291 	}
2292 	g_slist_free(candidates);
2293 	if(candidate == NULL) {
2294 		JANUS_LOG(LOG_WARN, "Candidate with foundation %s not found?\n", foundation);
2295 		return;
2296 	}
2297 #endif
2298 	/* Render the candidate and add it to the remote_candidates cache for the admin API */
2299 	if(candidate->type != NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
2300 		/* ... but only if it's 'prflx', the others we add ourselves */
2301 		goto candidatedone;
2302 	}
2303 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream #%d, Component #%d\n", handle->handle_id, candidate->stream_id, candidate->component_id);
2304 	gchar address[NICE_ADDRESS_STRING_LEN], base_address[NICE_ADDRESS_STRING_LEN];
2305 	gint port = 0, base_port = 0;
2306 	nice_address_to_string(&(candidate->addr), (gchar *)&address);
2307 	port = nice_address_get_port(&(candidate->addr));
2308 	nice_address_to_string(&(candidate->base_addr), (gchar *)&base_address);
2309 	base_port = nice_address_get_port(&(candidate->base_addr));
2310 	JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Address:    %s:%d\n", handle->handle_id, address, port);
2311 	JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Priority:   %d\n", handle->handle_id, candidate->priority);
2312 	JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Foundation: %s\n", handle->handle_id, candidate->foundation);
2313 	char buffer[200];
2314 	if(candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
2315 		g_snprintf(buffer, sizeof(buffer),
2316 			"%s %d %s %d %s %d typ prflx raddr %s rport %d\r\n",
2317 				candidate->foundation,
2318 				candidate->component_id,
2319 				"udp",
2320 				candidate->priority,
2321 				address,
2322 				port,
2323 				base_address,
2324 				base_port);
2325 	} else {
2326 		if(!janus_ice_tcp_enabled) {
2327 			/* ICETCP support disabled */
2328 			JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping prflx TCP candidate, ICETCP support disabled...\n", handle->handle_id);
2329 			goto candidatedone;
2330 		}
2331 #ifndef HAVE_LIBNICE_TCP
2332 		/* TCP candidates are only supported since libnice 0.1.8 */
2333 		JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping prflx TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
2334 			goto candidatedone;
2335 #else
2336 		const char *type = NULL;
2337 		switch(candidate->transport) {
2338 			case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2339 				type = "active";
2340 				break;
2341 			case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2342 				type = "passive";
2343 				break;
2344 			case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2345 				type = "so";
2346 				break;
2347 			default:
2348 				break;
2349 		}
2350 		if(type == NULL) {
2351 			/* FIXME Unsupported transport */
2352 			JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping nonUDP/TCP prflx candidate...\n", handle->handle_id);
2353 			goto candidatedone;
2354 		} else {
2355 			g_snprintf(buffer, sizeof(buffer),
2356 				"%s %d %s %d %s %d typ prflx raddr %s rport %d tcptype %s\r\n",
2357 					candidate->foundation,
2358 					candidate->component_id,
2359 					"tcp",
2360 					candidate->priority,
2361 					address,
2362 					port,
2363 					base_address,
2364 					base_port,
2365 					type);
2366 		}
2367 #endif
2368 	}
2369 
2370 	/* Now parse the candidate as if we received it from the Janus API */
2371 	int res = janus_sdp_parse_candidate(stream, buffer, 1);
2372 	if(res != 0) {
2373 		JANUS_LOG(LOG_ERR, "[%"SCNu64"] Failed to parse prflx candidate... (%d)\n", handle->handle_id, res);
2374 	}
2375 
2376 candidatedone:
2377 #ifndef HAVE_LIBNICE_TCP
2378 	nice_candidate_free(candidate);
2379 #endif
2380 	return;
2381 }
2382 
2383 static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer ice) {
2384 	janus_ice_component *component = (janus_ice_component *)ice;
2385 	if(!component) {
2386 		JANUS_LOG(LOG_ERR, "No component %d in stream %d??\n", component_id, stream_id);
2387 		return;
2388 	}
2389 	janus_ice_stream *stream = component->stream;
2390 	if(!stream) {
2391 		JANUS_LOG(LOG_ERR, "No stream %d??\n", stream_id);
2392 		return;
2393 	}
2394 	janus_ice_handle *handle = stream->handle;
2395 	if(!handle) {
2396 		JANUS_LOG(LOG_ERR, "No handle for stream %d??\n", stream_id);
2397 		return;
2398 	}
2399 	janus_session *session = (janus_session *)handle->session;
2400 	if(!component->dtls) {	/* Still waiting for the DTLS stack */
2401 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Still waiting for the DTLS stack for component %d in stream %d...\n", handle->handle_id, component_id, stream_id);
2402 		return;
2403 	}
2404 	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP) || janus_is_stopping()) {
2405 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Forced to stop it here...\n", handle->handle_id);
2406 		return;
2407 	}
2408 	/* What is this? */
2409 	if(janus_is_dtls(buf) || (!janus_is_rtp(buf, len) && !janus_is_rtcp(buf, len))) {
2410 		/* This is DTLS: either handshake stuff, or data coming from SCTP DataChannels */
2411 		JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Looks like DTLS!\n", handle->handle_id);
2412 		janus_dtls_srtp_incoming_msg(component->dtls, buf, len);
2413 		/* Update stats (TODO Do the same for the last second window as well) */
2414 		component->in_stats.data.packets++;
2415 		component->in_stats.data.bytes += len;
2416 		return;
2417 	}
2418 	/* Not DTLS... RTP or RTCP? (http://tools.ietf.org/html/rfc5761#section-4) */
2419 	if(janus_is_rtp(buf, len)) {
2420 		/* This is RTP */
2421 		if(janus_is_webrtc_encryption_enabled() && (!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_in)) {
2422 			JANUS_LOG(LOG_WARN, "[%"SCNu64"]     Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
2423 		} else {
2424 			janus_rtp_header *header = (janus_rtp_header *)buf;
2425 			guint32 packet_ssrc = ntohl(header->ssrc);
2426 			/* Is this audio or video? */
2427 			int video = 0, vindex = 0, rtx = 0;
2428 			/* Bundled streams, check SSRC */
2429 			video = ((stream->video_ssrc_peer[0] == packet_ssrc
2430 				|| stream->video_ssrc_peer_rtx[0] == packet_ssrc
2431 				|| stream->video_ssrc_peer[1] == packet_ssrc
2432 				|| stream->video_ssrc_peer_rtx[1] == packet_ssrc
2433 				|| stream->video_ssrc_peer[2] == packet_ssrc
2434 				|| stream->video_ssrc_peer_rtx[2] == packet_ssrc) ? 1 : 0);
2435 			if(!video && stream->audio_ssrc_peer != packet_ssrc) {
2436 				/* Apparently we were not told the peer SSRCs, try the RTP mid extension (or payload types) */
2437 				gboolean found = FALSE;
2438 				if(handle->stream->mid_ext_id > 0) {
2439 					char sdes_item[16];
2440 					if(janus_rtp_header_extension_parse_mid(buf, len, handle->stream->mid_ext_id, sdes_item, sizeof(sdes_item)) == 0) {
2441 						if(handle->audio_mid && !strcmp(handle->audio_mid, sdes_item)) {
2442 							/* It's audio */
2443 							JANUS_LOG(LOG_VERB, "[%"SCNu64"] Unadvertized SSRC (%"SCNu32") is audio! (mid %s)\n", handle->handle_id, packet_ssrc, sdes_item);
2444 							video = 0;
2445 							stream->audio_ssrc_peer = packet_ssrc;
2446 							found = TRUE;
2447 						} else if(handle->video_mid && !strcmp(handle->video_mid, sdes_item)) {
2448 							/* It's video */
2449 							JANUS_LOG(LOG_VERB, "[%"SCNu64"] Unadvertized SSRC (%"SCNu32") is video! (mid %s)\n", handle->handle_id, packet_ssrc, sdes_item);
2450 							video = 1;
2451 							/* Check if simulcasting is involved */
2452 							if(stream->rid[0] == NULL || stream->rid_ext_id < 1) {
2453 								stream->video_ssrc_peer[0] = packet_ssrc;
2454 								found = TRUE;
2455 							} else {
2456 								if(janus_rtp_header_extension_parse_rid(buf, len, stream->rid_ext_id, sdes_item, sizeof(sdes_item)) == 0) {
2457 									/* Try the RTP stream ID */
2458 									if(stream->rid[0] != NULL && !strcmp(stream->rid[0], sdes_item)) {
2459 										JANUS_LOG(LOG_VERB, "[%"SCNu64"]  -- Simulcasting: rid=%s\n", handle->handle_id, sdes_item);
2460 										stream->video_ssrc_peer[0] = packet_ssrc;
2461 										vindex = 0;
2462 										found = TRUE;
2463 									} else if(stream->rid[1] != NULL && !strcmp(stream->rid[1], sdes_item)) {
2464 										JANUS_LOG(LOG_VERB, "[%"SCNu64"]  -- Simulcasting #1: rid=%s\n", handle->handle_id, sdes_item);
2465 										stream->video_ssrc_peer[1] = packet_ssrc;
2466 										vindex = 1;
2467 										found = TRUE;
2468 									} else if(stream->rid[2] != NULL && !strcmp(stream->rid[2], sdes_item)) {
2469 										JANUS_LOG(LOG_VERB, "[%"SCNu64"]  -- Simulcasting #2: rid=%s\n", handle->handle_id, sdes_item);
2470 										stream->video_ssrc_peer[2] = packet_ssrc;
2471 										vindex = 2;
2472 										found = TRUE;
2473 									} else {
2474 										JANUS_LOG(LOG_WARN, "[%"SCNu64"]  -- Simulcasting: unknown rid %s..?\n", handle->handle_id, sdes_item);
2475 									}
2476 								} else if(stream->ridrtx_ext_id > 0 &&
2477 										janus_rtp_header_extension_parse_rid(buf, len, stream->ridrtx_ext_id, sdes_item, sizeof(sdes_item)) == 0) {
2478 									/* Try the repaired RTP stream ID */
2479 									if(stream->rid[0] != NULL && !strcmp(stream->rid[0], sdes_item)) {
2480 										JANUS_LOG(LOG_VERB, "[%"SCNu64"]  -- Simulcasting: rid=%s (rtx)\n", handle->handle_id, sdes_item);
2481 										stream->video_ssrc_peer_rtx[0] = packet_ssrc;
2482 										vindex = 0;
2483 										rtx = 1;
2484 										found = TRUE;
2485 									} else if(stream->rid[1] != NULL && !strcmp(stream->rid[1], sdes_item)) {
2486 										JANUS_LOG(LOG_VERB, "[%"SCNu64"]  -- Simulcasting #1: rid=%s (rtx)\n", handle->handle_id, sdes_item);
2487 										stream->video_ssrc_peer_rtx[1] = packet_ssrc;
2488 										vindex = 1;
2489 										rtx = 1;
2490 										found = TRUE;
2491 									} else if(stream->rid[2] != NULL && !strcmp(stream->rid[2], sdes_item)) {
2492 										JANUS_LOG(LOG_VERB, "[%"SCNu64"]  -- Simulcasting #2: rid=%s (rtx)\n", handle->handle_id, sdes_item);
2493 										stream->video_ssrc_peer_rtx[2] = packet_ssrc;
2494 										vindex = 2;
2495 										rtx = 1;
2496 										found = TRUE;
2497 									} else {
2498 										JANUS_LOG(LOG_WARN, "[%"SCNu64"]  -- Simulcasting: unknown rid %s..?\n", handle->handle_id, sdes_item);
2499 									}
2500 								}
2501 							}
2502 						}
2503 					}
2504 				}
2505 				if(!found) {
2506 					JANUS_LOG(LOG_WARN, "[%"SCNu64"] Not video and not audio? dropping (SSRC %"SCNu32")...\n", handle->handle_id, packet_ssrc);
2507 					return;
2508 				}
2509 			}
2510 			/* Make sure we're prepared to receive this media packet */
2511 			if((!video && !stream->audio_recv) || (video && !stream->video_recv))
2512 				return;
2513 			/* If this is video, check if this is simulcast and/or a retransmission using RFC4588 */
2514 			if(video) {
2515 				if(stream->video_ssrc_peer[1] == packet_ssrc) {
2516 					/* FIXME Simulcast (1) */
2517 					JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Simulcast #1 (SSRC %"SCNu32")...\n", handle->handle_id, packet_ssrc);
2518 					vindex = 1;
2519 				} else if(stream->video_ssrc_peer[2] == packet_ssrc) {
2520 					/* FIXME Simulcast (2) */
2521 					JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Simulcast #2 (SSRC %"SCNu32")...\n", handle->handle_id, packet_ssrc);
2522 					vindex = 2;
2523 				} else {
2524 					/* Maybe a video retransmission using RFC4588? */
2525 					if(stream->video_ssrc_peer_rtx[0] == packet_ssrc) {
2526 						rtx = 1;
2527 						vindex = 0;
2528 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] RFC4588 rtx packet on video (SSRC %"SCNu32")...\n",
2529 							handle->handle_id, packet_ssrc);
2530 					} else if(stream->video_ssrc_peer_rtx[1] == packet_ssrc) {
2531 						rtx = 1;
2532 						vindex = 1;
2533 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] RFC4588 rtx packet on video #%d (SSRC %"SCNu32")...\n",
2534 							handle->handle_id, vindex, packet_ssrc);
2535 					} else if(stream->video_ssrc_peer_rtx[2] == packet_ssrc) {
2536 						rtx = 1;
2537 						vindex = 2;
2538 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] RFC4588 rtx packet on video #%d (SSRC %"SCNu32")...\n",
2539 							handle->handle_id, vindex, packet_ssrc);
2540 					}
2541 				}
2542 			}
2543 
2544 			int buflen = len;
2545 			srtp_err_status_t res = janus_is_webrtc_encryption_enabled() ?
2546 				srtp_unprotect(component->dtls->srtp_in, buf, &buflen) : srtp_err_status_ok;
2547 			if(res != srtp_err_status_ok) {
2548 				if(res != srtp_err_status_replay_fail && res != srtp_err_status_replay_old) {
2549 					/* Only print the error if it's not a 'replay fail' or 'replay old' (which is probably just the result of us NACKing a packet) */
2550 					guint32 timestamp = ntohl(header->timestamp);
2551 					guint16 seq = ntohs(header->seq_number);
2552 					JANUS_LOG(LOG_ERR, "[%"SCNu64"]     SRTP unprotect error: %s (len=%d-->%d, ts=%"SCNu32", seq=%"SCNu16")\n", handle->handle_id, janus_srtp_error_str(res), len, buflen, timestamp, seq);
2553 				}
2554 			} else {
2555 				if(video) {
2556 					if(stream->video_ssrc_peer[0] == 0) {
2557 						stream->video_ssrc_peer[0] = ntohl(header->ssrc);
2558 						JANUS_LOG(LOG_VERB, "[%"SCNu64"]     Peer video SSRC: %u\n", handle->handle_id, stream->video_ssrc_peer[0]);
2559 					}
2560 				} else {
2561 					if(stream->audio_ssrc_peer == 0) {
2562 						stream->audio_ssrc_peer = ntohl(header->ssrc);
2563 						JANUS_LOG(LOG_VERB, "[%"SCNu64"]     Peer audio SSRC: %u\n", handle->handle_id, stream->audio_ssrc_peer);
2564 					}
2565 				}
2566 				/* Do we need to dump this packet for debugging? */
2567 				if(g_atomic_int_get(&handle->dump_packets))
2568 					janus_text2pcap_dump(handle->text2pcap, JANUS_TEXT2PCAP_RTP, TRUE, buf, buflen,
2569 						"[session=%"SCNu64"][handle=%"SCNu64"]", session->session_id, handle->handle_id);
2570 				/* If this is a retransmission using RFC4588, we have to do something first to get the original packet */
2571 				janus_rtp_header *header = (janus_rtp_header *)buf;
2572 				int plen = 0;
2573 				char *payload = janus_rtp_payload(buf, buflen, &plen);
2574 				if (!payload) {
2575 					  JANUS_LOG(LOG_ERR, "[%"SCNu64"]     Error accessing the RTP payload len=%d\n", handle->handle_id, buflen);
2576 				}
2577 				if(rtx) {
2578 					/* The original sequence number is in the first two bytes of the payload */
2579 					/* Rewrite the header with the info from the original packet (payload type, SSRC, sequence number) */
2580 					header->type = stream->video_payload_type;
2581 					packet_ssrc = stream->video_ssrc_peer[vindex];
2582 					header->ssrc = htonl(packet_ssrc);
2583 					if(plen > 0) {
2584 						memcpy(&header->seq_number, payload, 2);
2585 						/* Finally, remove the original sequence number from the payload: move the whole
2586 						 * payload back two bytes rather than shifting the header forward (avoid misaligned access) */
2587 						buflen -= 2;
2588 						plen -= 2;
2589 						memmove(payload, payload+2, plen);
2590 						header = (janus_rtp_header *)buf;
2591 						if(stream->rid_ext_id > 1 && stream->ridrtx_ext_id > 1) {
2592 							/* Replace the 'repaired' extension ID as well with the 'regular' one */
2593 							janus_rtp_header_extension_replace_id(buf, buflen, stream->ridrtx_ext_id, stream->rid_ext_id);
2594 						}
2595 					}
2596 				}
2597 				/* Check if we need to handle transport wide cc */
2598 				if(stream->do_transport_wide_cc) {
2599 					guint16 transport_seq_num;
2600 					/* Get transport wide seq num */
2601 					if(janus_rtp_header_extension_parse_transport_wide_cc(buf, buflen, stream->transport_wide_cc_ext_id, &transport_seq_num)==0) {
2602 						/* Get current timestamp */
2603 						struct timeval now;
2604 						gettimeofday(&now,0);
2605 						/* Create <seq num, time> pair */
2606 						janus_rtcp_transport_wide_cc_stats *stats = g_malloc0(sizeof(janus_rtcp_transport_wide_cc_stats));
2607 						/* Check if we have a sequence wrap */
2608 						if(transport_seq_num<0x0FFF && (stream->transport_wide_cc_last_seq_num&0xFFFF)>0xF000) {
2609 							/* Increase cycles */
2610 							stream->transport_wide_cc_cycles++;
2611 						}
2612 						/* Get extended value */
2613 						guint32 transport_ext_seq_num = stream->transport_wide_cc_cycles<<16 | transport_seq_num;
2614 						/* Store last received transport seq num */
2615 						stream->transport_wide_cc_last_seq_num = transport_seq_num;
2616 						/* Set stats values */
2617 						stats->transport_seq_num = transport_ext_seq_num;
2618 						stats->timestamp = (((guint64)now.tv_sec)*1E6+now.tv_usec);
2619 						/* Lock and append to received list */
2620 						janus_mutex_lock(&stream->mutex);
2621 						stream->transport_wide_received_seq_nums = g_slist_prepend(stream->transport_wide_received_seq_nums, stats);
2622 						janus_mutex_unlock(&stream->mutex);
2623 					}
2624 				}
2625 				if(video) {
2626 					/* Check if this packet is a duplicate: can happen with RFC4588 */
2627 					guint16 seqno = ntohs(header->seq_number);
2628 					int nstate = stream->rtx_nacked[vindex] ?
2629 						GPOINTER_TO_INT(g_hash_table_lookup(stream->rtx_nacked[vindex], GUINT_TO_POINTER(seqno))) : 0;
2630 					if(nstate == 1) {
2631 						/* Packet was NACKed and this is the first time we receive it: change state to received */
2632 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Received NACKed packet %"SCNu16" (SSRC %"SCNu32", vindex %d)...\n",
2633 							handle->handle_id, seqno, packet_ssrc, vindex);
2634 						g_hash_table_insert(stream->rtx_nacked[vindex], GUINT_TO_POINTER(seqno), GUINT_TO_POINTER(2));
2635 					} else if(nstate == 2) {
2636 						/* We already received this packet: drop it */
2637 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Detected duplicate packet %"SCNu16" (SSRC %"SCNu32", vindex %d)...\n",
2638 							handle->handle_id, seqno, packet_ssrc, vindex);
2639 						return;
2640 					} else if(rtx && nstate == 0) {
2641 						/* We received a retransmission for a packet we didn't NACK: drop it
2642 						 * FIXME This seems to happen with Chrome when RFC4588 is enabled: in that case,
2643 						 * Chrome sends the first packet ~8 times as a retransmission, probably to ensure
2644 						 * we receive it, since the first packet cannot be NACKed (NACKs are triggered
2645 						 * when there's a gap in between two packets, and the first doesn't have a reference)
2646 						 * Rather than dropping, we should add a better check in the future */
2647 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Got a retransmission for non-NACKed packet %"SCNu16" (SSRC %"SCNu32", vindex %d)...\n",
2648 							handle->handle_id, seqno, packet_ssrc, vindex);
2649 						return;
2650 					}
2651 				}
2652 				/* Backup the RTP header before passing it to the proper RTP switching context */
2653 				janus_rtp_header backup = *header;
2654 				if(!video) {
2655 					if(stream->audio_ssrc_peer_orig == 0)
2656 						stream->audio_ssrc_peer_orig = packet_ssrc;
2657 					janus_rtp_header_update(header, &stream->rtp_ctx[0], FALSE, 0);
2658 					header->ssrc = htonl(stream->audio_ssrc_peer_orig);
2659 				} else {
2660 					if(stream->video_ssrc_peer_orig[vindex] == 0)
2661 						stream->video_ssrc_peer_orig[vindex] = packet_ssrc;
2662 					janus_rtp_header_update(header, &stream->rtp_ctx[vindex], TRUE, 0);
2663 					header->ssrc = htonl(stream->video_ssrc_peer_orig[vindex]);
2664 				}
2665 				/* Keep track of payload types too */
2666 				if(!video && stream->audio_payload_type < 0) {
2667 					stream->audio_payload_type = header->type;
2668 					if(stream->audio_codec == NULL) {
2669 						const char *codec = janus_get_codec_from_pt(handle->local_sdp, stream->audio_payload_type);
2670 						if(codec != NULL)
2671 							stream->audio_codec = g_strdup(codec);
2672 					}
2673 				} else if(video && stream->video_payload_type < 0) {
2674 					stream->video_payload_type = header->type;
2675 					if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX) &&
2676 							stream->rtx_payload_types && g_hash_table_size(stream->rtx_payload_types) > 0) {
2677 						stream->video_rtx_payload_type = GPOINTER_TO_INT(g_hash_table_lookup(stream->rtx_payload_types, GINT_TO_POINTER(stream->video_payload_type)));
2678 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Retransmissions will have payload type %d\n",
2679 							handle->handle_id, stream->video_rtx_payload_type);
2680 					}
2681 					if(stream->video_codec == NULL) {
2682 						const char *codec = janus_get_codec_from_pt(handle->local_sdp, stream->video_payload_type);
2683 						if(codec != NULL)
2684 							stream->video_codec = g_strdup(codec);
2685 					}
2686 					if(stream->video_is_keyframe == NULL && stream->video_codec != NULL) {
2687 						if(!strcasecmp(stream->video_codec, "vp8"))
2688 							stream->video_is_keyframe = &janus_vp8_is_keyframe;
2689 						else if(!strcasecmp(stream->video_codec, "vp9"))
2690 							stream->video_is_keyframe = &janus_vp9_is_keyframe;
2691 						else if(!strcasecmp(stream->video_codec, "h264"))
2692 							stream->video_is_keyframe = &janus_h264_is_keyframe;
2693 						else if(!strcasecmp(stream->video_codec, "av1"))
2694 							stream->video_is_keyframe = &janus_av1_is_keyframe;
2695 						else if(!strcasecmp(stream->video_codec, "h265"))
2696 							stream->video_is_keyframe = &janus_h265_is_keyframe;
2697 					}
2698 				}
2699 				/* Prepare the data to pass to the responsible plugin */
2700 				janus_plugin_rtp rtp = { .video = video, .buffer = buf, .length = buflen };
2701 				janus_plugin_rtp_extensions_reset(&rtp.extensions);
2702 				/* Parse RTP extensions before involving the plugin */
2703 				if(stream->audiolevel_ext_id != -1) {
2704 					gboolean vad = FALSE;
2705 					int level = -1;
2706 					if(janus_rtp_header_extension_parse_audio_level(buf, buflen,
2707 							stream->audiolevel_ext_id, &vad, &level) == 0) {
2708 						rtp.extensions.audio_level = level;
2709 						rtp.extensions.audio_level_vad = vad;
2710 					}
2711 				}
2712 				if(stream->videoorientation_ext_id != -1) {
2713 					gboolean c = FALSE, f = FALSE, r1 = FALSE, r0 = FALSE;
2714 					if(janus_rtp_header_extension_parse_video_orientation(buf, buflen,
2715 							stream->videoorientation_ext_id, &c, &f, &r1, &r0) == 0) {
2716 						rtp.extensions.video_rotation = 0;
2717 						if(r1 && r0)
2718 							rtp.extensions.video_rotation = 270;
2719 						else if(r1)
2720 							rtp.extensions.video_rotation = 180;
2721 						else if(r0)
2722 							rtp.extensions.video_rotation = 90;
2723 						rtp.extensions.video_back_camera = c;
2724 						rtp.extensions.video_flipped = f;
2725 					}
2726 				}
2727 				/* Pass the packet to the plugin */
2728 				janus_plugin *plugin = (janus_plugin *)handle->app;
2729 				if(plugin && plugin->incoming_rtp && handle->app_handle &&
2730 						!g_atomic_int_get(&handle->app_handle->stopped) &&
2731 						!g_atomic_int_get(&handle->destroyed))
2732 					plugin->incoming_rtp(handle->app_handle, &rtp);
2733 				/* Restore the header for the stats (plugins may have messed with it) */
2734 				*header = backup;
2735 				/* Update stats (overall data received, and data received in the last second) */
2736 				if(buflen > 0) {
2737 					gint64 now = janus_get_monotonic_time();
2738 					if(!video) {
2739 						if(component->in_stats.audio.bytes == 0 || component->in_stats.audio.notified_lastsec) {
2740 							/* We either received our first audio packet, or we started receiving it again after missing more than a second */
2741 							component->in_stats.audio.notified_lastsec = FALSE;
2742 							janus_ice_notify_media(handle, FALSE, 0, TRUE);
2743 						}
2744 						/* Overall audio data */
2745 						component->in_stats.audio.packets++;
2746 						component->in_stats.audio.bytes += buflen;
2747 						/* Last second audio data */
2748 						if(component->in_stats.audio.updated == 0)
2749 							component->in_stats.audio.updated = now;
2750 						if(now > component->in_stats.audio.updated &&
2751 								now - component->in_stats.audio.updated >= G_USEC_PER_SEC) {
2752 							component->in_stats.audio.bytes_lastsec = component->in_stats.audio.bytes_lastsec_temp;
2753 							component->in_stats.audio.bytes_lastsec_temp = 0;
2754 							component->in_stats.audio.updated = now;
2755 						}
2756 						component->in_stats.audio.bytes_lastsec_temp += buflen;
2757 					} else {
2758 						if(component->in_stats.video[vindex].bytes == 0 || component->in_stats.video[vindex].notified_lastsec) {
2759 							/* We either received our first video packet, or we started receiving it again after missing more than a second */
2760 							component->in_stats.video[vindex].notified_lastsec = FALSE;
2761 							janus_ice_notify_media(handle, TRUE, vindex, TRUE);
2762 						}
2763 						/* Overall video data for this SSRC */
2764 						component->in_stats.video[vindex].packets++;
2765 						component->in_stats.video[vindex].bytes += buflen;
2766 						/* Last second video data for this SSRC */
2767 						if(component->in_stats.video[vindex].updated == 0)
2768 							component->in_stats.video[vindex].updated = now;
2769 						if(now > component->in_stats.video[vindex].updated &&
2770 								now - component->in_stats.video[vindex].updated >= G_USEC_PER_SEC) {
2771 							component->in_stats.video[vindex].bytes_lastsec = component->in_stats.video[vindex].bytes_lastsec_temp;
2772 							component->in_stats.video[vindex].bytes_lastsec_temp = 0;
2773 							component->in_stats.video[vindex].updated = now;
2774 						}
2775 						component->in_stats.video[vindex].bytes_lastsec_temp += buflen;
2776 					}
2777 				}
2778 
2779 				/* Update the RTCP context as well */
2780 				rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx[vindex] : stream->audio_rtcp_ctx;
2781 				gboolean retransmissions_disabled = (!video && !component->do_audio_nacks) || (video && !component->do_video_nacks);
2782 				janus_rtcp_process_incoming_rtp(rtcp_ctx, buf, buflen,
2783 						(video && rtx) ? TRUE : FALSE,
2784 						(video && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX)),
2785 						retransmissions_disabled, stream->clock_rates
2786 				);
2787 
2788 				/* Keep track of RTP sequence numbers, in case we need to NACK them */
2789 				/* 	Note: unsigned int overflow/underflow wraps (defined behavior) */
2790 				if(retransmissions_disabled) {
2791 					/* ... unless NACKs are disabled for this medium */
2792 					return;
2793 				}
2794 				guint16 new_seqn = ntohs(header->seq_number);
2795 				/* If this is video, check if this is a keyframe: if so, we empty our NACK queue */
2796 				if(video && stream->video_is_keyframe) {
2797 					if(stream->video_is_keyframe(payload, plen)) {
2798 						if(rtcp_ctx && (int16_t)(new_seqn - rtcp_ctx->max_seq_nr) > 0) {
2799 							JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Keyframe received with a highest sequence number, resetting NACK queue\n", handle->handle_id);
2800 							janus_seq_list_free(&component->last_seqs_video[vindex]);
2801 						}
2802 					}
2803 				}
2804 				guint16 cur_seqn;
2805 				int last_seqs_len = 0;
2806 				janus_mutex_lock(&component->mutex);
2807 				janus_seq_info **last_seqs = video ? &component->last_seqs_video[vindex] : &component->last_seqs_audio;
2808 				janus_seq_info *cur_seq = *last_seqs;
2809 				if(cur_seq) {
2810 					cur_seq = cur_seq->prev;
2811 					cur_seqn = cur_seq->seq;
2812 				} else {
2813 					/* First seq, set up to add one seq */
2814 					cur_seqn = new_seqn - (guint16)1; /* Can wrap */
2815 				}
2816 				if(!janus_seq_in_range(new_seqn, cur_seqn, LAST_SEQS_MAX_LEN) &&
2817 						!janus_seq_in_range(cur_seqn, new_seqn, 1000)) {
2818 					/* Jump too big, start fresh */
2819 					JANUS_LOG(LOG_WARN, "[%"SCNu64"] Big sequence number jump %hu -> %hu (%s stream #%d)\n",
2820 						handle->handle_id, cur_seqn, new_seqn, video ? "video" : "audio", vindex);
2821 					janus_seq_list_free(last_seqs);
2822 					cur_seq = NULL;
2823 					cur_seqn = new_seqn - (guint16)1;
2824 				}
2825 
2826 				GSList *nacks = NULL;
2827 				gint64 now = janus_get_monotonic_time();
2828 
2829 				if(janus_seq_in_range(new_seqn, cur_seqn, LAST_SEQS_MAX_LEN)) {
2830 					/* Add new seq objs forward */
2831 					while(cur_seqn != new_seqn) {
2832 						cur_seqn += (guint16)1; /* can wrap */
2833 						janus_seq_info *seq_obj = g_malloc0(sizeof(janus_seq_info));
2834 						seq_obj->seq = cur_seqn;
2835 						seq_obj->ts = now;
2836 						seq_obj->state = (cur_seqn == new_seqn) ? SEQ_RECVED : SEQ_MISSING;
2837 						janus_seq_append(last_seqs, seq_obj);
2838 						last_seqs_len++;
2839 					}
2840 				}
2841 				if(cur_seq) {
2842 					/* Scan old seq objs backwards */
2843 					while(cur_seq != NULL) {
2844 						last_seqs_len++;
2845 						if(cur_seq->seq == new_seqn) {
2846 							JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Received missed sequence number %"SCNu16" (%s stream #%d)\n",
2847 								handle->handle_id, cur_seq->seq, video ? "video" : "audio", vindex);
2848 							cur_seq->state = SEQ_RECVED;
2849 						} else if(cur_seq->state == SEQ_MISSING && now - cur_seq->ts > SEQ_MISSING_WAIT) {
2850 							JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Missed sequence number %"SCNu16" (%s stream #%d), sending 1st NACK\n",
2851 								handle->handle_id, cur_seq->seq, video ? "video" : "audio", vindex);
2852 							nacks = g_slist_prepend(nacks, GUINT_TO_POINTER(cur_seq->seq));
2853 							cur_seq->state = SEQ_NACKED;
2854 							if(video && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX)) {
2855 								/* Keep track of this sequence number, we need to avoid duplicates */
2856 								JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Tracking NACKed packet %"SCNu16" (SSRC %"SCNu32", vindex %d)...\n",
2857 									handle->handle_id, cur_seq->seq, packet_ssrc, vindex);
2858 								if(stream->rtx_nacked[vindex] == NULL)
2859 									stream->rtx_nacked[vindex] = g_hash_table_new(NULL, NULL);
2860 								g_hash_table_insert(stream->rtx_nacked[vindex], GUINT_TO_POINTER(cur_seq->seq), GINT_TO_POINTER(1));
2861 								/* We don't track it forever, though: add a timed source to remove it in a few seconds */
2862 								janus_ice_nacked_packet *np = g_malloc(sizeof(janus_ice_nacked_packet));
2863 								np->handle = handle;
2864 								np->seq_number = cur_seq->seq;
2865 								np->vindex = vindex;
2866 								if(stream->pending_nacked_cleanup == NULL)
2867 									stream->pending_nacked_cleanup = g_hash_table_new(NULL, NULL);
2868 								GSource *timeout_source = g_timeout_source_new_seconds(5);
2869 								g_source_set_callback(timeout_source, janus_ice_nacked_packet_cleanup, np, (GDestroyNotify)g_free);
2870 								np->source_id = g_source_attach(timeout_source, handle->mainctx);
2871 								g_source_unref(timeout_source);
2872 								g_hash_table_insert(stream->pending_nacked_cleanup, GUINT_TO_POINTER(np->source_id), timeout_source);
2873 							}
2874 						} else if(cur_seq->state == SEQ_NACKED  && now - cur_seq->ts > SEQ_NACKED_WAIT) {
2875 							JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Missed sequence number %"SCNu16" (%s stream #%d), sending 2nd NACK\n",
2876 								handle->handle_id, cur_seq->seq, video ? "video" : "audio", vindex);
2877 							nacks = g_slist_prepend(nacks, GUINT_TO_POINTER(cur_seq->seq));
2878 							cur_seq->state = SEQ_GIVEUP;
2879 						}
2880 						if(cur_seq == *last_seqs) {
2881 							/* Just processed head */
2882 							break;
2883 						}
2884 						cur_seq = cur_seq->prev;
2885 					}
2886 				}
2887 				while(last_seqs_len > LAST_SEQS_MAX_LEN) {
2888 					janus_seq_info *node = janus_seq_pop_head(last_seqs);
2889 					g_free(node);
2890 					last_seqs_len--;
2891 				}
2892 
2893 				guint nacks_count = g_slist_length(nacks);
2894 				if(nacks_count) {
2895 					/* Generate a NACK and send it */
2896 					JANUS_LOG(LOG_DBG, "[%"SCNu64"] Now sending NACK for %u missed packets (%s stream #%d)\n",
2897 						handle->handle_id, nacks_count, video ? "video" : "audio", vindex);
2898 					char nackbuf[120];
2899 					int res = janus_rtcp_nacks(nackbuf, sizeof(nackbuf), nacks);
2900 					if(res > 0) {
2901 						/* Set the right local and remote SSRC in the RTCP packet */
2902 						janus_rtcp_fix_ssrc(NULL, nackbuf, res, 1,
2903 							video ? stream->video_ssrc : stream->audio_ssrc,
2904 							video ? stream->video_ssrc_peer[vindex] : stream->audio_ssrc_peer);
2905 						janus_plugin_rtcp rtcp = { .video = video, .buffer = nackbuf, .length = res };
2906 						janus_ice_relay_rtcp_internal(handle, &rtcp, FALSE);
2907 					}
2908 					/* Update stats */
2909 					component->nack_sent_recent_cnt += nacks_count;
2910 					if(video) {
2911 						component->out_stats.video[vindex].nacks += nacks_count;
2912 					} else {
2913 						component->out_stats.audio.nacks += nacks_count;
2914 					}
2915 				}
2916 				if(component->nack_sent_recent_cnt &&
2917 						(now - component->nack_sent_log_ts) > 5*G_USEC_PER_SEC) {
2918 					JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sent NACKs for %u missing packets (%s stream #%d)\n",
2919 						handle->handle_id, component->nack_sent_recent_cnt, video ? "video" : "audio", vindex);
2920 					component->nack_sent_recent_cnt = 0;
2921 					component->nack_sent_log_ts = now;
2922 				}
2923 				janus_mutex_unlock(&component->mutex);
2924 				g_slist_free(nacks);
2925 				nacks = NULL;
2926 			}
2927 		}
2928 		return;
2929 	} else if(janus_is_rtcp(buf, len)) {
2930 		/* This is RTCP */
2931 		JANUS_LOG(LOG_HUGE, "[%"SCNu64"]  Got an RTCP packet\n", handle->handle_id);
2932 		if(janus_is_webrtc_encryption_enabled() && (!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_in)) {
2933 			JANUS_LOG(LOG_WARN, "[%"SCNu64"]     Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
2934 		} else {
2935 			int buflen = len;
2936 			srtp_err_status_t res = janus_is_webrtc_encryption_enabled() ?
2937 				srtp_unprotect_rtcp(component->dtls->srtp_in, buf, &buflen) : srtp_err_status_ok;
2938 			if(res != srtp_err_status_ok) {
2939 				JANUS_LOG(LOG_ERR, "[%"SCNu64"]     SRTCP unprotect error: %s (len=%d-->%d)\n", handle->handle_id, janus_srtp_error_str(res), len, buflen);
2940 			} else {
2941 				/* Do we need to dump this packet for debugging? */
2942 				if(g_atomic_int_get(&handle->dump_packets))
2943 					janus_text2pcap_dump(handle->text2pcap, JANUS_TEXT2PCAP_RTCP, TRUE, buf, buflen,
2944 						"[session=%"SCNu64"][handle=%"SCNu64"]", session->session_id, handle->handle_id);
2945 				/* Check if there's an RTCP BYE: in case, let's log it */
2946 				if(janus_rtcp_has_bye(buf, buflen)) {
2947 					/* Note: we used to use this as a trigger to close the PeerConnection, but not anymore
2948 					 * Discussion here, https://groups.google.com/forum/#!topic/meetecho-janus/4XtfbYB7Jvc */
2949 					JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got RTCP BYE on stream %u (component %u)\n", handle->handle_id, stream->stream_id, component->component_id);
2950 				}
2951 				/* Is this audio or video? */
2952 				int video = 0, vindex = 0;
2953 				if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX)) {
2954 					janus_rtcp_swap_report_blocks(buf, buflen, stream->video_ssrc_rtx);
2955 				}
2956 				/* Bundled streams, should we check the SSRCs? */
2957 				if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO)) {
2958 					/* No audio has been negotiated, definitely video */
2959 					JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is video (no audio has been negotiated)\n", handle->handle_id);
2960 					if(stream->video_ssrc_peer[0] == 0) {
2961 						/* We don't know the remote SSRC: this can happen for recvonly clients
2962 						 * (see https://groups.google.com/forum/#!topic/discuss-webrtc/5yuZjV7lkNc)
2963 						 * Check the local SSRC, compare it to what we have */
2964 						guint32 rtcp_ssrc = janus_rtcp_get_receiver_ssrc(buf, buflen);
2965 						if(rtcp_ssrc == 0) {
2966 							/* No SSRC, maybe an empty RR? */
2967 							return;
2968 						}
2969 						if(rtcp_ssrc == stream->video_ssrc) {
2970 							video = 1;
2971 						} else if(rtcp_ssrc == stream->video_ssrc_rtx) {
2972 							/* rtx SSRC, we don't care */
2973 							return;
2974 						} else if(janus_rtcp_has_fir(buf, buflen) || janus_rtcp_has_pli(buf, buflen) || janus_rtcp_get_remb(buf, buflen)) {
2975 							/* Mh, no SR or RR? Try checking if there's any FIR, PLI or REMB */
2976 							video = 1;
2977 						} else {
2978 							JANUS_LOG(LOG_VERB, "[%"SCNu64"] Dropping RTCP packet with unknown SSRC (%"SCNu32")\n", handle->handle_id, rtcp_ssrc);
2979 							return;
2980 						}
2981 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (local SSRC: video=%"SCNu32", got %"SCNu32")\n",
2982 							handle->handle_id, video ? "video" : "audio", stream->video_ssrc, rtcp_ssrc);
2983 					} else {
2984 						/* Check the remote SSRC, compare it to what we have: in case
2985 							* we're simulcasting, let's compare to the other SSRCs too */
2986 						guint32 rtcp_ssrc = janus_rtcp_get_sender_ssrc(buf, buflen);
2987 						if(rtcp_ssrc == 0) {
2988 							/* No SSRC, maybe an empty RR? */
2989 							return;
2990 						}
2991 						if(stream->video_ssrc_peer[0] && rtcp_ssrc == stream->video_ssrc_peer[0]) {
2992 							video = 1;
2993 							vindex = 0;
2994 						} else if(stream->video_ssrc_peer[1] && rtcp_ssrc == stream->video_ssrc_peer[1]) {
2995 							video = 1;
2996 							vindex = 1;
2997 						} else if(stream->video_ssrc_peer[2] && rtcp_ssrc == stream->video_ssrc_peer[2]) {
2998 							video = 1;
2999 							vindex = 2;
3000 						} else {
3001 							JANUS_LOG(LOG_VERB, "[%"SCNu64"] Dropping RTCP packet with unknown SSRC (%"SCNu32")\n", handle->handle_id, rtcp_ssrc);
3002 							return;
3003 						}
3004 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (remote SSRC: video=%"SCNu32" #%d, got %"SCNu32")\n",
3005 							handle->handle_id, video ? "video" : "audio", stream->video_ssrc_peer[vindex], vindex, rtcp_ssrc);
3006 					}
3007 				} else if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)) {
3008 					/* No video has been negotiated, definitely audio */
3009 					JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is audio (no video has been negotiated)\n", handle->handle_id);
3010 					video = 0;
3011 				} else {
3012 					if(stream->audio_ssrc_peer == 0 || stream->video_ssrc_peer[0] == 0) {
3013 						/* We don't know the remote SSRC: this can happen for recvonly clients
3014 						 * (see https://groups.google.com/forum/#!topic/discuss-webrtc/5yuZjV7lkNc)
3015 						 * Check the local SSRC, compare it to what we have */
3016 						guint32 rtcp_ssrc = janus_rtcp_get_receiver_ssrc(buf, buflen);
3017 						if(rtcp_ssrc == 0) {
3018 							/* No SSRC, maybe an empty RR? */
3019 							return;
3020 						}
3021 						if(rtcp_ssrc == stream->audio_ssrc) {
3022 							video = 0;
3023 						} else if(rtcp_ssrc == stream->video_ssrc) {
3024 							video = 1;
3025 						} else if(rtcp_ssrc == stream->video_ssrc_rtx) {
3026 							/* rtx SSRC, we don't care */
3027 							return;
3028 						} else if(janus_rtcp_has_fir(buf, buflen) || janus_rtcp_has_pli(buf, buflen) || janus_rtcp_get_remb(buf, buflen)) {
3029 							/* Mh, no SR or RR? Try checking if there's any FIR, PLI or REMB */
3030 							video = 1;
3031 						} else {
3032 							JANUS_LOG(LOG_VERB, "[%"SCNu64"] Dropping RTCP packet with unknown SSRC (%"SCNu32")\n", handle->handle_id, rtcp_ssrc);
3033 							return;
3034 						}
3035 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (local SSRC: video=%"SCNu32", audio=%"SCNu32", got %"SCNu32")\n",
3036 							handle->handle_id, video ? "video" : "audio", stream->video_ssrc, stream->audio_ssrc, rtcp_ssrc);
3037 					} else {
3038 						/* Check the remote SSRC, compare it to what we have: in case
3039 						 * we're simulcasting, let's compare to the other SSRCs too */
3040 						guint32 rtcp_ssrc = janus_rtcp_get_sender_ssrc(buf, buflen);
3041 						if(rtcp_ssrc == 0) {
3042 							/* No SSRC, maybe an empty RR? */
3043 							return;
3044 						}
3045 						if(rtcp_ssrc == stream->audio_ssrc_peer) {
3046 							video = 0;
3047 						} else if(rtcp_ssrc == stream->video_ssrc_peer[0]) {
3048 							video = 1;
3049 						} else if(stream->video_ssrc_peer[1] && rtcp_ssrc == stream->video_ssrc_peer[1]) {
3050 							video = 1;
3051 							vindex = 1;
3052 						} else if(stream->video_ssrc_peer[2] && rtcp_ssrc == stream->video_ssrc_peer[2]) {
3053 							video = 1;
3054 							vindex = 2;
3055 						} else {
3056 							JANUS_LOG(LOG_VERB, "[%"SCNu64"] Dropping RTCP packet with unknown SSRC (%"SCNu32")\n", handle->handle_id, rtcp_ssrc);
3057 							return;
3058 						}
3059 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (remote SSRC: video=%"SCNu32" #%d, audio=%"SCNu32", got %"SCNu32")\n",
3060 							handle->handle_id, video ? "video" : "audio", stream->video_ssrc_peer[vindex], vindex, stream->audio_ssrc_peer, rtcp_ssrc);
3061 					}
3062 				}
3063 
3064 				/* Let's process this RTCP (compound?) packet, and update the RTCP context for this stream in case */
3065 				rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx[vindex] : stream->audio_rtcp_ctx;
3066 				uint32_t rtt = rtcp_ctx ? rtcp_ctx->rtt : 0;
3067 				if(janus_rtcp_parse(rtcp_ctx, buf, buflen) < 0) {
3068 					/* Drop the packet if the parsing function returns with an error */
3069 					return;
3070 				}
3071 				if(rtcp_ctx && rtcp_ctx->rtt != rtt) {
3072 					/* Check the current RTT, to see if we need to update the size of the queue: we take
3073 					 * the highest RTT (audio or video) and add 100ms just to be conservative */
3074 					uint32_t audio_rtt = janus_rtcp_context_get_rtt(stream->audio_rtcp_ctx),
3075 						video_rtt = janus_rtcp_context_get_rtt(stream->video_rtcp_ctx[0]);
3076 					uint16_t nack_queue_ms = (audio_rtt > video_rtt ? audio_rtt : video_rtt) + 100;
3077 					if(nack_queue_ms > DEFAULT_MAX_NACK_QUEUE)
3078 						nack_queue_ms = DEFAULT_MAX_NACK_QUEUE;
3079 					else if(nack_queue_ms < min_nack_queue)
3080 						nack_queue_ms = min_nack_queue;
3081 					uint16_t mavg = rtt ? ((7*stream->nack_queue_ms + nack_queue_ms)/8) : nack_queue_ms;
3082 					if(mavg > DEFAULT_MAX_NACK_QUEUE)
3083 						mavg = DEFAULT_MAX_NACK_QUEUE;
3084 					else if(mavg < min_nack_queue)
3085 						mavg = min_nack_queue;
3086 					stream->nack_queue_ms = mavg;
3087 				}
3088 				JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Got %s RTCP (%d bytes)\n", handle->handle_id, video ? "video" : "audio", buflen);
3089 				/* See if there's any REMB bitrate to track */
3090 				uint32_t bitrate = janus_rtcp_get_remb(buf, buflen);
3091 				if(bitrate > 0)
3092 					stream->remb_bitrate = bitrate;
3093 
3094 				/* Now let's see if there are any NACKs to handle */
3095 				gint64 now = janus_get_monotonic_time();
3096 				GSList *nacks = janus_rtcp_get_nacks(buf, buflen);
3097 				guint nacks_count = g_slist_length(nacks);
3098 				if(nacks_count && ((!video && component->do_audio_nacks) || (video && component->do_video_nacks))) {
3099 					/* Handle NACK */
3100 					JANUS_LOG(LOG_HUGE, "[%"SCNu64"]     Just got some NACKS (%d) we should handle...\n", handle->handle_id, nacks_count);
3101 					GHashTable *retransmit_seqs = (video ? component->video_retransmit_seqs : component->audio_retransmit_seqs);
3102 					GSList *list = (retransmit_seqs != NULL ? nacks : NULL);
3103 					int retransmits_cnt = 0;
3104 					janus_mutex_lock(&component->mutex);
3105 					while(list) {
3106 						unsigned int seqnr = GPOINTER_TO_UINT(list->data);
3107 						JANUS_LOG(LOG_DBG, "[%"SCNu64"]   >> %u\n", handle->handle_id, seqnr);
3108 						int in_rb = 0;
3109 						/* Check if we have the packet */
3110 						janus_rtp_packet *p = g_hash_table_lookup(retransmit_seqs, GUINT_TO_POINTER(seqnr));
3111 						if(p == NULL) {
3112 							JANUS_LOG(LOG_HUGE, "[%"SCNu64"]   >> >> Can't retransmit packet %u, we don't have it...\n", handle->handle_id, seqnr);
3113 						} else {
3114 							/* Should we retransmit this packet? */
3115 							if((p->last_retransmit > 0) && (now-p->last_retransmit < MAX_NACK_IGNORE)) {
3116 								JANUS_LOG(LOG_HUGE, "[%"SCNu64"]   >> >> Packet %u was retransmitted just %"SCNi64"ms ago, skipping\n", handle->handle_id, seqnr, now-p->last_retransmit);
3117 								list = list->next;
3118 								continue;
3119 							}
3120 							in_rb = 1;
3121 							JANUS_LOG(LOG_HUGE, "[%"SCNu64"]   >> >> Scheduling %u for retransmission due to NACK\n", handle->handle_id, seqnr);
3122 							p->last_retransmit = now;
3123 							retransmits_cnt++;
3124 							/* Enqueue it */
3125 							janus_ice_queued_packet *pkt = g_malloc(sizeof(janus_ice_queued_packet));
3126 							pkt->data = g_malloc(p->length+SRTP_MAX_TAG_LEN);
3127 							memcpy(pkt->data, p->data, p->length);
3128 							pkt->length = p->length;
3129 							pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
3130 							pkt->control = FALSE;
3131 							pkt->retransmission = TRUE;
3132 							pkt->label = NULL;
3133 							pkt->protocol = NULL;
3134 							pkt->added = janus_get_monotonic_time();
3135 							/* What to send and how depends on whether we're doing RFC4588 or not */
3136 							if(!video || !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX)) {
3137 								/* We're not: just clarify the packet was already encrypted before */
3138 								pkt->encrypted = TRUE;
3139 							} else {
3140 								/* We are: overwrite the RTP header (which means we'll need a new SRTP encrypt) */
3141 								pkt->encrypted = FALSE;
3142 								janus_rtp_header *header = (janus_rtp_header *)pkt->data;
3143 								header->type = stream->video_rtx_payload_type;
3144 								header->ssrc = htonl(stream->video_ssrc_rtx);
3145 								component->rtx_seq_number++;
3146 								header->seq_number = htons(component->rtx_seq_number);
3147 							}
3148 							if(handle->queued_packets != NULL) {
3149 #if GLIB_CHECK_VERSION(2, 46, 0)
3150 								g_async_queue_push_front(handle->queued_packets, pkt);
3151 #else
3152 								g_async_queue_push(handle->queued_packets, pkt);
3153 #endif
3154 								g_main_context_wakeup(handle->mainctx);
3155 							} else {
3156 								janus_ice_free_queued_packet(pkt);
3157 							}
3158 						}
3159 						if(rtcp_ctx != NULL && in_rb) {
3160 							g_atomic_int_inc(&rtcp_ctx->nack_count);
3161 						}
3162 						list = list->next;
3163 					}
3164 					component->retransmit_recent_cnt += retransmits_cnt;
3165 					/* FIXME Remove the NACK compound packet, we've handled it */
3166 					buflen = janus_rtcp_remove_nacks(buf, buflen);
3167 					/* Update stats */
3168 					if(video) {
3169 						component->in_stats.video[vindex].nacks += nacks_count;
3170 					} else {
3171 						component->in_stats.audio.nacks += nacks_count;
3172 					}
3173 					janus_mutex_unlock(&component->mutex);
3174 					g_slist_free(nacks);
3175 					nacks = NULL;
3176 				}
3177 				if(component->retransmit_recent_cnt &&
3178 						now - component->retransmit_log_ts > 5*G_USEC_PER_SEC) {
3179 					JANUS_LOG(LOG_VERB, "[%"SCNu64"] Retransmitted %u packets due to NACK (%s stream #%d)\n",
3180 						handle->handle_id, component->retransmit_recent_cnt, video ? "video" : "audio", vindex);
3181 					component->retransmit_recent_cnt = 0;
3182 					component->retransmit_log_ts = now;
3183 				}
3184 
3185 				/* Fix packet data for RTCP SR and RTCP RR */
3186 				janus_rtp_switching_context *rtp_ctx = video ? &stream->rtp_ctx[vindex] : &stream->rtp_ctx[0];
3187 				uint32_t base_ts = video ? rtp_ctx->v_base_ts : rtp_ctx->a_base_ts;
3188 				uint32_t base_ts_prev = video ? rtp_ctx->v_base_ts_prev : rtp_ctx->a_base_ts_prev;
3189 				uint32_t ssrc_peer = video ? stream->video_ssrc_peer_orig[vindex] : stream->audio_ssrc_peer_orig;
3190 				uint32_t ssrc_local = video ? stream->video_ssrc : stream->audio_ssrc;
3191 				uint32_t ssrc_expected = video ? rtp_ctx->v_last_ssrc : rtp_ctx->a_last_ssrc;
3192 				if (janus_rtcp_fix_report_data(buf, buflen, base_ts, base_ts_prev, ssrc_peer, ssrc_local, ssrc_expected, video) < 0) {
3193 					/* Drop packet in case of parsing error or SSRC different from the one expected. */
3194 					/* This might happen at the very beginning of the communication or early after */
3195 					/* a re-negotation has been concluded. */
3196 					return;
3197 				}
3198 
3199 				janus_plugin_rtcp rtcp = { .video = video, .buffer = buf, .length = buflen };
3200 				janus_plugin *plugin = (janus_plugin *)handle->app;
3201 				if(plugin && plugin->incoming_rtcp && handle->app_handle &&
3202 						!g_atomic_int_get(&handle->app_handle->stopped) &&
3203 						!g_atomic_int_get(&handle->destroyed))
3204 					plugin->incoming_rtcp(handle->app_handle, &rtcp);
3205 			}
3206 		}
3207 		return;
3208 	} else {
3209 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Not RTP and not RTCP... may these be data channels?\n", handle->handle_id);
3210 		janus_dtls_srtp_incoming_msg(component->dtls, buf, len);
3211 		/* Update stats (only overall data received) */
3212 		if(len > 0) {
3213 			component->in_stats.data.packets++;
3214 			component->in_stats.data.bytes += len;
3215 		}
3216 		return;
3217 	}
3218 }
3219 
3220 void janus_ice_incoming_data(janus_ice_handle *handle, char *label, char *protocol, gboolean textdata, char *buffer, int length) {
3221 	if(handle == NULL || buffer == NULL || length <= 0)
3222 		return;
3223 	janus_plugin_data data = { .label = label, .protocol = protocol, .binary = !textdata, .buffer = buffer, .length = length };
3224 	janus_plugin *plugin = (janus_plugin *)handle->app;
3225 	if(plugin && plugin->incoming_data && handle->app_handle &&
3226 			!g_atomic_int_get(&handle->app_handle->stopped) &&
3227 			!g_atomic_int_get(&handle->destroyed))
3228 		plugin->incoming_data(handle->app_handle, &data);
3229 }
3230 
3231 
3232 /* Helper: encoding local candidates to string/SDP */
3233 static int janus_ice_candidate_to_string(janus_ice_handle *handle, NiceCandidate *c, char *buffer, int buflen, gboolean log_candidate, gboolean force_private, guint public_ip_index) {
3234 	if(!handle || !handle->agent || !c || !buffer || buflen < 1)
3235 		return -1;
3236 	janus_ice_stream *stream = handle->stream;
3237 	if(!stream)
3238 		return -2;
3239 	janus_ice_component *component = stream->component;
3240 	if(!component)
3241 		return -3;
3242 	char *host_ip = NULL;
3243 	gboolean ipv6 = (nice_address_ip_version(&c->addr) == 6);
3244 	if(nat_1_1_enabled && !force_private) {
3245 		/* A 1:1 NAT mapping was specified, either overwrite all the host addresses with the public IP, or add new candidates */
3246 		host_ip = janus_get_public_ip(public_ip_index);
3247 		gboolean host_ip_v6 = (strchr(host_ip, ':') != NULL);
3248 		if(host_ip_v6 != ipv6) {
3249 			/* nat-1-1 address and candidate are not the same address family, don't do anything */
3250 			buffer[0] = '\0';
3251 			return 0;
3252 		}
3253 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Public IP specified and 1:1 NAT mapping enabled (%s), using that as host address in the candidates\n", handle->handle_id, host_ip);
3254 	}
3255 	/* Encode the candidate to a string */
3256 	gchar address[NICE_ADDRESS_STRING_LEN], base_address[NICE_ADDRESS_STRING_LEN];
3257 	gint port = 0, base_port = 0;
3258 	nice_address_to_string(&(c->addr), (gchar *)&address);
3259 	port = nice_address_get_port(&(c->addr));
3260 	nice_address_to_string(&(c->base_addr), (gchar *)&base_address);
3261 	base_port = nice_address_get_port(&(c->base_addr));
3262 	JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Address:    %s:%d\n", handle->handle_id, address, port);
3263 	JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Priority:   %d\n", handle->handle_id, c->priority);
3264 	JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Foundation: %s\n", handle->handle_id, c->foundation);
3265 	/* Start */
3266 	if(c->type == NICE_CANDIDATE_TYPE_HOST) {
3267 		/* 'host' candidate */
3268 		if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
3269 			g_snprintf(buffer, buflen,
3270 				"%s %d %s %d %s %d typ host",
3271 					c->foundation, c->component_id,
3272 					"udp", c->priority,
3273 					host_ip ? host_ip : address, port);
3274 		} else {
3275 			if(!janus_ice_tcp_enabled) {
3276 				/* ICE-TCP support disabled */
3277 				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping host TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
3278 				return -4;
3279 			}
3280 #ifndef HAVE_LIBNICE_TCP
3281 			/* TCP candidates are only supported since libnice 0.1.8 */
3282 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping host TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
3283 			return -4;
3284 #else
3285 			const char *type = NULL;
3286 			switch(c->transport) {
3287 				case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
3288 					type = "active";
3289 					break;
3290 				case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
3291 					type = "passive";
3292 					break;
3293 				case NICE_CANDIDATE_TRANSPORT_TCP_SO:
3294 					type = "so";
3295 					break;
3296 				default:
3297 					break;
3298 			}
3299 			if(type == NULL) {
3300 				/* FIXME Unsupported transport */
3301 				JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP host candidate...\n", handle->handle_id);
3302 				return -5;
3303 			}
3304 			g_snprintf(buffer, buflen,
3305 				"%s %d %s %d %s %d typ host tcptype %s",
3306 					c->foundation, c->component_id,
3307 					"tcp", c->priority,
3308 					host_ip ? host_ip : address, port, type);
3309 #endif
3310 		}
3311 	} else if(c->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ||
3312 			c->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE ||
3313 			c->type == NICE_CANDIDATE_TYPE_RELAYED) {
3314 		/* 'srflx', 'prflx', or 'relay' candidate: what is this, exactly? */
3315 		const char *ltype = NULL;
3316 		switch(c->type) {
3317 			case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
3318 				ltype = "srflx";
3319 				break;
3320 			case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
3321 				ltype = "prflx";
3322 				break;
3323 			case NICE_CANDIDATE_TYPE_RELAYED:
3324 				ltype = "relay";
3325 				break;
3326 			default:
3327 				break;
3328 		}
3329 		if(ltype == NULL)
3330 			return -5;
3331 		if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
3332 			nice_address_to_string(&(c->base_addr), (gchar *)&base_address);
3333 			gint base_port = nice_address_get_port(&(c->base_addr));
3334 			g_snprintf(buffer, buflen,
3335 				"%s %d %s %d %s %d typ %s raddr %s rport %d",
3336 					c->foundation, c->component_id,
3337 					"udp", c->priority,
3338 					address, port, ltype,
3339 					base_address, base_port);
3340 		} else {
3341 			if(!janus_ice_tcp_enabled) {
3342 				/* ICE-TCP support disabled */
3343 				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping srflx TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
3344 				return -4;
3345 			}
3346 #ifndef HAVE_LIBNICE_TCP
3347 			/* TCP candidates are only supported since libnice 0.1.8 */
3348 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping srflx TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
3349 			return -4;
3350 #else
3351 			const char *type = NULL;
3352 			switch(c->transport) {
3353 				case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
3354 					type = "active";
3355 					break;
3356 				case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
3357 					type = "passive";
3358 					break;
3359 				case NICE_CANDIDATE_TRANSPORT_TCP_SO:
3360 					type = "so";
3361 					break;
3362 				default:
3363 					break;
3364 			}
3365 			if(type == NULL) {
3366 				/* FIXME Unsupported transport */
3367 				JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP srflx candidate...\n", handle->handle_id);
3368 				return -5;
3369 			} else {
3370 				g_snprintf(buffer, buflen,
3371 					"%s %d %s %d %s %d typ %s raddr %s rport %d tcptype %s",
3372 						c->foundation, c->component_id,
3373 						"tcp", c->priority,
3374 						address, port, ltype,
3375 						base_address, base_port, type);
3376 			}
3377 #endif
3378 		}
3379 	}
3380 	JANUS_LOG(LOG_VERB, "[%"SCNu64"]     %s\n", handle->handle_id, buffer);
3381 	if(log_candidate) {
3382 		/* Save for the summary, in case we need it */
3383 		component->local_candidates = g_slist_append(component->local_candidates, g_strdup(buffer));
3384 		/* Notify event handlers */
3385 		if(janus_events_is_enabled()) {
3386 			janus_session *session = (janus_session *)handle->session;
3387 			json_t *info = json_object();
3388 			json_object_set_new(info, "local-candidate", json_string(buffer));
3389 			json_object_set_new(info, "stream_id", json_integer(stream->stream_id));
3390 			json_object_set_new(info, "component_id", json_integer(component->component_id));
3391 			janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, JANUS_EVENT_SUBTYPE_WEBRTC_LCAND,
3392 				session->session_id, handle->handle_id, handle->opaque_id, info);
3393 		}
3394 	}
3395 	return 0;
3396 }
3397 
3398 void janus_ice_candidates_to_sdp(janus_ice_handle *handle, janus_sdp_mline *mline, guint stream_id, guint component_id) {
3399 	if(!handle || !handle->agent || !mline)
3400 		return;
3401 	janus_ice_stream *stream = handle->stream;
3402 	if(!stream || stream->stream_id != stream_id) {
3403 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
3404 		return;
3405 	}
3406 	janus_ice_component *component = stream->component;
3407 	if(!component || component->component_id != component_id) {
3408 		JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
3409 		return;
3410 	}
3411 	NiceAgent *agent = handle->agent;
3412 	/* Iterate on all */
3413 	gchar buffer[200];
3414 	GSList *candidates, *i;
3415 	candidates = nice_agent_get_local_candidates (agent, stream_id, component_id);
3416 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] We have %d candidates for Stream #%d, Component #%d\n", handle->handle_id, g_slist_length(candidates), stream_id, component_id);
3417 	gboolean log_candidates = (component->local_candidates == NULL);
3418 	for(i = candidates; i; i = i->next) {
3419 		NiceCandidate *c = (NiceCandidate *) i->data;
3420 		gboolean ipv6 = (nice_address_ip_version(&c->addr) == 6);
3421 		gboolean same_family = (!ipv6 && janus_has_public_ipv4_ip()) || (ipv6 && janus_has_public_ipv6_ip());
3422 		guint public_ip_index = 0;
3423 		do {
3424 			if(janus_ice_candidate_to_string(handle, c, buffer, sizeof(buffer), log_candidates, FALSE, public_ip_index) == 0) {
3425 				/* Candidate encoded, add to the SDP (but only if it's not a 'prflx') */
3426 				if(c->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
3427 					JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping prflx candidate...\n", handle->handle_id);
3428 				} else {
3429 					if(strlen(buffer) > 0) {
3430 						janus_sdp_attribute *a = janus_sdp_attribute_create("candidate", "%s", buffer);
3431 						mline->attributes = g_list_append(mline->attributes, a);
3432 					}
3433 					if(nat_1_1_enabled && public_ip_index == 0 && (keep_private_host || !same_family) &&
3434 							janus_ice_candidate_to_string(handle, c, buffer, sizeof(buffer), log_candidates, TRUE, public_ip_index) == 0) {
3435 						/* Candidate with private host encoded, add to the SDP (but only if it's not a 'prflx') */
3436 						if(c->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
3437 							JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping prflx candidate...\n", handle->handle_id);
3438 						} else if(strlen(buffer) > 0) {
3439 							janus_sdp_attribute *a = janus_sdp_attribute_create("candidate", "%s", buffer);
3440 							mline->attributes = g_list_append(mline->attributes, a);
3441 						}
3442 					}
3443 				}
3444 			}
3445 			public_ip_index++;
3446 			if(!same_family) {
3447 				/* We don't have any nat-1-1 address of the same family as this candidate, we're done */
3448 				break;
3449 			}
3450 		} while (public_ip_index < janus_get_public_ip_count());
3451 		nice_candidate_free(c);
3452 	}
3453 	/* Done */
3454 	g_slist_free(candidates);
3455 }
3456 
3457 void janus_ice_add_remote_candidate(janus_ice_handle *handle, NiceCandidate *c) {
3458 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Queueing candidate %p\n", handle->handle_id, c);
3459 	if(handle->queued_candidates != NULL)
3460 		g_async_queue_push(handle->queued_candidates, c);
3461 	if(handle->queued_packets != NULL) {
3462 #if GLIB_CHECK_VERSION(2, 46, 0)
3463 		g_async_queue_push_front(handle->queued_packets, &janus_ice_add_candidates);
3464 #else
3465 		g_async_queue_push(handle->queued_packets, &janus_ice_add_candidates);
3466 #endif
3467 		g_main_context_wakeup(handle->mainctx);
3468 	}
3469 }
3470 
3471 void janus_ice_setup_remote_candidates(janus_ice_handle *handle, guint stream_id, guint component_id) {
3472 	if(!handle || !handle->agent)
3473 		return;
3474 	janus_ice_stream *stream = handle->stream;
3475 	if(!stream || stream->stream_id != stream_id) {
3476 		JANUS_LOG(LOG_ERR, "[%"SCNu64"] No such stream %d: cannot setup remote candidates for component %d\n", handle->handle_id, stream_id, component_id);
3477 		return;
3478 	}
3479 	janus_ice_component *component = stream->component;
3480 	if(!component || component->component_id != component_id) {
3481 		JANUS_LOG(LOG_ERR, "[%"SCNu64"] No such component %d in stream %d: cannot setup remote candidates\n", handle->handle_id, component_id, stream_id);
3482 		return;
3483 	}
3484 	if(component->process_started) {
3485 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Component %d in stream %d has already been set up\n", handle->handle_id, component_id, stream_id);
3486 		return;
3487 	}
3488 	if(!component->candidates || !component->candidates->data) {
3489 		if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE)
3490 				|| janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES)) {
3491 			JANUS_LOG(LOG_ERR, "[%"SCNu64"] No remote candidates for component %d in stream %d: was the remote SDP parsed?\n", handle->handle_id, component_id, stream_id);
3492 		}
3493 		return;
3494 	}
3495 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] ## Setting remote candidates: stream %d, component %d (%u in the list)\n",
3496 		handle->handle_id, stream_id, component_id, g_slist_length(component->candidates));
3497 	/* Add all candidates */
3498 	NiceCandidate *c = NULL;
3499 	GSList *gsc = component->candidates;
3500 	while(gsc) {
3501 		c = (NiceCandidate *) gsc->data;
3502 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Queueing candidate %p (startup)\n", handle->handle_id, c);
3503 		if(handle->queued_candidates != NULL)
3504 			g_async_queue_push(handle->queued_candidates, c);
3505 		gsc = gsc->next;
3506 	}
3507 	if(handle->queued_packets != NULL) {
3508 #if GLIB_CHECK_VERSION(2, 46, 0)
3509 		g_async_queue_push_front(handle->queued_packets, &janus_ice_add_candidates);
3510 #else
3511 		g_async_queue_push(handle->queued_packets, &janus_ice_add_candidates);
3512 #endif
3513 		g_main_context_wakeup(handle->mainctx);
3514 	}
3515 	component->process_started = TRUE;
3516 }
3517 
3518 int janus_ice_setup_local(janus_ice_handle *handle, int offer, int audio, int video, int data, int trickle) {
3519 	if(!handle || g_atomic_int_get(&handle->destroyed))
3520 		return -1;
3521 	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AGENT)) {
3522 		JANUS_LOG(LOG_WARN, "[%"SCNu64"] Agent already exists?\n", handle->handle_id);
3523 		return -2;
3524 	}
3525 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting ICE locally: got %s (%d audios, %d videos)\n", handle->handle_id, offer ? "OFFER" : "ANSWER", audio, video);
3526 	g_atomic_int_set(&handle->closepc, 0);
3527 	janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AGENT);
3528 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_START);
3529 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_NEGOTIATED);
3530 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
3531 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
3532 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
3533 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
3534 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
3535 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
3536 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ICE_RESTART);
3537 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RESEND_TRICKLES);
3538 
3539 	/* Note: in case this is not an OFFER, we don't know whether any medium are supported on the other side or not yet */
3540 	if(audio) {
3541 		janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
3542 	} else {
3543 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
3544 	}
3545 	if(video) {
3546 		janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
3547 	} else {
3548 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
3549 	}
3550 	if(data) {
3551 		janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS);
3552 	} else {
3553 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS);
3554 	}
3555 	/* Note: in case this is not an OFFER, we don't know whether ICE trickling is supported on the other side or not yet */
3556 	if(offer && trickle) {
3557 		janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE);
3558 	} else {
3559 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE);
3560 	}
3561 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES);
3562 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE_SYNCED);
3563 
3564 	/* Note: NICE_COMPATIBILITY_RFC5245 is only available in more recent versions of libnice */
3565 	handle->controlling = janus_ice_lite_enabled ? FALSE : !offer;
3566 	JANUS_LOG(LOG_INFO, "[%"SCNu64"] Creating ICE agent (ICE %s mode, %s)\n", handle->handle_id,
3567 		janus_ice_lite_enabled ? "Lite" : "Full", handle->controlling ? "controlling" : "controlled");
3568 	handle->agent = g_object_new(NICE_TYPE_AGENT,
3569 		"compatibility", NICE_COMPATIBILITY_DRAFT19,
3570 		"main-context", handle->mainctx,
3571 		"reliable", FALSE,
3572 		"full-mode", janus_ice_lite_enabled ? FALSE : TRUE,
3573 #ifdef HAVE_ICE_NOMINATION
3574 		"nomination-mode", janus_ice_nomination,
3575 #endif
3576 		"keepalive-conncheck", janus_ice_keepalive_connchecks ? TRUE : FALSE,
3577 #ifdef HAVE_LIBNICE_TCP
3578 		"ice-udp", TRUE,
3579 		"ice-tcp", janus_ice_tcp_enabled ? TRUE : FALSE,
3580 #endif
3581 		NULL);
3582 	handle->agent_created = janus_get_monotonic_time();
3583 	handle->srtp_errors_count = 0;
3584 	handle->last_srtp_error = 0;
3585 	/* Any STUN server to use? */
3586 	if(janus_stun_server != NULL && janus_stun_port > 0) {
3587 		g_object_set(G_OBJECT(handle->agent),
3588 			"stun-server", janus_stun_server,
3589 			"stun-server-port", janus_stun_port,
3590 			NULL);
3591 	}
3592 	/* Any dynamic TURN credentials to retrieve via REST API? */
3593 	gboolean have_turnrest_credentials = FALSE;
3594 #ifdef HAVE_TURNRESTAPI
3595 	/* When using the TURN REST API, we use the handle's opaque_id as a username
3596 	 * by default, and fall back to the session_id when it's missing. Refer to this
3597 	 * issue for more context: https://github.com/meetecho/janus-gateway/issues/2199 */
3598 	char turnrest_username[20];
3599 	if(handle->opaque_id == NULL) {
3600 		janus_session *session = (janus_session *)handle->session;
3601 		g_snprintf(turnrest_username, sizeof(turnrest_username), "%"SCNu64, session->session_id);
3602 	}
3603 	janus_turnrest_response *turnrest_credentials = janus_turnrest_request((const char *)(handle->opaque_id ?
3604 		handle->opaque_id : turnrest_username));
3605 	if(turnrest_credentials != NULL) {
3606 		have_turnrest_credentials = TRUE;
3607 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got credentials from the TURN REST API backend!\n", handle->handle_id);
3608 		JANUS_LOG(LOG_HUGE, "  -- Username: %s\n", turnrest_credentials->username);
3609 		JANUS_LOG(LOG_HUGE, "  -- Password: %s\n", turnrest_credentials->password);
3610 		JANUS_LOG(LOG_HUGE, "  -- TTL:      %"SCNu32"\n", turnrest_credentials->ttl);
3611 		JANUS_LOG(LOG_HUGE, "  -- Servers:  %d\n", g_list_length(turnrest_credentials->servers));
3612 		GList *server = turnrest_credentials->servers;
3613 		while(server != NULL) {
3614 			janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
3615 			JANUS_LOG(LOG_HUGE, "  -- -- URI: %s:%"SCNu16" (%d)\n", instance->server, instance->port, instance->transport);
3616 			server = server->next;
3617 		}
3618 	}
3619 #endif
3620 	g_object_set(G_OBJECT(handle->agent), "upnp", FALSE, NULL);
3621 	g_object_set(G_OBJECT(handle->agent), "controlling-mode", handle->controlling, NULL);
3622 	g_signal_connect (G_OBJECT (handle->agent), "candidate-gathering-done",
3623 		G_CALLBACK (janus_ice_cb_candidate_gathering_done), handle);
3624 	g_signal_connect (G_OBJECT (handle->agent), "component-state-changed",
3625 		G_CALLBACK (janus_ice_cb_component_state_changed), handle);
3626 #ifndef HAVE_LIBNICE_TCP
3627 	g_signal_connect (G_OBJECT (handle->agent), "new-selected-pair",
3628 #else
3629 	g_signal_connect (G_OBJECT (handle->agent), "new-selected-pair-full",
3630 #endif
3631 		G_CALLBACK (janus_ice_cb_new_selected_pair), handle);
3632 	if(janus_full_trickle_enabled) {
3633 #ifndef HAVE_LIBNICE_TCP
3634 		g_signal_connect (G_OBJECT (handle->agent), "new-candidate",
3635 #else
3636 		g_signal_connect (G_OBJECT (handle->agent), "new-candidate-full",
3637 #endif
3638 			G_CALLBACK (janus_ice_cb_new_local_candidate), handle);
3639 	}
3640 #ifndef HAVE_LIBNICE_TCP
3641 	g_signal_connect (G_OBJECT (handle->agent), "new-remote-candidate",
3642 #else
3643 	g_signal_connect (G_OBJECT (handle->agent), "new-remote-candidate-full",
3644 #endif
3645 		G_CALLBACK (janus_ice_cb_new_remote_candidate), handle);
3646 
3647 	/* Add all local addresses, except those in the ignore list */
3648 	struct ifaddrs *ifaddr, *ifa;
3649 	int family, s, n;
3650 	char host[NI_MAXHOST];
3651 	if(getifaddrs(&ifaddr) == -1) {
3652 		JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error getting list of interfaces... %d (%s)\n",
3653 			handle->handle_id, errno, g_strerror(errno));
3654 	} else {
3655 		for(ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
3656 			if(ifa->ifa_addr == NULL)
3657 				continue;
3658 			/* Skip interfaces which are not up and running */
3659 			if(!((ifa->ifa_flags & IFF_UP) && (ifa->ifa_flags & IFF_RUNNING)))
3660 				continue;
3661 			/* Skip loopback interfaces */
3662 			if(ifa->ifa_flags & IFF_LOOPBACK)
3663 				continue;
3664 			family = ifa->ifa_addr->sa_family;
3665 			if(family != AF_INET && family != AF_INET6)
3666 				continue;
3667 			/* We only add IPv6 addresses if support for them has been explicitly enabled */
3668 			if(family == AF_INET6 && !janus_ipv6_enabled)
3669 				continue;
3670 			/* Check the interface name first, we can ignore that as well: enforce list would be checked later */
3671 			if(janus_ice_enforce_list == NULL && ifa->ifa_name != NULL && janus_ice_is_ignored(ifa->ifa_name))
3672 				continue;
3673 			s = getnameinfo(ifa->ifa_addr,
3674 					(family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
3675 					host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
3676 			if(s != 0) {
3677 				JANUS_LOG(LOG_ERR, "[%"SCNu64"] getnameinfo() failed: %s\n", handle->handle_id, gai_strerror(s));
3678 				continue;
3679 			}
3680 			/* Skip 0.0.0.0, :: and, unless otherwise configured, local scoped addresses  */
3681 			if(!strcmp(host, "0.0.0.0") || !strcmp(host, "::") || (!janus_ipv6_linklocal_enabled && !strncmp(host, "fe80:", 5)))
3682 				continue;
3683 			/* Check if this IP address is in the ignore/enforce list: the enforce list has the precedence but the ignore list can then discard candidates */
3684 			if(janus_ice_enforce_list != NULL) {
3685 				if(ifa->ifa_name != NULL && !janus_ice_is_enforced(ifa->ifa_name) && !janus_ice_is_enforced(host))
3686 					continue;
3687 			}
3688 			if(janus_ice_is_ignored(host))
3689 				continue;
3690 			/* Ok, add interface to the ICE agent */
3691 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Adding %s to the addresses to gather candidates for\n", handle->handle_id, host);
3692 			NiceAddress addr_local;
3693 			nice_address_init (&addr_local);
3694 			if(!nice_address_set_from_string (&addr_local, host)) {
3695 				JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping invalid address %s\n", handle->handle_id, host);
3696 				continue;
3697 			}
3698 			nice_agent_add_local_address (handle->agent, &addr_local);
3699 		}
3700 		freeifaddrs(ifaddr);
3701 	}
3702 
3703 	handle->cdone = 0;
3704 	handle->stream_id = 0;
3705 	/* If this is our first offer, let's generate some mids */
3706 	if(!offer) {
3707 		if(audio) {
3708 			if(handle->audio_mid == NULL)
3709 				handle->audio_mid = g_strdup("audio");
3710 			if(handle->stream_mid == NULL)
3711 				handle->stream_mid = handle->audio_mid;
3712 		}
3713 		if(video) {
3714 			if(handle->video_mid == NULL)
3715 				handle->video_mid = g_strdup("video");
3716 			if(handle->stream_mid == NULL)
3717 				handle->stream_mid = handle->video_mid;
3718 		}
3719 #ifdef HAVE_SCTP
3720 		if(data) {
3721 			if(handle->data_mid == NULL)
3722 				handle->data_mid = g_strdup("data");
3723 			if(handle->stream_mid == NULL)
3724 				handle->stream_mid = handle->data_mid;
3725 		}
3726 #endif
3727 	}
3728 	/* Now create an ICE stream for all the media we'll handle */
3729 	handle->stream_id = nice_agent_add_stream(handle->agent, 1);
3730 	if(dscp_ef > 0) {
3731 		/* A DSCP value was configured, shift it and pass it to libnice as a TOS */
3732 		nice_agent_set_stream_tos(handle->agent, handle->stream_id, dscp_ef << 2);
3733 	}
3734 	janus_ice_stream *stream = g_malloc0(sizeof(janus_ice_stream));
3735 	janus_refcount_init(&stream->ref, janus_ice_stream_free);
3736 	janus_refcount_increase(&handle->ref);
3737 	stream->stream_id = handle->stream_id;
3738 	stream->handle = handle;
3739 	stream->audio_payload_type = -1;
3740 	stream->video_payload_type = -1;
3741 	stream->video_rtx_payload_type = -1;
3742 	stream->nack_queue_ms = min_nack_queue;
3743 	/* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
3744 	stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
3745 	if(audio) {
3746 		stream->audio_ssrc = janus_random_uint32();	/* FIXME Should we look for conflicts? */
3747 		stream->audio_rtcp_ctx = g_malloc0(sizeof(janus_rtcp_context));
3748 		stream->audio_rtcp_ctx->tb = 48000;	/* May change later */
3749 	}
3750 	if(video) {
3751 		stream->video_ssrc = janus_random_uint32();	/* FIXME Should we look for conflicts? */
3752 		if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX)) {
3753 			/* Create an SSRC for RFC4588 as well */
3754 			stream->video_ssrc_rtx = janus_random_uint32();	/* FIXME Should we look for conflicts? */
3755 		}
3756 		stream->video_rtcp_ctx[0] = g_malloc0(sizeof(janus_rtcp_context));
3757 		stream->video_rtcp_ctx[0]->tb = 90000;
3758 	}
3759 	janus_mutex_init(&stream->mutex);
3760 	if(!have_turnrest_credentials) {
3761 		/* No TURN REST API server and credentials, any static ones? */
3762 		if(janus_turn_server != NULL) {
3763 			/* We need relay candidates as well */
3764 			gboolean ok = nice_agent_set_relay_info(handle->agent, handle->stream_id, 1,
3765 				janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
3766 			if(!ok) {
3767 				JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
3768 					janus_turn_server, janus_turn_port);
3769 			}
3770 		}
3771 #ifdef HAVE_TURNRESTAPI
3772 	} else {
3773 		/* We need relay candidates as well: add all those we got */
3774 		GList *server = turnrest_credentials->servers;
3775 		while(server != NULL) {
3776 			janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
3777 			gboolean ok = nice_agent_set_relay_info(handle->agent, handle->stream_id, 1,
3778 				instance->server, instance->port,
3779 				turnrest_credentials->username, turnrest_credentials->password,
3780 				instance->transport);
3781 			if(!ok) {
3782 				JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
3783 					instance->server, instance->port);
3784 			}
3785 			server = server->next;
3786 		}
3787 #endif
3788 	}
3789 	handle->stream = stream;
3790 	janus_ice_component *component = g_malloc0(sizeof(janus_ice_component));
3791 	janus_refcount_init(&component->ref, janus_ice_component_free);
3792 	component->stream = stream;
3793 	janus_refcount_increase(&stream->ref);
3794 	component->stream_id = stream->stream_id;
3795 	component->component_id = 1;
3796 	janus_mutex_init(&component->mutex);
3797 	stream->component = component;
3798 #ifdef HAVE_PORTRANGE
3799 	/* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
3800 	nice_agent_set_port_range(handle->agent, handle->stream_id, 1, rtp_range_min, rtp_range_max);
3801 #endif
3802 	/* Gather now only if we're doing hanf-trickle */
3803 	if(!janus_full_trickle_enabled && !nice_agent_gather_candidates(handle->agent, handle->stream_id)) {
3804 #ifdef HAVE_TURNRESTAPI
3805 		if(turnrest_credentials != NULL) {
3806 			janus_turnrest_response_destroy(turnrest_credentials);
3807 			turnrest_credentials = NULL;
3808 		}
3809 #endif
3810 		JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error gathering candidates...\n", handle->handle_id);
3811 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AGENT);
3812 		janus_ice_webrtc_hangup(handle, "Gathering error");
3813 		return -1;
3814 	}
3815 	nice_agent_attach_recv(handle->agent, handle->stream_id, 1, g_main_loop_get_context(handle->mainloop),
3816 		janus_ice_cb_nice_recv, component);
3817 #ifdef HAVE_TURNRESTAPI
3818 	if(turnrest_credentials != NULL) {
3819 		janus_turnrest_response_destroy(turnrest_credentials);
3820 		turnrest_credentials = NULL;
3821 	}
3822 #endif
3823 	/* Create DTLS-SRTP context, at last */
3824 	component->dtls = janus_dtls_srtp_create(component, stream->dtls_role);
3825 	if(!component->dtls) {
3826 		/* FIXME We should clear some resources... */
3827 		JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating DTLS-SRTP stack...\n", handle->handle_id);
3828 		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AGENT);
3829 		janus_ice_webrtc_hangup(handle, "DTLS-SRTP stack error");
3830 		return -1;
3831 	}
3832 	janus_refcount_increase(&component->dtls->ref);
3833 	/* If we're doing full-tricke, start gathering asynchronously */
3834 	if(janus_full_trickle_enabled) {
3835 #if GLIB_CHECK_VERSION(2, 46, 0)
3836 		g_async_queue_push_front(handle->queued_packets, &janus_ice_start_gathering);
3837 #else
3838 		g_async_queue_push(handle->queued_packets, &janus_ice_start_gathering);
3839 #endif
3840 		g_main_context_wakeup(handle->mainctx);
3841 	}
3842 	return 0;
3843 }
3844 
3845 void janus_ice_restart(janus_ice_handle *handle) {
3846 	if(!handle || !handle->agent || !handle->stream)
3847 		return;
3848 	/* Restart ICE */
3849 	if(nice_agent_restart(handle->agent) == FALSE) {
3850 		JANUS_LOG(LOG_WARN, "[%"SCNu64"] ICE restart failed...\n", handle->handle_id);
3851 	}
3852 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ICE_RESTART);
3853 }
3854 
3855 void janus_ice_resend_trickles(janus_ice_handle *handle) {
3856 	if(!handle || !handle->agent)
3857 		return;
3858 	janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RESEND_TRICKLES);
3859 	janus_ice_stream *stream = handle->stream;
3860 	if(!stream)
3861 		return;
3862 	janus_ice_component *component = stream->component;
3863 	if(!component)
3864 		return;
3865 	NiceAgent *agent = handle->agent;
3866 	/* Iterate on all existing local candidates */
3867 	gchar buffer[200];
3868 	GSList *candidates, *i;
3869 	candidates = nice_agent_get_local_candidates (agent, stream->stream_id, component->component_id);
3870 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] We have %d candidates for Stream #%d, Component #%d\n",
3871 		handle->handle_id, g_slist_length(candidates), stream->stream_id, component->component_id);
3872 	for(i = candidates; i; i = i->next) {
3873 		NiceCandidate *c = (NiceCandidate *) i->data;
3874 		if(c->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
3875 			nice_candidate_free(c);
3876 			continue;
3877 		}
3878 
3879 		guint public_ip_index = 0;
3880 		do {
3881 			if(janus_ice_candidate_to_string(handle, c, buffer, sizeof(buffer), FALSE, FALSE, public_ip_index) == 0) {
3882 				/* Candidate encoded, send a "trickle" event to the browser */
3883 				janus_ice_notify_trickle(handle, buffer);
3884 				/* If nat-1-1 is enabled but we want to keep the private host, add another candidate */
3885 				if(nat_1_1_enabled && keep_private_host && public_ip_index == 0 &&
3886 						janus_ice_candidate_to_string(handle, c, buffer, sizeof(buffer), FALSE, TRUE, public_ip_index) == 0) {
3887 					/* Candidate encoded, send a "trickle" event to the browser */
3888 					janus_ice_notify_trickle(handle, buffer);
3889 				}
3890 			}
3891 			public_ip_index++;
3892 		} while (public_ip_index < janus_get_public_ip_count());
3893 		nice_candidate_free(c);
3894 	}
3895 	/* Send a "completed" trickle at the end */
3896 	janus_ice_notify_trickle(handle, NULL);
3897 }
3898 
3899 static gint rtcp_transport_wide_cc_stats_comparator(gconstpointer item1, gconstpointer item2) {
3900 	return ((rtcp_transport_wide_cc_stats*)item1)->transport_seq_num - ((rtcp_transport_wide_cc_stats*)item2)->transport_seq_num;
3901 }
3902 static gboolean janus_ice_outgoing_transport_wide_cc_feedback(gpointer user_data) {
3903 	janus_ice_handle *handle = (janus_ice_handle *)user_data;
3904 	janus_ice_stream *stream = handle->stream;
3905 	if(stream && stream->video_recv && stream->do_transport_wide_cc) {
3906 		/* Create a transport wide feedback message */
3907 		size_t size = 1300;
3908 		char rtcpbuf[1300];
3909 		/* Order packet list */
3910 		stream->transport_wide_received_seq_nums = g_slist_sort(stream->transport_wide_received_seq_nums,
3911 			rtcp_transport_wide_cc_stats_comparator);
3912 		/* Create full stats queue */
3913 		GQueue *packets = g_queue_new();
3914 		/* For all packets */
3915 		GSList *it = NULL;
3916 		for(it = stream->transport_wide_received_seq_nums; it; it = it->next) {
3917 			/* Get stat */
3918 			janus_rtcp_transport_wide_cc_stats *stats = (janus_rtcp_transport_wide_cc_stats *)it->data;
3919 			/* Get transport seq */
3920 			guint32 transport_seq_num = stats->transport_seq_num;
3921 			/* Check if it is an out of order  */
3922 			if(transport_seq_num < stream->transport_wide_cc_last_feedback_seq_num) {
3923 				/* Skip, it was already reported as lost */
3924 				g_free(stats);
3925 				continue;
3926 			}
3927 			/* If not first */
3928 			if(stream->transport_wide_cc_last_feedback_seq_num) {
3929 				/* For each lost */
3930 				guint32 i = 0;
3931 				for(i = stream->transport_wide_cc_last_feedback_seq_num+1; i<transport_seq_num; ++i) {
3932 					/* Create new stat */
3933 					janus_rtcp_transport_wide_cc_stats *missing = g_malloc(sizeof(janus_rtcp_transport_wide_cc_stats));
3934 					/* Add missing packet */
3935 					missing->transport_seq_num = i;
3936 					missing->timestamp = 0;
3937 					/* Add it */
3938 					g_queue_push_tail(packets, missing);
3939 				}
3940 			}
3941 			/* Store last */
3942 			stream->transport_wide_cc_last_feedback_seq_num = transport_seq_num;
3943 			/* Add this one */
3944 			g_queue_push_tail(packets, stats);
3945 		}
3946 		/* Free and reset stats list */
3947 		g_slist_free(stream->transport_wide_received_seq_nums);
3948 		stream->transport_wide_received_seq_nums = NULL;
3949 		/* Create and enqueue RTCP packets */
3950 		guint packets_len = 0;
3951 		while((packets_len = g_queue_get_length(packets)) > 0) {
3952 			GQueue *packets_to_process;
3953 			/* If we have more than 400 packets to acknowledge, let's send more than one message */
3954 			if(packets_len > 400) {
3955 				/* Split the queue into two */
3956 				GList *new_head = g_queue_peek_nth_link(packets, 400);
3957 				GList *new_tail = new_head->prev;
3958 				new_head->prev = NULL;
3959 				new_tail->next = NULL;
3960 				packets_to_process = g_queue_new();
3961 				packets_to_process->head = packets->head;
3962 				packets_to_process->tail = new_tail;
3963 				packets_to_process->length = 400;
3964 				packets->head = new_head;
3965 				/* packets->tail is unchanged */
3966 				packets->length = packets_len - 400;
3967 			} else {
3968 				packets_to_process = packets;
3969 			}
3970 			/* Get feedback packet count and increase it for next one */
3971 			guint8 feedback_packet_count = stream->transport_wide_cc_feedback_count++;
3972 			/* Create RTCP packet */
3973 			int len = janus_rtcp_transport_wide_cc_feedback(rtcpbuf, size,
3974 				stream->video_ssrc, stream->video_ssrc_peer[0], feedback_packet_count, packets_to_process);
3975 			/* Enqueue it, we'll send it later */
3976 			if(len > 0) {
3977 				janus_plugin_rtcp rtcp = { .video = TRUE, .buffer = rtcpbuf, .length = len };
3978 				janus_ice_relay_rtcp_internal(handle, &rtcp, FALSE);
3979 			}
3980 			if(packets_to_process != packets) {
3981 				g_queue_free(packets_to_process);
3982 			}
3983 		}
3984 		/* Free mem */
3985 		g_queue_free(packets);
3986 	}
3987 	return G_SOURCE_CONTINUE;
3988 }
3989 
3990 static gboolean janus_ice_outgoing_rtcp_handle(gpointer user_data) {
3991 	janus_ice_handle *handle = (janus_ice_handle *)user_data;
3992 	janus_ice_stream *stream = handle->stream;
3993 	/* Audio */
3994 	if(stream && stream->audio_send && stream->component && stream->component->out_stats.audio.packets > 0) {
3995 		/* Create a SR/SDES compound */
3996 		int srlen = 28;
3997 		int sdeslen = 16;
3998 		char rtcpbuf[sizeof(janus_rtcp_sr)+sdeslen];
3999 		memset(rtcpbuf, 0, sizeof(rtcpbuf));
4000 		rtcp_sr *sr = (rtcp_sr *)&rtcpbuf;
4001 		sr->header.version = 2;
4002 		sr->header.type = RTCP_SR;
4003 		sr->header.rc = 0;
4004 		sr->header.length = htons((srlen/4)-1);
4005 		sr->ssrc = htonl(stream->audio_ssrc);
4006 		struct timeval tv;
4007 		gettimeofday(&tv, NULL);
4008 		uint32_t s = tv.tv_sec + 2208988800u;
4009 		uint32_t u = tv.tv_usec;
4010 		uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6);
4011 		sr->si.ntp_ts_msw = htonl(s);
4012 		sr->si.ntp_ts_lsw = htonl(f);
4013 		/* Compute an RTP timestamp coherent with the NTP one */
4014 		rtcp_context *rtcp_ctx = stream->audio_rtcp_ctx;
4015 		if(rtcp_ctx == NULL) {
4016 			sr->si.rtp_ts = htonl(stream->audio_last_rtp_ts);	/* FIXME */
4017 		} else {
4018 			int64_t ntp = tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
4019 			uint32_t rtp_ts = ((ntp-stream->audio_last_ntp_ts)*(rtcp_ctx->tb))/1000000 + stream->audio_last_rtp_ts;
4020 			sr->si.rtp_ts = htonl(rtp_ts);
4021 		}
4022 		sr->si.s_packets = htonl(stream->component->out_stats.audio.packets);
4023 		sr->si.s_octets = htonl(stream->component->out_stats.audio.bytes);
4024 		rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[srlen];
4025 		janus_rtcp_sdes_cname((char *)sdes, sdeslen, "janus", 5);
4026 		sdes->chunk.ssrc = htonl(stream->audio_ssrc);
4027 		/* Enqueue it, we'll send it later */
4028 		janus_plugin_rtcp rtcp = { .video = FALSE, .buffer = rtcpbuf, .length = srlen+sdeslen };
4029 		janus_ice_relay_rtcp_internal(handle, &rtcp, FALSE);
4030 		/* Check if we detected too many losses, and send a slowlink event in case */
4031 		guint lost = janus_rtcp_context_get_lost_all(rtcp_ctx, TRUE);
4032 		janus_slow_link_update(stream->component, handle, FALSE, TRUE, lost);
4033 	}
4034 	if(stream && stream->audio_recv) {
4035 		/* Create a RR too */
4036 		int rrlen = 32;
4037 		char rtcpbuf[32];
4038 		memset(rtcpbuf, 0, sizeof(rtcpbuf));
4039 		rtcp_rr *rr = (rtcp_rr *)&rtcpbuf;
4040 		rr->header.version = 2;
4041 		rr->header.type = RTCP_RR;
4042 		rr->header.rc = 1;
4043 		rr->header.length = htons((rrlen/4)-1);
4044 		rr->ssrc = htonl(stream->audio_ssrc);
4045 		janus_rtcp_report_block(stream->audio_rtcp_ctx, &rr->rb[0]);
4046 		rr->rb[0].ssrc = htonl(stream->audio_ssrc_peer);
4047 		/* Enqueue it, we'll send it later */
4048 		janus_plugin_rtcp rtcp = { .video = FALSE, .buffer = rtcpbuf, .length = 32 };
4049 		janus_ice_relay_rtcp_internal(handle, &rtcp, FALSE);
4050 		/* Check if we detected too many losses, and send a slowlink event in case */
4051 		guint lost = janus_rtcp_context_get_lost_all(stream->audio_rtcp_ctx, FALSE);
4052 		janus_slow_link_update(stream->component, handle, FALSE, FALSE, lost);
4053 	}
4054 	/* Now do the same for video */
4055 	if(stream && stream->video_send && stream->component && stream->component->out_stats.video[0].packets > 0) {
4056 		/* Create a SR/SDES compound */
4057 		int srlen = 28;
4058 		int sdeslen = 16;
4059 		char rtcpbuf[sizeof(janus_rtcp_sr)+sdeslen];
4060 		memset(rtcpbuf, 0, sizeof(rtcpbuf));
4061 		rtcp_sr *sr = (rtcp_sr *)&rtcpbuf;
4062 		sr->header.version = 2;
4063 		sr->header.type = RTCP_SR;
4064 		sr->header.rc = 0;
4065 		sr->header.length = htons((srlen/4)-1);
4066 		sr->ssrc = htonl(stream->video_ssrc);
4067 		struct timeval tv;
4068 		gettimeofday(&tv, NULL);
4069 		uint32_t s = tv.tv_sec + 2208988800u;
4070 		uint32_t u = tv.tv_usec;
4071 		uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6);
4072 		sr->si.ntp_ts_msw = htonl(s);
4073 		sr->si.ntp_ts_lsw = htonl(f);
4074 		/* Compute an RTP timestamp coherent with the NTP one */
4075 		rtcp_context *rtcp_ctx = stream->video_rtcp_ctx[0];
4076 		if(rtcp_ctx == NULL) {
4077 			sr->si.rtp_ts = htonl(stream->video_last_rtp_ts);	/* FIXME */
4078 		} else {
4079 			int64_t ntp = tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
4080 			uint32_t rtp_ts = ((ntp-stream->video_last_ntp_ts)*(rtcp_ctx->tb))/1000000 + stream->video_last_rtp_ts;
4081 			sr->si.rtp_ts = htonl(rtp_ts);
4082 		}
4083 		sr->si.s_packets = htonl(stream->component->out_stats.video[0].packets);
4084 		sr->si.s_octets = htonl(stream->component->out_stats.video[0].bytes);
4085 		rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[srlen];
4086 		janus_rtcp_sdes_cname((char *)sdes, sdeslen, "janus", 5);
4087 		sdes->chunk.ssrc = htonl(stream->video_ssrc);
4088 		/* Enqueue it, we'll send it later */
4089 		janus_plugin_rtcp rtcp = { .video = TRUE, .buffer = rtcpbuf, .length = srlen+sdeslen };
4090 		janus_ice_relay_rtcp_internal(handle, &rtcp, FALSE);
4091 		/* Check if we detected too many losses, and send a slowlink event in case */
4092 		guint lost = janus_rtcp_context_get_lost_all(rtcp_ctx, TRUE);
4093 		janus_slow_link_update(stream->component, handle, TRUE, TRUE, lost);
4094 	}
4095 	if(stream && stream->video_recv) {
4096 		/* Create a RR too (for each SSRC, if we're simulcasting) */
4097 		int vindex=0;
4098 		for(vindex=0; vindex<3; vindex++) {
4099 			if(stream->video_rtcp_ctx[vindex] && stream->video_rtcp_ctx[vindex]->rtp_recvd) {
4100 				/* Create a RR */
4101 				int rrlen = 32;
4102 				char rtcpbuf[32];
4103 				memset(rtcpbuf, 0, sizeof(rtcpbuf));
4104 				rtcp_rr *rr = (rtcp_rr *)&rtcpbuf;
4105 				rr->header.version = 2;
4106 				rr->header.type = RTCP_RR;
4107 				rr->header.rc = 1;
4108 				rr->header.length = htons((rrlen/4)-1);
4109 				rr->ssrc = htonl(stream->video_ssrc);
4110 				janus_rtcp_report_block(stream->video_rtcp_ctx[vindex], &rr->rb[0]);
4111 				rr->rb[0].ssrc = htonl(stream->video_ssrc_peer[vindex]);
4112 				/* Enqueue it, we'll send it later */
4113 				janus_plugin_rtcp rtcp = { .video = TRUE, .buffer = rtcpbuf, .length = 32 };
4114 				janus_ice_relay_rtcp_internal(handle, &rtcp, FALSE);
4115 			}
4116 		}
4117 		/* Check if we detected too many losses, and send a slowlink event in case */
4118 		guint lost = janus_rtcp_context_get_lost_all(stream->video_rtcp_ctx[0], FALSE);
4119 		janus_slow_link_update(stream->component, handle, TRUE, FALSE, lost);
4120 	}
4121 	if(twcc_period == 1000) {
4122 		/* The Transport Wide CC feedback period is 1s as well, send it here */
4123 		janus_ice_outgoing_transport_wide_cc_feedback(handle);
4124 	}
4125 	return G_SOURCE_CONTINUE;
4126 }
4127 
4128 static gboolean janus_ice_outgoing_stats_handle(gpointer user_data) {
4129 	janus_ice_handle *handle = (janus_ice_handle *)user_data;
4130 	/* This callback is for stats and other things we need to do on a regular basis (typically called once per second) */
4131 	janus_session *session = (janus_session *)handle->session;
4132 	gint64 now = janus_get_monotonic_time();
4133 	/* Reset the last second counters if too much time passed with no data in or out */
4134 	janus_ice_stream *stream = handle->stream;
4135 	if(stream == NULL || stream->component == NULL)
4136 		return G_SOURCE_CONTINUE;
4137 	janus_ice_component *component = stream->component;
4138 	/* Audio */
4139 	gint64 last = component->in_stats.audio.updated;
4140 	if(last && now > last && now-last >= 2*G_USEC_PER_SEC && component->in_stats.audio.bytes_lastsec_temp > 0) {
4141 		component->in_stats.audio.bytes_lastsec = 0;
4142 		component->in_stats.audio.bytes_lastsec_temp = 0;
4143 	}
4144 	last = component->out_stats.audio.updated;
4145 	if(last && now > last && now-last >= 2*G_USEC_PER_SEC && component->out_stats.audio.bytes_lastsec_temp > 0) {
4146 		component->out_stats.audio.bytes_lastsec = 0;
4147 		component->out_stats.audio.bytes_lastsec_temp = 0;
4148 	}
4149 	/* Video */
4150 	int vindex = 0;
4151 	for(vindex=0; vindex < 3; vindex++) {
4152 		gint64 last = component->in_stats.video[vindex].updated;
4153 		if(last && now > last && now-last >= 2*G_USEC_PER_SEC && component->in_stats.video[vindex].bytes_lastsec_temp > 0) {
4154 			component->in_stats.video[vindex].bytes_lastsec = 0;
4155 			component->in_stats.video[vindex].bytes_lastsec_temp = 0;
4156 		}
4157 		last = component->out_stats.video[vindex].updated;
4158 		if(last && now > last && now-last >= 2*G_USEC_PER_SEC && component->out_stats.video[vindex].bytes_lastsec_temp > 0) {
4159 			component->out_stats.video[vindex].bytes_lastsec = 0;
4160 			component->out_stats.video[vindex].bytes_lastsec_temp = 0;
4161 		}
4162 	}
4163 	/* Now let's see if we need to notify the user about no incoming audio or video */
4164 	if(no_media_timer > 0 && component->dtls && component->dtls->dtls_connected > 0 && (now - component->dtls->dtls_connected >= G_USEC_PER_SEC)) {
4165 		/* Audio */
4166 		gint64 last = component->in_stats.audio.updated;
4167 		if(!component->in_stats.audio.notified_lastsec && last &&
4168 				!component->in_stats.audio.bytes_lastsec && !component->in_stats.audio.bytes_lastsec_temp &&
4169 					now-last >= (gint64)no_media_timer*G_USEC_PER_SEC) {
4170 			/* We missed more than no_second_timer seconds of audio! */
4171 			component->in_stats.audio.notified_lastsec = TRUE;
4172 			JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive audio for more than %d seconds...\n", handle->handle_id, no_media_timer);
4173 			janus_ice_notify_media(handle, FALSE, 0, FALSE);
4174 		}
4175 		/* Video */
4176 		int vindex=0;
4177 		for(vindex=0; vindex<3; vindex++) {
4178 			last = component->in_stats.video[vindex].updated;
4179 			if(!component->in_stats.video[vindex].notified_lastsec && last &&
4180 					!component->in_stats.video[vindex].bytes_lastsec && !component->in_stats.video[vindex].bytes_lastsec_temp &&
4181 						now-last >= (gint64)no_media_timer*G_USEC_PER_SEC) {
4182 				/* We missed more than no_second_timer seconds of this video stream! */
4183 				component->in_stats.video[vindex].notified_lastsec = TRUE;
4184 				JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive video #%d for more than a second...\n", handle->handle_id, vindex);
4185 				janus_ice_notify_media(handle, TRUE, vindex, FALSE);
4186 			}
4187 		}
4188 	}
4189 	/* We also send live stats to event handlers every tot-seconds (configurable) */
4190 	handle->last_event_stats++;
4191 	if(janus_ice_event_stats_period > 0 && handle->last_event_stats >= janus_ice_event_stats_period) {
4192 		handle->last_event_stats = 0;
4193 		json_t *combined_event = NULL;
4194 		/* Shall janus send dedicated events per media or one per peerConnection */
4195 		if(janus_events_is_enabled() && janus_ice_event_get_combine_media_stats())
4196 			combined_event = json_array();
4197 		/* Audio */
4198 		if(janus_events_is_enabled() && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO)) {
4199 			if(stream && stream->audio_rtcp_ctx) {
4200 				json_t *info = json_object();
4201 				json_object_set_new(info, "media", json_string("audio"));
4202 				json_object_set_new(info, "base", json_integer(stream->audio_rtcp_ctx->tb));
4203 				json_object_set_new(info, "rtt", json_integer(janus_rtcp_context_get_rtt(stream->audio_rtcp_ctx)));
4204 				json_object_set_new(info, "lost", json_integer(janus_rtcp_context_get_lost_all(stream->audio_rtcp_ctx, FALSE)));
4205 				json_object_set_new(info, "lost-by-remote", json_integer(janus_rtcp_context_get_lost_all(stream->audio_rtcp_ctx, TRUE)));
4206 				json_object_set_new(info, "jitter-local", json_integer(janus_rtcp_context_get_jitter(stream->audio_rtcp_ctx, FALSE)));
4207 				json_object_set_new(info, "jitter-remote", json_integer(janus_rtcp_context_get_jitter(stream->audio_rtcp_ctx, TRUE)));
4208 				json_object_set_new(info, "in-link-quality", json_integer(janus_rtcp_context_get_in_link_quality(stream->audio_rtcp_ctx)));
4209 				json_object_set_new(info, "in-media-link-quality", json_integer(janus_rtcp_context_get_in_media_link_quality(stream->audio_rtcp_ctx)));
4210 				json_object_set_new(info, "out-link-quality", json_integer(janus_rtcp_context_get_out_link_quality(stream->audio_rtcp_ctx)));
4211 				json_object_set_new(info, "out-media-link-quality", json_integer(janus_rtcp_context_get_out_media_link_quality(stream->audio_rtcp_ctx)));
4212 				if(stream->component) {
4213 					json_object_set_new(info, "packets-received", json_integer(stream->component->in_stats.audio.packets));
4214 					json_object_set_new(info, "packets-sent", json_integer(stream->component->out_stats.audio.packets));
4215 					json_object_set_new(info, "bytes-received", json_integer(stream->component->in_stats.audio.bytes));
4216 					json_object_set_new(info, "bytes-sent", json_integer(stream->component->out_stats.audio.bytes));
4217 					json_object_set_new(info, "bytes-received-lastsec", json_integer(stream->component->in_stats.audio.bytes_lastsec));
4218 					json_object_set_new(info, "bytes-sent-lastsec", json_integer(stream->component->out_stats.audio.bytes_lastsec));
4219 					json_object_set_new(info, "nacks-received", json_integer(stream->component->in_stats.audio.nacks));
4220 					json_object_set_new(info, "nacks-sent", json_integer(stream->component->out_stats.audio.nacks));
4221 					json_object_set_new(info, "retransmissions-received", json_integer(stream->audio_rtcp_ctx->retransmitted));
4222 				}
4223 				if(combined_event != NULL) {
4224 					json_array_append_new(combined_event, info);
4225 				} else {
4226 					janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, JANUS_EVENT_SUBTYPE_MEDIA_STATS,
4227 						session->session_id, handle->handle_id, handle->opaque_id, info);
4228 				}
4229 			}
4230 		}
4231 		/* Do the same for video */
4232 		if(janus_events_is_enabled() && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)) {
4233 			int vindex=0;
4234 			for(vindex=0; vindex<3; vindex++) {
4235 				if(stream && stream->video_rtcp_ctx[vindex]) {
4236 					json_t *info = json_object();
4237 					if(vindex == 0)
4238 						json_object_set_new(info, "media", json_string("video"));
4239 					else if(vindex == 1)
4240 						json_object_set_new(info, "media", json_string("video-sim1"));
4241 					else
4242 						json_object_set_new(info, "media", json_string("video-sim2"));
4243 					json_object_set_new(info, "base", json_integer(stream->video_rtcp_ctx[vindex]->tb));
4244 					if(vindex == 0)
4245 						json_object_set_new(info, "rtt", json_integer(janus_rtcp_context_get_rtt(stream->video_rtcp_ctx[vindex])));
4246 					json_object_set_new(info, "lost", json_integer(janus_rtcp_context_get_lost_all(stream->video_rtcp_ctx[vindex], FALSE)));
4247 					json_object_set_new(info, "lost-by-remote", json_integer(janus_rtcp_context_get_lost_all(stream->video_rtcp_ctx[vindex], TRUE)));
4248 					json_object_set_new(info, "jitter-local", json_integer(janus_rtcp_context_get_jitter(stream->video_rtcp_ctx[vindex], FALSE)));
4249 					json_object_set_new(info, "jitter-remote", json_integer(janus_rtcp_context_get_jitter(stream->video_rtcp_ctx[vindex], TRUE)));
4250 					json_object_set_new(info, "in-link-quality", json_integer(janus_rtcp_context_get_in_link_quality(stream->video_rtcp_ctx[vindex])));
4251 					json_object_set_new(info, "in-media-link-quality", json_integer(janus_rtcp_context_get_in_media_link_quality(stream->video_rtcp_ctx[vindex])));
4252 					json_object_set_new(info, "out-link-quality", json_integer(janus_rtcp_context_get_out_link_quality(stream->video_rtcp_ctx[vindex])));
4253 					json_object_set_new(info, "out-media-link-quality", json_integer(janus_rtcp_context_get_out_media_link_quality(stream->video_rtcp_ctx[vindex])));
4254 					if(vindex == 0 && stream->remb_bitrate > 0)
4255 						json_object_set_new(info, "remb-bitrate", json_integer(stream->remb_bitrate));
4256 					if(stream->component) {
4257 						json_object_set_new(info, "packets-received", json_integer(stream->component->in_stats.video[vindex].packets));
4258 						json_object_set_new(info, "packets-sent", json_integer(stream->component->out_stats.video[vindex].packets));
4259 						json_object_set_new(info, "bytes-received", json_integer(stream->component->in_stats.video[vindex].bytes));
4260 						json_object_set_new(info, "bytes-sent", json_integer(stream->component->out_stats.video[vindex].bytes));
4261 						json_object_set_new(info, "bytes-received-lastsec", json_integer(stream->component->in_stats.video[vindex].bytes_lastsec));
4262 						json_object_set_new(info, "bytes-sent-lastsec", json_integer(stream->component->out_stats.video[vindex].bytes_lastsec));
4263 						json_object_set_new(info, "nacks-received", json_integer(stream->component->in_stats.video[vindex].nacks));
4264 						json_object_set_new(info, "nacks-sent", json_integer(stream->component->out_stats.video[vindex].nacks));
4265 						json_object_set_new(info, "retransmissions-received", json_integer(stream->video_rtcp_ctx[vindex]->retransmitted));
4266 					}
4267 					if(combined_event) {
4268 						json_array_append_new(combined_event, info);
4269 					} else {
4270 						janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, JANUS_EVENT_SUBTYPE_MEDIA_STATS,
4271 							session->session_id, handle->handle_id, handle->opaque_id, info);
4272 					}
4273 				}
4274 			}
4275 			if(combined_event) {
4276 				janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, JANUS_EVENT_SUBTYPE_MEDIA_STATS,
4277 					session->session_id, handle->handle_id, handle->opaque_id, combined_event);
4278 			}
4279 		}
4280 	}
4281 	/* Should we clean up old NACK buffers for any of the streams? */
4282 	janus_cleanup_nack_buffer(now, handle->stream, TRUE, TRUE);
4283 	/* Check if we should also print a summary of SRTP-related errors */
4284 	handle->last_srtp_summary++;
4285 	if(handle->last_srtp_summary == 0 || handle->last_srtp_summary == 2) {
4286 		if(handle->srtp_errors_count > 0) {
4287 			JANUS_LOG(LOG_ERR, "[%"SCNu64"] Got %d SRTP/SRTCP errors in the last few seconds (last error: %s)\n",
4288 				handle->handle_id, handle->srtp_errors_count, janus_srtp_error_str(handle->last_srtp_error));
4289 			handle->srtp_errors_count = 0;
4290 			handle->last_srtp_error = 0;
4291 		}
4292 		handle->last_srtp_summary = 0;
4293 	}
4294 	return G_SOURCE_CONTINUE;
4295 }
4296 
4297 static gboolean janus_ice_outgoing_traffic_handle(janus_ice_handle *handle, janus_ice_queued_packet *pkt) {
4298 	janus_session *session = (janus_session *)handle->session;
4299 	janus_ice_stream *stream = handle->stream;
4300 	janus_ice_component *component = stream ? stream->component : NULL;
4301 	if(pkt == &janus_ice_start_gathering) {
4302 		/* Start gathering candidates */
4303 		if(handle->agent == NULL) {
4304 			JANUS_LOG(LOG_WARN, "[%"SCNu64"] No ICE agent, not going to gather candidates...\n", handle->handle_id);
4305 		} else if(!nice_agent_gather_candidates(handle->agent, handle->stream_id)) {
4306 			JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error gathering candidates...\n", handle->handle_id);
4307 			janus_ice_webrtc_hangup(handle, "ICE gathering error");
4308 		}
4309 		return G_SOURCE_CONTINUE;
4310 	} else if(pkt == &janus_ice_add_candidates) {
4311 		/* There are remote candidates pending, add them now */
4312 		GSList *candidates = NULL;
4313 		NiceCandidate *c = NULL;
4314 		while((c = g_async_queue_try_pop(handle->queued_candidates)) != NULL) {
4315 			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Processing candidate %p\n", handle->handle_id, c);
4316 			candidates = g_slist_append(candidates, c);
4317 		}
4318 		guint count = g_slist_length(candidates);
4319 		if(stream != NULL && component != NULL && count > 0) {
4320 			int added = nice_agent_set_remote_candidates(handle->agent, stream->stream_id, component->component_id, candidates);
4321 			if(added < 0 || (guint)added != count) {
4322 				JANUS_LOG(LOG_WARN, "[%"SCNu64"] Failed to add some remote candidates (added %u, expected %u)\n",
4323 					handle->handle_id, added, count);
4324 			} else {
4325 				JANUS_LOG(LOG_VERB, "[%"SCNu64"] %d remote %s added\n", handle->handle_id,
4326 					count, (count > 1 ? "candidates" : "candidate"));
4327 			}
4328 		}
4329 		g_slist_free(candidates);
4330 		return G_SOURCE_CONTINUE;
4331 	} else if(pkt == &janus_ice_dtls_handshake) {
4332 		if(!janus_is_webrtc_encryption_enabled()) {
4333 			JANUS_LOG(LOG_WARN, "[%"SCNu64"] WebRTC encryption disabled, skipping DTLS handshake\n", handle->handle_id);
4334 			janus_ice_dtls_handshake_done(handle, component);
4335 			return G_SOURCE_CONTINUE;
4336 		} else if(!component) {
4337 			JANUS_LOG(LOG_WARN, "[%"SCNu64"] ICE component not initialized, aborting DTLS handshake\n", handle->handle_id);
4338 			return G_SOURCE_CONTINUE;
4339 		}
4340 		/* Start the DTLS handshake */
4341 		janus_dtls_srtp_handshake(component->dtls);
4342 		/* Create retransmission timer */
4343 		component->dtlsrt_source = g_timeout_source_new(50);
4344 		g_source_set_callback(component->dtlsrt_source, janus_dtls_retry, component->dtls, NULL);
4345 		guint id = g_source_attach(component->dtlsrt_source, handle->mainctx);
4346 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Creating retransmission timer with ID %u\n", handle->handle_id, id);
4347 		return G_SOURCE_CONTINUE;
4348 	} else if(pkt == &janus_ice_media_stopped) {
4349 		/* Either audio or video has been disabled on the way in, so use the callback to notify the peer */
4350 		if(!component->in_stats.audio.notified_lastsec && component->in_stats.audio.bytes && !stream->audio_send) {
4351 			/* Audio won't be received for a while, notify */
4352 			component->in_stats.audio.notified_lastsec = TRUE;
4353 			janus_ice_notify_media(handle, FALSE, 0, FALSE);
4354 		}
4355 		int vindex=0;
4356 		for(vindex=0; vindex<3; vindex++) {
4357 			if(!component->in_stats.video[vindex].notified_lastsec && component->in_stats.video[vindex].bytes && !stream->video_recv) {
4358 				/* Video won't be received for a while, notify */
4359 				component->in_stats.video[vindex].notified_lastsec = TRUE;
4360 				janus_ice_notify_media(handle, TRUE, vindex, FALSE);
4361 			}
4362 		}
4363 		return G_SOURCE_CONTINUE;
4364 	} else if(pkt == &janus_ice_hangup_peerconnection) {
4365 		/* The media session is over, send an alert on all streams and components */
4366 		if(handle->stream && handle->stream->component && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY)) {
4367 			janus_dtls_srtp_send_alert(handle->stream->component->dtls);
4368 		}
4369 		/* Notify the plugin about the fact this PeerConnection has just gone */
4370 		janus_plugin *plugin = (janus_plugin *)handle->app;
4371 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about the hangup (%s)\n",
4372 			handle->handle_id, plugin ? plugin->get_name() : "??");
4373 		if(plugin != NULL && handle->app_handle != NULL) {
4374 			plugin->hangup_media(handle->app_handle);
4375 		}
4376 		/* Get rid of the attached sources */
4377 		if(handle->rtcp_source) {
4378 			g_source_destroy(handle->rtcp_source);
4379 			g_source_unref(handle->rtcp_source);
4380 			handle->rtcp_source = NULL;
4381 		}
4382 		if(handle->twcc_source) {
4383 			g_source_destroy(handle->twcc_source);
4384 			g_source_unref(handle->twcc_source);
4385 			handle->twcc_source = NULL;
4386 		}
4387 		if(handle->stats_source) {
4388 			g_source_destroy(handle->stats_source);
4389 			g_source_unref(handle->stats_source);
4390 			handle->stats_source = NULL;
4391 		}
4392 		/* If event handlers are active, send stats one last time */
4393 		if(janus_events_is_enabled()) {
4394 			handle->last_event_stats = janus_ice_event_stats_period;
4395 			(void)janus_ice_outgoing_stats_handle(handle);
4396 		}
4397 		janus_ice_webrtc_free(handle);
4398 		return G_SOURCE_CONTINUE;
4399 	} else if(pkt == &janus_ice_detach_handle) {
4400 		/* This handle has just been detached, notify the plugin */
4401 		janus_plugin *plugin = (janus_plugin *)handle->app;
4402 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about the handle detach (%s)\n",
4403 			handle->handle_id, plugin ? plugin->get_name() : "??");
4404 		if(plugin != NULL && handle->app_handle != NULL) {
4405 			int error = 0;
4406 			plugin->destroy_session(handle->app_handle, &error);
4407 		}
4408 		handle->app_handle = NULL;
4409 		/* TODO Get rid of the loop by removing the source */
4410 		if(handle->rtp_source) {
4411 			g_source_destroy(handle->rtp_source);
4412 			g_source_unref(handle->rtp_source);
4413 			handle->rtp_source = NULL;
4414 		}
4415 		/* Prepare JSON event to notify user/application */
4416 		json_t *event = json_object();
4417 		json_object_set_new(event, "janus", json_string("detached"));
4418 		json_object_set_new(event, "session_id", json_integer(session->session_id));
4419 		json_object_set_new(event, "sender", json_integer(handle->handle_id));
4420 		if(opaqueid_in_api && handle->opaque_id != NULL)
4421 			json_object_set_new(event, "opaque_id", json_string(handle->opaque_id));
4422 		/* Send the event */
4423 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...; %p\n", handle->handle_id, handle);
4424 		janus_session_notify_event(session, event);
4425 		/* Notify event handlers as well */
4426 		if(janus_events_is_enabled())
4427 			janus_events_notify_handlers(JANUS_EVENT_TYPE_HANDLE, JANUS_EVENT_SUBTYPE_NONE,
4428 				session->session_id, handle->handle_id, "detached",
4429 				plugin ? plugin->get_package() : NULL, handle->opaque_id, handle->token);
4430 		return G_SOURCE_REMOVE;
4431 	} else if(pkt == &janus_ice_data_ready) {
4432 		/* Data is writable on this PeerConnection, notify the plugin */
4433 		janus_plugin *plugin = (janus_plugin *)handle->app;
4434 		if(plugin != NULL && plugin->data_ready != NULL && handle->app_handle != NULL) {
4435 			JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Telling the plugin about the data channel being ready (%s)\n",
4436 				handle->handle_id, plugin ? plugin->get_name() : "??");
4437 			plugin->data_ready(handle->app_handle);
4438 		}
4439 	}
4440 	if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY)) {
4441 		janus_ice_free_queued_packet(pkt);
4442 		return G_SOURCE_CONTINUE;
4443 	}
4444 	/* Now let's get on with the packet */
4445 	if(pkt == NULL)
4446 		return G_SOURCE_CONTINUE;
4447 	if(pkt->data == NULL || stream == NULL) {
4448 		janus_ice_free_queued_packet(pkt);
4449 		return G_SOURCE_CONTINUE;
4450 	}
4451 	gint64 age = (janus_get_monotonic_time() - pkt->added);
4452 	if(age > G_USEC_PER_SEC) {
4453 		JANUS_LOG(LOG_WARN, "[%"SCNu64"] Discarding too old outgoing packet (age=%"SCNi64"us)\n", handle->handle_id, age);
4454 		janus_ice_free_queued_packet(pkt);
4455 		return G_SOURCE_CONTINUE;
4456 	}
4457 	if(!stream->cdone) {
4458 		if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
4459 			JANUS_LOG(LOG_ERR, "[%"SCNu64"] No candidates not gathered yet for stream??\n", handle->handle_id);
4460 			stream->noerrorlog = TRUE;	/* Don't flood with the same error all over again */
4461 		}
4462 		janus_ice_free_queued_packet(pkt);
4463 		return G_SOURCE_CONTINUE;
4464 	}
4465 	if(pkt->control) {
4466 		/* RTCP */
4467 		int video = (pkt->type == JANUS_ICE_PACKET_VIDEO);
4468 		stream->noerrorlog = FALSE;
4469 		if(janus_is_webrtc_encryption_enabled() && (!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_out)) {
4470 			if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
4471 				JANUS_LOG(LOG_WARN, "[%"SCNu64"] %s stream (#%u) component has no valid SRTP session (yet?)\n",
4472 					handle->handle_id, video ? "video" : "audio", stream->stream_id);
4473 				component->noerrorlog = TRUE;	/* Don't flood with the same error all over again */
4474 			}
4475 			janus_ice_free_queued_packet(pkt);
4476 			return G_SOURCE_CONTINUE;
4477 		}
4478 		component->noerrorlog = FALSE;
4479 		if(pkt->encrypted) {
4480 			/* Already SRTCP */
4481 			int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, pkt->length, (const gchar *)pkt->data);
4482 			if(sent < pkt->length) {
4483 				JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, pkt->length);
4484 			}
4485 		} else {
4486 			/* Check if there's anything we need to do before sending */
4487 			uint32_t bitrate = janus_rtcp_get_remb(pkt->data, pkt->length);
4488 			if(bitrate > 0) {
4489 				/* There's a REMB, prepend a RR as it won't work otherwise */
4490 				int rrlen = 8;
4491 				char *rtcpbuf = g_malloc0(rrlen+pkt->length+SRTP_MAX_TAG_LEN+4);
4492 				rtcp_rr *rr = (rtcp_rr *)rtcpbuf;
4493 				rr->header.version = 2;
4494 				rr->header.type = RTCP_RR;
4495 				rr->header.rc = 0;
4496 				rr->header.length = htons((rrlen/4)-1);
4497 				janus_ice_stream *stream = handle->stream;
4498 				/* Append REMB */
4499 				memcpy(rtcpbuf+rrlen, pkt->data, pkt->length);
4500 				/* If we're simulcasting, set the extra SSRCs (the first one will be set by janus_rtcp_fix_ssrc) */
4501 				if(stream->video_ssrc_peer[1] && pkt->length >= 28) {
4502 					rtcp_fb *rtcpfb = (rtcp_fb *)(rtcpbuf+rrlen);
4503 					rtcp_remb *remb = (rtcp_remb *)rtcpfb->fci;
4504 					remb->ssrc[1] = htonl(stream->video_ssrc_peer[1]);
4505 					if(stream->video_ssrc_peer[2] && pkt->length >= 32) {
4506 						remb->ssrc[2] = htonl(stream->video_ssrc_peer[2]);
4507 					}
4508 				}
4509 				/* Free old packet and update */
4510 				char *prev_data = pkt->data;
4511 				pkt->data = rtcpbuf;
4512 				pkt->length = rrlen+pkt->length;
4513 				g_clear_pointer(&prev_data, g_free);
4514 			}
4515 			/* Do we need to dump this packet for debugging? */
4516 			if(g_atomic_int_get(&handle->dump_packets))
4517 				janus_text2pcap_dump(handle->text2pcap, JANUS_TEXT2PCAP_RTCP, FALSE, pkt->data, pkt->length,
4518 					"[session=%"SCNu64"][handle=%"SCNu64"]", session->session_id, handle->handle_id);
4519 			/* Encrypt SRTCP */
4520 			int protected = pkt->length;
4521 			int res = janus_is_webrtc_encryption_enabled() ?
4522 				srtp_protect_rtcp(component->dtls->srtp_out, pkt->data, &protected) : srtp_err_status_ok;
4523 			if(res != srtp_err_status_ok) {
4524 				/* We don't spam the logs for every SRTP error: just take note of this, and print a summary later */
4525 				handle->srtp_errors_count++;
4526 				handle->last_srtp_error = res;
4527 				/* If we're debugging, though, print every occurrence */
4528 				JANUS_LOG(LOG_DBG, "[%"SCNu64"] ... SRTCP protect error... %s (len=%d-->%d)...\n", handle->handle_id, janus_srtp_error_str(res), pkt->length, protected);
4529 			} else {
4530 				/* Shoot! */
4531 				int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, protected, pkt->data);
4532 				if(sent < protected) {
4533 					JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, protected);
4534 				}
4535 			}
4536 		}
4537 		janus_ice_free_queued_packet(pkt);
4538 	} else {
4539 		/* RTP or data */
4540 		if(pkt->type == JANUS_ICE_PACKET_AUDIO || pkt->type == JANUS_ICE_PACKET_VIDEO) {
4541 			/* RTP */
4542 			int video = (pkt->type == JANUS_ICE_PACKET_VIDEO);
4543 			if((!video && !stream->audio_send) || (video && !stream->video_send)) {
4544 				janus_ice_free_queued_packet(pkt);
4545 				return G_SOURCE_CONTINUE;
4546 			}
4547 			if(janus_is_webrtc_encryption_enabled() && (!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_out)) {
4548 				if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
4549 					JANUS_LOG(LOG_WARN, "[%"SCNu64"] %s stream component has no valid SRTP session (yet?)\n",
4550 						handle->handle_id, video ? "video" : "audio");
4551 					component->noerrorlog = TRUE;	/* Don't flood with the same error all over again */
4552 				}
4553 				janus_ice_free_queued_packet(pkt);
4554 				return G_SOURCE_CONTINUE;
4555 			}
4556 			component->noerrorlog = FALSE;
4557 			if(pkt->encrypted) {
4558 				/* Already RTP (probably a retransmission?) */
4559 				janus_rtp_header *header = (janus_rtp_header *)pkt->data;
4560 				JANUS_LOG(LOG_HUGE, "[%"SCNu64"] ... Retransmitting seq.nr %"SCNu16"\n\n", handle->handle_id, ntohs(header->seq_number));
4561 				int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, pkt->length, (const gchar *)pkt->data);
4562 				if(sent < pkt->length) {
4563 					JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, pkt->length);
4564 				}
4565 			} else {
4566 				/* Overwrite SSRC */
4567 				janus_rtp_header *header = (janus_rtp_header *)pkt->data;
4568 				if(!pkt->retransmission) {
4569 					/* ... but only if this isn't a retransmission (for those we already set it before) */
4570 					header->ssrc = htonl(video ? stream->video_ssrc : stream->audio_ssrc);
4571 				}
4572 				/* Set the abs-send-time value, if needed */
4573 				if(video && stream->abs_send_time_ext_id > 0) {
4574 					int64_t now = (((janus_get_monotonic_time()/1000) << 18) + 500) / 1000;
4575 					uint32_t abs_ts = (uint32_t)now & 0x00FFFFFF;
4576 					if(janus_rtp_header_extension_set_abs_send_time(pkt->data, pkt->length,
4577 							stream->abs_send_time_ext_id, abs_ts) < 0) {
4578 						JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error setting abs-send-time value...\n", handle->handle_id);
4579 					}
4580 				}
4581 				/* Set the transport-wide sequence number, if needed */
4582 				if(video && stream->transport_wide_cc_ext_id > 0) {
4583 					stream->transport_wide_cc_out_seq_num++;
4584 					if(janus_rtp_header_extension_set_transport_wide_cc(pkt->data, pkt->length,
4585 							stream->transport_wide_cc_ext_id, stream->transport_wide_cc_out_seq_num) < 0) {
4586 						JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error setting transport wide CC sequence number...\n", handle->handle_id);
4587 					}
4588 				}
4589 				/* Keep track of payload types too */
4590 				if(!video && stream->audio_payload_type < 0) {
4591 					stream->audio_payload_type = header->type;
4592 					if(stream->audio_codec == NULL) {
4593 						const char *codec = janus_get_codec_from_pt(handle->local_sdp, stream->audio_payload_type);
4594 						if(codec != NULL)
4595 							stream->audio_codec = g_strdup(codec);
4596 					}
4597 				} else if(video && stream->video_payload_type < 0) {
4598 					stream->video_payload_type = header->type;
4599 					if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX) &&
4600 							stream->rtx_payload_types && g_hash_table_size(stream->rtx_payload_types) > 0) {
4601 						stream->video_rtx_payload_type = GPOINTER_TO_INT(g_hash_table_lookup(stream->rtx_payload_types, GINT_TO_POINTER(stream->video_payload_type)));
4602 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Retransmissions will have payload type %d\n",
4603 							handle->handle_id, stream->video_rtx_payload_type);
4604 					}
4605 					if(stream->video_codec == NULL) {
4606 						const char *codec = janus_get_codec_from_pt(handle->local_sdp, stream->video_payload_type);
4607 						if(codec != NULL)
4608 							stream->video_codec = g_strdup(codec);
4609 					}
4610 					if(stream->video_is_keyframe == NULL && stream->video_codec != NULL) {
4611 						if(!strcasecmp(stream->video_codec, "vp8"))
4612 							stream->video_is_keyframe = &janus_vp8_is_keyframe;
4613 						else if(!strcasecmp(stream->video_codec, "vp9"))
4614 							stream->video_is_keyframe = &janus_vp9_is_keyframe;
4615 						else if(!strcasecmp(stream->video_codec, "h264"))
4616 							stream->video_is_keyframe = &janus_h264_is_keyframe;
4617 						else if(!strcasecmp(stream->video_codec, "av1"))
4618 							stream->video_is_keyframe = &janus_av1_is_keyframe;
4619 						else if(!strcasecmp(stream->video_codec, "h265"))
4620 							stream->video_is_keyframe = &janus_h265_is_keyframe;
4621 					}
4622 				}
4623 				/* Do we need to dump this packet for debugging? */
4624 				if(g_atomic_int_get(&handle->dump_packets))
4625 					janus_text2pcap_dump(handle->text2pcap, JANUS_TEXT2PCAP_RTP, FALSE, pkt->data, pkt->length,
4626 						"[session=%"SCNu64"][handle=%"SCNu64"]", session->session_id, handle->handle_id);
4627 				/* If this is video and NACK optimizations are enabled, check if this is
4628 				 * a keyframe: if so, we empty our retransmit buffer for incoming NACKs */
4629 				if(video && nack_optimizations && stream->video_is_keyframe) {
4630 					int plen = 0;
4631 					char *payload = janus_rtp_payload(pkt->data, pkt->length, &plen);
4632 					if(stream->video_is_keyframe(payload, plen)) {
4633 						JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Keyframe sent, cleaning retransmit buffer\n", handle->handle_id);
4634 						janus_cleanup_nack_buffer(0, stream, FALSE, TRUE);
4635 					}
4636 				}
4637 				/* Before encrypting, check if we need to copy the unencrypted payload (e.g., for rtx/90000) */
4638 				janus_rtp_packet *p = NULL;
4639 				if(stream->nack_queue_ms > 0 && !pkt->retransmission && pkt->type == JANUS_ICE_PACKET_VIDEO && component->do_video_nacks &&
4640 						janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX)) {
4641 					/* Save the packet for retransmissions that may be needed later: start by
4642 					 * making room for two more bytes to store the original sequence number */
4643 					p = g_malloc(sizeof(janus_rtp_packet));
4644 					janus_rtp_header *header = (janus_rtp_header *)pkt->data;
4645 					guint16 original_seq = header->seq_number;
4646 					p->data = g_malloc(pkt->length+2);
4647 					p->length = pkt->length+2;
4648 					/* Check where the payload starts */
4649 					int plen = 0;
4650 					char *payload = janus_rtp_payload(pkt->data, pkt->length, &plen);
4651 					if(plen == 0) {
4652 						JANUS_LOG(LOG_WARN, "[%"SCNu64"] Discarding outgoing empty RTP packet\n", handle->handle_id);
4653 						janus_ice_free_rtp_packet(p);
4654 						janus_ice_free_queued_packet(pkt);
4655 						return G_SOURCE_CONTINUE;
4656 					}
4657 					size_t hsize = payload - pkt->data;
4658 					/* Copy the header first */
4659 					memcpy(p->data, pkt->data, hsize);
4660 					/* Copy the original sequence number */
4661 					memcpy(p->data+hsize, &original_seq, 2);
4662 					/* Copy the payload */
4663 					memcpy(p->data+hsize+2, payload, pkt->length - hsize);
4664 				}
4665 				/* Encrypt SRTP */
4666 				int protected = pkt->length;
4667 				int res = janus_is_webrtc_encryption_enabled() ?
4668 					srtp_protect(component->dtls->srtp_out, pkt->data, &protected) : srtp_err_status_ok;
4669 				if(res != srtp_err_status_ok) {
4670 					/* We don't spam the logs for every SRTP error: just take note of this, and print a summary later */
4671 					handle->srtp_errors_count++;
4672 					handle->last_srtp_error = res;
4673 					/* If we're debugging, though, print every occurrence */
4674 					janus_rtp_header *header = (janus_rtp_header *)pkt->data;
4675 					guint32 timestamp = ntohl(header->timestamp);
4676 					guint16 seq = ntohs(header->seq_number);
4677 					JANUS_LOG(LOG_DBG, "[%"SCNu64"] ... SRTP protect error... %s (len=%d-->%d, ts=%"SCNu32", seq=%"SCNu16")...\n",
4678 						handle->handle_id, janus_srtp_error_str(res), pkt->length, protected, timestamp, seq);
4679 					janus_ice_free_rtp_packet(p);
4680 				} else {
4681 					/* Shoot! */
4682 					int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, protected, pkt->data);
4683 					if(sent < protected) {
4684 						JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, protected);
4685 					}
4686 					/* Update stats */
4687 					if(sent > 0) {
4688 						/* Update the RTCP context as well */
4689 						janus_rtp_header *header = (janus_rtp_header *)pkt->data;
4690 						guint32 timestamp = ntohl(header->timestamp);
4691 						if(pkt->type == JANUS_ICE_PACKET_AUDIO) {
4692 							component->out_stats.audio.packets++;
4693 							component->out_stats.audio.bytes += pkt->length;
4694 							/* Last second outgoing audio */
4695 							gint64 now = janus_get_monotonic_time();
4696 							if(component->out_stats.audio.updated == 0)
4697 								component->out_stats.audio.updated = now;
4698 							if(now > component->out_stats.audio.updated &&
4699 									now - component->out_stats.audio.updated >= G_USEC_PER_SEC) {
4700 								component->out_stats.audio.bytes_lastsec = component->out_stats.audio.bytes_lastsec_temp;
4701 								component->out_stats.audio.bytes_lastsec_temp = 0;
4702 								component->out_stats.audio.updated = now;
4703 							}
4704 							component->out_stats.audio.bytes_lastsec_temp += pkt->length;
4705 							struct timeval tv;
4706 							gettimeofday(&tv, NULL);
4707 							if(stream->audio_last_ntp_ts == 0 || (gint32)(timestamp - stream->audio_last_rtp_ts) > 0) {
4708 								stream->audio_last_ntp_ts = (gint64)tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
4709 								stream->audio_last_rtp_ts = timestamp;
4710 							}
4711 							if(stream->audio_first_ntp_ts == 0) {
4712 								stream->audio_first_ntp_ts = (gint64)tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
4713 								stream->audio_first_rtp_ts = timestamp;
4714 							}
4715 							/* Let's check if this is not Opus: in case we may need to change the timestamp base */
4716 							rtcp_context *rtcp_ctx = stream->audio_rtcp_ctx;
4717 							int pt = header->type;
4718 							uint32_t clock_rate = stream->clock_rates ?
4719 								GPOINTER_TO_UINT(g_hash_table_lookup(stream->clock_rates, GINT_TO_POINTER(pt))) : 48000;
4720 							if(rtcp_ctx->tb != clock_rate)
4721 								rtcp_ctx->tb = clock_rate;
4722 						} else if(pkt->type == JANUS_ICE_PACKET_VIDEO) {
4723 							component->out_stats.video[0].packets++;
4724 							component->out_stats.video[0].bytes += pkt->length;
4725 							/* Last second outgoing video */
4726 							gint64 now = janus_get_monotonic_time();
4727 							if(component->out_stats.video[0].updated == 0)
4728 								component->out_stats.video[0].updated = now;
4729 							if(now > component->out_stats.video[0].updated &&
4730 									now - component->out_stats.video[0].updated >= G_USEC_PER_SEC) {
4731 								component->out_stats.video[0].bytes_lastsec = component->out_stats.video[0].bytes_lastsec_temp;
4732 								component->out_stats.video[0].bytes_lastsec_temp = 0;
4733 								component->out_stats.video[0].updated = now;
4734 							}
4735 							component->out_stats.video[0].bytes_lastsec_temp += pkt->length;
4736 							struct timeval tv;
4737 							gettimeofday(&tv, NULL);
4738 							if(stream->video_last_ntp_ts == 0 || (gint32)(timestamp - stream->video_last_rtp_ts) > 0) {
4739 								stream->video_last_ntp_ts = (gint64)tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
4740 								stream->video_last_rtp_ts = timestamp;
4741 							}
4742 							if(stream->video_first_ntp_ts[0] == 0) {
4743 								stream->video_first_ntp_ts[0] = (gint64)tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
4744 								stream->video_first_rtp_ts[0] = timestamp;
4745 							}
4746 						}
4747 						/* Update sent packets counter */
4748 						rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx[0] : stream->audio_rtcp_ctx;
4749 						if(rtcp_ctx)
4750 							g_atomic_int_inc(&rtcp_ctx->sent_packets_since_last_rr);
4751 					}
4752 					if(stream->nack_queue_ms > 0 && !pkt->retransmission) {
4753 						/* Save the packet for retransmissions that may be needed later */
4754 						if((pkt->type == JANUS_ICE_PACKET_AUDIO && !component->do_audio_nacks) ||
4755 								(pkt->type == JANUS_ICE_PACKET_VIDEO && !component->do_video_nacks)) {
4756 							/* ... unless NACKs are disabled for this medium */
4757 							janus_ice_free_queued_packet(pkt);
4758 							return G_SOURCE_CONTINUE;
4759 						}
4760 						if(p == NULL) {
4761 							/* If we're not doing RFC4588, we're saving the SRTP packet as it is */
4762 							p = g_malloc(sizeof(janus_rtp_packet));
4763 							p->data = g_malloc(protected);
4764 							memcpy(p->data, pkt->data, protected);
4765 							p->length = protected;
4766 						}
4767 						p->created = janus_get_monotonic_time();
4768 						p->last_retransmit = 0;
4769 						janus_rtp_header *header = (janus_rtp_header *)pkt->data;
4770 						guint16 seq = ntohs(header->seq_number);
4771 						if(!video) {
4772 							if(component->audio_retransmit_buffer == NULL) {
4773 								component->audio_retransmit_buffer = g_queue_new();
4774 								component->audio_retransmit_seqs = g_hash_table_new(NULL, NULL);
4775 							}
4776 							g_queue_push_tail(component->audio_retransmit_buffer, p);
4777 							/* Insert in the table too, for quick lookup */
4778 							g_hash_table_insert(component->audio_retransmit_seqs, GUINT_TO_POINTER(seq), p);
4779 						} else {
4780 							if(component->video_retransmit_buffer == NULL) {
4781 								component->video_retransmit_buffer = g_queue_new();
4782 								component->video_retransmit_seqs = g_hash_table_new(NULL, NULL);
4783 							}
4784 							g_queue_push_tail(component->video_retransmit_buffer, p);
4785 							/* Insert in the table too, for quick lookup */
4786 							g_hash_table_insert(component->video_retransmit_seqs, GUINT_TO_POINTER(seq), p);
4787 						}
4788 					} else {
4789 						janus_ice_free_rtp_packet(p);
4790 					}
4791 				}
4792 			}
4793 		} else if(pkt->type == JANUS_ICE_PACKET_TEXT || pkt->type == JANUS_ICE_PACKET_BINARY) {
4794 			/* Data */
4795 			if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS)) {
4796 				janus_ice_free_queued_packet(pkt);
4797 				return G_SOURCE_CONTINUE;
4798 			}
4799 #ifdef HAVE_SCTP
4800 			if(!component->dtls) {
4801 				if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
4802 					JANUS_LOG(LOG_WARN, "[%"SCNu64"] SCTP stream component has no valid DTLS session (yet?)\n", handle->handle_id);
4803 					component->noerrorlog = TRUE;	/* Don't flood with the same error all over again */
4804 				}
4805 				janus_ice_free_queued_packet(pkt);
4806 				return G_SOURCE_CONTINUE;
4807 			}
4808 			component->noerrorlog = FALSE;
4809 			/* TODO Support binary data */
4810 			janus_dtls_wrap_sctp_data(component->dtls, pkt->label, pkt->protocol,
4811 				pkt->type == JANUS_ICE_PACKET_TEXT, pkt->data, pkt->length);
4812 #endif
4813 		} else if(pkt->type == JANUS_ICE_PACKET_SCTP) {
4814 			/* SCTP data to push */
4815 			if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS)) {
4816 				janus_ice_free_queued_packet(pkt);
4817 				return G_SOURCE_CONTINUE;
4818 			}
4819 #ifdef HAVE_SCTP
4820 			/* Encapsulate this data in DTLS and send it */
4821 			if(!component->dtls) {
4822 				if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
4823 					JANUS_LOG(LOG_WARN, "[%"SCNu64"] SCTP stream component has no valid DTLS session (yet?)\n", handle->handle_id);
4824 					component->noerrorlog = TRUE;	/* Don't flood with the same error all over again */
4825 				}
4826 				janus_ice_free_queued_packet(pkt);
4827 				return G_SOURCE_CONTINUE;
4828 			}
4829 			component->noerrorlog = FALSE;
4830 			janus_dtls_send_sctp_data(component->dtls, pkt->data, pkt->length);
4831 #endif
4832 		} else {
4833 			JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported packet type %d\n", handle->handle_id, pkt->type);
4834 		}
4835 		janus_ice_free_queued_packet(pkt);
4836 	}
4837 	return G_SOURCE_CONTINUE;
4838 }
4839 
4840 static void janus_ice_queue_packet(janus_ice_handle *handle, janus_ice_queued_packet *pkt) {
4841 	/* TODO: There is a potential race condition where the "queued_packets"
4842 	 * could get released between the condition and pushing the packet. */
4843 	if(handle->queued_packets != NULL) {
4844 		g_async_queue_push(handle->queued_packets, pkt);
4845 		g_main_context_wakeup(handle->mainctx);
4846 	} else {
4847 		janus_ice_free_queued_packet(pkt);
4848 	}
4849 }
4850 
4851 void janus_ice_relay_rtp(janus_ice_handle *handle, janus_plugin_rtp *packet) {
4852 	if(!handle || !handle->stream || handle->queued_packets == NULL || packet == NULL || packet->buffer == NULL ||
4853 			!janus_is_rtp(packet->buffer, packet->length))
4854 		return;
4855 	if((!packet->video && !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO))
4856 			|| (packet->video && !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)))
4857 		return;
4858 	uint16_t totlen = RTP_HEADER_SIZE;
4859 	/* Check how large the payload is */
4860 	int plen = 0;
4861 	char *payload = janus_rtp_payload(packet->buffer, packet->length, &plen);
4862 	if(payload != NULL)
4863 		totlen += plen;
4864 	/* We need to strip extensions, here, and add those that need to be there manually */
4865 	uint16_t extlen = 0;
4866 	char extensions[50];
4867 	janus_rtp_header *header = (janus_rtp_header *)packet->buffer;
4868 	int origext = header->extension;
4869 	header->extension = 0;
4870 	/* Add core and plugin extensions, if any */
4871 	if(handle->stream->mid_ext_id > 0 || (packet->video && handle->stream->abs_send_time_ext_id > 0) ||
4872 			(packet->video && handle->stream->transport_wide_cc_ext_id > 0) ||
4873 			(!packet->video && packet->extensions.audio_level != -1 && handle->stream->audiolevel_ext_id > 0) ||
4874 			(packet->video && packet->extensions.video_rotation != -1 && handle->stream->videoorientation_ext_id > 0)) {
4875 		header->extension = 1;
4876 		memset(extensions, 0, sizeof(extensions));
4877 		janus_rtp_header_extension *extheader = (janus_rtp_header_extension *)extensions;
4878 		extheader->type = htons(0xBEDE);
4879 		extheader->length = 0;
4880 		/* Iterate on all extensions we need */
4881 		char *index = extensions + 4;
4882 		/* Check if we need to add the abs-send-time extension */
4883 		if(packet->video && handle->stream->abs_send_time_ext_id > 0) {
4884 			*index = (handle->stream->abs_send_time_ext_id << 4) + 2;
4885 			/* We'll actually set the value later, when sending the packet */
4886 			memset(index+1, 0, 3);
4887 			index += 4;
4888 			extlen += 4;
4889 		}
4890 		/* Check if we need to add the transport-wide CC extension */
4891 		if(packet->video && handle->stream->transport_wide_cc_ext_id > 0) {
4892 			*index = (handle->stream->transport_wide_cc_ext_id << 4) + 1;
4893 			/* We'll actually set the sequence number later, when sending the packet */
4894 			memset(index+1, 0, 2);
4895 			index += 3;
4896 			extlen += 3;
4897 		}
4898 		/* Check if we need to add the mid extension */
4899 		if(handle->stream->mid_ext_id > 0) {
4900 			char *mid = packet->video ? handle->video_mid : handle->audio_mid;
4901 			if(mid != NULL) {
4902 				size_t midlen = strlen(mid) & 0x0F;
4903 				*index = (handle->stream->mid_ext_id << 4) + (midlen ? midlen-1 : 0);
4904 				memcpy(index+1, mid, midlen);
4905 				index += (midlen + 1);
4906 				extlen += (midlen + 1);
4907 			}
4908 		}
4909 		/* Check if the plugin (or source) included other extensions */
4910 		if(!packet->video && packet->extensions.audio_level != -1 && handle->stream->audiolevel_ext_id > 0) {
4911 			/* Add audio-level extension */
4912 			*index = (handle->stream->audiolevel_ext_id << 4);
4913 			*(index+1) = (packet->extensions.audio_level_vad << 7) + (packet->extensions.audio_level & 0x7F);
4914 			index += 2;
4915 			extlen += 2;
4916 		}
4917 		if(packet->video && packet->extensions.video_rotation != -1 && handle->stream->videoorientation_ext_id > 0) {
4918 			/* Add video-orientation extension */
4919 			*index = (handle->stream->videoorientation_ext_id << 4);
4920 			gboolean c = packet->extensions.video_back_camera,
4921 				f = packet->extensions.video_flipped, r1 = FALSE, r0 = FALSE;
4922 			switch(packet->extensions.video_rotation) {
4923 				case 270:
4924 					r1 = TRUE;
4925 					r0 = TRUE;
4926 					break;
4927 				case 180:
4928 					r1 = TRUE;
4929 					r0 = FALSE;
4930 					break;
4931 				case 90:
4932 					r1 = FALSE;
4933 					r0 = TRUE;
4934 					break;
4935 				case 0:
4936 				default:
4937 					r1 = FALSE;
4938 					r0 = FALSE;
4939 					break;
4940 			}
4941 			*(index+1) = (c<<3) + (f<<2) + (r1<<1) + r0;
4942 			index += 2;
4943 			extlen += 2;
4944 		}
4945 		/* Calculate the whole length */
4946 		uint16_t words = extlen/4;
4947 		if(extlen%4 != 0)
4948 			words++;
4949 		extheader->length = htons(words);
4950 		/* Update lengths (taking into account the RFC5285 header) */
4951 		extlen = 4 + (words*4);
4952 		totlen += extlen;
4953 	}
4954 	/* Queue this packet */
4955 	janus_ice_queued_packet *pkt = g_malloc(sizeof(janus_ice_queued_packet));
4956 	pkt->data = g_malloc(totlen + SRTP_MAX_TAG_LEN);
4957 	/* RTP header first */
4958 	memcpy(pkt->data, packet->buffer, RTP_HEADER_SIZE);
4959 	/* Then RTP extensions, if any */
4960 	if(extlen > 0)
4961 		memcpy(pkt->data + RTP_HEADER_SIZE, extensions, extlen);
4962 	/* Finally the RTP payload, if available */
4963 	if(payload != NULL && plen > 0)
4964 		memcpy(pkt->data + RTP_HEADER_SIZE + extlen, payload, plen);
4965 	pkt->length = totlen;
4966 	pkt->type = packet->video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
4967 	pkt->control = FALSE;
4968 	pkt->encrypted = FALSE;
4969 	pkt->retransmission = FALSE;
4970 	pkt->label = NULL;
4971 	pkt->protocol = NULL;
4972 	pkt->added = janus_get_monotonic_time();
4973 	janus_ice_queue_packet(handle, pkt);
4974 	/* Restore the extension flag to what the plugin set it to */
4975 	header->extension = origext;
4976 }
4977 
4978 void janus_ice_relay_rtcp_internal(janus_ice_handle *handle, janus_plugin_rtcp *packet, gboolean filter_rtcp) {
4979 	if(!handle || handle->queued_packets == NULL || packet == NULL || packet->buffer == NULL ||
4980 			!janus_is_rtcp(packet->buffer, packet->length))
4981 		return;
4982 	/* We use this internal method to check whether we need to filter RTCP (e.g., to make
4983 	 * sure we don't just forward any SR/RR from peers/plugins, but use our own) or it has
4984 	 * already been done, and so this is actually a packet added by the ICE send thread */
4985 	char *rtcp_buf = packet->buffer;
4986 	int rtcp_len = packet->length;
4987 	if(filter_rtcp) {
4988 		/* FIXME Strip RR/SR/SDES/NACKs/etc. */
4989 		janus_ice_stream *stream = handle->stream;
4990 		if(stream == NULL)
4991 			return;
4992 		rtcp_buf = janus_rtcp_filter(packet->buffer, packet->length, &rtcp_len);
4993 		if(rtcp_buf == NULL || rtcp_len < 1) {
4994 			g_free(rtcp_buf);
4995 			return;
4996 		}
4997 		/* Fix all SSRCs before enqueueing, as we need to use the ones for this media
4998 		 * leg. Note that this is only needed for RTCP packets coming from plugins: the
4999 		 * ones created by the core already have the right SSRCs in the right place */
5000 		JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Fixing SSRCs (local %u, peer %u)\n", handle->handle_id,
5001 			packet->video ? stream->video_ssrc : stream->audio_ssrc,
5002 			packet->video ? stream->video_ssrc_peer[0] : stream->audio_ssrc_peer);
5003 		janus_rtcp_fix_ssrc(NULL, rtcp_buf, rtcp_len, 1,
5004 			packet->video ? stream->video_ssrc : stream->audio_ssrc,
5005 			packet->video ? stream->video_ssrc_peer[0] : stream->audio_ssrc_peer);
5006 	}
5007 	/* Queue this packet */
5008 	janus_ice_queued_packet *pkt = g_malloc(sizeof(janus_ice_queued_packet));
5009 	pkt->data = g_malloc(rtcp_len+SRTP_MAX_TAG_LEN+4);
5010 	memcpy(pkt->data, rtcp_buf, rtcp_len);
5011 	pkt->length = rtcp_len;
5012 	pkt->type = packet->video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
5013 	pkt->control = TRUE;
5014 	pkt->encrypted = FALSE;
5015 	pkt->retransmission = FALSE;
5016 	pkt->label = NULL;
5017 	pkt->protocol = NULL;
5018 	pkt->added = janus_get_monotonic_time();
5019 	janus_ice_queue_packet(handle, pkt);
5020 	if(rtcp_buf != packet->buffer) {
5021 		/* We filtered the original packet, deallocate it */
5022 		g_free(rtcp_buf);
5023 	}
5024 }
5025 
5026 void janus_ice_relay_rtcp(janus_ice_handle *handle, janus_plugin_rtcp *packet) {
5027 	janus_ice_relay_rtcp_internal(handle, packet, TRUE);
5028 	/* If this is a PLI and we're simulcasting, send a PLI on other layers as well */
5029 	if(janus_rtcp_has_pli(packet->buffer, packet->length)) {
5030 		janus_ice_stream *stream = handle->stream;
5031 		if(stream == NULL)
5032 			return;
5033 		if(stream->video_ssrc_peer[1]) {
5034 			char plibuf[12];
5035 			memset(plibuf, 0, 12);
5036 			janus_rtcp_pli((char *)&plibuf, 12);
5037 			janus_rtcp_fix_ssrc(NULL, plibuf, sizeof(plibuf), 1,
5038 				stream->video_ssrc, stream->video_ssrc_peer[1]);
5039 			janus_plugin_rtcp rtcp = { .video = TRUE, .buffer = plibuf, .length = sizeof(plibuf) };
5040 			janus_ice_relay_rtcp_internal(handle, &rtcp, FALSE);
5041 		}
5042 		if(stream->video_ssrc_peer[2]) {
5043 			char plibuf[12];
5044 			memset(plibuf, 0, 12);
5045 			janus_rtcp_pli((char *)&plibuf, 12);
5046 			janus_rtcp_fix_ssrc(NULL, plibuf, sizeof(plibuf), 1,
5047 				stream->video_ssrc, stream->video_ssrc_peer[2]);
5048 			janus_plugin_rtcp rtcp = { .video = TRUE, .buffer = plibuf, .length = sizeof(plibuf) };
5049 			janus_ice_relay_rtcp_internal(handle, &rtcp, FALSE);
5050 		}
5051 	}
5052 }
5053 
5054 void janus_ice_send_pli(janus_ice_handle *handle) {
5055 	char rtcpbuf[12];
5056 	memset(rtcpbuf, 0, 12);
5057 	janus_rtcp_pli((char *)&rtcpbuf, 12);
5058 	janus_plugin_rtcp rtcp = { .video = TRUE, .buffer = rtcpbuf, .length = 12 };
5059 	janus_ice_relay_rtcp(handle, &rtcp);
5060 }
5061 
5062 void janus_ice_send_remb(janus_ice_handle *handle, uint32_t bitrate) {
5063 	char rtcpbuf[24];
5064 	janus_rtcp_remb((char *)&rtcpbuf, 24, bitrate);
5065 	janus_plugin_rtcp rtcp = { .video = TRUE, .buffer = rtcpbuf, .length = 24 };
5066 	janus_ice_relay_rtcp(handle, &rtcp);
5067 }
5068 
5069 #ifdef HAVE_SCTP
5070 void janus_ice_relay_data(janus_ice_handle *handle, janus_plugin_data *packet) {
5071 	if(!handle || handle->queued_packets == NULL || packet == NULL || packet->buffer == NULL || packet->length < 1)
5072 		return;
5073 	/* Queue this packet */
5074 	janus_ice_queued_packet *pkt = g_malloc(sizeof(janus_ice_queued_packet));
5075 	pkt->data = g_malloc(packet->length);
5076 	memcpy(pkt->data, packet->buffer, packet->length);
5077 	pkt->length = packet->length;
5078 	pkt->type = packet->binary ? JANUS_ICE_PACKET_BINARY : JANUS_ICE_PACKET_TEXT;
5079 	pkt->control = FALSE;
5080 	pkt->encrypted = FALSE;
5081 	pkt->retransmission = FALSE;
5082 	pkt->label = packet->label ? g_strdup(packet->label) : NULL;
5083 	pkt->protocol = packet->protocol ? g_strdup(packet->protocol) : NULL;
5084 	pkt->added = janus_get_monotonic_time();
5085 	janus_ice_queue_packet(handle, pkt);
5086 }
5087 #endif
5088 
5089 void janus_ice_relay_sctp(janus_ice_handle *handle, char *buffer, int length) {
5090 #ifdef HAVE_SCTP
5091 	if(!handle || handle->queued_packets == NULL || buffer == NULL || length < 1)
5092 		return;
5093 	/* Queue this packet */
5094 	janus_ice_queued_packet *pkt = g_malloc(sizeof(janus_ice_queued_packet));
5095 	pkt->data = g_malloc(length);
5096 	memcpy(pkt->data, buffer, length);
5097 	pkt->length = length;
5098 	pkt->type = JANUS_ICE_PACKET_SCTP;
5099 	pkt->control = FALSE;
5100 	pkt->encrypted = FALSE;
5101 	pkt->retransmission = FALSE;
5102 	pkt->label = NULL;
5103 	pkt->protocol = NULL;
5104 	pkt->added = janus_get_monotonic_time();
5105 	janus_ice_queue_packet(handle, pkt);
5106 #endif
5107 }
5108 
5109 void janus_ice_notify_data_ready(janus_ice_handle *handle) {
5110 #ifdef HAVE_SCTP
5111 	if(!handle || handle->queued_packets == NULL)
5112 		return;
5113 	/* Queue this event */
5114 #if GLIB_CHECK_VERSION(2, 46, 0)
5115 	g_async_queue_push_front(handle->queued_packets, &janus_ice_data_ready);
5116 #else
5117 	g_async_queue_push(handle->queued_packets, &janus_ice_data_ready);
5118 #endif
5119 	g_main_context_wakeup(handle->mainctx);
5120 #endif
5121 }
5122 
5123 void janus_ice_notify_media_stopped(janus_ice_handle *handle) {
5124 	if(!handle || handle->queued_packets == NULL)
5125 		return;
5126 	/* Queue this event */
5127 #if GLIB_CHECK_VERSION(2, 46, 0)
5128 	g_async_queue_push_front(handle->queued_packets, &janus_ice_media_stopped);
5129 #else
5130 	g_async_queue_push(handle->queued_packets, &janus_ice_media_stopped);
5131 #endif
5132 	g_main_context_wakeup(handle->mainctx);
5133 }
5134 
5135 void janus_ice_dtls_handshake_done(janus_ice_handle *handle, janus_ice_component *component) {
5136 	if(!handle || !component)
5137 		return;
5138 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] The DTLS handshake for the component %d in stream %d has been completed\n",
5139 		handle->handle_id, component->component_id, component->stream_id);
5140 	/* Check if all components are ready */
5141 	janus_mutex_lock(&handle->mutex);
5142 	if(handle->stream && janus_is_webrtc_encryption_enabled()) {
5143 		if(handle->stream->component && (!handle->stream->component->dtls ||
5144 				!handle->stream->component->dtls->srtp_valid)) {
5145 			/* Still waiting for this component to become ready */
5146 			janus_mutex_unlock(&handle->mutex);
5147 			return;
5148 		}
5149 	}
5150 	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY)) {
5151 		/* Already notified */
5152 		janus_mutex_unlock(&handle->mutex);
5153 		return;
5154 	}
5155 	janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
5156 	/* Create a source for RTCP and one for stats */
5157 	handle->rtcp_source = g_timeout_source_new_seconds(1);
5158 	g_source_set_priority(handle->rtcp_source, G_PRIORITY_DEFAULT);
5159 	g_source_set_callback(handle->rtcp_source, janus_ice_outgoing_rtcp_handle, handle, NULL);
5160 	g_source_attach(handle->rtcp_source, handle->mainctx);
5161 	if(twcc_period != 1000) {
5162 		/* The Transport Wide CC feedback period is different, create another source */
5163 		handle->twcc_source = g_timeout_source_new(twcc_period);
5164 		g_source_set_priority(handle->twcc_source, G_PRIORITY_DEFAULT);
5165 		g_source_set_callback(handle->twcc_source, janus_ice_outgoing_transport_wide_cc_feedback, handle, NULL);
5166 		g_source_attach(handle->twcc_source, handle->mainctx);
5167 	}
5168 	handle->last_event_stats = 0;
5169 	handle->last_srtp_summary = -1;
5170 	handle->stats_source = g_timeout_source_new_seconds(1);
5171 	g_source_set_callback(handle->stats_source, janus_ice_outgoing_stats_handle, handle, NULL);
5172 	g_source_set_priority(handle->stats_source, G_PRIORITY_DEFAULT);
5173 	g_source_attach(handle->stats_source, handle->mainctx);
5174 	janus_mutex_unlock(&handle->mutex);
5175 	JANUS_LOG(LOG_INFO, "[%"SCNu64"] The DTLS handshake has been completed\n", handle->handle_id);
5176 	/* Notify the plugin that the WebRTC PeerConnection is ready to be used */
5177 	janus_plugin *plugin = (janus_plugin *)handle->app;
5178 	if(plugin != NULL) {
5179 		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about it (%s)\n", handle->handle_id, plugin->get_name());
5180 		if(plugin && plugin->setup_media && janus_plugin_session_is_alive(handle->app_handle))
5181 			plugin->setup_media(handle->app_handle);
5182 	}
5183 	/* Also prepare JSON event to notify user/application */
5184 	janus_session *session = (janus_session *)handle->session;
5185 	if(session == NULL)
5186 		return;
5187 	json_t *event = json_object();
5188 	json_object_set_new(event, "janus", json_string("webrtcup"));
5189 	json_object_set_new(event, "session_id", json_integer(session->session_id));
5190 	json_object_set_new(event, "sender", json_integer(handle->handle_id));
5191 	if(opaqueid_in_api && handle->opaque_id != NULL)
5192 		json_object_set_new(event, "opaque_id", json_string(handle->opaque_id));
5193 	/* Send the event */
5194 	JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...; %p\n", handle->handle_id, handle);
5195 	janus_session_notify_event(session, event);
5196 	/* Notify event handlers as well */
5197 	if(janus_events_is_enabled()) {
5198 		json_t *info = json_object();
5199 		json_object_set_new(info, "connection", json_string("webrtcup"));
5200 		janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, JANUS_EVENT_SUBTYPE_WEBRTC_STATE,
5201 			session->session_id, handle->handle_id, handle->opaque_id, info);
5202 	}
5203 }
5204