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