Statistics
| Branch: | Revision:

janus-gateway / ice.c @ edbdcdd8

History | View | Annotate | Download (159 KB)

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 gateway callbacks instead. 
12
 * 
13
 * \ingroup protocols
14
 * \ref protocols
15
 */
16
 
17
#include <ifaddrs.h>
18
#include <net/if.h>
19
#include <sys/socket.h>
20
#include <sys/time.h>
21
#include <netdb.h>
22
#include <fcntl.h>
23
#include <stun/usages/bind.h>
24
#include <nice/debug.h>
25

    
26
#include "janus.h"
27
#include "debug.h"
28
#include "ice.h"
29
#include "turnrest.h"
30
#include "dtls.h"
31
#include "sdp.h"
32
#include "rtp.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

    
42
char *janus_ice_get_stun_server(void) {
43
        return janus_stun_server;
44
}
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

    
56
char *janus_ice_get_turn_server(void) {
57
        return janus_turn_server;
58
}
59
uint16_t janus_ice_get_turn_port(void) {
60
        return janus_turn_port;
61
}
62

    
63

    
64
/* TURN REST API support, if any */
65
char *janus_ice_get_turn_rest_api(void) {
66
#ifndef HAVE_LIBCURL
67
        return NULL;
68
#else
69
        return (char *)janus_turnrest_get_backend();
70
#endif
71
}
72

    
73

    
74
/* ICE-Lite status */
75
static gboolean janus_ice_lite_enabled;
76
gboolean janus_ice_is_ice_lite_enabled(void) {
77
        return janus_ice_lite_enabled;
78
}
79

    
80
/* ICE-TCP support (only libnice >= 0.1.8, currently broken) */
81
static gboolean janus_ice_tcp_enabled;
82
gboolean janus_ice_is_ice_tcp_enabled(void) {
83
        return janus_ice_tcp_enabled;
84
}
85

    
86
/* IPv6 support (still mostly WIP) */
87
static gboolean janus_ipv6_enabled;
88
gboolean janus_ice_is_ipv6_enabled(void) {
89
        return janus_ipv6_enabled;
90
}
91

    
92
/* Whether BUNDLE support is mandatory or not (false by default) */
93
static gboolean janus_force_bundle;
94
void janus_ice_force_bundle(gboolean forced) {
95
        janus_force_bundle = forced;
96
        JANUS_LOG(LOG_INFO, "BUNDLE %s going to be forced\n", janus_force_bundle ? "is" : "is NOT");
97
}
98
gboolean janus_ice_is_bundle_forced(void) {
99
        return janus_force_bundle;
100
}
101

    
102
/* Whether rtcp-mux support is mandatory or not (false by default) */
103
static gboolean janus_force_rtcpmux;
104
static gint janus_force_rtcpmux_blackhole_port = 1234;
105
static gint janus_force_rtcpmux_blackhole_fd = -1;
106
void janus_ice_force_rtcpmux(gboolean forced) {
107
        janus_force_rtcpmux = forced;
108
        JANUS_LOG(LOG_INFO, "rtcp-mux %s going to be forced\n", janus_force_rtcpmux ? "is" : "is NOT");
109
        if(!janus_force_rtcpmux) {
110
                /*
111
                 * Since rtcp-mux is NOT going to be forced, we need to do some magic to get rid of unneeded
112
                 * RTCP components when rtcp-mux is indeed negotiated when creating a PeerConnection. In
113
                 * particular, there's no way to remove a component in libnice (you can only remove streams),
114
                 * and you can read why this is a problem here:
115
                 *                 https://github.com/meetecho/janus-gateway/issues/154
116
                 *                 https://github.com/meetecho/janus-gateway/pull/362
117
                 * This means that, to effectively do that without just ignoring the component, we need
118
                 * to set a dummy candidate on it to "trick" libnice into thinking ICE is done for it.
119
                 * Since libnice will still occasionally send keepalives to the dummy peer, and we don't
120
                 * want it to send messages to a service that might not like it, we create a "blackhole"
121
                 * UDP server to receive all those keepalives and then just discard them.
122
                 */
123
                int blackhole = socket(AF_INET, SOCK_DGRAM, 0);
124
                if(blackhole < 0) {
125
                        JANUS_LOG(LOG_WARN, "Error creating RTCP component blackhole socket, using port %d instead\n", janus_force_rtcpmux_blackhole_port);
126
                        return;
127
                }
128
                fcntl(blackhole, F_SETFL, O_NONBLOCK);
129
                struct sockaddr_in serveraddr;
130
                serveraddr.sin_family = AF_INET;
131
                serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
132
                serveraddr.sin_port = htons(0);                /* Choose a random port, that works for us */
133
                if(bind(blackhole, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
134
                        JANUS_LOG(LOG_WARN, "Error binding RTCP component blackhole socket, using port %d instead\n", janus_force_rtcpmux_blackhole_port);
135
                        close(blackhole);
136
                        return;
137
                }
138
                socklen_t len = sizeof(serveraddr);
139
                if(getsockname(blackhole, (struct sockaddr *)&serveraddr, &len) < 0) {
140
                        JANUS_LOG(LOG_WARN, "Error retrieving port assigned to RTCP component blackhole socket, using port %d instead\n", janus_force_rtcpmux_blackhole_port);
141
                        close(blackhole);
142
                        return;
143
                }
144
                janus_force_rtcpmux_blackhole_port = ntohs(serveraddr.sin_port);
145
                JANUS_LOG(LOG_VERB, "  -- RTCP component blackhole socket bound to port %d\n", janus_force_rtcpmux_blackhole_port);
146
                janus_force_rtcpmux_blackhole_fd = blackhole;
147
        }
148
}
149
gint janus_ice_get_rtcpmux_blackhole_port(void) {
150
        return janus_force_rtcpmux_blackhole_port;
151
}
152
gboolean janus_ice_is_rtcpmux_forced(void) {
153
        return janus_force_rtcpmux;
154
}
155

    
156

    
157
/* libnice debugging */
158
static gboolean janus_ice_debugging_enabled;
159
gboolean janus_ice_is_ice_debugging_enabled(void) {
160
        return janus_ice_debugging_enabled;
161
}
162
void janus_ice_debugging_enable(void) {
163
        JANUS_LOG(LOG_VERB, "Enabling libnice debugging...\n");
164
        if(g_getenv("NICE_DEBUG") == NULL) {
165
                JANUS_LOG(LOG_WARN, "No NICE_DEBUG environment variable set, setting maximum debug\n");
166
                g_setenv("NICE_DEBUG", "all", TRUE);
167
        }
168
        if(g_getenv("G_MESSAGES_DEBUG") == NULL) {
169
                JANUS_LOG(LOG_WARN, "No G_MESSAGES_DEBUG environment variable set, setting maximum debug\n");
170
                g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
171
        }
172
        JANUS_LOG(LOG_VERB, "Debugging NICE_DEBUG=%s G_MESSAGES_DEBUG=%s\n",
173
                g_getenv("NICE_DEBUG"), g_getenv("G_MESSAGES_DEBUG"));
174
        janus_ice_debugging_enabled = TRUE;
175
        nice_debug_enable(strstr(g_getenv("NICE_DEBUG"), "all") || strstr(g_getenv("NICE_DEBUG"), "stun"));
176
}
177
void janus_ice_debugging_disable(void) {
178
        JANUS_LOG(LOG_VERB, "Disabling libnice debugging...\n");
179
        janus_ice_debugging_enabled = FALSE;
180
        nice_debug_disable(TRUE);
181
}
182

    
183

    
184
/* NAT 1:1 stuff */
185
static gboolean nat_1_1_enabled = FALSE;
186
void janus_ice_enable_nat_1_1(void) {
187
        nat_1_1_enabled = TRUE;
188
}
189

    
190
/* Interface/IP enforce/ignore lists */
191
GList *janus_ice_enforce_list = NULL, *janus_ice_ignore_list = NULL;
192
janus_mutex ice_list_mutex;
193

    
194
void janus_ice_enforce_interface(const char *ip) {
195
        if(ip == NULL)
196
                return;
197
        /* Is this an IP or an interface? */
198
        janus_mutex_lock(&ice_list_mutex);
199
        janus_ice_enforce_list = g_list_append(janus_ice_enforce_list, (gpointer)ip);
200
        janus_mutex_unlock(&ice_list_mutex);
201
}
202
gboolean janus_ice_is_enforced(const char *ip) {
203
        if(ip == NULL || janus_ice_enforce_list == NULL)
204
                return false;
205
        janus_mutex_lock(&ice_list_mutex);
206
        GList *temp = janus_ice_enforce_list;
207
        while(temp) {
208
                const char *enforced = (const char *)temp->data;
209
                if(enforced != NULL && strstr(ip, enforced)) {
210
                        janus_mutex_unlock(&ice_list_mutex);
211
                        return true;
212
                }
213
                temp = temp->next;
214
        }
215
        janus_mutex_unlock(&ice_list_mutex);
216
        return false;
217
}
218

    
219
void janus_ice_ignore_interface(const char *ip) {
220
        if(ip == NULL)
221
                return;
222
        /* Is this an IP or an interface? */
223
        janus_mutex_lock(&ice_list_mutex);
224
        janus_ice_ignore_list = g_list_append(janus_ice_ignore_list, (gpointer)ip);
225
        if(janus_ice_enforce_list != NULL) {
226
                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);
227
        }
228
        janus_mutex_unlock(&ice_list_mutex);
229
}
230
gboolean janus_ice_is_ignored(const char *ip) {
231
        if(ip == NULL || janus_ice_ignore_list == NULL)
232
                return false;
233
        janus_mutex_lock(&ice_list_mutex);
234
        GList *temp = janus_ice_ignore_list;
235
        while(temp) {
236
                const char *ignored = (const char *)temp->data;
237
                if(ignored != NULL && strstr(ip, ignored)) {
238
                        janus_mutex_unlock(&ice_list_mutex);
239
                        return true;
240
                }
241
                temp = temp->next;
242
        }
243
        janus_mutex_unlock(&ice_list_mutex);
244
        return false;
245
}
246

    
247

    
248
/* RTP/RTCP port range */
249
uint16_t rtp_range_min = 0;
250
uint16_t rtp_range_max = 0;
251

    
252

    
253
/* Helpers to demultiplex protocols */
254
static gboolean janus_is_dtls(gchar *buf) {
255
        return ((*buf >= 20) && (*buf <= 64));
256
}
257

    
258
static gboolean janus_is_rtp(gchar *buf) {
259
        rtp_header *header = (rtp_header *)buf;
260
        return ((header->type < 64) || (header->type >= 96));
261
}
262

    
263
static gboolean janus_is_rtcp(gchar *buf) {
264
        rtp_header *header = (rtp_header *)buf;
265
        return ((header->type >= 64) && (header->type < 96));
266
}
267

    
268

    
269
#define JANUS_ICE_PACKET_AUDIO        0
270
#define JANUS_ICE_PACKET_VIDEO        1
271
#define JANUS_ICE_PACKET_DATA        2
272
/* Janus enqueued (S)RTP/(S)RTCP packet to send */
273
typedef struct janus_ice_queued_packet {
274
        char *data;
275
        gint length;
276
        gint type;
277
        gboolean control;
278
        gboolean encrypted;
279
} janus_ice_queued_packet;
280
/* This is a static, fake, message we use as a trigger to send a DTLS alert */
281
static janus_ice_queued_packet janus_ice_dtls_alert;
282

    
283

    
284
/* Time, in seconds, that should pass with no media (audio or video) being
285
 * received before Janus notifies you about this with a receiving=false */
286
#define DEFAULT_NO_MEDIA_TIMER        1
287
static uint no_media_timer = DEFAULT_NO_MEDIA_TIMER;
288
void janus_set_no_media_timer(uint timer) {
289
        no_media_timer = timer;
290
        if(no_media_timer == 0)
291
                JANUS_LOG(LOG_VERB, "Disabling no-media timer\n");
292
        else
293
                JANUS_LOG(LOG_VERB, "Setting no-media timer to %ds\n", no_media_timer);
294
}
295
uint janus_get_no_media_timer(void) {
296
        return no_media_timer;
297
}
298

    
299

    
300
/* Maximum value, in milliseconds, for the NACK queue/retransmissions (default=300ms) */
301
#define DEFAULT_MAX_NACK_QUEUE        300
302
/* Maximum ignore count after retransmission (100ms) */
303
#define MAX_NACK_IGNORE                        100000
304

    
305
static uint max_nack_queue = DEFAULT_MAX_NACK_QUEUE;
306
void janus_set_max_nack_queue(uint mnq) {
307
        max_nack_queue = mnq;
308
        if(max_nack_queue == 0)
309
                JANUS_LOG(LOG_VERB, "Disabling NACK queue\n");
310
        else
311
                JANUS_LOG(LOG_VERB, "Setting max NACK queue to %ds\n", max_nack_queue);
312
}
313
uint janus_get_max_nack_queue(void) {
314
        return max_nack_queue;
315
}
316
/* Helper to clean old NACK packets in the buffer when they exceed the queue time limit */
317
static void janus_cleanup_nack_buffer(gint64 now, janus_ice_stream *stream) {
318
        if(stream && stream->rtp_component) {
319
                janus_ice_component *component = stream->rtp_component;
320
                janus_mutex_lock(&component->mutex);
321
                if(component->retransmit_buffer) {
322
                        GList *first = g_list_first(component->retransmit_buffer);
323
                        janus_rtp_packet *p = (janus_rtp_packet *)first->data;
324
                        while(p && (now - p->created >= max_nack_queue*1000)) {
325
                                /* Packet is too old, get rid of it */
326
                                first->data = NULL;
327
                                component->retransmit_buffer = g_list_delete_link(component->retransmit_buffer, first);
328
                                g_free(p->data);
329
                                p->data = NULL;
330
                                g_free(p);
331
                                first = g_list_first(component->retransmit_buffer);
332
                                p = (janus_rtp_packet *)(first ? first->data : NULL);
333
                        }
334
                }
335
                janus_mutex_unlock(&component->mutex);
336
        }
337
}
338

    
339

    
340
#define SEQ_MISSING_WAIT 12000 /*  12ms */
341
#define SEQ_NACKED_WAIT 155000 /* 155ms */
342
/* janus_seq_info list functions */
343
static void janus_seq_append(janus_seq_info **head, janus_seq_info *new_seq) {
344
        if(*head == NULL) {
345
                new_seq->prev = new_seq;
346
                new_seq->next = new_seq;
347
                *head = new_seq;
348
        } else {
349
                janus_seq_info *last_seq = (*head)->prev;
350
                new_seq->prev = last_seq;
351
                new_seq->next = *head;
352
                (*head)->prev = new_seq;
353
                last_seq->next = new_seq;
354
        }
355
}
356
static janus_seq_info *janus_seq_pop_head(janus_seq_info **head) {
357
        janus_seq_info *pop_seq = *head;
358
        if(pop_seq) {
359
                janus_seq_info *new_head = pop_seq->next;
360
                if(pop_seq == new_head || new_head == NULL) {
361
                        *head = NULL;
362
                } else {
363
                        *head = new_head;
364
                        new_head->prev = pop_seq->prev;
365
                        new_head->prev->next = new_head;
366
                }
367
        }
368
        return pop_seq;
369
}
370
static void janus_seq_list_free(janus_seq_info **head) {
371
        if(!*head)
372
                return;
373
        janus_seq_info *cur = *head;
374
        do {
375
                janus_seq_info *next = cur->next;
376
                g_free(cur);
377
                cur = next;
378
        } while(cur != *head);
379
        *head = NULL;
380
}
381
static int janus_seq_in_range(guint16 seqn, guint16 start, guint16 len) {
382
        /* Supports wrapping sequence (easier with int range) */
383
        int n = seqn;
384
        int nh = (1<<16) + n;
385
        int s = start;
386
        int e = s + len;
387
        return (s <= n && n < e) || (s <= nh && nh < e);
388
}
389

    
390

    
391
/* Internal method for relaying RTCP messages, optionally filtering them in case they come from plugins */
392
void janus_ice_relay_rtcp_internal(janus_ice_handle *handle, int video, char *buf, int len, gboolean filter_rtcp);
393

    
394

    
395
/* Map of old plugin sessions that have been closed */
396
static GHashTable *old_plugin_sessions;
397
static janus_mutex old_plugin_sessions_mutex;
398
gboolean janus_plugin_session_is_alive(janus_plugin_session *plugin_session) {
399
        /* Make sure this plugin session is still alive */
400
        janus_mutex_lock_nodebug(&old_plugin_sessions_mutex);
401
        janus_plugin_session *result = g_hash_table_lookup(old_plugin_sessions, plugin_session);
402
        janus_mutex_unlock_nodebug(&old_plugin_sessions_mutex);
403
        if(result != NULL) {
404
                JANUS_LOG(LOG_ERR, "Invalid plugin session (%p)\n", plugin_session);
405
        }
406
        return (result == NULL);
407
}
408

    
409
/* Watchdog for removing old handles */
410
static GHashTable *old_handles = NULL;
411
static GMainContext *handles_watchdog_context = NULL;
412
GMainLoop *handles_watchdog_loop = NULL;
413
GThread *handles_watchdog = NULL;
414
static janus_mutex old_handles_mutex;
415

    
416
static gboolean janus_ice_handles_cleanup(gpointer user_data) {
417
        janus_ice_handle *handle = (janus_ice_handle *) user_data;
418

    
419
        JANUS_LOG(LOG_INFO, "Cleaning up handle %"SCNu64"...\n", handle->handle_id);
420
        janus_ice_free(handle);
421

    
422
        return G_SOURCE_REMOVE;
423
}
424

    
425
static gboolean janus_ice_handles_check(gpointer user_data) {
426
        GMainContext *watchdog_context = (GMainContext *) user_data;
427
        janus_mutex_lock(&old_handles_mutex);
428
        if(old_handles && g_hash_table_size(old_handles) > 0) {
429
                GHashTableIter iter;
430
                gpointer value;
431
                g_hash_table_iter_init(&iter, old_handles);
432
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
433
                        janus_ice_handle *handle = (janus_ice_handle *) value;
434
                        if (!handle) {
435
                                continue;
436
                        }
437
                        /* Schedule the ICE handle for deletion */
438
                        g_hash_table_iter_remove(&iter);
439
                        GSource *timeout_source = g_timeout_source_new_seconds(3);
440
                        g_source_set_callback(timeout_source, janus_ice_handles_cleanup, handle, NULL);
441
                        g_source_attach(timeout_source, watchdog_context);
442
                        g_source_unref(timeout_source);
443
                }
444
        }
445
        janus_mutex_unlock(&old_handles_mutex);
446

    
447
        if(janus_force_rtcpmux_blackhole_fd >= 0) {
448
                /* Also read the blackhole socket (unneeded RTCP components keepalives) and dump the packets */
449
                char buffer[1500];
450
                struct sockaddr_storage addr;
451
                socklen_t len = sizeof(addr);
452
                ssize_t res = 0;
453
                do {
454
                        /* Read and ignore */
455
                        res = recvfrom(janus_force_rtcpmux_blackhole_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, &len);
456
                } while(res > -1);
457
        }
458

    
459
        return G_SOURCE_CONTINUE;
460
}
461

    
462
static gpointer janus_ice_handles_watchdog(gpointer user_data) {
463
        GMainLoop *loop = (GMainLoop *) user_data;
464
        GMainContext *watchdog_context = g_main_loop_get_context(loop);
465
        GSource *timeout_source;
466

    
467
        timeout_source = g_timeout_source_new_seconds(1);
468
        g_source_set_callback(timeout_source, janus_ice_handles_check, watchdog_context, NULL);
469
        g_source_attach(timeout_source, watchdog_context);
470
        g_source_unref(timeout_source);
471

    
472
        JANUS_LOG(LOG_INFO, "ICE handles watchdog started\n");
473

    
474
        g_main_loop_run(loop);
475

    
476
        return NULL;
477
}
478

    
479

    
480
static void janus_ice_notify_media(janus_ice_handle *handle, gboolean video, gboolean up) {
481
        if(handle == NULL)
482
                return;
483
        /* Prepare JSON event to notify user/application */
484
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Notifying that we %s receiving %s\n",
485
                handle->handle_id, up ? "are" : "are NOT", video ? "video" : "audio");
486
        janus_session *session = (janus_session *)handle->session;
487
        if(session == NULL)
488
                return;
489
        json_t *event = json_object();
490
        json_object_set_new(event, "janus", json_string("media"));
491
        json_object_set_new(event, "session_id", json_integer(session->session_id));
492
        json_object_set_new(event, "sender", json_integer(handle->handle_id));
493
        json_object_set_new(event, "type", json_string(video ? "video" : "audio"));
494
        json_object_set_new(event, "receiving", up ? json_true() : json_false());
495
        if(!up && no_media_timer > 1)
496
                json_object_set_new(event, "seconds", json_integer(no_media_timer));
497
        /* Send the event */
498
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
499
        janus_session_notify_event(session->session_id, event);
500
        /* Notify event handlers as well */
501
        if(janus_events_is_enabled()) {
502
                json_t *info = json_object();
503
                json_object_set_new(info, "media", json_string(video ? "video" : "audio"));
504
                json_object_set_new(info, "receiving", up ? json_true() : json_false());
505
                if(!up && no_media_timer > 1)
506
                        json_object_set_new(info, "seconds", json_integer(no_media_timer));
507
                janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, session->session_id, handle->handle_id, info);
508
        }
509
}
510

    
511
void janus_ice_notify_hangup(janus_ice_handle *handle, const char *reason) {
512
        if(handle == NULL)
513
                return;
514
        /* Prepare JSON event to notify user/application */
515
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Notifying WebRTC hangup\n", handle->handle_id);
516
        janus_session *session = (janus_session *)handle->session;
517
        if(session == NULL)
518
                return;
519
        json_t *event = json_object();
520
        json_object_set_new(event, "janus", json_string("hangup"));
521
        json_object_set_new(event, "session_id", json_integer(session->session_id));
522
        json_object_set_new(event, "sender", json_integer(handle->handle_id));
523
        if(reason != NULL)
524
                json_object_set_new(event, "reason", json_string(reason));
525
        /* Send the event */
526
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
527
        janus_session_notify_event(session->session_id, event);
528
        /* Notify event handlers as well */
529
        if(janus_events_is_enabled()) {
530
                json_t *info = json_object();
531
                json_object_set_new(info, "connection", json_string("hangup"));
532
                janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, session->session_id, handle->handle_id, info);
533
        }
534
}
535

    
536

    
537
/* Trickle helpers */
538
janus_ice_trickle *janus_ice_trickle_new(janus_ice_handle *handle, const char *transaction, json_t *candidate) {
539
        if(transaction == NULL || candidate == NULL)
540
                return NULL;
541
        janus_ice_trickle *trickle = g_malloc0(sizeof(janus_ice_trickle));
542
        trickle->handle = handle;
543
        trickle->received = janus_get_monotonic_time();
544
        trickle->transaction = g_strdup(transaction);
545
        trickle->candidate = json_deep_copy(candidate);
546
        return trickle;
547
}
548

    
549
gint janus_ice_trickle_parse(janus_ice_handle *handle, json_t *candidate, const char **error) {
550
        const char *ignore_error = NULL;
551
        if (error == NULL) {
552
                error = &ignore_error;
553
        }
554
        if(handle == NULL) {
555
                *error = "Invalid handle";
556
                return JANUS_ERROR_HANDLE_NOT_FOUND;
557
        }
558
        /* Parse trickle candidate */
559
        if(!json_is_object(candidate) || json_object_get(candidate, "completed") != NULL) {
560
                JANUS_LOG(LOG_VERB, "No more remote candidates for handle %"SCNu64"!\n", handle->handle_id);
561
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES);
562
        } else {
563
                /* Handle remote candidate */
564
                json_t *mid = json_object_get(candidate, "sdpMid");
565
                if(!mid) {
566
                        *error = "Trickle error: missing mandatory element (sdpMid)";
567
                        return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
568
                }
569
                if(!json_is_string(mid)) {
570
                        *error = "Trickle error: invalid element type (sdpMid should be a string)";
571
                        return JANUS_ERROR_INVALID_ELEMENT_TYPE;
572
                }
573
                json_t *mline = json_object_get(candidate, "sdpMLineIndex");
574
                if(!mline) {
575
                        *error = "Trickle error: missing mandatory element (sdpMLineIndex)";
576
                        return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
577
                }
578
                if(!json_is_integer(mline) || json_integer_value(mline) < 0) {
579
                        *error = "Trickle error: invalid element type (sdpMLineIndex should be an integer)";
580
                        return JANUS_ERROR_INVALID_ELEMENT_TYPE;
581
                }
582
                json_t *rc = json_object_get(candidate, "candidate");
583
                if(!rc) {
584
                        *error = "Trickle error: missing mandatory element (candidate)";
585
                        return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
586
                }
587
                if(!json_is_string(rc)) {
588
                        *error = "Trickle error: invalid element type (candidate should be a string)";
589
                        return JANUS_ERROR_INVALID_ELEMENT_TYPE;
590
                }
591
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Trickle candidate (%s): %s\n", handle->handle_id, json_string_value(mid), json_string_value(rc));
592
                /* Parse it */
593
                int sdpMLineIndex = json_integer_value(mline);
594
                int video = 0, data = 0;
595
                /* FIXME badly, we should have an array of m-lines in the handle object */
596
                switch(sdpMLineIndex) {
597
                        case 0:
598
                                if(handle->audio_stream == NULL) {
599
                                        video = handle->video_stream ? 1 : 0;
600
                                        data = !video;
601
                                }
602
                                break;
603
                        case 1:
604
                                if(handle->audio_stream == NULL) {
605
                                        data = 1;
606
                                } else {
607
                                        video = handle->video_stream ? 1 : 0;
608
                                        data = !video;
609
                                }
610
                                break;
611
                        case 2:
612
                                data = 1;
613
                                break;
614
                        default:
615
                                /* FIXME We don't support more than 3 m-lines right now */
616
                                *error = "Trickle error: invalid element type (sdpMLineIndex not [0,2])";
617
                                return JANUS_ERROR_INVALID_ELEMENT_TYPE;
618
                }
619
#ifndef HAVE_SCTP
620
                data = 0;
621
#endif
622
                if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)
623
                                && sdpMLineIndex != 0) {
624
                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got a %s candidate but we're bundling, ignoring...\n", handle->handle_id, json_string_value(mid));
625
                } else {
626
                        janus_ice_stream *stream = video ? handle->video_stream : (data ? handle->data_stream : handle->audio_stream);
627
                        if(stream == NULL) {
628
                                *error = "Trickle error: invalid element type (no such stream)";
629
                                return JANUS_ERROR_TRICKE_INVALID_STREAM;
630
                        }
631
                        int res = janus_sdp_parse_candidate(stream, json_string_value(rc), 1);
632
                        if(res != 0) {
633
                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Failed to parse candidate... (%d)\n", handle->handle_id, res);
634
                                /* FIXME Should we return an error? */
635
                        }
636
                }
637
        }
638
        return 0;
639
}
640

    
641
void janus_ice_trickle_destroy(janus_ice_trickle *trickle) {
642
        if(trickle == NULL)
643
                return;
644
        trickle->handle = NULL;
645
        if(trickle->transaction)
646
                g_free(trickle->transaction);
647
        trickle->transaction = NULL;
648
        if(trickle->candidate)
649
                json_decref(trickle->candidate);
650
        trickle->candidate = NULL;
651
        g_free(trickle);
652
}
653

    
654

    
655
/* libnice initialization */
656
void janus_ice_init(gboolean ice_lite, gboolean ice_tcp, gboolean ipv6, uint16_t rtp_min_port, uint16_t rtp_max_port) {
657
        janus_ice_lite_enabled = ice_lite;
658
        janus_ice_tcp_enabled = ice_tcp;
659
        janus_ipv6_enabled = ipv6;
660
        JANUS_LOG(LOG_INFO, "Initializing ICE stuff (%s mode, ICE-TCP candidates %s, IPv6 support %s)\n",
661
                janus_ice_lite_enabled ? "Lite" : "Full",
662
                janus_ice_tcp_enabled ? "enabled" : "disabled",
663
                janus_ipv6_enabled ? "enabled" : "disabled");
664
        if(janus_ice_tcp_enabled) {
665
#ifndef HAVE_LIBNICE_TCP
666
                JANUS_LOG(LOG_WARN, "libnice version < 0.1.8, disabling ICE-TCP support\n");
667
                janus_ice_tcp_enabled = FALSE;
668
#else
669
                if(!janus_ice_lite_enabled) {
670
                        JANUS_LOG(LOG_WARN, "ICE-TCP only works in libnice if you enable ICE Lite too: disabling ICE-TCP support\n");
671
                        janus_ice_tcp_enabled = FALSE;
672
                }
673
#endif
674
        }
675
        /* libnice debugging is disabled unless explicitly stated */
676
        nice_debug_disable(TRUE);
677

    
678
        /*! \note The RTP/RTCP port range configuration may be just a placeholder: for
679
         * instance, libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails
680
         * when linking with an undefined reference to \c nice_agent_set_port_range 
681
         * so this is checked by the install.sh script in advance. */
682
        rtp_range_min = rtp_min_port;
683
        rtp_range_max = rtp_max_port;
684
        if(rtp_range_max < rtp_range_min) {
685
                JANUS_LOG(LOG_WARN, "Invalid ICE port range: %"SCNu16" > %"SCNu16"\n", rtp_range_min, rtp_range_max);
686
        } else if(rtp_range_min > 0 || rtp_range_max > 0) {
687
#ifndef HAVE_PORTRANGE
688
                JANUS_LOG(LOG_WARN, "nice_agent_set_port_range unavailable, port range disabled\n");
689
#else
690
                JANUS_LOG(LOG_INFO, "ICE port range: %"SCNu16"-%"SCNu16"\n", rtp_range_min, rtp_range_max);
691
#endif
692
        }
693

    
694
        /* We keep track of old plugin sessions to avoid problems */
695
        old_plugin_sessions = g_hash_table_new(NULL, NULL);
696
        janus_mutex_init(&old_plugin_sessions_mutex);
697

    
698
        /* Start the handles watchdog */
699
        janus_mutex_init(&old_handles_mutex);
700
        old_handles = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
701
        handles_watchdog_context = g_main_context_new();
702
        handles_watchdog_loop = g_main_loop_new(handles_watchdog_context, FALSE);
703
        GError *error = NULL;
704
        handles_watchdog = g_thread_try_new("handles watchdog", &janus_ice_handles_watchdog, handles_watchdog_loop, &error);
705
        if(error != NULL) {
706
                JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to start handles watchdog...\n", error->code, error->message ? error->message : "??");
707
                exit(1);
708
        }
709
        
710
#ifdef HAVE_LIBCURL
711
        /* Initialize the TURN REST API client stack, whether we're going to use it or not */
712
        janus_turnrest_init();
713
#endif
714

    
715
}
716

    
717
void janus_ice_deinit(void) {
718
        JANUS_LOG(LOG_INFO, "Ending ICE handles watchdog mainloop...\n");
719
        g_main_loop_quit(handles_watchdog_loop);
720
        g_thread_join(handles_watchdog);
721
        handles_watchdog = NULL;
722
        g_main_loop_unref(handles_watchdog_loop);
723
        g_main_context_unref(handles_watchdog_context);
724
        janus_mutex_lock(&old_handles_mutex);
725
        if(old_handles != NULL)
726
                g_hash_table_destroy(old_handles);
727
        if(janus_force_rtcpmux_blackhole_fd >= 0)
728
                close(janus_force_rtcpmux_blackhole_fd);
729
        old_handles = NULL;
730
        janus_mutex_unlock(&old_handles_mutex);
731
#ifdef HAVE_LIBCURL
732
        janus_turnrest_deinit();
733
#endif
734
}
735

    
736
int janus_ice_set_stun_server(gchar *stun_server, uint16_t stun_port) {
737
        if(stun_server == NULL)
738
                return 0;        /* No initialization needed */
739
        if(stun_port == 0)
740
                stun_port = 3478;
741
        JANUS_LOG(LOG_INFO, "STUN server to use: %s:%u\n", stun_server, stun_port);
742
        /* Resolve address to get an IP */
743
        struct addrinfo *res = NULL;
744
        janus_network_address addr;
745
        janus_network_address_string_buffer addr_buf;
746
        if(getaddrinfo(stun_server, NULL, NULL, &res) != 0 ||
747
                        janus_network_address_from_sockaddr(res->ai_addr, &addr) != 0 ||
748
                        janus_network_address_to_string_buffer(&addr, &addr_buf) != 0) {
749
                JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", stun_server);
750
                if(res)
751
                        freeaddrinfo(res);
752
                return -1;
753
        }
754
        freeaddrinfo(res);
755
        janus_stun_server = g_strdup(janus_network_address_string_from_buffer(&addr_buf));
756
        if(janus_stun_server == NULL) {
757
                JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", stun_server);
758
                return -1;
759
        }
760
        janus_stun_port = stun_port;
761
        JANUS_LOG(LOG_VERB, "  >> %s:%u\n", janus_stun_server, janus_stun_port);
762
        /* Test the STUN server */
763
        StunAgent stun;
764
        stun_agent_init (&stun, STUN_ALL_KNOWN_ATTRIBUTES, STUN_COMPATIBILITY_RFC5389, 0);
765
        StunMessage msg;
766
        uint8_t buf[1500];
767
        size_t len = stun_usage_bind_create(&stun, &msg, buf, 1500);
768
        JANUS_LOG(LOG_INFO, "Testing STUN server: message is of %zu bytes\n", len);
769
        /* TODO Use the janus_network_address info to drive the socket creation */
770
        int fd = socket(AF_INET, SOCK_DGRAM, 0);
771
        struct sockaddr_in address, remote;
772
        address.sin_family = AF_INET;
773
        address.sin_port = 0;
774
        address.sin_addr.s_addr = INADDR_ANY;
775
        remote.sin_family = AF_INET;
776
        remote.sin_port = htons(janus_stun_port);
777
        remote.sin_addr.s_addr = inet_addr(janus_stun_server);
778
        if(bind(fd, (struct sockaddr *)(&address), sizeof(struct sockaddr)) < 0) {
779
                JANUS_LOG(LOG_FATAL, "Bind failed for STUN BINDING test\n");
780
                close(fd);
781
                return -1;
782
        }
783
        int bytes = sendto(fd, buf, len, 0, (struct sockaddr*)&remote, sizeof(remote));
784
        if(bytes < 0) {
785
                JANUS_LOG(LOG_FATAL, "Error sending STUN BINDING test\n");
786
                close(fd);
787
                return -1;
788
        }
789
        JANUS_LOG(LOG_VERB, "  >> Sent %d bytes %s:%u, waiting for reply...\n", bytes, janus_stun_server, janus_stun_port);
790
        struct timeval timeout;
791
        fd_set readfds;
792
        FD_ZERO(&readfds);
793
        FD_SET(fd, &readfds);
794
        timeout.tv_sec = 5;        /* FIXME Don't wait forever */
795
        timeout.tv_usec = 0;
796
        select(fd+1, &readfds, NULL, NULL, &timeout);
797
        if(!FD_ISSET(fd, &readfds)) {
798
                JANUS_LOG(LOG_FATAL, "No response to our STUN BINDING test\n");
799
                close(fd);
800
                return -1;
801
        }
802
        socklen_t addrlen = sizeof(remote);
803
        bytes = recvfrom(fd, buf, 1500, 0, (struct sockaddr*)&remote, &addrlen);
804
        JANUS_LOG(LOG_VERB, "  >> Got %d bytes...\n", bytes);
805
        if(stun_agent_validate (&stun, &msg, buf, bytes, NULL, NULL) != STUN_VALIDATION_SUCCESS) {
806
                JANUS_LOG(LOG_FATAL, "Failed to validate STUN BINDING response\n");
807
                close(fd);
808
                return -1;
809
        }
810
        StunClass class = stun_message_get_class(&msg);
811
        StunMethod method = stun_message_get_method(&msg);
812
        if(class != STUN_RESPONSE || method != STUN_BINDING) {
813
                JANUS_LOG(LOG_FATAL, "Unexpected STUN response: %d/%d\n", class, method);
814
                close(fd);
815
                return -1;
816
        }
817
        StunMessageReturn ret = stun_message_find_xor_addr(&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, (struct sockaddr_storage *)&address, &addrlen);
818
        JANUS_LOG(LOG_VERB, "  >> XOR-MAPPED-ADDRESS: %d\n", ret);
819
        if(ret == STUN_MESSAGE_RETURN_SUCCESS) {
820
                if(janus_network_address_from_sockaddr((struct sockaddr *)&address, &addr) != 0 ||
821
                                janus_network_address_to_string_buffer(&addr, &addr_buf) != 0) {
822
                        JANUS_LOG(LOG_ERR, "Could not resolve XOR-MAPPED-ADDRESS...\n");
823
                } else {
824
                        const char *public_ip = janus_network_address_string_from_buffer(&addr_buf);
825
                        JANUS_LOG(LOG_INFO, "  >> Our public address is %s\n", public_ip);
826
                        janus_set_public_ip(public_ip);
827
                        close(fd);
828
                }
829
                return 0;
830
        }
831
        ret = stun_message_find_addr(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, (struct sockaddr_storage *)&address, &addrlen);
832
        JANUS_LOG(LOG_VERB, "  >> MAPPED-ADDRESS: %d\n", ret);
833
        if(ret == STUN_MESSAGE_RETURN_SUCCESS) {
834
                if(janus_network_address_from_sockaddr((struct sockaddr *)&address, &addr) != 0 ||
835
                                janus_network_address_to_string_buffer(&addr, &addr_buf) != 0) {
836
                        JANUS_LOG(LOG_ERR, "Could not resolve MAPPED-ADDRESS...\n");
837
                } else {
838
                        const char *public_ip = janus_network_address_string_from_buffer(&addr_buf);
839
                        JANUS_LOG(LOG_INFO, "  >> Our public address is %s\n", public_ip);
840
                        janus_set_public_ip(public_ip);
841
                        close(fd);
842
                }
843
                return 0;
844
        }
845
        close(fd);
846
        return -1;
847
}
848

    
849
int janus_ice_set_turn_server(gchar *turn_server, uint16_t turn_port, gchar *turn_type, gchar *turn_user, gchar *turn_pwd) {
850
        if(turn_server == NULL)
851
                return 0;        /* No initialization needed */
852
        if(turn_type == NULL)
853
                turn_type = (char *)"udp";
854
        if(turn_port == 0)
855
                turn_port = 3478;
856
        JANUS_LOG(LOG_INFO, "TURN server to use: %s:%u (%s)\n", turn_server, turn_port, turn_type);
857
        if(!strcasecmp(turn_type, "udp")) {
858
                janus_turn_type = NICE_RELAY_TYPE_TURN_UDP;
859
        } else if(!strcasecmp(turn_type, "tcp")) {
860
                janus_turn_type = NICE_RELAY_TYPE_TURN_TCP;
861
        } else if(!strcasecmp(turn_type, "tls")) {
862
                janus_turn_type = NICE_RELAY_TYPE_TURN_TLS;
863
        } else {
864
                JANUS_LOG(LOG_ERR, "Unsupported relay type '%s'...\n", turn_type);
865
                return -1;
866
        }
867
        /* Resolve address to get an IP */
868
        struct addrinfo *res = NULL;
869
        janus_network_address addr;
870
        janus_network_address_string_buffer addr_buf;
871
        if(getaddrinfo(turn_server, NULL, NULL, &res) != 0 ||
872
                        janus_network_address_from_sockaddr(res->ai_addr, &addr) != 0 ||
873
                        janus_network_address_to_string_buffer(&addr, &addr_buf) != 0) {
874
                JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", turn_server);
875
                if(res)
876
                        freeaddrinfo(res);
877
                return -1;
878
        }
879
        freeaddrinfo(res);
880
        janus_turn_server = g_strdup(janus_network_address_string_from_buffer(&addr_buf));
881
        if(janus_turn_server == NULL) {
882
                JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", turn_server);
883
                return -1;
884
        }
885
        janus_turn_port = turn_port;
886
        JANUS_LOG(LOG_VERB, "  >> %s:%u\n", janus_turn_server, janus_turn_port);
887
        if(janus_turn_user != NULL)
888
                g_free(janus_turn_user);
889
        janus_turn_user = NULL;
890
        if(turn_user)
891
                janus_turn_user = g_strdup(turn_user);
892
        if(janus_turn_pwd != NULL)
893
                g_free(janus_turn_pwd);
894
        janus_turn_pwd = NULL;
895
        if(turn_pwd)
896
                janus_turn_pwd = g_strdup(turn_pwd);
897
        return 0;
898
}
899

    
900
int janus_ice_set_turn_rest_api(gchar *api_server, gchar *api_key, gchar *api_method) {
901
#ifndef HAVE_LIBCURL
902
        JANUS_LOG(LOG_ERR, "Janus has been nuilt with no libcurl support, TURN REST API unavailable\n");
903
        return -1; 
904
#else
905
        if(api_server != NULL &&
906
                        (strstr(api_server, "http://") != api_server && strstr(api_server, "https://") != api_server)) {
907
                JANUS_LOG(LOG_ERR, "Invalid TURN REST API backend: not an HTTP address\n");
908
                return -1;
909
        }
910
        janus_turnrest_set_backend(api_server, api_key, api_method);
911
        JANUS_LOG(LOG_INFO, "TURN REST API backend: %s\n", api_server ? api_server : "(disabled)");
912
#endif
913
        return 0;
914
}
915

    
916

    
917
/* ICE stuff */
918
static const gchar *janus_ice_state_name[] = 
919
{
920
        "disconnected",
921
        "gathering",
922
        "connecting",
923
        "connected",
924
        "ready",
925
        "failed"
926
};
927
const gchar *janus_get_ice_state_name(gint state) {
928
        if(state < 0 || state > 5)
929
                return NULL;
930
        return janus_ice_state_name[state];
931
}
932

    
933
/* Stats */
934
static void janus_ice_stats_queue_free(gpointer data) {
935
        janus_ice_stats_item *s = (janus_ice_stats_item *)data;
936
        g_free(s);
937
}
938

    
939
void janus_ice_stats_reset(janus_ice_stats *stats) {
940
        if(stats == NULL)
941
                return;
942
        stats->audio_packets = 0;
943
        stats->audio_bytes = 0;
944
        if(stats->audio_bytes_lastsec)
945
                g_list_free_full(stats->audio_bytes_lastsec, &janus_ice_stats_queue_free);
946
        stats->audio_bytes_lastsec = NULL;
947
        stats->audio_notified_lastsec = FALSE;
948
        stats->audio_nacks = 0;
949
        stats->video_packets = 0;
950
        stats->video_bytes = 0;
951
        if(stats->video_bytes_lastsec)
952
                g_list_free_full(stats->video_bytes_lastsec, &janus_ice_stats_queue_free);
953
        stats->video_bytes_lastsec = NULL;
954
        stats->video_notified_lastsec = FALSE;
955
        stats->video_nacks = 0;
956
        stats->data_packets = 0;
957
        stats->data_bytes = 0;
958
        stats->last_slowlink_time = 0;
959
        stats->sl_nack_period_ts = 0;
960
        stats->sl_nack_recent_cnt = 0;
961
}
962

    
963

    
964
/* ICE Handles */
965
janus_ice_handle *janus_ice_handle_create(void *gateway_session, const char *opaque_id) {
966
        if(gateway_session == NULL)
967
                return NULL;
968
        janus_session *session = (janus_session *)gateway_session;
969
        guint64 handle_id = 0;
970
        while(handle_id == 0) {
971
                handle_id = janus_random_uint64();
972
                if(janus_ice_handle_find(gateway_session, handle_id) != NULL) {
973
                        /* Handle ID already taken, try another one */
974
                        handle_id = 0;
975
                }
976
        }
977
        JANUS_LOG(LOG_INFO, "Creating new handle in session %"SCNu64": %"SCNu64"\n", session->session_id, handle_id);
978
        janus_ice_handle *handle = (janus_ice_handle *)g_malloc0(sizeof(janus_ice_handle));
979
        if(handle == NULL) {
980
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
981
                return NULL;
982
        }
983
        handle->session = gateway_session;
984
        if(opaque_id)
985
                handle->opaque_id = g_strdup(opaque_id);
986
        handle->created = janus_get_monotonic_time();
987
        handle->handle_id = handle_id;
988
        handle->app = NULL;
989
        handle->app_handle = NULL;
990
        janus_mutex_init(&handle->mutex);
991

    
992
        /* Set up other stuff. */
993
        janus_mutex_lock(&session->mutex);
994
        if(session->ice_handles == NULL)
995
                session->ice_handles = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
996
        g_hash_table_insert(session->ice_handles, janus_uint64_dup(handle->handle_id), handle);
997
        janus_mutex_unlock(&session->mutex);
998

    
999
        return handle;
1000
}
1001

    
1002
janus_ice_handle *janus_ice_handle_find(void *gateway_session, guint64 handle_id) {
1003
        if(gateway_session == NULL)
1004
                return NULL;
1005
        janus_session *session = (janus_session *)gateway_session;
1006
        janus_mutex_lock(&session->mutex);
1007
        janus_ice_handle *handle = session->ice_handles ? g_hash_table_lookup(session->ice_handles, &handle_id) : NULL;
1008
        janus_mutex_unlock(&session->mutex);
1009
        return handle;
1010
}
1011

    
1012
gint janus_ice_handle_attach_plugin(void *gateway_session, guint64 handle_id, janus_plugin *plugin) {
1013
        if(gateway_session == NULL)
1014
                return JANUS_ERROR_SESSION_NOT_FOUND;
1015
        if(plugin == NULL)
1016
                return JANUS_ERROR_PLUGIN_NOT_FOUND;
1017
        janus_session *session = (janus_session *)gateway_session;
1018
        janus_ice_handle *handle = janus_ice_handle_find(session, handle_id);
1019
        if(handle == NULL)
1020
                return JANUS_ERROR_HANDLE_NOT_FOUND;
1021
        janus_mutex_lock(&session->mutex);
1022
        if(handle->app != NULL) {
1023
                /* This handle is already attached to a plugin */
1024
                janus_mutex_unlock(&session->mutex);
1025
                return JANUS_ERROR_PLUGIN_ATTACH;
1026
        }
1027
        int error = 0;
1028
        janus_plugin_session *session_handle = g_malloc0(sizeof(janus_plugin_session));
1029
        if(session_handle == NULL) {
1030
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
1031
                janus_mutex_unlock(&session->mutex);
1032
                return JANUS_ERROR_UNKNOWN;        /* FIXME Do we need something like "Internal Server Error"? */
1033
        }
1034
        session_handle->gateway_handle = handle;
1035
        session_handle->plugin_handle = NULL;
1036
        session_handle->stopped = 0;
1037
        plugin->create_session(session_handle, &error);
1038
        if(error) {
1039
                /* TODO Make error struct to pass verbose information */
1040
                janus_mutex_unlock(&session->mutex);
1041
                return error;
1042
        }
1043
        handle->app = plugin;
1044
        handle->app_handle = session_handle;
1045
        /* Make sure this plugin session is not in the old sessions list */
1046
        janus_mutex_lock(&old_plugin_sessions_mutex);
1047
        g_hash_table_remove(old_plugin_sessions, session_handle);
1048
        janus_mutex_unlock(&old_plugin_sessions_mutex);
1049
        janus_mutex_unlock(&session->mutex);
1050
        /* Notify event handlers */
1051
        if(janus_events_is_enabled())
1052
                janus_events_notify_handlers(JANUS_EVENT_TYPE_HANDLE,
1053
                        session->session_id, handle_id, "attached", plugin->get_package(), handle->opaque_id);
1054
        return 0;
1055
}
1056

    
1057
gint janus_ice_handle_destroy(void *gateway_session, guint64 handle_id) {
1058
        if(gateway_session == NULL)
1059
                return JANUS_ERROR_SESSION_NOT_FOUND;
1060
        janus_session *session = (janus_session *)gateway_session;
1061
        janus_ice_handle *handle = janus_ice_handle_find(session, handle_id);
1062
        if(handle == NULL)
1063
                return JANUS_ERROR_HANDLE_NOT_FOUND;
1064
        janus_mutex_lock(&session->mutex);
1065
        janus_plugin *plugin_t = (janus_plugin *)handle->app;
1066
        if(plugin_t == NULL) {
1067
                /* There was no plugin attached, probably something went wrong there */
1068
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1069
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
1070
                if(handle->iceloop) {
1071
                        if(handle->audio_id > 0) {
1072
                                nice_agent_attach_recv(handle->agent, handle->audio_id, 1, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1073
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX))
1074
                                        nice_agent_attach_recv(handle->agent, handle->audio_id, 2, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1075
                        }
1076
                        if(handle->video_id > 0) {
1077
                                nice_agent_attach_recv(handle->agent, handle->video_id, 1, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1078
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX))
1079
                                        nice_agent_attach_recv(handle->agent, handle->video_id, 2, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1080
                        }
1081
                        if(handle->data_id > 0) {
1082
                                nice_agent_attach_recv(handle->agent, handle->data_id, 1, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1083
                        }
1084
                        g_main_loop_quit(handle->iceloop);
1085
                }
1086
                janus_mutex_unlock(&session->mutex);
1087
                return 0;
1088
        }
1089
        JANUS_LOG(LOG_INFO, "Detaching handle from %s\n", plugin_t->get_name());
1090
        /* TODO Actually detach handle... */
1091
        int error = 0;
1092
        janus_mutex_lock(&old_plugin_sessions_mutex);
1093
        /* This is to tell the plugin to stop using this session: we'll get rid of it later */
1094
        handle->app_handle->stopped = 1;
1095
        /* And this is to put the plugin session in the old sessions list, to avoid it being used */
1096
        g_hash_table_insert(old_plugin_sessions, handle->app_handle, handle->app_handle);
1097
        janus_mutex_unlock(&old_plugin_sessions_mutex);
1098
        /* Notify the plugin that the session's over */
1099
        plugin_t->destroy_session(handle->app_handle, &error);
1100
        /* Get rid of the handle now */
1101
        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1102
        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
1103
        if(handle->iceloop) {
1104
                if(handle->audio_id > 0) {
1105
                        nice_agent_attach_recv(handle->agent, handle->audio_id, 1, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1106
                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX))
1107
                                nice_agent_attach_recv(handle->agent, handle->audio_id, 2, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1108
                }
1109
                if(handle->video_id > 0) {
1110
                        nice_agent_attach_recv(handle->agent, handle->video_id, 1, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1111
                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX))
1112
                                nice_agent_attach_recv(handle->agent, handle->video_id, 2, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1113
                }
1114
                if(handle->data_id > 0) {
1115
                        nice_agent_attach_recv(handle->agent, handle->data_id, 1, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1116
                }
1117
                g_main_loop_quit(handle->iceloop);
1118
        }
1119

    
1120
        /* Prepare JSON event to notify user/application */
1121
        json_t *event = json_object();
1122
        json_object_set_new(event, "janus", json_string("detached"));
1123
        json_object_set_new(event, "session_id", json_integer(session->session_id));
1124
        json_object_set_new(event, "sender", json_integer(handle_id));
1125
        /* Send the event */
1126
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
1127
        janus_session_notify_event(session->session_id, event);
1128
        janus_mutex_unlock(&session->mutex);
1129
        /* We only actually destroy the handle later */
1130
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Handle detached (error=%d), scheduling destruction\n", handle_id, error);
1131
        janus_mutex_lock(&old_handles_mutex);
1132
        g_hash_table_insert(old_handles, janus_uint64_dup(handle->handle_id), handle);
1133
        janus_mutex_unlock(&old_handles_mutex);
1134
        /* Notify event handlers as well */
1135
        if(janus_events_is_enabled())
1136
                janus_events_notify_handlers(JANUS_EVENT_TYPE_HANDLE,
1137
                        session->session_id, handle_id, "detached", plugin_t->get_package(), NULL);
1138
        return error;
1139
}
1140

    
1141
void janus_ice_free(janus_ice_handle *handle) {
1142
        if(handle == NULL)
1143
                return;
1144
        janus_mutex_lock(&handle->mutex);
1145
        handle->session = NULL;
1146
        handle->app = NULL;
1147
        if(handle->app_handle != NULL) {
1148
                janus_mutex_lock(&old_plugin_sessions_mutex);
1149
                handle->app_handle->stopped = 1;
1150
                g_hash_table_insert(old_plugin_sessions, handle->app_handle, handle->app_handle);
1151
                handle->app_handle->gateway_handle = NULL;
1152
                handle->app_handle->plugin_handle = NULL;
1153
                g_free(handle->app_handle);
1154
                handle->app_handle = NULL;
1155
                janus_mutex_unlock(&old_plugin_sessions_mutex);
1156
        }
1157
        janus_mutex_unlock(&handle->mutex);
1158
        janus_ice_webrtc_free(handle);
1159
        JANUS_LOG(LOG_INFO, "[%"SCNu64"] Handle and related resources freed\n", handle->handle_id);
1160
        g_free(handle->opaque_id);
1161
        g_free(handle);
1162
        handle = NULL;
1163
}
1164

    
1165
void janus_ice_webrtc_hangup(janus_ice_handle *handle) {
1166
        if(handle == NULL)
1167
                return;
1168
        if(handle->queued_packets != NULL)
1169
                g_async_queue_push(handle->queued_packets, &janus_ice_dtls_alert);
1170
        if(handle->send_thread == NULL) {
1171
                /* Get rid of the loop */
1172
                if(handle->iceloop) {
1173
                        if(handle->audio_id > 0) {
1174
                                nice_agent_attach_recv(handle->agent, handle->audio_id, 1, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1175
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX))
1176
                                        nice_agent_attach_recv(handle->agent, handle->audio_id, 2, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1177
                        }
1178
                        if(handle->video_id > 0) {
1179
                                nice_agent_attach_recv(handle->agent, handle->video_id, 1, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1180
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX))
1181
                                        nice_agent_attach_recv(handle->agent, handle->video_id, 2, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1182
                        }
1183
                        if(handle->data_id > 0) {
1184
                                nice_agent_attach_recv(handle->agent, handle->data_id, 1, g_main_loop_get_context (handle->iceloop), NULL, NULL);
1185
                        }
1186
                        gint64 waited = 0;
1187
                        while(handle->iceloop && !g_main_loop_is_running(handle->iceloop)) {
1188
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE loop exists but is not running, waiting for it to run\n", handle->handle_id);
1189
                                g_usleep (100000);
1190
                                waited += 100000;
1191
                                if(waited >= G_USEC_PER_SEC) {
1192
                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   -- Waited a second, that's enough!\n", handle->handle_id);
1193
                                        break;
1194
                                }
1195
                        }
1196
                        if(handle->iceloop && g_main_loop_is_running(handle->iceloop)) {
1197
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Forcing ICE loop to quit (%s)\n", handle->handle_id, g_main_loop_is_running(handle->iceloop) ? "running" : "NOT running");
1198
                                g_main_loop_quit(handle->iceloop);
1199
                                g_main_context_wakeup(handle->icectx);
1200
                        }
1201
                }
1202
        }
1203
        handle->icethread = NULL;
1204
}
1205

    
1206
void janus_ice_webrtc_free(janus_ice_handle *handle) {
1207
        if(handle == NULL)
1208
                return;
1209
        janus_mutex_lock(&handle->mutex);
1210
        if(handle->iceloop != NULL) {
1211
                g_main_loop_unref (handle->iceloop);
1212
                handle->iceloop = NULL;
1213
        }
1214
        if(handle->icectx != NULL) {
1215
                g_main_context_unref (handle->icectx);
1216
                handle->icectx = NULL;
1217
        }
1218
        handle->icethread = NULL;
1219
        if(handle->streams != NULL) {
1220
                janus_ice_stream_free(handle->streams, handle->audio_stream);
1221
                handle->audio_stream = NULL;
1222
                janus_ice_stream_free(handle->streams, handle->video_stream);
1223
                handle->video_stream = NULL;
1224
                janus_ice_stream_free(handle->streams, handle->data_stream);
1225
                handle->data_stream = NULL;
1226
                g_hash_table_destroy(handle->streams);
1227
                handle->streams = NULL;
1228
        }
1229
        if(handle->agent != NULL) {
1230
                if(G_IS_OBJECT(handle->agent))
1231
                        g_object_unref(handle->agent);
1232
                handle->agent = NULL;
1233
        }
1234
        handle->agent_created = 0;
1235
        if(handle->pending_trickles) {
1236
                while(handle->pending_trickles) {
1237
                        GList *temp = g_list_first(handle->pending_trickles);
1238
                        handle->pending_trickles = g_list_remove_link(handle->pending_trickles, temp);
1239
                        janus_ice_trickle *trickle = (janus_ice_trickle *)temp->data;
1240
                        g_list_free(temp);
1241
                        janus_ice_trickle_destroy(trickle);
1242
                }
1243
        }
1244
        handle->pending_trickles = NULL;
1245
        g_free(handle->rtp_profile);
1246
        handle->rtp_profile = NULL;
1247
        g_free(handle->local_sdp);
1248
        handle->local_sdp = NULL;
1249
        g_free(handle->remote_sdp);
1250
        handle->remote_sdp = NULL;
1251
        if(handle->queued_packets != NULL) {
1252
                janus_ice_queued_packet *pkt = NULL;
1253
                while(g_async_queue_length(handle->queued_packets) > 0) {
1254
                        pkt = g_async_queue_try_pop(handle->queued_packets);
1255
                        if(pkt != NULL && pkt != &janus_ice_dtls_alert) {
1256
                                g_free(pkt->data);
1257
                                pkt->data = NULL;
1258
                                g_free(pkt);
1259
                                pkt = NULL;
1260
                        }
1261
                }
1262
                g_async_queue_unref(handle->queued_packets);
1263
                handle->queued_packets = NULL;
1264
        }
1265
        if(handle->audio_mid != NULL) {
1266
                g_free(handle->audio_mid);
1267
                handle->audio_mid = NULL;
1268
        }
1269
        if(handle->video_mid != NULL) {
1270
                g_free(handle->video_mid);
1271
                handle->video_mid = NULL;
1272
        }
1273
        if(handle->data_mid != NULL) {
1274
                g_free(handle->data_mid);
1275
                handle->data_mid = NULL;
1276
        }
1277
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
1278
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
1279
        g_atomic_int_set(&handle->send_thread_created, 0);
1280
        janus_mutex_unlock(&handle->mutex);
1281
        JANUS_LOG(LOG_INFO, "[%"SCNu64"] WebRTC resources freed\n", handle->handle_id);
1282
}
1283

    
1284
void janus_ice_stream_free(GHashTable *streams, janus_ice_stream *stream) {
1285
        if(stream == NULL)
1286
                return;
1287
        if(streams != NULL)
1288
                g_hash_table_remove(streams, GUINT_TO_POINTER(stream->stream_id));
1289
        if(stream->components != NULL) {
1290
                janus_ice_component_free(stream->components, stream->rtp_component);
1291
                stream->rtp_component = NULL;
1292
                janus_ice_component_free(stream->components, stream->rtcp_component);
1293
                stream->rtcp_component = NULL;
1294
                g_hash_table_destroy(stream->components);
1295
        }
1296
        stream->handle = NULL;
1297
        if(stream->remote_hashing != NULL) {
1298
                g_free(stream->remote_hashing);
1299
                stream->remote_hashing = NULL;
1300
        }
1301
        if(stream->remote_fingerprint != NULL) {
1302
                g_free(stream->remote_fingerprint);
1303
                stream->remote_fingerprint = NULL;
1304
        }
1305
        if(stream->ruser != NULL) {
1306
                g_free(stream->ruser);
1307
                stream->ruser = NULL;
1308
        }
1309
        if(stream->rpass != NULL) {
1310
                g_free(stream->rpass);
1311
                stream->rpass = NULL;
1312
        }
1313
        g_list_free(stream->audio_payload_types);
1314
        stream->audio_payload_types = NULL;
1315
        g_list_free(stream->video_payload_types);
1316
        stream->video_payload_types = NULL;
1317
        g_free(stream->audio_rtcp_ctx);
1318
        stream->audio_rtcp_ctx = NULL;
1319
        g_free(stream->video_rtcp_ctx);
1320
        stream->video_rtcp_ctx = NULL;
1321
        stream->audio_last_ts = 0;
1322
        stream->video_last_ts = 0;
1323
        g_free(stream);
1324
        stream = NULL;
1325
}
1326

    
1327
void janus_ice_component_free(GHashTable *components, janus_ice_component *component) {
1328
        if(component == NULL)
1329
                return;
1330
        janus_ice_stream *stream = component->stream;
1331
        if(stream == NULL)
1332
                return;
1333
        janus_ice_handle *handle = stream->handle;
1334
        if(handle == NULL)
1335
                return;
1336
        //~ janus_mutex_lock(&handle->mutex);
1337
        if(components != NULL)
1338
                g_hash_table_remove(components, GUINT_TO_POINTER(component->component_id));
1339
        component->stream = NULL;
1340
        if(component->source != NULL) {
1341
                g_source_destroy(component->source);
1342
                g_source_unref(component->source);
1343
                component->source = NULL;
1344
        }
1345
        if(component->dtls != NULL) {
1346
                janus_dtls_srtp_destroy(component->dtls);
1347
                component->dtls = NULL;
1348
        }
1349
        if(component->retransmit_buffer != NULL) {
1350
                janus_rtp_packet *p = NULL;
1351
                GList *first = g_list_first(component->retransmit_buffer);
1352
                while(first != NULL) {
1353
                        p = (janus_rtp_packet *)first->data;
1354
                        first->data = NULL;
1355
                        component->retransmit_buffer = g_list_delete_link(component->retransmit_buffer, first);
1356
                        g_free(p->data);
1357
                        p->data = NULL;
1358
                        g_free(p);
1359
                        first = g_list_first(component->retransmit_buffer);
1360
                }
1361
        }
1362
        if(component->candidates != NULL) {
1363
                GSList *i = NULL, *candidates = component->candidates;
1364
                for (i = candidates; i; i = i->next) {
1365
                        NiceCandidate *c = (NiceCandidate *) i->data;
1366
                        if(c != NULL) {
1367
                                nice_candidate_free(c);
1368
                                c = NULL;
1369
                        }
1370
                }
1371
                g_slist_free(candidates);
1372
                candidates = NULL;
1373
        }
1374
        component->candidates = NULL;
1375
        if(component->local_candidates != NULL) {
1376
                GSList *i = NULL, *candidates = component->local_candidates;
1377
                for (i = candidates; i; i = i->next) {
1378
                        gchar *c = (gchar *) i->data;
1379
                        if(c != NULL) {
1380
                                g_free(c);
1381
                                c = NULL;
1382
                        }
1383
                }
1384
                g_slist_free(candidates);
1385
                candidates = NULL;
1386
        }
1387
        component->local_candidates = NULL;
1388
        if(component->remote_candidates != NULL) {
1389
                GSList *i = NULL, *candidates = component->remote_candidates;
1390
                for (i = candidates; i; i = i->next) {
1391
                        gchar *c = (gchar *) i->data;
1392
                        if(c != NULL) {
1393
                                g_free(c);
1394
                                c = NULL;
1395
                        }
1396
                }
1397
                g_slist_free(candidates);
1398
                candidates = NULL;
1399
        }
1400
        component->remote_candidates = NULL;
1401
        if(component->selected_pair != NULL)
1402
                g_free(component->selected_pair);
1403
        component->selected_pair = NULL;
1404
        if(component->last_seqs_audio)
1405
                janus_seq_list_free(&component->last_seqs_audio);
1406
        if(component->last_seqs_video)
1407
                janus_seq_list_free(&component->last_seqs_video);
1408
        janus_ice_stats_reset(&component->in_stats);
1409
        janus_ice_stats_reset(&component->out_stats);
1410
        g_free(component);
1411
        //~ janus_mutex_unlock(&handle->mutex);
1412
}
1413

    
1414
/* Call plugin slow_link callback if enough NACKs within a second */
1415
#define SLOW_LINK_NACKS_PER_SEC 8
1416
static void
1417
janus_slow_link_update(janus_ice_component *component, janus_ice_handle *handle,
1418
                guint nacks, int video, int uplink, gint64 now) {
1419
        /* We keep the counters in different janus_ice_stats objects, depending on the direction */
1420
        gint64 sl_nack_period_ts = uplink ? component->in_stats.sl_nack_period_ts : component->out_stats.sl_nack_period_ts;
1421
        /* Is the NACK too old? */
1422
        if(now-sl_nack_period_ts > 2*G_USEC_PER_SEC) {
1423
                /* Old nacks too old, don't count them */
1424
                if(uplink) {
1425
                        component->in_stats.sl_nack_period_ts = now;
1426
                        component->in_stats.sl_nack_recent_cnt = 0;
1427
                } else {
1428
                        component->out_stats.sl_nack_period_ts = now;
1429
                        component->out_stats.sl_nack_recent_cnt = 0;
1430
                }
1431
        }
1432
        if(uplink) {
1433
                component->in_stats.sl_nack_recent_cnt += nacks;
1434
        } else {
1435
                component->out_stats.sl_nack_recent_cnt += nacks;
1436
        }
1437
        gint64 last_slowlink_time = uplink ? component->in_stats.last_slowlink_time : component->out_stats.last_slowlink_time;
1438
        guint sl_nack_recent_cnt = uplink ? component->in_stats.sl_nack_recent_cnt : component->out_stats.sl_nack_recent_cnt;
1439
        if((sl_nack_recent_cnt >= SLOW_LINK_NACKS_PER_SEC) && (now-last_slowlink_time > 1*G_USEC_PER_SEC)) {
1440
                /* Tell the plugin */
1441
                janus_plugin *plugin = (janus_plugin *)handle->app;
1442
                if(plugin && plugin->slow_link && janus_plugin_session_is_alive(handle->app_handle))
1443
                        plugin->slow_link(handle->app_handle, uplink, video);
1444
                /* Notify the user/application too */
1445
                janus_session *session = (janus_session *)handle->session;
1446
                if(session != NULL) {
1447
                        json_t *event = json_object();
1448
                        json_object_set_new(event, "janus", json_string("slowlink"));
1449
                        json_object_set_new(event, "session_id", json_integer(session->session_id));
1450
                        json_object_set_new(event, "sender", json_integer(handle->handle_id));
1451
                        json_object_set_new(event, "uplink", uplink ? json_true() : json_false());
1452
                        json_object_set_new(event, "nacks", json_integer(sl_nack_recent_cnt));
1453
                        /* Send the event */
1454
                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
1455
                        janus_session_notify_event(session->session_id, event);
1456
                        /* Finally, notify event handlers */
1457
                        if(janus_events_is_enabled()) {
1458
                                json_t *info = json_object();
1459
                                json_object_set_new(info, "media", json_string(video ? "video" : "audio"));
1460
                                json_object_set_new(info, "slow_link", json_string(uplink ? "uplink" : "downlink"));
1461
                                json_object_set_new(info, "nacks_lastsec", json_integer(sl_nack_recent_cnt));
1462
                                janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, session->session_id, handle->handle_id, info);
1463
                        }
1464
                }
1465
                /* Update the counters */
1466
                if(uplink) {
1467
                        component->in_stats.last_slowlink_time = now;
1468
                        component->in_stats.sl_nack_period_ts = now;
1469
                        component->in_stats.sl_nack_recent_cnt = 0;
1470
                } else {
1471
                        component->out_stats.last_slowlink_time = now;
1472
                        component->out_stats.sl_nack_period_ts = now;
1473
                        component->out_stats.sl_nack_recent_cnt = 0;
1474
                }
1475
        }
1476
}
1477

    
1478

    
1479
/* Callbacks */
1480
void janus_ice_cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer user_data) {
1481
        janus_ice_handle *handle = (janus_ice_handle *)user_data;
1482
        if(!handle)
1483
                return;
1484
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Gathering done for stream %d\n", handle->handle_id, stream_id);
1485
        handle->cdone++;
1486
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
1487
        if(!stream) {
1488
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]  No stream %d??\n", handle->handle_id, stream_id);
1489
                return;
1490
        }
1491
        stream->cdone = 1;
1492
}
1493

    
1494
void janus_ice_cb_component_state_changed(NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer ice) {
1495
        janus_ice_handle *handle = (janus_ice_handle *)ice;
1496
        if(!handle)
1497
                return;
1498
        if(component_id > 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
1499
                /* State changed for a component we don't need anymore (rtcp-mux) */
1500
                return;
1501
        }
1502
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Component state changed for component %d in stream %d: %d (%s)\n",
1503
                handle->handle_id, component_id, stream_id, state, janus_get_ice_state_name(state));
1504
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
1505
        if(!stream) {
1506
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
1507
                return;
1508
        }
1509
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
1510
        if(!component) {
1511
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
1512
                return;
1513
        }
1514
        component->state = state;
1515
        /* Notify event handlers */
1516
        if(janus_events_is_enabled()) {
1517
                janus_session *session = (janus_session *)handle->session;
1518
                json_t *info = json_object();
1519
                json_object_set_new(info, "ice", json_string(janus_get_ice_state_name(state)));
1520
                json_object_set_new(info, "stream_id", json_integer(stream_id));
1521
                json_object_set_new(info, "component_id", json_integer(component_id));
1522
                janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, session->session_id, handle->handle_id, info);
1523
        }
1524
        /* Handle new state */
1525
        if((state == NICE_COMPONENT_STATE_CONNECTED || state == NICE_COMPONENT_STATE_READY)
1526
                        && handle->send_thread == NULL) {
1527
                /* Make sure we're not trying to start the thread more than once */
1528
                if(!g_atomic_int_compare_and_exchange(&handle->send_thread_created, 0, 1)) {
1529
                        return;
1530
                }
1531
                /* Start the outgoing data thread */
1532
                GError *error = NULL;
1533
                char tname[16];
1534
                g_snprintf(tname, sizeof(tname), "icesend %"SCNu64, handle->handle_id);
1535
                handle->send_thread = g_thread_try_new(tname, &janus_ice_send_thread, handle, &error);
1536
                if(error != NULL) {
1537
                        /* FIXME We should clear some resources... */
1538
                        JANUS_LOG(LOG_ERR, "[%"SCNu64"] Got error %d (%s) trying to launch the ICE send thread...\n", handle->handle_id, error->code, error->message ? error->message : "??");
1539
                        return;
1540
                }
1541
        }
1542
        /* FIXME Even in case the state is 'connected', we wait for the 'new-selected-pair' callback to do anything */
1543
        if(state == NICE_COMPONENT_STATE_FAILED) {
1544
                /* Failed doesn't mean necessarily we need to give up: we may be trickling */
1545
                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));
1546
                gboolean answer_recv = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_GOT_ANSWER);
1547
                gboolean alert_set = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1548
                if(handle && trickle_recv && answer_recv && !alert_set) {
1549
                        /* FIXME Should we really give up for what may be a failure in only one of the media? */
1550
                        if(stream->disabled) {
1551
                                JANUS_LOG(LOG_WARN, "[%"SCNu64"] ICE failed for component %d in stream %d, but stream is disabled so we don't care...\n", handle->handle_id, component_id, stream_id);
1552
                                return;
1553
                        }
1554
                        JANUS_LOG(LOG_ERR, "[%"SCNu64"] ICE failed for component %d in stream %d...\n", handle->handle_id, component_id, stream_id);
1555
                        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1556
                        janus_plugin *plugin = (janus_plugin *)handle->app;
1557
                        if(plugin != NULL) {
1558
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about it (%s)\n", handle->handle_id, plugin->get_name());
1559
                                if(plugin && plugin->hangup_media)
1560
                                        plugin->hangup_media(handle->app_handle);
1561
                        }
1562
                        janus_ice_notify_hangup(handle, "ICE failed");
1563
                } else {
1564
                        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",
1565
                                handle->handle_id, component_id, stream_id,
1566
                                trickle_recv ? "received" : "pending",
1567
                                answer_recv ? "received" : "pending",
1568
                                alert_set ? "set" : "not set");
1569
                }
1570
        }
1571
}
1572

    
1573
#ifndef HAVE_LIBNICE_TCP
1574
void janus_ice_cb_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, gchar *local, gchar *remote, gpointer ice) {
1575
#else
1576
void janus_ice_cb_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, NiceCandidate *local, NiceCandidate *remote, gpointer ice) {
1577
#endif
1578
        janus_ice_handle *handle = (janus_ice_handle *)ice;
1579
        if(!handle)
1580
                return;
1581
        if(component_id > 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
1582
                /* New selected pair for a component we don't need anymore (rtcp-mux) */
1583
                return;
1584
        }
1585
#ifndef HAVE_LIBNICE_TCP
1586
        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);
1587
#else
1588
        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);
1589
#endif
1590
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
1591
        if(!stream) {
1592
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
1593
                return;
1594
        }
1595
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
1596
        if(!component) {
1597
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
1598
                return;
1599
        }
1600
        char sp[200];
1601
#ifndef HAVE_LIBNICE_TCP
1602
        g_snprintf(sp, 200, "%s <-> %s", local, remote);
1603
#else
1604
        gchar laddress[NICE_ADDRESS_STRING_LEN], raddress[NICE_ADDRESS_STRING_LEN];
1605
        gint lport = 0, rport = 0;
1606
        nice_address_to_string(&(local->addr), (gchar *)&laddress);
1607
        nice_address_to_string(&(remote->addr), (gchar *)&raddress);
1608
        lport = nice_address_get_port(&(local->addr));
1609
        rport = nice_address_get_port(&(remote->addr));
1610
        const char *ltype = NULL, *rtype = NULL; 
1611
        switch(local->type) {
1612
                case NICE_CANDIDATE_TYPE_HOST:
1613
                        ltype = "host";
1614
                        break;
1615
                case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
1616
                        ltype = "srflx";
1617
                        break;
1618
                case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
1619
                        ltype = "prflx";
1620
                        break;
1621
                case NICE_CANDIDATE_TYPE_RELAYED:
1622
                        ltype = "relay";
1623
                        break;
1624
                default:
1625
                        break;
1626
        }
1627
        switch(remote->type) {
1628
                case NICE_CANDIDATE_TYPE_HOST:
1629
                        rtype = "host";
1630
                        break;
1631
                case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
1632
                        rtype = "srflx";
1633
                        break;
1634
                case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
1635
                        rtype = "prflx";
1636
                        break;
1637
                case NICE_CANDIDATE_TYPE_RELAYED:
1638
                        rtype = "relay";
1639
                        break;
1640
                default:
1641
                        break;
1642
        }
1643
        g_snprintf(sp, 200, "%s:%d [%s,%s] <-> %s:%d [%s,%s]",
1644
                laddress, lport, ltype, local->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "udp" : "tcp",
1645
                raddress, rport, rtype, remote->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "udp" : "tcp");
1646
#endif
1647
        gchar *prev_selected_pair = component->selected_pair;
1648
        component->selected_pair = g_strdup(sp);
1649
        g_clear_pointer(&prev_selected_pair, g_free);
1650
        /* Notify event handlers */
1651
        if(janus_events_is_enabled()) {
1652
                janus_session *session = (janus_session *)handle->session;
1653
                json_t *info = json_object();
1654
                json_object_set_new(info, "selected-pair", json_string(sp));
1655
                json_object_set_new(info, "stream_id", json_integer(stream_id));
1656
                json_object_set_new(info, "component_id", json_integer(component_id));
1657
                janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, session->session_id, handle->handle_id, info);
1658
        }
1659
        /* Now we can start the DTLS handshake (FIXME This was on the 'connected' state notification, before) */
1660
        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Component is ready enough, starting DTLS handshake...\n", handle->handle_id);
1661
        /* Have we been here before? (might happen, when trickling) */
1662
        if(component->dtls != NULL)
1663
                return;
1664
        component->component_connected = janus_get_monotonic_time();
1665
        /* Create DTLS-SRTP context, at last */
1666
        component->dtls = janus_dtls_srtp_create(component, stream->dtls_role);
1667
        if(!component->dtls) {
1668
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component DTLS-SRTP session??\n", handle->handle_id);
1669
                return;
1670
        }
1671
        janus_dtls_srtp_handshake(component->dtls);
1672
        /* Create retransmission timer */
1673
        component->source = g_timeout_source_new(100);
1674
        g_source_set_callback(component->source, janus_dtls_retry, component->dtls, NULL);
1675
        guint id = g_source_attach(component->source, handle->icectx);
1676
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Creating retransmission timer with ID %u\n", handle->handle_id, id);
1677
}
1678

    
1679
#ifndef HAVE_LIBNICE_TCP
1680
void janus_ice_cb_new_remote_candidate (NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation, gpointer ice) {
1681
#else
1682
void janus_ice_cb_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate, gpointer ice) {
1683
#endif
1684
        janus_ice_handle *handle = (janus_ice_handle *)ice;
1685
#ifndef HAVE_LIBNICE_TCP
1686
        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);
1687
#else
1688
        const char *ctype = NULL;
1689
        switch(candidate->type) {
1690
                case NICE_CANDIDATE_TYPE_HOST:
1691
                        ctype = "host";
1692
                        break;
1693
                case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
1694
                        ctype = "srflx";
1695
                        break;
1696
                case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
1697
                        ctype = "prflx";
1698
                        break;
1699
                case NICE_CANDIDATE_TYPE_RELAYED:
1700
                        ctype = "relay";
1701
                        break;
1702
                default:
1703
                        break;
1704
        }
1705
        guint stream_id = candidate->stream_id;
1706
        guint component_id = candidate->component_id;
1707
        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);
1708
#endif
1709
        if(!handle)
1710
                return;
1711
        if(component_id > 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
1712
                /* New remote candidate for a component we don't need anymore (rtcp-mux) */
1713
                return;
1714
        }
1715
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
1716
        if(!stream) {
1717
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
1718
                return;
1719
        }
1720
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
1721
        if(!component) {
1722
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
1723
                return;
1724
        }
1725
#ifndef HAVE_LIBNICE_TCP
1726
        /* Get remote candidates and look for the related foundation */
1727
        NiceCandidate *candidate = NULL;
1728
        GSList *candidates = nice_agent_get_remote_candidates(agent, component_id, stream_id), *tmp = candidates;
1729
        while(tmp) {
1730
                NiceCandidate *c = (NiceCandidate *)tmp->data;
1731
                if(candidate == NULL) {
1732
                        /* Check if this is what we're looking for */
1733
                        if(!strcasecmp(c->foundation, foundation)) {
1734
                                /* It is! */
1735
                                candidate = c;
1736
                                tmp = tmp->next;
1737
                                continue;
1738
                        }
1739
                }
1740
                nice_candidate_free(c);
1741
                tmp = tmp->next;
1742
        }
1743
        g_slist_free(candidates);
1744
        if(candidate == NULL) {
1745
                JANUS_LOG(LOG_WARN, "Candidate with foundation %s not found?\n", foundation);
1746
                return;
1747
        }
1748
#endif
1749
        /* Render the candidate and add it to the remote_candidates cache for the admin API */
1750
        if(candidate->type != NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
1751
                /* ... but only if it's 'prflx', the others we add ourselves */
1752
                goto candidatedone;
1753
        }
1754
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream #%d, Component #%d\n", handle->handle_id, candidate->stream_id, candidate->component_id);
1755
        gchar address[NICE_ADDRESS_STRING_LEN], base_address[NICE_ADDRESS_STRING_LEN];
1756
        gint port = 0, base_port = 0;
1757
        nice_address_to_string(&(candidate->addr), (gchar *)&address);
1758
        port = nice_address_get_port(&(candidate->addr));
1759
        nice_address_to_string(&(candidate->base_addr), (gchar *)&base_address);
1760
        base_port = nice_address_get_port(&(candidate->base_addr));
1761
        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Address:    %s:%d\n", handle->handle_id, address, port);
1762
        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Priority:   %d\n", handle->handle_id, candidate->priority);
1763
        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Foundation: %s\n", handle->handle_id, candidate->foundation);
1764
        char buffer[100];
1765
        if(candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
1766
                g_snprintf(buffer, 100,
1767
                        "%s %d %s %d %s %d typ prflx raddr %s rport %d\r\n", 
1768
                                candidate->foundation,
1769
                                candidate->component_id,
1770
                                "udp",
1771
                                candidate->priority,
1772
                                address,
1773
                                port,
1774
                                base_address,
1775
                                base_port);
1776
        } else {
1777
                if(!janus_ice_tcp_enabled) {
1778
                        /* ICETCP support disabled */
1779
                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping prflx TCP candidate, ICETCP support disabled...\n", handle->handle_id);
1780
                        goto candidatedone;
1781
                }
1782
#ifndef HAVE_LIBNICE_TCP
1783
                /* TCP candidates are only supported since libnice 0.1.8 */
1784
                JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping prflx TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
1785
                        goto candidatedone;
1786
#else
1787
                const char *type = NULL;
1788
                switch(candidate->transport) {
1789
                        case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
1790
                                type = "active";
1791
                                break;
1792
                        case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
1793
                                type = "passive";
1794
                                break;
1795
                        case NICE_CANDIDATE_TRANSPORT_TCP_SO:
1796
                                type = "so";
1797
                                break;
1798
                        default:
1799
                                break;
1800
                }
1801
                if(type == NULL) {
1802
                        /* FIXME Unsupported transport */
1803
                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping nonUDP/TCP prflx candidate...\n", handle->handle_id);
1804
                        goto candidatedone;
1805
                } else {
1806
                        g_snprintf(buffer, 100,
1807
                                "%s %d %s %d %s %d typ prflx raddr %s rport %d tcptype %s\r\n",
1808
                                        candidate->foundation,
1809
                                        candidate->component_id,
1810
                                        "tcp",
1811
                                        candidate->priority,
1812
                                        address,
1813
                                        port,
1814
                                        base_address,
1815
                                        base_port,
1816
                                        type);
1817
                }
1818
#endif
1819
        }
1820

    
1821
        /* Save for the summary, in case we need it */
1822
        component->remote_candidates = g_slist_append(component->remote_candidates, g_strdup(buffer));
1823

    
1824
candidatedone:
1825
#ifndef HAVE_LIBNICE_TCP
1826
        nice_candidate_free(candidate);
1827
#endif
1828
        return;
1829
}
1830

    
1831
void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer ice) {
1832
        janus_ice_component *component = (janus_ice_component *)ice;
1833
        if(!component) {
1834
                JANUS_LOG(LOG_ERR, "No component %d in stream %d??\n", component_id, stream_id);
1835
                return;
1836
        }
1837
        janus_ice_stream *stream = component->stream;
1838
        if(!stream) {
1839
                JANUS_LOG(LOG_ERR, "No stream %d??\n", stream_id);
1840
                return;
1841
        }
1842
        janus_ice_handle *handle = stream->handle;
1843
        if(!handle) {
1844
                JANUS_LOG(LOG_ERR, "No handle for stream %d??\n", stream_id);
1845
                return;
1846
        }
1847
        if(!component->dtls) {        /* Still waiting for the DTLS stack */
1848
                JANUS_LOG(LOG_WARN, "[%"SCNu64"] Still waiting for the DTLS stack for component %d in stream %d...\n", handle->handle_id, component_id, stream_id);
1849
                return;
1850
        }
1851
        /* What is this? */
1852
        if (janus_is_dtls(buf) || (!janus_is_rtp(buf) && !janus_is_rtcp(buf))) {
1853
                /* This is DTLS: either handshake stuff, or data coming from SCTP DataChannels */
1854
                JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Looks like DTLS!\n", handle->handle_id);
1855
                janus_dtls_srtp_incoming_msg(component->dtls, buf, len);
1856
                /* Update stats (TODO Do the same for the last second window as well) */
1857
                component->in_stats.data_packets++;
1858
                component->in_stats.data_bytes += len;
1859
                return;
1860
        }
1861
        /* Not DTLS... RTP or RTCP? (http://tools.ietf.org/html/rfc5761#section-4) */
1862
        if(len < 12)
1863
                return;        /* Definitely nothing useful */
1864
        if(component_id == 1 && (!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) || janus_is_rtp(buf))) {
1865
                /* FIXME If rtcp-mux is not used, a first component is always RTP; otherwise, we need to check */
1866
                //~ JANUS_LOG(LOG_HUGE, "[%"SCNu64"]  Got an RTP packet (%s stream)!\n", handle->handle_id,
1867
                        //~ janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? "bundled" : (stream->stream_id == handle->audio_id ? "audio" : "video"));
1868
                if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_in) {
1869
                        JANUS_LOG(LOG_WARN, "[%"SCNu64"]     Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
1870
                } else {
1871
                        rtp_header *header = (rtp_header *)buf;
1872
                        /* Is this audio or video? */
1873
                        int video = 0;
1874
                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
1875
                                /* Easy enough */
1876
                                video = (stream->stream_id == handle->video_id ? 1 : 0);
1877
                        } else {
1878
                                /* Bundled streams, check SSRC */
1879
                                guint32 packet_ssrc = ntohl(header->ssrc);
1880
                                video = ((stream->video_ssrc_peer == packet_ssrc || stream->video_ssrc_peer_rtx == packet_ssrc) ? 1 : 0);
1881
                                if(!video && stream->audio_ssrc_peer != packet_ssrc) {
1882
                                        /* FIXME In case it happens, we should check what it is */
1883
                                        if(stream->audio_ssrc_peer == 0 || stream->video_ssrc_peer == 0) {
1884
                                                /* Apparently we were not told the peer SSRCs, try to guess from the payload type */
1885
                                                gboolean found = FALSE;
1886
                                                guint16 pt = header->type;
1887
                                                if(stream->audio_ssrc_peer == 0 && stream->audio_payload_types) {
1888
                                                        GList *pts = stream->audio_payload_types;
1889
                                                        while(pts) {
1890
                                                                guint16 audio_pt = GPOINTER_TO_UINT(pts->data);
1891
                                                                if(pt == audio_pt) {
1892
                                                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Unadvertized SSRC (%"SCNu32") is audio! (payload type %"SCNu16")\n", handle->handle_id, packet_ssrc, pt);
1893
                                                                        video = 0;
1894
                                                                        stream->audio_ssrc_peer = packet_ssrc;
1895
                                                                        found = TRUE;
1896
                                                                        break;
1897
                                                                }
1898
                                                                pts = pts->next;
1899
                                                        }
1900
                                                }
1901
                                                if(!found && stream->video_ssrc_peer == 0 && stream->video_payload_types) {
1902
                                                        GList *pts = stream->video_payload_types;
1903
                                                        while(pts) {
1904
                                                                guint16 video_pt = GPOINTER_TO_UINT(pts->data);
1905
                                                                if(pt == video_pt) {
1906
                                                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Unadvertized SSRC (%"SCNu32") is video! (payload type %"SCNu16")\n", handle->handle_id, packet_ssrc, pt);
1907
                                                                        video = 1;
1908
                                                                        stream->video_ssrc_peer = packet_ssrc;
1909
                                                                        found = TRUE;
1910
                                                                        break;
1911
                                                                }
1912
                                                                pts = pts->next;
1913
                                                        }
1914
                                                }
1915
                                        }
1916
                                        if(!video && stream->audio_ssrc_peer != packet_ssrc) {
1917
                                                JANUS_LOG(LOG_WARN, "[%"SCNu64"] Not video and not audio? dropping (SSRC %"SCNu32")...\n", handle->handle_id, packet_ssrc);
1918
                                                return;
1919
                                        }
1920
                                }
1921
                                if(stream->video_ssrc_peer_rtx == packet_ssrc) {
1922
                                        /* FIXME This is a video retransmission: set the regular peer SSRC so
1923
                                         * that we avoid outgoing SRTP errors in case we got the packet already */
1924
                                        header->ssrc = htonl(stream->video_ssrc_peer);
1925
                                }
1926
                                //~ JANUS_LOG(LOG_VERB, "[RTP] Bundling: this is %s (video=%"SCNu64", audio=%"SCNu64", got %ld)\n",
1927
                                        //~ video ? "video" : "audio", stream->video_ssrc_peer, stream->audio_ssrc_peer, ntohl(header->ssrc));
1928
                        }
1929

    
1930
                        int buflen = len;
1931
                        srtp_err_status_t res = srtp_unprotect(component->dtls->srtp_in, buf, &buflen);
1932
                        if(res != srtp_err_status_ok) {
1933
                                if(res != srtp_err_status_replay_fail && res != srtp_err_status_replay_old) {
1934
                                        /* 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) */
1935
                                        rtp_header *header = (rtp_header *)buf;
1936
                                        guint32 timestamp = ntohl(header->timestamp);
1937
                                        guint16 seq = ntohs(header->seq_number);
1938
                                        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);
1939
                                }
1940
                        } else {
1941
                                if(video) {
1942
                                        if(stream->video_ssrc_peer == 0) {
1943
                                                stream->video_ssrc_peer = ntohl(header->ssrc);
1944
                                                JANUS_LOG(LOG_VERB, "[%"SCNu64"]     Peer video SSRC: %u\n", handle->handle_id, stream->video_ssrc_peer);
1945
                                        }
1946
                                } else {
1947
                                        if(stream->audio_ssrc_peer == 0) {
1948
                                                stream->audio_ssrc_peer = ntohl(header->ssrc);
1949
                                                JANUS_LOG(LOG_VERB, "[%"SCNu64"]     Peer audio SSRC: %u\n", handle->handle_id, stream->audio_ssrc_peer);
1950
                                        }
1951
                                }
1952
                                /* Pass the data to the responsible plugin */
1953
                                janus_plugin *plugin = (janus_plugin *)handle->app;
1954
                                if(plugin && plugin->incoming_rtp)
1955
                                        plugin->incoming_rtp(handle->app_handle, video, buf, buflen);
1956
                                /* Update stats (TODO Do the same for the last second window as well) */
1957
                                if(buflen > 0) {
1958
                                        /* Update the last sec queue as well */
1959
                                        janus_ice_stats_item *s = g_malloc0(sizeof(janus_ice_stats_item));
1960
                                        s->bytes = buflen;
1961
                                        s->when = janus_get_monotonic_time();
1962
                                        janus_mutex_lock(&component->mutex);
1963
                                        if(!video) {
1964
                                                if(component->in_stats.audio_bytes == 0 || component->in_stats.audio_notified_lastsec) {
1965
                                                        /* We either received our first audio packet, or we started receiving it again after missing more than a second */
1966
                                                        component->in_stats.audio_notified_lastsec = FALSE;
1967
                                                        janus_ice_notify_media(handle, FALSE, TRUE);
1968
                                                }
1969
                                                component->in_stats.audio_packets++;
1970
                                                component->in_stats.audio_bytes += buflen;
1971
                                                component->in_stats.audio_bytes_lastsec = g_list_append(component->in_stats.audio_bytes_lastsec, s);
1972
                                                if(g_list_length(component->in_stats.audio_bytes_lastsec) > 100) {
1973
                                                        GList *first = g_list_first(component->in_stats.audio_bytes_lastsec);
1974
                                                        s = (janus_ice_stats_item *)first->data;
1975
                                                        first->data = NULL;
1976
                                                        component->in_stats.audio_bytes_lastsec = g_list_delete_link(component->in_stats.audio_bytes_lastsec, first);
1977
                                                        g_free(s);
1978
                                                }
1979
                                        } else {
1980
                                                if(component->in_stats.video_bytes == 0 || component->in_stats.video_notified_lastsec) {
1981
                                                        /* We either received our first video packet, or we started receiving it again after missing more than a second */
1982
                                                        component->in_stats.video_notified_lastsec = FALSE;
1983
                                                        janus_ice_notify_media(handle, TRUE, TRUE);
1984
                                                }
1985
                                                component->in_stats.video_packets++;
1986
                                                component->in_stats.video_bytes += buflen;
1987
                                                component->in_stats.video_bytes_lastsec = g_list_append(component->in_stats.video_bytes_lastsec, s);
1988
                                                if(g_list_length(component->in_stats.video_bytes_lastsec) > 100) {
1989
                                                        GList *first = g_list_first(component->in_stats.video_bytes_lastsec);
1990
                                                        s = (janus_ice_stats_item *)first->data;
1991
                                                        first->data = NULL;
1992
                                                        component->in_stats.video_bytes_lastsec = g_list_delete_link(component->in_stats.video_bytes_lastsec, first);
1993
                                                        g_free(s);
1994
                                                }
1995
                                        }
1996
                                        janus_mutex_unlock(&component->mutex);
1997
                                }
1998

    
1999
                                /* Update the RTCP context as well */
2000
                                rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx : stream->audio_rtcp_ctx;
2001
                                janus_rtcp_process_incoming_rtp(rtcp_ctx, buf, buflen);
2002

    
2003
                                /* Keep track of RTP sequence numbers, in case we need to NACK them */
2004
                                /*         Note: unsigned int overflow/underflow wraps (defined behavior) */
2005
                                guint16 new_seqn = ntohs(header->seq_number);
2006
                                guint16 cur_seqn;
2007
                                int last_seqs_len = 0;
2008
                                janus_mutex_lock(&component->mutex);
2009
                                janus_seq_info **last_seqs = video ? &component->last_seqs_video : &component->last_seqs_audio;
2010
                                janus_seq_info *cur_seq = *last_seqs;
2011
                                if(cur_seq) {
2012
                                        cur_seq = cur_seq->prev;
2013
                                        cur_seqn = cur_seq->seq;
2014
                                } else {
2015
                                        /* First seq, set up to add one seq */
2016
                                        cur_seqn = new_seqn - (guint16)1; /* Can wrap */
2017
                                }
2018
                                if(!janus_seq_in_range(new_seqn, cur_seqn, LAST_SEQS_MAX_LEN) &&
2019
                                                !janus_seq_in_range(cur_seqn, new_seqn, 1000)) {
2020
                                        /* Jump too big, start fresh */
2021
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Big sequence number jump %hu -> %hu (%s stream)\n",
2022
                                                handle->handle_id, cur_seqn, new_seqn, video ? "video" : "audio");
2023
                                        janus_seq_list_free(last_seqs);
2024
                                        cur_seq = NULL;
2025
                                        cur_seqn = new_seqn - (guint16)1;
2026
                                }
2027

    
2028
                                GSList *nacks = NULL;
2029
                                gint64 now = janus_get_monotonic_time();
2030

    
2031
                                if(janus_seq_in_range(new_seqn, cur_seqn, LAST_SEQS_MAX_LEN)) {
2032
                                        /* Add new seq objs forward */
2033
                                        while(cur_seqn != new_seqn) {
2034
                                                cur_seqn += (guint16)1; /* can wrap */
2035
                                                janus_seq_info *seq_obj = g_malloc0(sizeof(janus_seq_info));
2036
                                                seq_obj->seq = cur_seqn;
2037
                                                seq_obj->ts = now;
2038
                                                seq_obj->state = (cur_seqn == new_seqn) ? SEQ_RECVED : SEQ_MISSING;
2039
                                                janus_seq_append(last_seqs, seq_obj);
2040
                                                last_seqs_len++;
2041
                                        }
2042
                                }
2043
                                if(cur_seq) {
2044
                                        /* Scan old seq objs backwards */
2045
                                        while(cur_seq != NULL) {
2046
                                                last_seqs_len++;
2047
                                                if(cur_seq->seq == new_seqn) {
2048
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Received missed sequence number %"SCNu16"\n", handle->handle_id, cur_seq->seq);
2049
                                                        cur_seq->state = SEQ_RECVED;
2050
                                                } else if(cur_seq->state == SEQ_MISSING && now - cur_seq->ts > SEQ_MISSING_WAIT) {
2051
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Missed sequence number %"SCNu16", sending 1st NACK\n", handle->handle_id, cur_seq->seq);
2052
                                                        nacks = g_slist_append(nacks, GUINT_TO_POINTER(cur_seq->seq));
2053
                                                        cur_seq->state = SEQ_NACKED;
2054
                                                } else if(cur_seq->state == SEQ_NACKED  && now - cur_seq->ts > SEQ_NACKED_WAIT) {
2055
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Missed sequence number %"SCNu16", sending 2nd NACK\n", handle->handle_id, cur_seq->seq);
2056
                                                        nacks = g_slist_append(nacks, GUINT_TO_POINTER(cur_seq->seq));
2057
                                                        cur_seq->state = SEQ_GIVEUP;
2058
                                                }
2059
                                                if(cur_seq == *last_seqs) {
2060
                                                        /* Just processed head */
2061
                                                        break;
2062
                                                }
2063
                                                cur_seq = cur_seq->prev;
2064
                                        }
2065
                                }
2066
                                while(last_seqs_len > LAST_SEQS_MAX_LEN) {
2067
                                        janus_seq_info *node = janus_seq_pop_head(last_seqs);
2068
                                        g_free(node);
2069
                                        last_seqs_len--;
2070
                                }
2071

    
2072
                                guint nacks_count = g_slist_length(nacks);
2073
                                if(nacks_count) {
2074
                                        /* Generate a NACK and send it */
2075
                                        JANUS_LOG(LOG_DBG, "[%"SCNu64"] now sending NACK for %u missed packets\n", handle->handle_id, nacks_count);
2076
                                        char nackbuf[120];
2077
                                        int res = janus_rtcp_nacks(nackbuf, sizeof(nackbuf), nacks);
2078
                                        if(res > 0)
2079
                                                janus_ice_relay_rtcp_internal(handle, video, nackbuf, res, FALSE);
2080
                                        /* Update stats */
2081
                                        component->nack_sent_recent_cnt += nacks_count;
2082
                                        if(video) {
2083
                                                component->out_stats.video_nacks += nacks_count;
2084
                                        } else {
2085
                                                component->out_stats.audio_nacks += nacks_count;
2086
                                        }
2087
                                        /* Inform the plugin about the slow downlink in case it's needed */
2088
                                        janus_slow_link_update(component, handle, nacks_count, video, 0, now);
2089
                                }
2090
                                if (component->nack_sent_recent_cnt &&
2091
                                    now - component->nack_sent_log_ts > 5 * G_USEC_PER_SEC) {
2092
                                        JANUS_LOG(LOG_VERB, "[%10"SCNu64"]  sent NACKs for %u missing packets\n",
2093
                                                              handle->handle_id, component->nack_sent_recent_cnt);
2094
                                        component->nack_sent_recent_cnt = 0;
2095
                                        component->nack_sent_log_ts = now;
2096
                                }
2097
                                janus_mutex_unlock(&component->mutex);
2098
                                g_slist_free(nacks);
2099
                                nacks = NULL;
2100
                        }
2101
                }
2102
                return;
2103
        }
2104
        if(component_id == 2 || (component_id == 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) && janus_is_rtcp(buf))) {
2105
                /* FIXME A second component is always RTCP; in case of rtcp-mux, we need to check */
2106
                JANUS_LOG(LOG_HUGE, "[%"SCNu64"]  Got an RTCP packet (%s stream)!\n", handle->handle_id,
2107
                        janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? "bundled" : (stream->stream_id == handle->audio_id ? "audio" : "video"));
2108
                if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_in) {
2109
                        JANUS_LOG(LOG_WARN, "[%"SCNu64"]     Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
2110
                } else {
2111
                        int buflen = len;
2112
                        srtp_err_status_t res = srtp_unprotect_rtcp(component->dtls->srtp_in, buf, &buflen);
2113
                        if(res != srtp_err_status_ok) {
2114
                                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     SRTCP unprotect error: %s (len=%d-->%d)\n", handle->handle_id, janus_srtp_error_str(res), len, buflen);
2115
                        } else {
2116
                                /* Check if there's an RTCP BYE: in case, let's wrap up */
2117
                                if(janus_rtcp_has_bye(buf, buflen)) {
2118
                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got RTCP BYE on stream %"SCNu16" (component %"SCNu16"), closing...\n", handle->handle_id, stream->stream_id, component->component_id);
2119
                                        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
2120
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) {
2121
                                                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
2122
                                                if(handle->iceloop)
2123
                                                        g_main_loop_quit(handle->iceloop);
2124
                                                janus_plugin *plugin = (janus_plugin *)handle->app;
2125
                                                if(plugin != NULL) {
2126
                                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about it (%s)\n", handle->handle_id, plugin->get_name());
2127
                                                        if(plugin && plugin->hangup_media)
2128
                                                                plugin->hangup_media(handle->app_handle);
2129
                                                        janus_ice_notify_hangup(handle, "RTCP BYE");
2130
                                                }
2131
                                        }
2132
                                        return;
2133
                                }
2134
                                /* Is this audio or video? */
2135
                                int video = 0;
2136
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
2137
                                        /* Easy enough */
2138
                                        video = (stream->stream_id == handle->video_id ? 1 : 0);
2139
                                } else {
2140
                                        /* Bundled streams, should we check the SSRCs? */
2141
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO)) {
2142
                                                /* No audio has been negotiated, definitely video */
2143
                                                JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is video (no audio has been negotiated)\n", handle->handle_id);
2144
                                                video = 1;
2145
                                        } else if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)) {
2146
                                                /* No video has been negotiated, definitely audio */
2147
                                                JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is audio (no video has been negotiated)\n", handle->handle_id);
2148
                                                video = 0;
2149
                                        } else {
2150
                                                if(stream->audio_ssrc_peer == 0 || stream->video_ssrc_peer == 0) {
2151
                                                        /* We don't know the remote SSRC: this can happen for recvonly clients
2152
                                                         * (see https://groups.google.com/forum/#!topic/discuss-webrtc/5yuZjV7lkNc)
2153
                                                         * Check the local SSRC, compare it to what we have */
2154
                                                        guint32 rtcp_ssrc = janus_rtcp_get_receiver_ssrc(buf, len);
2155
                                                        if(rtcp_ssrc == stream->audio_ssrc) {
2156
                                                                video = 0;
2157
                                                        } else if(rtcp_ssrc == stream->video_ssrc) {
2158
                                                                video = 1;
2159
                                                        } else {
2160
                                                                /* Mh, no SR or RR? Try checking if there's any FIR, PLI or REMB */
2161
                                                                if(janus_rtcp_has_fir(buf, len) || janus_rtcp_has_pli(buf, len) || janus_rtcp_get_remb(buf, len)) {
2162
                                                                        video = 1;
2163
                                                                }
2164
                                                        }
2165
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (local SSRC: video=%"SCNu32", audio=%"SCNu32", got %"SCNu32")\n",
2166
                                                                handle->handle_id, video ? "video" : "audio", stream->video_ssrc, stream->audio_ssrc, rtcp_ssrc);
2167
                                                } else {
2168
                                                        /* Check the remote SSRC, compare it to what we have */
2169
                                                        guint32 rtcp_ssrc = janus_rtcp_get_sender_ssrc(buf, len);
2170
                                                        video = (stream->video_ssrc_peer == rtcp_ssrc ? 1 : 0);
2171
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (remote SSRC: video=%"SCNu32", audio=%"SCNu32", got %"SCNu32")\n",
2172
                                                                handle->handle_id, video ? "video" : "audio", stream->video_ssrc_peer, stream->audio_ssrc_peer, rtcp_ssrc);
2173
                                                }
2174
                                        }
2175
                                }
2176
                                /* Let's process this RTCP (compound?) packet, and update the RTCP context for this stream in case */
2177
                                rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx : stream->audio_rtcp_ctx;
2178
                                janus_rtcp_parse(rtcp_ctx, buf, buflen);
2179

    
2180
                                /* Now let's see if there are any NACKs to handle */
2181
                                gint64 now = janus_get_monotonic_time();
2182
                                GSList *nacks = janus_rtcp_get_nacks(buf, buflen);
2183
                                guint nacks_count = g_slist_length(nacks);
2184
                                if(nacks_count) {
2185
                                        /* Handle NACK */
2186
                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"]     Just got some NACKS (%d) we should handle...\n", handle->handle_id, nacks_count);
2187
                                        GSList *list = nacks;
2188
                                        int retransmits_cnt = 0;
2189
                                        janus_mutex_lock(&component->mutex);
2190
                                        while(list) {
2191
                                                unsigned int seqnr = GPOINTER_TO_UINT(list->data);
2192
                                                JANUS_LOG(LOG_DBG, "[%"SCNu64"]   >> %u\n", handle->handle_id, seqnr);
2193
                                                GList *rp = component->retransmit_buffer;
2194
                                                while(rp) {
2195
                                                        janus_rtp_packet *p = (janus_rtp_packet *)rp->data;
2196
                                                        if(p) {
2197
                                                                rtp_header *rh = (rtp_header *)p->data;
2198
                                                                if(ntohs(rh->seq_number) == seqnr) {
2199
                                                                        /* Should we retransmit this packet? */
2200
                                                                        if((p->last_retransmit > 0) && (now-p->last_retransmit < MAX_NACK_IGNORE)) {
2201
                                                                                JANUS_LOG(LOG_HUGE, "[%"SCNu64"]   >> >> Packet %u was retransmitted just %"SCNi64"ms ago, skipping\n", handle->handle_id, seqnr, now-p->last_retransmit);
2202
                                                                                break;
2203
                                                                        }
2204
                                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"]   >> >> Scheduling %u for retransmission due to NACK\n", handle->handle_id, seqnr);
2205
                                                                        p->last_retransmit = now;
2206
                                                                        retransmits_cnt++;
2207
                                                                        /* Enqueue it */
2208
                                                                        janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
2209
                                                                        pkt->data = g_malloc0(p->length);
2210
                                                                        memcpy(pkt->data, p->data, p->length);
2211
                                                                        pkt->length = p->length;
2212
                                                                        pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
2213
                                                                        pkt->control = FALSE;
2214
                                                                        pkt->encrypted = TRUE;        /* This was already encrypted before */
2215
                                                                        if(handle->queued_packets != NULL)
2216
                                                                                g_async_queue_push(handle->queued_packets, pkt);
2217
                                                                        break;
2218
                                                                }
2219
                                                        }
2220
                                                        rp = rp->next;
2221
                                                }
2222
                                                list = list->next;
2223
                                        }
2224
                                        component->retransmit_recent_cnt += retransmits_cnt;
2225
                                        /* FIXME Remove the NACK compound packet, we've handled it */
2226
                                        buflen = janus_rtcp_remove_nacks(buf, buflen);
2227
                                        /* Update stats */
2228
                                        if(video) {
2229
                                                component->in_stats.video_nacks += nacks_count;
2230
                                        } else {
2231
                                                component->in_stats.audio_nacks += nacks_count;
2232
                                        }
2233
                                        /* Inform the plugin about the slow uplink in case it's needed */
2234
                                        janus_slow_link_update(component, handle, retransmits_cnt, video, 1, now);
2235
                                        janus_mutex_unlock(&component->mutex);
2236
                                        g_slist_free(nacks);
2237
                                        nacks = NULL;
2238
                                }
2239
                                if (component->retransmit_recent_cnt &&
2240
                                    now - component->retransmit_log_ts > 5 * G_USEC_PER_SEC) {
2241
                                        JANUS_LOG(LOG_VERB, "[%10"SCNu64"]  retransmitted %u packets due to NACK\n",
2242
                                                              handle->handle_id,    component->retransmit_recent_cnt);
2243
                                        component->retransmit_recent_cnt = 0;
2244
                                        component->retransmit_log_ts = now;
2245
                                }
2246

    
2247
                                janus_plugin *plugin = (janus_plugin *)handle->app;
2248
                                if(plugin && plugin->incoming_rtcp)
2249
                                        plugin->incoming_rtcp(handle->app_handle, video, buf, buflen);
2250
                        }
2251
                }
2252
                return;
2253
        }
2254
        if(component_id == 3 || (janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)
2255
                        && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS))) {
2256
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Not RTP and not RTCP... may these be data channels?\n", handle->handle_id);
2257
                janus_dtls_srtp_incoming_msg(component->dtls, buf, len);
2258
                /* Update stats (TODO Do the same for the last second window as well) */
2259
                if(len > 0) {
2260
                        component->in_stats.data_packets++;
2261
                        component->in_stats.data_bytes += len;
2262
                }
2263
                return;
2264
        }
2265
}
2266

    
2267
void janus_ice_incoming_data(janus_ice_handle *handle, char *buffer, int length) {
2268
        if(handle == NULL || buffer == NULL || length <= 0)
2269
                return;
2270
        janus_plugin *plugin = (janus_plugin *)handle->app;
2271
        if(plugin && plugin->incoming_data)
2272
                plugin->incoming_data(handle->app_handle, buffer, length);
2273
}
2274

    
2275

    
2276
/* Thread to create agent */
2277
void *janus_ice_thread(void *data) {
2278
        janus_ice_handle *handle = data;
2279
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE thread started\n", handle->handle_id);
2280
        GMainLoop *loop = handle->iceloop;
2281
        if(loop == NULL) {
2282
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Invalid loop...\n", handle->handle_id);
2283
                g_thread_unref(g_thread_self());
2284
                return NULL;
2285
        }
2286
        g_usleep (100000);
2287
        JANUS_LOG(LOG_DBG, "[%"SCNu64"] Looping (ICE)...\n", handle->handle_id);
2288
        g_main_loop_run (loop);
2289
        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
2290
        if(handle->cdone == 0)
2291
                handle->cdone = -1;
2292
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE thread ended!\n", handle->handle_id);
2293
        /* This handle has been destroyed, wait a bit and then free all the resources */
2294
        g_usleep (1*G_USEC_PER_SEC);
2295
        if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP)) {
2296
                //~ janus_ice_free(handle);
2297
        } else {
2298
                janus_ice_webrtc_free(handle);
2299
        }
2300
        g_thread_unref(g_thread_self());
2301
        return NULL;
2302
}
2303

    
2304
/* Helper: candidates */
2305
void janus_ice_candidates_to_sdp(janus_ice_handle *handle, janus_sdp_mline *mline, guint stream_id, guint component_id)
2306
{
2307
        if(!handle || !handle->agent || !mline)
2308
                return;
2309
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
2310
        if(!stream) {
2311
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
2312
                return;
2313
        }
2314
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
2315
        if(!component) {
2316
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
2317
                return;
2318
        }
2319
        NiceAgent* agent = handle->agent;
2320
        /* adding a stream should cause host candidates to be generated */
2321
        char *host_ip = NULL;
2322
        if(nat_1_1_enabled) {
2323
                /* A 1:1 NAT mapping was specified, overwrite all the host addresses with the public IP */
2324
                host_ip = janus_get_public_ip();
2325
                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);
2326
        }
2327
        GSList *candidates, *i;
2328
        candidates = nice_agent_get_local_candidates (agent, stream_id, component_id);
2329
        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);
2330
        gboolean log_candidates = (component->local_candidates == NULL);
2331
        for (i = candidates; i; i = i->next) {
2332
                NiceCandidate *c = (NiceCandidate *) i->data;
2333
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream #%d, Component #%d\n", handle->handle_id, c->stream_id, c->component_id);
2334
                gchar address[NICE_ADDRESS_STRING_LEN], base_address[NICE_ADDRESS_STRING_LEN];
2335
                gint port = 0, base_port = 0;
2336
                nice_address_to_string(&(c->addr), (gchar *)&address);
2337
                port = nice_address_get_port(&(c->addr));
2338
                nice_address_to_string(&(c->base_addr), (gchar *)&base_address);
2339
                base_port = nice_address_get_port(&(c->base_addr));
2340
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Address:    %s:%d\n", handle->handle_id, address, port);
2341
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Priority:   %d\n", handle->handle_id, c->priority);
2342
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Foundation: %s\n", handle->handle_id, c->foundation);
2343
                /* SDP time */
2344
                gchar buffer[200];
2345
                if(c->type == NICE_CANDIDATE_TYPE_HOST) {
2346
                        /* 'host' candidate */
2347
                        if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
2348
                                g_snprintf(buffer, sizeof(buffer),
2349
                                        "%s %d %s %d %s %d typ host",
2350
                                                c->foundation,
2351
                                                c->component_id,
2352
                                                "udp",
2353
                                                c->priority,
2354
                                                host_ip ? host_ip : address,
2355
                                                port);
2356
                        } else {
2357
                                if(!janus_ice_tcp_enabled) {
2358
                                        /* ICE-TCP support disabled */
2359
                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping host TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
2360
                                        nice_candidate_free(c);
2361
                                        continue;
2362
                                }
2363
#ifndef HAVE_LIBNICE_TCP
2364
                                /* TCP candidates are only supported since libnice 0.1.8 */
2365
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping host TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
2366
                                nice_candidate_free(c);
2367
                                continue;
2368
#else
2369
                                const char *type = NULL;
2370
                                switch(c->transport) {
2371
                                        case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2372
                                                type = "active";
2373
                                                break;
2374
                                        case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2375
                                                type = "passive";
2376
                                                break;
2377
                                        case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2378
                                                type = "so";
2379
                                                break;
2380
                                        default:
2381
                                                break;
2382
                                }
2383
                                if(type == NULL) {
2384
                                        /* FIXME Unsupported transport */
2385
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP host candidate...\n", handle->handle_id);
2386
                                        nice_candidate_free(c);
2387
                                        continue;
2388
                                } else {
2389
                                        g_snprintf(buffer, sizeof(buffer),
2390
                                                "%s %d %s %d %s %d typ host tcptype %s",
2391
                                                        c->foundation,
2392
                                                        c->component_id,
2393
                                                        "tcp",
2394
                                                        c->priority,
2395
                                                        host_ip ? host_ip : address,
2396
                                                        port,
2397
                                                        type);
2398
                                }
2399
#endif
2400
                        }
2401
                } else if(c->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) {
2402
                        /* 'srflx' candidate */
2403
                        if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
2404
                                nice_address_to_string(&(c->base_addr), (gchar *)&base_address);
2405
                                gint base_port = nice_address_get_port(&(c->base_addr));
2406
                                g_snprintf(buffer, sizeof(buffer),
2407
                                        "%s %d %s %d %s %d typ srflx raddr %s rport %d",
2408
                                                c->foundation,
2409
                                                c->component_id,
2410
                                                "udp",
2411
                                                c->priority,
2412
                                                address,
2413
                                                port,
2414
                                                base_address,
2415
                                                base_port);
2416
                        } else {
2417
                                if(!janus_ice_tcp_enabled) {
2418
                                        /* ICE-TCP support disabled */
2419
                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping srflx TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
2420
                                        nice_candidate_free(c);
2421
                                        continue;
2422
                                }
2423
#ifndef HAVE_LIBNICE_TCP
2424
                                /* TCP candidates are only supported since libnice 0.1.8 */
2425
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping srflx TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
2426
                                nice_candidate_free(c);
2427
                                continue;
2428
#else
2429
                                const char *type = NULL;
2430
                                switch(c->transport) {
2431
                                        case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2432
                                                type = "active";
2433
                                                break;
2434
                                        case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2435
                                                type = "passive";
2436
                                                break;
2437
                                        case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2438
                                                type = "so";
2439
                                                break;
2440
                                        default:
2441
                                                break;
2442
                                }
2443
                                if(type == NULL) {
2444
                                        /* FIXME Unsupported transport */
2445
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP srflx candidate...\n", handle->handle_id);
2446
                                        nice_candidate_free(c);
2447
                                        continue;
2448
                                } else {
2449
                                        g_snprintf(buffer, sizeof(buffer),
2450
                                                "%s %d %s %d %s %d typ srflx raddr %s rport %d tcptype %s",
2451
                                                        c->foundation,
2452
                                                        c->component_id,
2453
                                                        "tcp",
2454
                                                        c->priority,
2455
                                                        address,
2456
                                                        port,
2457
                                                        base_address,
2458
                                                        base_port,
2459
                                                        type);
2460
                                }
2461
#endif
2462
                        }
2463
                } else if(c->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
2464
                        /* 'prflx' candidate: skip it, we don't add them to the SDP */
2465
                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping prflx candidate...\n", handle->handle_id);
2466
                        nice_candidate_free(c);
2467
                        continue;
2468
                } else if(c->type == NICE_CANDIDATE_TYPE_RELAYED) {
2469
                        /* 'relay' candidate */
2470
                        if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
2471
                                g_snprintf(buffer, sizeof(buffer),
2472
                                        "%s %d %s %d %s %d typ relay raddr %s rport %d",
2473
                                                c->foundation,
2474
                                                c->component_id,
2475
                                                "udp",
2476
                                                c->priority,
2477
                                                address,
2478
                                                port,
2479
                                                base_address,
2480
                                                base_port);
2481
                        } else {
2482
                                if(!janus_ice_tcp_enabled) {
2483
                                        /* ICE-TCP support disabled */
2484
                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping relay TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
2485
                                        nice_candidate_free(c);
2486
                                        continue;
2487
                                }
2488
#ifndef HAVE_LIBNICE_TCP
2489
                                /* TCP candidates are only supported since libnice 0.1.8 */
2490
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping relay TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
2491
                                nice_candidate_free(c);
2492
                                continue;
2493
#else
2494
                                const char *type = NULL;
2495
                                switch(c->transport) {
2496
                                        case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2497
                                                type = "active";
2498
                                                break;
2499
                                        case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2500
                                                type = "passive";
2501
                                                break;
2502
                                        case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2503
                                                type = "so";
2504
                                                break;
2505
                                        default:
2506
                                                break;
2507
                                }
2508
                                if(type == NULL) {
2509
                                        /* FIXME Unsupported transport */
2510
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP relay candidate...\n", handle->handle_id);
2511
                                        nice_candidate_free(c);
2512
                                        continue;
2513
                                } else {
2514
                                        g_snprintf(buffer, sizeof(buffer),
2515
                                                "%s %d %s %d %s %d typ relay raddr %s rport %d tcptype %s",
2516
                                                        c->foundation,
2517
                                                        c->component_id,
2518
                                                        "tcp",
2519
                                                        c->priority,
2520
                                                        address,
2521
                                                        port,
2522
                                                        base_address,
2523
                                                        base_port,
2524
                                                        type);
2525
                                }
2526
#endif
2527
                        }
2528
                }
2529
                janus_sdp_attribute *a = janus_sdp_attribute_create("candidate", "%s", buffer);
2530
                mline->attributes = g_list_append(mline->attributes, a);
2531
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]     %s", handle->handle_id, buffer); /* buffer already newline terminated */
2532
                if(log_candidates) {
2533
                        /* Save for the summary, in case we need it */
2534
                        component->local_candidates = g_slist_append(component->local_candidates, g_strdup(buffer));
2535
                }
2536
                nice_candidate_free(c);
2537
        }
2538
        g_slist_free(candidates);
2539
}
2540

    
2541
void janus_ice_setup_remote_candidates(janus_ice_handle *handle, guint stream_id, guint component_id) {
2542
        if(!handle || !handle->agent || !handle->streams)
2543
                return;
2544
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
2545
        if(!stream || !stream->components) {
2546
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] No such stream %d: cannot setup remote candidates for component %d\n", handle->handle_id, stream_id, component_id);
2547
                return;
2548
        }
2549
        if(stream->disabled) {
2550
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream %d is disabled, skipping remote candidates for component %d\n", handle->handle_id, stream_id, component_id);
2551
                return;
2552
        }
2553
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
2554
        if(!component) {
2555
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] No such component %d in stream %d: cannot setup remote candidates\n", handle->handle_id, component_id, stream_id);
2556
                return;
2557
        }
2558
        if(component->process_started) {
2559
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Component %d in stream %d has already been set up\n", handle->handle_id, component_id, stream_id);
2560
                return;
2561
        }
2562
        if(!component->candidates || !component->candidates->data) {
2563
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE)
2564
                                || janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES)) { 
2565
                        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);
2566
                }
2567
                return;
2568
        }
2569
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ## Setting remote candidates: stream %d, component %d (%u in the list)\n",
2570
                handle->handle_id, stream_id, component_id, g_slist_length(component->candidates));
2571
        /* Add all candidates */
2572
        NiceCandidate *c = NULL;
2573
        GSList *gsc = component->candidates;
2574
        gchar *rufrag = NULL, *rpwd = NULL;
2575
        while(gsc) {
2576
                c = (NiceCandidate *) gsc->data;
2577
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] >> Remote Stream #%d, Component #%d\n", handle->handle_id, c->stream_id, c->component_id);
2578
                if(c->username && !rufrag)
2579
                        rufrag = c->username;
2580
                if(c->password && !rpwd)
2581
                        rpwd = c->password;
2582
                gchar address[NICE_ADDRESS_STRING_LEN];
2583
                nice_address_to_string(&(c->addr), (gchar *)&address);
2584
                gint port = nice_address_get_port(&(c->addr));
2585
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Address:    %s:%d\n", handle->handle_id, address, port);
2586
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Priority:   %d\n", handle->handle_id, c->priority);
2587
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Foundation: %s\n", handle->handle_id, c->foundation);
2588
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Username:   %s\n", handle->handle_id, c->username);
2589
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Password:   %s\n", handle->handle_id, c->password);
2590
                gsc = gsc->next;
2591
        }
2592
        if(rufrag && rpwd) {
2593
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]  Setting remote credentials...\n", handle->handle_id);
2594
                if(!nice_agent_set_remote_credentials(handle->agent, stream_id, rufrag, rpwd)) {
2595
                        JANUS_LOG(LOG_ERR, "[%"SCNu64"]  failed to set remote credentials!\n", handle->handle_id);
2596
                }
2597
        }
2598
        guint added = nice_agent_set_remote_candidates(handle->agent, stream_id, component_id, component->candidates);
2599
        if(added < g_slist_length(component->candidates)) {
2600
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Failed to set remote candidates :-( (added %u, expected %u)\n",
2601
                        handle->handle_id, added, g_slist_length(component->candidates));
2602
        } else {
2603
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Remote candidates set!\n", handle->handle_id);
2604
                component->process_started = TRUE;
2605
        }
2606
}
2607

    
2608
int janus_ice_setup_local(janus_ice_handle *handle, int offer, int audio, int video, int data, int bundle, int rtcpmux, int trickle) {
2609
        if(!handle)
2610
                return -1;
2611
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting ICE locally: got %s (%d audios, %d videos)\n", handle->handle_id, offer ? "OFFER" : "ANSWER", audio, video);
2612
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_START);
2613
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
2614
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
2615
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
2616
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
2617
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
2618
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
2619

    
2620
        /* Note: in case this is not an OFFER, we don't know whether any medium are supported on the other side or not yet */
2621
        if(audio) {
2622
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
2623
        } else {
2624
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
2625
        }
2626
        if(video) {
2627
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
2628
        } else {
2629
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
2630
        }
2631
        if(data) {
2632
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS);
2633
        } else {
2634
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS);
2635
        }
2636
        /* Note: in case this is not an OFFER, we don't know whether BUNDLE is supported on the other side or not yet,
2637
         * unless Janus was configured to force BUNDLE in which case we enable it on our side anyway */
2638
        if((offer && bundle) || janus_force_bundle) {
2639
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE);
2640
        } else {
2641
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE);
2642
        }
2643
        /* Note: in case this is not an OFFER, we don't know whether rtcp-mux is supported on the other side or not yet,
2644
         * unless Janus was configured to force rtcp-mux in which case we enable it on our side anyway */
2645
        if((offer && rtcpmux) || janus_force_rtcpmux) {
2646
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX);
2647
        } else {
2648
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX);
2649
        }
2650
        /* Note: in case this is not an OFFER, we don't know whether ICE trickling is supported on the other side or not yet */
2651
        if(offer && trickle) {
2652
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE);
2653
        } else {
2654
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE);
2655
        }
2656
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES);
2657
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE_SYNCED);
2658

    
2659
        handle->icectx = g_main_context_new();
2660
        handle->iceloop = g_main_loop_new(handle->icectx, FALSE);
2661
        GError *error = NULL;
2662
        char tname[16];
2663
        g_snprintf(tname, sizeof(tname), "iceloop %"SCNu64, handle->handle_id);
2664
        handle->icethread = g_thread_try_new(tname, &janus_ice_thread, handle, &error);
2665
        if(error != NULL) {
2666
                /* FIXME We should clear some resources... */
2667
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Got error %d (%s) trying to launch the ICE thread...\n", handle->handle_id, error->code, error->message ? error->message : "??");
2668
                return -1;
2669
         }
2670
        handle->queued_packets = g_async_queue_new();
2671
        /* We wait for ICE to succeed before creating the related thread */
2672
        handle->send_thread = NULL;
2673
        /* Note: NICE_COMPATIBILITY_RFC5245 is only available in more recent versions of libnice */
2674
        handle->controlling = janus_ice_lite_enabled ? FALSE : !offer;
2675
        JANUS_LOG(LOG_INFO, "[%"SCNu64"] Creating ICE agent (ICE %s mode, %s)\n", handle->handle_id,
2676
                janus_ice_lite_enabled ? "Lite" : "Full", handle->controlling ? "controlling" : "controlled");
2677
        g_atomic_int_set(&handle->send_thread_created, 0);
2678
        handle->agent = g_object_new(NICE_TYPE_AGENT,
2679
                "compatibility", NICE_COMPATIBILITY_DRAFT19,
2680
                "main-context", handle->icectx,
2681
                "reliable", FALSE,
2682
                "full-mode", janus_ice_lite_enabled ? FALSE : TRUE,
2683
#ifdef HAVE_LIBNICE_TCP
2684
                "ice-udp", TRUE,
2685
                "ice-tcp", janus_ice_tcp_enabled ? TRUE : FALSE,
2686
#endif
2687
                NULL);
2688
        handle->agent_created = janus_get_monotonic_time();
2689
        handle->srtp_errors_count = 0;
2690
        handle->last_srtp_error = 0;
2691
        /* Any STUN server to use? */
2692
        if(janus_stun_server != NULL && janus_stun_port > 0) {
2693
                g_object_set(G_OBJECT(handle->agent),
2694
                        "stun-server", janus_stun_server,
2695
                        "stun-server-port", janus_stun_port,
2696
                        NULL);
2697
        }
2698
        /* Any dynamic TURN credentials to retrieve via REST API? */
2699
        gboolean have_turnrest_credentials = FALSE;
2700
#ifdef HAVE_LIBCURL
2701
        janus_turnrest_response *turnrest_credentials = janus_turnrest_request();
2702
        if(turnrest_credentials != NULL) {
2703
                have_turnrest_credentials = TRUE;
2704
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got credentials from the TURN REST API backend!\n", handle->handle_id);
2705
                JANUS_LOG(LOG_HUGE, "  -- Username: %s\n", turnrest_credentials->username);
2706
                JANUS_LOG(LOG_HUGE, "  -- Password: %s\n", turnrest_credentials->password);
2707
                JANUS_LOG(LOG_HUGE, "  -- TTL:      %"SCNu32"\n", turnrest_credentials->ttl);
2708
                JANUS_LOG(LOG_HUGE, "  -- Servers:  %d\n", g_list_length(turnrest_credentials->servers));
2709
                GList *server = turnrest_credentials->servers;
2710
                while(server != NULL) {
2711
                        janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2712
                        JANUS_LOG(LOG_HUGE, "  -- -- URI: %s:%"SCNu16" (%d)\n", instance->server, instance->port, instance->transport);
2713
                        server = server->next;
2714
                }
2715
        }
2716
#endif
2717
        g_object_set(G_OBJECT(handle->agent), "upnp", FALSE, NULL);
2718
        g_object_set(G_OBJECT(handle->agent), "controlling-mode", handle->controlling, NULL);
2719
        g_signal_connect (G_OBJECT (handle->agent), "candidate-gathering-done",
2720
                G_CALLBACK (janus_ice_cb_candidate_gathering_done), handle);
2721
        g_signal_connect (G_OBJECT (handle->agent), "component-state-changed",
2722
                G_CALLBACK (janus_ice_cb_component_state_changed), handle);
2723
#ifndef HAVE_LIBNICE_TCP
2724
        g_signal_connect (G_OBJECT (handle->agent), "new-selected-pair",
2725
#else
2726
        g_signal_connect (G_OBJECT (handle->agent), "new-selected-pair-full",
2727
#endif
2728
                G_CALLBACK (janus_ice_cb_new_selected_pair), handle);
2729
#ifndef HAVE_LIBNICE_TCP
2730
        g_signal_connect (G_OBJECT (handle->agent), "new-remote-candidate",
2731
#else
2732
        g_signal_connect (G_OBJECT (handle->agent), "new-remote-candidate-full",
2733
#endif
2734
                G_CALLBACK (janus_ice_cb_new_remote_candidate), handle);
2735

    
2736
        /* Add all local addresses, except those in the ignore list */
2737
        struct ifaddrs *ifaddr, *ifa;
2738
        int family, s, n;
2739
        char host[NI_MAXHOST];
2740
        if(getifaddrs(&ifaddr) == -1) {
2741
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error getting list of interfaces...", handle->handle_id);
2742
        } else {
2743
                for(ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
2744
                        if(ifa->ifa_addr == NULL)
2745
                                continue;
2746
                        /* Skip interfaces which are not up and running */
2747
                        if (!((ifa->ifa_flags & IFF_UP) && (ifa->ifa_flags & IFF_RUNNING)))
2748
                                continue;
2749
                        /* Skip loopback interfaces */
2750
                        if (ifa->ifa_flags & IFF_LOOPBACK)
2751
                                continue;
2752
                        family = ifa->ifa_addr->sa_family;
2753
                        if(family != AF_INET && family != AF_INET6)
2754
                                continue;
2755
                        /* We only add IPv6 addresses if support for them has been explicitly enabled (still WIP, mostly) */
2756
                        if(family == AF_INET6 && !janus_ipv6_enabled)
2757
                                continue;
2758
                        /* Check the interface name first, we can ignore that as well: enforce list would be checked later */
2759
                        if(janus_ice_enforce_list == NULL && ifa->ifa_name != NULL && janus_ice_is_ignored(ifa->ifa_name))
2760
                                continue;
2761
                        s = getnameinfo(ifa->ifa_addr,
2762
                                        (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
2763
                                        host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
2764
                        if(s != 0) {
2765
                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] getnameinfo() failed: %s\n", handle->handle_id, gai_strerror(s));
2766
                                continue;
2767
                        }
2768
                        /* Skip 0.0.0.0, :: and local scoped addresses  */
2769
                        if(!strcmp(host, "0.0.0.0") || !strcmp(host, "::") || !strncmp(host, "fe80:", 5))
2770
                                continue;
2771
                        /* Check if this IP address is in the ignore/enforce list, now: the enforce list has the precedence */
2772
                        if(janus_ice_enforce_list != NULL) {
2773
                                if(ifa->ifa_name != NULL && !janus_ice_is_enforced(ifa->ifa_name) && !janus_ice_is_enforced(host))
2774
                                        continue;
2775
                        } else {
2776
                                if(janus_ice_is_ignored(host))
2777
                                        continue;
2778
                        }
2779
                        /* Ok, add interface to the ICE agent */
2780
                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Adding %s to the addresses to gather candidates for\n", handle->handle_id, host);
2781
                        NiceAddress addr_local;
2782
                        nice_address_init (&addr_local);
2783
                        if(!nice_address_set_from_string (&addr_local, host)) {
2784
                                JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping invalid address %s\n", handle->handle_id, host);
2785
                                continue;
2786
                        }
2787
                        nice_agent_add_local_address (handle->agent, &addr_local);
2788
                }
2789
                freeifaddrs(ifaddr);
2790
        }
2791

    
2792
        handle->cdone = 0;
2793
        handle->streams_num = 0;
2794
        handle->streams = g_hash_table_new(NULL, NULL);
2795
        if(audio) {
2796
                /* Add an audio stream */
2797
                handle->streams_num++;
2798
                handle->audio_id = nice_agent_add_stream (handle->agent, janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) ? 1 : 2);
2799
                janus_ice_stream *audio_stream = (janus_ice_stream *)g_malloc0(sizeof(janus_ice_stream));
2800
                if(audio_stream == NULL) {
2801
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2802
                        return -1;
2803
                }
2804
                handle->audio_mid = NULL;
2805
                audio_stream->stream_id = handle->audio_id;
2806
                audio_stream->handle = handle;
2807
                audio_stream->cdone = 0;
2808
                audio_stream->payload_type = -1;
2809
                audio_stream->disabled = FALSE;
2810
                /* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
2811
                audio_stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
2812
                audio_stream->audio_ssrc = janus_random_uint32();        /* FIXME Should we look for conflicts? */
2813
                audio_stream->audio_ssrc_peer = 0;        /* FIXME Right now we don't know what this will be */
2814
                audio_stream->video_ssrc = 0;
2815
                if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
2816
                        /* If we're bundling, this stream is going to be used for video as well */
2817
                        audio_stream->video_ssrc = janus_random_uint32();        /* FIXME Should we look for conflicts? */
2818
                }
2819
                audio_stream->video_ssrc_peer = 0;        /* FIXME Right now we don't know what this will be */
2820
                audio_stream->video_ssrc_peer_rtx = 0;        /* FIXME Right now we don't know what this will be */
2821
                audio_stream->audio_rtcp_ctx = g_malloc0(sizeof(rtcp_context));
2822
                audio_stream->audio_rtcp_ctx->tb = 48000;        /* May change later */
2823
                audio_stream->video_rtcp_ctx = g_malloc0(sizeof(rtcp_context));
2824
                audio_stream->video_rtcp_ctx->tb = 90000;
2825
                audio_stream->noerrorlog = FALSE;
2826
                janus_mutex_init(&audio_stream->mutex);
2827
                audio_stream->components = g_hash_table_new(NULL, NULL);
2828
                g_hash_table_insert(handle->streams, GUINT_TO_POINTER(handle->audio_id), audio_stream);
2829
                if(!have_turnrest_credentials) {
2830
                        /* No TURN REST API server and credentials, any static ones? */
2831
                        if(janus_turn_server != NULL) {
2832
                                /* We need relay candidates as well */
2833
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 1,
2834
                                        janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
2835
                                if(!ok) {
2836
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2837
                                                janus_turn_server, janus_turn_port);
2838
                                }
2839
                        }
2840
#ifdef HAVE_LIBCURL
2841
                } else {
2842
                        /* We need relay candidates as well: add all those we got */
2843
                        GList *server = turnrest_credentials->servers;
2844
                        while(server != NULL) {
2845
                                janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2846
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 1,
2847
                                        instance->server, instance->port,
2848
                                        turnrest_credentials->username, turnrest_credentials->password,
2849
                                        instance->transport);
2850
                                if(!ok) {
2851
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2852
                                                instance->server, instance->port);
2853
                                }
2854
                                server = server->next;
2855
                        }
2856
#endif
2857
                }
2858
                handle->audio_stream = audio_stream;
2859
                janus_ice_component *audio_rtp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
2860
                if(audio_rtp == NULL) {
2861
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2862
                        return -1;
2863
                }
2864
                audio_rtp->stream = audio_stream;
2865
                audio_rtp->stream_id = audio_stream->stream_id;
2866
                audio_rtp->component_id = 1;
2867
                audio_rtp->candidates = NULL;
2868
                audio_rtp->local_candidates = NULL;
2869
                audio_rtp->remote_candidates = NULL;
2870
                audio_rtp->selected_pair = NULL;
2871
                audio_rtp->process_started = FALSE;
2872
                audio_rtp->source = NULL;
2873
                audio_rtp->dtls = NULL;
2874
                audio_rtp->retransmit_buffer = NULL;
2875
                audio_rtp->retransmit_log_ts = 0;
2876
                audio_rtp->retransmit_recent_cnt = 0;
2877
                audio_rtp->nack_sent_log_ts = 0;
2878
                audio_rtp->nack_sent_recent_cnt = 0;
2879
                audio_rtp->last_seqs_audio = NULL;
2880
                audio_rtp->last_seqs_video = NULL;
2881
                janus_ice_stats_reset(&audio_rtp->in_stats);
2882
                janus_ice_stats_reset(&audio_rtp->out_stats);
2883
                janus_mutex_init(&audio_rtp->mutex);
2884
                g_hash_table_insert(audio_stream->components, GUINT_TO_POINTER(1), audio_rtp);
2885
                audio_stream->rtp_component = audio_rtp;
2886
#ifdef HAVE_PORTRANGE
2887
                /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
2888
                nice_agent_set_port_range(handle->agent, handle->audio_id, 1, rtp_range_min, rtp_range_max);
2889
#endif
2890
                janus_ice_component *audio_rtcp = NULL;
2891
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
2892
                        audio_rtcp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
2893
                        if(audio_rtcp == NULL) {
2894
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
2895
                                return -1;
2896
                        }
2897
                        if(!have_turnrest_credentials) {
2898
                                /* No TURN REST API server and credentials, any static ones? */
2899
                                if(janus_turn_server != NULL) {
2900
                                        /* We need relay candidates as well */
2901
                                        gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 2,
2902
                                                janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
2903
                                        if(!ok) {
2904
                                                JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2905
                                                        janus_turn_server, janus_turn_port);
2906
                                        }
2907
                                }
2908
#ifdef HAVE_LIBCURL
2909
                        } else {
2910
                                /* We need relay candidates as well: add all those we got */
2911
                                GList *server = turnrest_credentials->servers;
2912
                                while(server != NULL) {
2913
                                        janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2914
                                        gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 2,
2915
                                                instance->server, instance->port,
2916
                                                turnrest_credentials->username, turnrest_credentials->password,
2917
                                                instance->transport);
2918
                                        if(!ok) {
2919
                                                JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2920
                                                        instance->server, instance->port);
2921
                                        }
2922
                                        server = server->next;
2923
                                }
2924
#endif
2925
                        }
2926
                        audio_rtcp->stream = audio_stream;
2927
                        audio_rtcp->stream_id = audio_stream->stream_id;
2928
                        audio_rtcp->component_id = 2;
2929
                        audio_rtcp->candidates = NULL;
2930
                        audio_rtcp->local_candidates = NULL;
2931
                        audio_rtcp->remote_candidates = NULL;
2932
                        audio_rtcp->selected_pair = NULL;
2933
                        audio_rtcp->process_started = FALSE;
2934
                        audio_rtcp->source = NULL;
2935
                        audio_rtcp->dtls = NULL;
2936
                        audio_rtcp->retransmit_buffer = NULL;
2937
                        audio_rtcp->retransmit_log_ts = 0;
2938
                        audio_rtcp->retransmit_recent_cnt = 0;
2939
                        janus_ice_stats_reset(&audio_rtcp->in_stats);
2940
                        janus_ice_stats_reset(&audio_rtcp->out_stats);
2941
                        janus_mutex_init(&audio_rtcp->mutex);
2942
                        g_hash_table_insert(audio_stream->components, GUINT_TO_POINTER(2), audio_rtcp);
2943
                        audio_stream->rtcp_component = audio_rtcp;
2944
#ifdef HAVE_PORTRANGE
2945
                /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
2946
                        nice_agent_set_port_range(handle->agent, handle->audio_id, 2, rtp_range_min, rtp_range_max);
2947
#endif
2948
                }
2949
                nice_agent_gather_candidates(handle->agent, handle->audio_id);
2950
                nice_agent_attach_recv(handle->agent, handle->audio_id, 1, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, audio_rtp);
2951
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) && audio_rtcp != NULL)
2952
                        nice_agent_attach_recv(handle->agent, handle->audio_id, 2, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, audio_rtcp);
2953
        }
2954
        if(video && (!audio || !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE))) {
2955
                /* Add a video stream */
2956
                handle->streams_num++;
2957
                handle->video_id = nice_agent_add_stream (handle->agent, janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) ? 1 : 2);
2958
                janus_ice_stream *video_stream = (janus_ice_stream *)g_malloc0(sizeof(janus_ice_stream));
2959
                if(video_stream == NULL) {
2960
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2961
                        return -1;
2962
                }
2963
                handle->video_mid = NULL;
2964
                video_stream->handle = handle;
2965
                video_stream->stream_id = handle->video_id;
2966
                video_stream->cdone = 0;
2967
                video_stream->payload_type = -1;
2968
                video_stream->disabled = FALSE;
2969
                /* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
2970
                video_stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
2971
                video_stream->video_ssrc = janus_random_uint32();        /* FIXME Should we look for conflicts? */
2972
                video_stream->video_ssrc_peer = 0;        /* FIXME Right now we don't know what this will be */
2973
                video_stream->video_ssrc_peer_rtx = 0;        /* FIXME Right now we don't know what this will be */
2974
                video_stream->audio_ssrc = 0;
2975
                video_stream->audio_ssrc_peer = 0;
2976
                video_stream->video_rtcp_ctx = g_malloc0(sizeof(rtcp_context));
2977
                video_stream->video_rtcp_ctx->tb = 90000;
2978
                video_stream->components = g_hash_table_new(NULL, NULL);
2979
                video_stream->noerrorlog = FALSE;
2980
                janus_mutex_init(&video_stream->mutex);
2981
                g_hash_table_insert(handle->streams, GUINT_TO_POINTER(handle->video_id), video_stream);
2982
                if(!have_turnrest_credentials) {
2983
                        /* No TURN REST API server and credentials, any static ones? */
2984
                        if(janus_turn_server != NULL) {
2985
                                /* We need relay candidates as well */
2986
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 1,
2987
                                        janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
2988
                                if(!ok) {
2989
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2990
                                                janus_turn_server, janus_turn_port);
2991
                                }
2992
                        }
2993
#ifdef HAVE_LIBCURL
2994
                } else {
2995
                        /* We need relay candidates as well: add all those we got */
2996
                        GList *server = turnrest_credentials->servers;
2997
                        while(server != NULL) {
2998
                                janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2999
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 1,
3000
                                        instance->server, instance->port,
3001
                                        turnrest_credentials->username, turnrest_credentials->password,
3002
                                        instance->transport);
3003
                                if(!ok) {
3004
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
3005
                                                instance->server, instance->port);
3006
                                }
3007
                                server = server->next;
3008
                        }
3009
#endif
3010
                }
3011
                handle->video_stream = video_stream;
3012
                janus_ice_component *video_rtp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
3013
                if(video_rtp == NULL) {
3014
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
3015
                        return -1;
3016
                }
3017
                video_rtp->stream = video_stream;
3018
                video_rtp->stream_id = video_stream->stream_id;
3019
                video_rtp->component_id = 1;
3020
                video_rtp->candidates = NULL;
3021
                video_rtp->local_candidates = NULL;
3022
                video_rtp->remote_candidates = NULL;
3023
                video_rtp->selected_pair = NULL;
3024
                video_rtp->process_started = FALSE;
3025
                video_rtp->source = NULL;
3026
                video_rtp->dtls = NULL;
3027
                video_rtp->retransmit_buffer = NULL;
3028
                video_rtp->retransmit_log_ts = 0;
3029
                video_rtp->retransmit_recent_cnt = 0;
3030
                video_rtp->nack_sent_log_ts = 0;
3031
                video_rtp->nack_sent_recent_cnt = 0;
3032
                video_rtp->last_seqs_audio = NULL;
3033
                video_rtp->last_seqs_video = NULL;
3034
                janus_ice_stats_reset(&video_rtp->in_stats);
3035
                janus_ice_stats_reset(&video_rtp->out_stats);
3036
                janus_mutex_init(&video_rtp->mutex);
3037
                g_hash_table_insert(video_stream->components, GUINT_TO_POINTER(1), video_rtp);
3038
                video_stream->rtp_component = video_rtp;
3039
#ifdef HAVE_PORTRANGE
3040
                /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
3041
                nice_agent_set_port_range(handle->agent, handle->video_id, 1, rtp_range_min, rtp_range_max);
3042
#endif
3043
                janus_ice_component *video_rtcp = NULL;
3044
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
3045
                        video_rtcp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
3046
                        if(video_rtcp == NULL) {
3047
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
3048
                                return -1;
3049
                        }
3050
                        if(!have_turnrest_credentials) {
3051
                                /* No TURN REST API server and credentials, any static ones? */
3052
                                if(janus_turn_server != NULL) {
3053
                                        /* We need relay candidates as well */
3054
                                        gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 2,
3055
                                                janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
3056
                                        if(!ok) {
3057
                                                JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
3058
                                                        janus_turn_server, janus_turn_port);
3059
                                        }
3060
                                }
3061
#ifdef HAVE_LIBCURL
3062
                        } else {
3063
                                /* We need relay candidates as well: add all those we got */
3064
                                GList *server = turnrest_credentials->servers;
3065
                                while(server != NULL) {
3066
                                        janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
3067
                                        gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 2,
3068
                                                instance->server, instance->port,
3069
                                                turnrest_credentials->username, turnrest_credentials->password,
3070
                                                instance->transport);
3071
                                        if(!ok) {
3072
                                                JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
3073
                                                        instance->server, instance->port);
3074
                                        }
3075
                                        server = server->next;
3076
                                }
3077
#endif
3078
                        }
3079
                        video_rtcp->stream = video_stream;
3080
                        video_rtcp->stream_id = video_stream->stream_id;
3081
                        video_rtcp->component_id = 2;
3082
                        video_rtcp->candidates = NULL;
3083
                        video_rtcp->local_candidates = NULL;
3084
                        video_rtcp->remote_candidates = NULL;
3085
                        video_rtcp->selected_pair = NULL;
3086
                        video_rtcp->process_started = FALSE;
3087
                        video_rtcp->source = NULL;
3088
                        video_rtcp->dtls = NULL;
3089
                        video_rtcp->retransmit_buffer = NULL;
3090
                        video_rtcp->retransmit_log_ts = 0;
3091
                        video_rtcp->retransmit_recent_cnt = 0;
3092
                        janus_ice_stats_reset(&video_rtcp->in_stats);
3093
                        janus_ice_stats_reset(&video_rtcp->out_stats);
3094
                        janus_mutex_init(&video_rtcp->mutex);
3095
                        g_hash_table_insert(video_stream->components, GUINT_TO_POINTER(2), video_rtcp);
3096
                        video_stream->rtcp_component = video_rtcp;
3097
#ifdef HAVE_PORTRANGE
3098
                        /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
3099
                        nice_agent_set_port_range(handle->agent, handle->video_id, 2, rtp_range_min, rtp_range_max);
3100
#endif
3101
                }
3102
                nice_agent_gather_candidates(handle->agent, handle->video_id);
3103
                nice_agent_attach_recv(handle->agent, handle->video_id, 1, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, video_rtp);
3104
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) && video_rtcp != NULL)
3105
                        nice_agent_attach_recv(handle->agent, handle->video_id, 2, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, video_rtcp);
3106
        }
3107
#ifndef HAVE_SCTP
3108
        handle->data_id = 0;
3109
        handle->data_stream = NULL;
3110
#else
3111
        if(data && ((!audio && !video) || !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE))) {
3112
                /* Add a SCTP/DataChannel stream */
3113
                handle->streams_num++;
3114
                handle->data_id = nice_agent_add_stream (handle->agent, 1);
3115
                janus_ice_stream *data_stream = (janus_ice_stream *)g_malloc0(sizeof(janus_ice_stream));
3116
                if(data_stream == NULL) {
3117
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
3118
                        return -1;
3119
                }
3120
                handle->data_mid = NULL;
3121
                if(!have_turnrest_credentials) {
3122
                        /* No TURN REST API server and credentials, any static ones? */
3123
                        if(janus_turn_server != NULL) {
3124
                                /* We need relay candidates as well */
3125
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->data_id, 1,
3126
                                        janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
3127
                                if(!ok) {
3128
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
3129
                                                janus_turn_server, janus_turn_port);
3130
                                }
3131
                        }
3132
#ifdef HAVE_LIBCURL
3133
                } else {
3134
                        /* We need relay candidates as well: add all those we got */
3135
                        GList *server = turnrest_credentials->servers;
3136
                        while(server != NULL) {
3137
                                janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
3138
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->data_id, 1,
3139
                                        instance->server, instance->port,
3140
                                        turnrest_credentials->username, turnrest_credentials->password,
3141
                                        instance->transport);
3142
                                if(!ok) {
3143
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
3144
                                                instance->server, instance->port);
3145
                                }
3146
                                server = server->next;
3147
                        }
3148
#endif
3149
                }
3150
                data_stream->handle = handle;
3151
                data_stream->stream_id = handle->data_id;
3152
                data_stream->cdone = 0;
3153
                data_stream->payload_type = -1;
3154
                data_stream->disabled = FALSE;
3155
                /* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
3156
                data_stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
3157
                data_stream->components = g_hash_table_new(NULL, NULL);
3158
                data_stream->noerrorlog = FALSE;
3159
                janus_mutex_init(&data_stream->mutex);
3160
                g_hash_table_insert(handle->streams, GUINT_TO_POINTER(handle->data_id), data_stream);
3161
                handle->data_stream = data_stream;
3162
                janus_ice_component *data_component = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
3163
                if(data_component == NULL) {
3164
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
3165
                        return -1;
3166
                }
3167
                data_component->stream = data_stream;
3168
                data_component->stream_id = data_component->stream_id;
3169
                data_component->component_id = 1;
3170
                data_component->candidates = NULL;
3171
                data_component->local_candidates = NULL;
3172
                data_component->remote_candidates = NULL;
3173
                data_component->selected_pair = NULL;
3174
                data_component->process_started = FALSE;
3175
                data_component->source = NULL;
3176
                data_component->dtls = NULL;
3177
                data_component->retransmit_buffer = NULL;
3178
                data_component->retransmit_log_ts = 0;
3179
                data_component->retransmit_recent_cnt = 0;
3180
                janus_ice_stats_reset(&data_component->in_stats);
3181
                janus_ice_stats_reset(&data_component->out_stats);
3182
                janus_mutex_init(&data_component->mutex);
3183
                g_hash_table_insert(data_stream->components, GUINT_TO_POINTER(1), data_component);
3184
                data_stream->rtp_component = data_component;        /* We use the component called 'RTP' for data */
3185
#ifdef HAVE_PORTRANGE
3186
                /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
3187
                nice_agent_set_port_range(handle->agent, handle->data_id, 1, rtp_range_min, rtp_range_max);
3188
#endif
3189
                nice_agent_gather_candidates(handle->agent, handle->data_id);
3190
                nice_agent_attach_recv(handle->agent, handle->data_id, 1, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, data_component);
3191
        }
3192
#endif
3193
#ifdef HAVE_LIBCURL
3194
        if(turnrest_credentials != NULL) {
3195
                janus_turnrest_response_destroy(turnrest_credentials);
3196
                turnrest_credentials = NULL;
3197
        }
3198
#endif
3199
        return 0;
3200
}
3201

    
3202
void *janus_ice_send_thread(void *data) {
3203
        janus_ice_handle *handle = (janus_ice_handle *)data;
3204
        janus_session *session = (janus_session *)handle->session;
3205
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE send thread started...\n", handle->handle_id);
3206
        janus_ice_queued_packet *pkt = NULL;
3207
        gint64 before = janus_get_monotonic_time(),
3208
                audio_rtcp_last_rr = before, audio_rtcp_last_sr = before, audio_last_event = before,
3209
                video_rtcp_last_rr = before, video_rtcp_last_sr = before, video_last_event = before,
3210
                last_srtp_summary = before, last_nack_cleanup = before;
3211
        while(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) {
3212
                if(handle->queued_packets != NULL) {
3213
                        pkt = g_async_queue_timeout_pop(handle->queued_packets, 500000);
3214
                } else {
3215
                        g_usleep(100000);
3216
                }
3217
                /* First of all, let's see if everything's fine on the recv side */
3218
                gint64 now = janus_get_monotonic_time();
3219
                if(no_media_timer > 0 && now-before >= G_USEC_PER_SEC) {
3220
                        if(handle->audio_stream && handle->audio_stream->rtp_component) {
3221
                                janus_ice_component *component = handle->audio_stream->rtp_component;
3222
                                GList *lastitem = g_list_last(component->in_stats.audio_bytes_lastsec);
3223
                                janus_ice_stats_item *last = lastitem ? ((janus_ice_stats_item *)lastitem->data) : NULL;
3224
                                if(!component->in_stats.audio_notified_lastsec && last && now-last->when >= no_media_timer*G_USEC_PER_SEC) {
3225
                                        /* We missed more than no_second_timer seconds of audio! */
3226
                                        component->in_stats.audio_notified_lastsec = TRUE;
3227
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive audio for more than %d seconds...\n", handle->handle_id, no_media_timer);
3228
                                        janus_ice_notify_media(handle, FALSE, FALSE);
3229
                                }
3230
                                if(!component->in_stats.video_notified_lastsec && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
3231
                                        lastitem = g_list_last(component->in_stats.video_bytes_lastsec);
3232
                                        last = lastitem ? ((janus_ice_stats_item *)lastitem->data) : NULL;
3233
                                        if(last && now-last->when >= no_media_timer*G_USEC_PER_SEC) {
3234
                                                /* We missed more than no_second_timer seconds of video! */
3235
                                                component->in_stats.video_notified_lastsec = TRUE;
3236
                                                JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive video for more than %d seconds...\n", handle->handle_id, no_media_timer);
3237
                                                janus_ice_notify_media(handle, TRUE, FALSE);
3238
                                        }
3239
                                }
3240
                        }
3241
                        if(handle->video_stream && handle->video_stream->rtp_component) {
3242
                                janus_ice_component *component = handle->video_stream->rtp_component;
3243
                                GList *lastitem = g_list_last(component->in_stats.video_bytes_lastsec);
3244
                                janus_ice_stats_item *last = lastitem ? ((janus_ice_stats_item *)lastitem->data) : NULL;
3245
                                if(!component->in_stats.video_notified_lastsec && last && now-last->when >= no_media_timer*G_USEC_PER_SEC) {
3246
                                        /* We missed more than no_second_timer seconds of video! */
3247
                                        component->in_stats.video_notified_lastsec = TRUE;
3248
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive video for more than a second...\n", handle->handle_id);
3249
                                        janus_ice_notify_media(handle, TRUE, FALSE);
3250
                                }
3251
                        }
3252
                        before = now;
3253
                }
3254
                /* Let's check if it's time to send a RTCP RR as well */
3255
                if(now-audio_rtcp_last_rr >= 5*G_USEC_PER_SEC) {
3256
                        janus_ice_stream *stream = handle->audio_stream;
3257
                        if(handle->audio_stream && stream->audio_rtcp_ctx && stream->audio_rtcp_ctx->rtp_recvd) {
3258
                                /* Create a RR */
3259
                                int rrlen = 32;
3260
                                char rtcpbuf[32];
3261
                                memset(rtcpbuf, 0, sizeof(rtcpbuf));
3262
                                rtcp_rr *rr = (rtcp_rr *)&rtcpbuf;
3263
                                rr->header.version = 2;
3264
                                rr->header.type = RTCP_RR;
3265
                                rr->header.rc = 1;
3266
                                rr->header.length = htons((rrlen/4)-1);
3267
                                janus_rtcp_report_block(stream->audio_rtcp_ctx, &rr->rb[0]);
3268
                                /* Enqueue it, we'll send it later */
3269
                                janus_ice_relay_rtcp_internal(handle, 0, rtcpbuf, 32, FALSE);
3270
                        }
3271
                        audio_rtcp_last_rr = now;
3272
                }
3273
                if(now-video_rtcp_last_rr >= 5*G_USEC_PER_SEC) {
3274
                        janus_ice_stream *stream = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? (handle->audio_stream ? handle->audio_stream : handle->video_stream) : (handle->video_stream);
3275
                        if(stream) {
3276
                                if(stream->video_rtcp_ctx && stream->video_rtcp_ctx->rtp_recvd) {
3277
                                        /* Create a RR */
3278
                                        int rrlen = 32;
3279
                                        char rtcpbuf[32];
3280
                                        memset(rtcpbuf, 0, sizeof(rtcpbuf));
3281
                                        rtcp_rr *rr = (rtcp_rr *)&rtcpbuf;
3282
                                        rr->header.version = 2;
3283
                                        rr->header.type = RTCP_RR;
3284
                                        rr->header.rc = 1;
3285
                                        rr->header.length = htons((rrlen/4)-1);
3286
                                        janus_rtcp_report_block(stream->video_rtcp_ctx, &rr->rb[0]);
3287
                                        /* Enqueue it, we'll send it later */
3288
                                        janus_ice_relay_rtcp_internal(handle, 1, rtcpbuf, 32, FALSE);
3289
                                }
3290
                        }
3291
                        video_rtcp_last_rr = now;
3292
                }
3293
                /* Do the same with SR/SDES */
3294
                if(now-audio_rtcp_last_sr >= 500000) {
3295
                        janus_ice_stream *stream = handle->audio_stream;
3296
                        if(stream && stream->rtp_component && stream->rtp_component->out_stats.audio_packets > 0) {
3297
                                /* Create a SR/SDES compound */
3298
                                int srlen = 28;
3299
                                int sdeslen = 20;
3300
                                char rtcpbuf[srlen+sdeslen];
3301
                                memset(rtcpbuf, 0, sizeof(rtcpbuf));
3302
                                rtcp_sr *sr = (rtcp_sr *)&rtcpbuf;
3303
                                sr->header.version = 2;
3304
                                sr->header.type = RTCP_SR;
3305
                                sr->header.rc = 0;
3306
                                sr->header.length = htons((srlen/4)-1);
3307
                                struct timeval tv;
3308
                                gettimeofday(&tv, NULL);
3309
                                uint32_t s = tv.tv_sec + 2208988800u;
3310
                                uint32_t u = tv.tv_usec;
3311
                                uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6);
3312
                                sr->si.ntp_ts_msw = htonl(s);
3313
                                sr->si.ntp_ts_lsw = htonl(f);
3314
                                /* Compute an RTP timestamp coherent with the NTP one */
3315
                                rtcp_context *rtcp_ctx = stream->audio_rtcp_ctx;
3316
                                if(rtcp_ctx == NULL) {
3317
                                        sr->si.rtp_ts = htonl(stream->audio_last_ts);        /* FIXME */
3318
                                } else {
3319
                                        int64_t ntp = tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
3320
                                        if(rtcp_ctx->fsr_ts == 0)
3321
                                                rtcp_ctx->fsr_ts = ntp;
3322
                                        uint32_t rtp_ts = ((ntp-rtcp_ctx->fsr_ts)/1000)*(rtcp_ctx->tb/1000);
3323
                                        sr->si.rtp_ts = htonl(rtp_ts);
3324
                                }
3325
                                sr->si.s_packets = htonl(stream->rtp_component->out_stats.audio_packets);
3326
                                sr->si.s_octets = htonl(stream->rtp_component->out_stats.audio_bytes);
3327
                                rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[28];
3328
                                janus_rtcp_sdes((char *)sdes, sdeslen, "janusaudio", 10);
3329
                                /* Enqueue it, we'll send it later */
3330
                                janus_ice_relay_rtcp_internal(handle, 0, rtcpbuf, srlen+sdeslen, FALSE);
3331
                        }
3332
                        audio_rtcp_last_sr = now;
3333
                }
3334
                if(now-video_rtcp_last_sr >= 500000) {
3335
                        janus_ice_stream *stream = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? (handle->audio_stream ? handle->audio_stream : handle->video_stream) : (handle->video_stream);
3336
                        if(stream && stream->rtp_component && stream->rtp_component->out_stats.video_packets > 0) {
3337
                                /* Create a SR/SDES compound */
3338
                                int srlen = 28;
3339
                                int sdeslen = 20;
3340
                                char rtcpbuf[srlen+sdeslen];
3341
                                memset(rtcpbuf, 0, sizeof(rtcpbuf));
3342
                                rtcp_sr *sr = (rtcp_sr *)&rtcpbuf;
3343
                                sr->header.version = 2;
3344
                                sr->header.type = RTCP_SR;
3345
                                sr->header.rc = 0;
3346
                                sr->header.length = htons((srlen/4)-1);
3347
                                struct timeval tv;
3348
                                gettimeofday(&tv, NULL);
3349
                                uint32_t s = tv.tv_sec + 2208988800u;
3350
                                uint32_t u = tv.tv_usec;
3351
                                uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6);
3352
                                sr->si.ntp_ts_msw = htonl(s);
3353
                                sr->si.ntp_ts_lsw = htonl(f);
3354
                                /* Compute an RTP timestamp coherent with the NTP one */
3355
                                rtcp_context *rtcp_ctx = stream->video_rtcp_ctx;
3356
                                if(rtcp_ctx == NULL) {
3357
                                        sr->si.rtp_ts = htonl(stream->video_last_ts);        /* FIXME */
3358
                                } else {
3359
                                        int64_t ntp = tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
3360
                                        if(rtcp_ctx->fsr_ts == 0)
3361
                                                rtcp_ctx->fsr_ts = ntp;
3362
                                        uint32_t rtp_ts = ((ntp-rtcp_ctx->fsr_ts)/1000)*(rtcp_ctx->tb/1000);
3363
                                        sr->si.rtp_ts = htonl(rtp_ts);
3364
                                }
3365
                                sr->si.s_packets = htonl(stream->rtp_component->out_stats.video_packets);
3366
                                sr->si.s_octets = htonl(stream->rtp_component->out_stats.video_bytes);
3367
                                rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[28];
3368
                                janus_rtcp_sdes((char *)sdes, sdeslen, "janusvideo", 10);
3369
                                /* Enqueue it, we'll send it later */
3370
                                janus_ice_relay_rtcp_internal(handle, 1, rtcpbuf, srlen+sdeslen, FALSE);
3371
                        }
3372
                        video_rtcp_last_sr = now;
3373
                }
3374
                /* We tell event handlers once per second about RTCP-related stuff
3375
                 * FIXME Should we really do this here? Would this slow down this thread and add delay? */
3376
                if(now-audio_last_event >= G_USEC_PER_SEC) {
3377
                        if(janus_events_is_enabled() && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO)) {
3378
                                janus_ice_stream *stream = handle->audio_stream;
3379
                                if(stream && stream->audio_rtcp_ctx) {
3380
                                        json_t *info = json_object();
3381
                                        json_object_set_new(info, "media", json_string("audio"));
3382
                                        json_object_set_new(info, "base", json_integer(stream->audio_rtcp_ctx->tb));
3383
                                        json_object_set_new(info, "lsr", json_integer(janus_rtcp_context_get_lsr(stream->audio_rtcp_ctx)));
3384
                                        json_object_set_new(info, "lost", json_integer(janus_rtcp_context_get_lost_all(stream->audio_rtcp_ctx, FALSE)));
3385
                                        json_object_set_new(info, "lost-by-remote", json_integer(janus_rtcp_context_get_lost_all(stream->audio_rtcp_ctx, TRUE)));
3386
                                        json_object_set_new(info, "jitter-local", json_integer(janus_rtcp_context_get_jitter(stream->audio_rtcp_ctx, FALSE)));
3387
                                        json_object_set_new(info, "jitter-remote", json_integer(janus_rtcp_context_get_jitter(stream->audio_rtcp_ctx, TRUE)));
3388
                                        if(stream->rtp_component) {
3389
                                                json_object_set_new(info, "packets-received", json_integer(stream->rtp_component->in_stats.audio_packets));
3390
                                                json_object_set_new(info, "packets-sent", json_integer(stream->rtp_component->out_stats.audio_packets));
3391
                                                json_object_set_new(info, "bytes-received", json_integer(stream->rtp_component->in_stats.audio_bytes));
3392
                                                json_object_set_new(info, "bytes-sent", json_integer(stream->rtp_component->out_stats.audio_bytes));
3393
                                                json_object_set_new(info, "nacks-received", json_integer(stream->rtp_component->in_stats.audio_nacks));
3394
                                                json_object_set_new(info, "nacks-sent", json_integer(stream->rtp_component->out_stats.audio_nacks));
3395
                                        }
3396
                                        janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, session->session_id, handle->handle_id, info);
3397
                                }
3398
                        }
3399
                        audio_last_event = now;
3400
                }
3401
                if(now-video_last_event >= G_USEC_PER_SEC) {
3402
                        if(janus_events_is_enabled() && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)) {
3403
                                janus_ice_stream *stream = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? (handle->audio_stream ? handle->audio_stream : handle->video_stream) : (handle->video_stream);
3404
                                if(stream && stream->video_rtcp_ctx) {
3405
                                        json_t *info = json_object();
3406
                                        json_object_set_new(info, "media", json_string("video"));
3407
                                        json_object_set_new(info, "base", json_integer(stream->video_rtcp_ctx->tb));
3408
                                        json_object_set_new(info, "lsr", json_integer(janus_rtcp_context_get_lsr(stream->video_rtcp_ctx)));
3409
                                        json_object_set_new(info, "lost", json_integer(janus_rtcp_context_get_lost_all(stream->video_rtcp_ctx, FALSE)));
3410
                                        json_object_set_new(info, "lost-by-remote", json_integer(janus_rtcp_context_get_lost_all(stream->video_rtcp_ctx, TRUE)));
3411
                                        json_object_set_new(info, "jitter-local", json_integer(janus_rtcp_context_get_jitter(stream->video_rtcp_ctx, FALSE)));
3412
                                        json_object_set_new(info, "jitter-remote", json_integer(janus_rtcp_context_get_jitter(stream->video_rtcp_ctx, TRUE)));
3413
                                        if(stream->rtp_component) {
3414
                                                json_object_set_new(info, "packets-received", json_integer(stream->rtp_component->in_stats.video_packets));
3415
                                                json_object_set_new(info, "packets-sent", json_integer(stream->rtp_component->out_stats.video_packets));
3416
                                                json_object_set_new(info, "bytes-received", json_integer(stream->rtp_component->in_stats.video_bytes));
3417
                                                json_object_set_new(info, "bytes-sent", json_integer(stream->rtp_component->out_stats.video_bytes));
3418
                                                json_object_set_new(info, "nacks-received", json_integer(stream->rtp_component->in_stats.video_nacks));
3419
                                                json_object_set_new(info, "nacks-sent", json_integer(stream->rtp_component->out_stats.video_nacks));
3420
                                        }
3421
                                        janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, session->session_id, handle->handle_id, info);
3422
                                }
3423
                        }
3424
                        video_last_event = now;
3425
                }
3426
                /* Should we clean up old NACK buffers? (we check each 1/4 of the max_nack_queue time) */
3427
                if(max_nack_queue > 0 && (now-last_nack_cleanup >= (max_nack_queue*250))) {
3428
                        /* Check if we do for both streams */
3429
                        janus_cleanup_nack_buffer(now, handle->audio_stream);
3430
                        janus_cleanup_nack_buffer(now, handle->video_stream);
3431
                        last_nack_cleanup = now;
3432
                }
3433
                /* Check if we should also print a summary of SRTP-related errors */
3434
                if(now-last_srtp_summary >= (2*G_USEC_PER_SEC)) {
3435
                        if(handle->srtp_errors_count > 0) {
3436
                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Got %d SRTP/SRTCP errors in the last few seconds (last error: %s)\n",
3437
                                        handle->handle_id, handle->srtp_errors_count, janus_srtp_error_str(handle->last_srtp_error));
3438
                                handle->srtp_errors_count = 0;
3439
                                handle->last_srtp_error = 0;
3440
                        }
3441
                        last_srtp_summary = now;
3442
                }
3443

    
3444
                /* Now let's get on with the packets */
3445
                if(pkt == NULL) {
3446
                        continue;
3447
                }
3448
                if(pkt == &janus_ice_dtls_alert) {
3449
                        /* The session is over, send an alert on all streams and components */
3450
                        if(handle->streams != NULL) {
3451
                                if(handle->audio_stream) {
3452
                                        janus_ice_stream *stream = handle->audio_stream;
3453
                                        if(stream->rtp_component)
3454
                                                janus_dtls_srtp_send_alert(stream->rtp_component->dtls);
3455
                                        if(stream->rtcp_component)
3456
                                                janus_dtls_srtp_send_alert(stream->rtcp_component->dtls);
3457
                                }
3458
                                if(handle->video_stream) {
3459
                                        janus_ice_stream *stream = handle->video_stream;
3460
                                        if(stream->rtp_component)
3461
                                                janus_dtls_srtp_send_alert(stream->rtp_component->dtls);
3462
                                        if(stream->rtcp_component)
3463
                                                janus_dtls_srtp_send_alert(stream->rtcp_component->dtls);
3464
                                }
3465
                                if(handle->data_stream) {
3466
                                        janus_ice_stream *stream = handle->data_stream;
3467
                                        if(stream->rtp_component)
3468
                                                janus_dtls_srtp_send_alert(stream->rtp_component->dtls);
3469
                                        if(stream->rtcp_component)
3470
                                                janus_dtls_srtp_send_alert(stream->rtcp_component->dtls);
3471
                                }
3472
                        }
3473
                        continue;
3474
                }
3475
                if(pkt->data == NULL) {
3476
                        g_free(pkt);
3477
                        pkt = NULL;
3478
                        continue;
3479
                }
3480
                if(pkt->control) {
3481
                        /* RTCP */
3482
                        int video = (pkt->type == JANUS_ICE_PACKET_VIDEO);
3483
                        janus_ice_stream *stream = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? (handle->audio_stream ? handle->audio_stream : handle->video_stream) : (video ? handle->video_stream : handle->audio_stream);
3484
                        if(!stream) {
3485
                                g_free(pkt->data);
3486
                                pkt->data = NULL;
3487
                                g_free(pkt);
3488
                                pkt = NULL;
3489
                                continue;
3490
                        }
3491
                        janus_ice_component *component = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) ? stream->rtp_component : stream->rtcp_component;
3492
                        if(!component) {
3493
                                g_free(pkt->data);
3494
                                pkt->data = NULL;
3495
                                g_free(pkt);
3496
                                pkt = NULL;
3497
                                continue;
3498
                        }
3499
                        if(!stream->cdone) {
3500
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
3501
                                        JANUS_LOG(LOG_ERR, "[%"SCNu64"]     %s candidates not gathered yet for stream??\n", handle->handle_id, video ? "video" : "audio");
3502
                                        stream->noerrorlog = TRUE;        /* Don't flood with the same error all over again */
3503
                                }
3504
                                g_free(pkt->data);
3505
                                pkt->data = NULL;
3506
                                g_free(pkt);
3507
                                pkt = NULL;
3508
                                continue;
3509
                        }
3510
                        stream->noerrorlog = FALSE;
3511
                        if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_out) {
3512
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
3513
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"]     %s stream (#%u) component has no valid SRTP session (yet?)\n", handle->handle_id, video ? "video" : "audio", stream->stream_id);
3514
                                        component->noerrorlog = TRUE;        /* Don't flood with the same error all over again */
3515
                                }
3516
                                g_free(pkt->data);
3517
                                pkt->data = NULL;
3518
                                g_free(pkt);
3519
                                pkt = NULL;
3520
                                continue;
3521
                        }
3522
                        component->noerrorlog = FALSE;
3523
                        if(pkt->encrypted) {
3524
                                /* Already SRTCP */
3525
                                int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, pkt->length, (const gchar *)pkt->data);
3526
                                if(sent < pkt->length) {
3527
                                        JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, pkt->length);
3528
                                }
3529
                        } else {
3530
                                /* Check if there's anything we need to do before sending */
3531
                                uint64_t bitrate = janus_rtcp_get_remb(pkt->data, pkt->length);
3532
                                if(bitrate > 0) {
3533
                                        /* There's a REMB, prepend a RR as it won't work otherwise */
3534
                                        int rrlen = 32;
3535
                                        char *rtcpbuf = g_malloc0(rrlen+pkt->length);
3536
                                        memset(rtcpbuf, 0, rrlen+pkt->length);
3537
                                        rtcp_rr *rr = (rtcp_rr *)rtcpbuf;
3538
                                        rr->header.version = 2;
3539
                                        rr->header.type = RTCP_RR;
3540
                                        rr->header.rc = 0;
3541
                                        rr->header.length = htons((rrlen/4)-1);
3542
                                        janus_ice_stream *stream = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? (handle->audio_stream ? handle->audio_stream : handle->video_stream) : (handle->video_stream);
3543
                                        if(stream && stream->video_rtcp_ctx && stream->video_rtcp_ctx->rtp_recvd) {
3544
                                                rr->header.rc = 1;
3545
                                                janus_rtcp_report_block(stream->video_rtcp_ctx, &rr->rb[0]);
3546
                                        }
3547
                                        /* Append REMB */
3548
                                        memcpy(rtcpbuf+rrlen, pkt->data, pkt->length);
3549
                                        /* Free old packet and update */
3550
                                        char *prev_data = pkt->data;
3551
                                        pkt->data = rtcpbuf;
3552
                                        pkt->length = rrlen+pkt->length;
3553
                                        g_clear_pointer(&prev_data, g_free);
3554
                                }
3555
                                /* FIXME Copy in a buffer and fix SSRC */
3556
                                char sbuf[JANUS_BUFSIZE];
3557
                                memcpy(sbuf, pkt->data, pkt->length);
3558
                                /* Fix all SSRCs! */
3559
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
3560
                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Fixing SSRCs (local %u, peer %u)\n", handle->handle_id,
3561
                                                video ? stream->video_ssrc : stream->audio_ssrc,
3562
                                                video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
3563
                                        janus_rtcp_fix_ssrc(NULL, sbuf, pkt->length, 1,
3564
                                                video ? stream->video_ssrc : stream->audio_ssrc,
3565
                                                video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
3566
                                } else {
3567
                                        /* Plan B involved, we trust the plugin to set the right 'local' SSRC and we don't mess with it */
3568
                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Fixing peer SSRC (Plan B, peer %u)\n", handle->handle_id,
3569
                                                video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
3570
                                        janus_rtcp_fix_ssrc(NULL, sbuf, pkt->length, 1, 0,
3571
                                                video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
3572
                                }
3573

    
3574
                                int protected = pkt->length;
3575
                                int res = 0;
3576
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
3577
                                        res = srtp_protect_rtcp(component->dtls->srtp_out, sbuf, &protected);
3578
                                } else {
3579
                                        /* We need to make sure different sources don't use the SRTP context at the same time */
3580
                                        janus_mutex_lock(&component->dtls->srtp_mutex);
3581
                                        res = srtp_protect_rtcp(component->dtls->srtp_out, sbuf, &protected);
3582
                                        janus_mutex_unlock(&component->dtls->srtp_mutex);
3583
                                }
3584
                                if(res != srtp_err_status_ok) {
3585
                                        /* We don't spam the logs for every SRTP error: just take note of this, and print a summary later */
3586
                                        handle->srtp_errors_count++;
3587
                                        handle->last_srtp_error = res;
3588
                                        /* If we're debugging, though, print every occurrence */
3589
                                        JANUS_LOG(LOG_DBG, "[%"SCNu64"] ... SRTCP protect error... %s (len=%d-->%d)...\n", handle->handle_id, janus_srtp_error_str(res), pkt->length, protected);
3590
                                } else {
3591
                                        /* Shoot! */
3592
                                        int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, protected, sbuf);
3593
                                        if(sent < protected) {
3594
                                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, protected);
3595
                                        }
3596
                                }
3597
                        }
3598
                        g_free(pkt->data);
3599
                        g_free(pkt);
3600
                        continue;
3601
                } else {
3602
                        /* RTP or data */
3603
                        if(pkt->type == JANUS_ICE_PACKET_AUDIO || pkt->type == JANUS_ICE_PACKET_VIDEO) {
3604
                                /* RTP */
3605
                                int video = (pkt->type == JANUS_ICE_PACKET_VIDEO);
3606
                                janus_ice_stream *stream = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? (handle->audio_stream ? handle->audio_stream : handle->video_stream) : (video ? handle->video_stream : handle->audio_stream);
3607
                                if(!stream) {
3608
                                        g_free(pkt->data);
3609
                                        pkt->data = NULL;
3610
                                        g_free(pkt);
3611
                                        pkt = NULL;
3612
                                        continue;
3613
                                }
3614
                                janus_ice_component *component = stream->rtp_component;
3615
                                if(!component) {
3616
                                        g_free(pkt->data);
3617
                                        pkt->data = NULL;
3618
                                        g_free(pkt);
3619
                                        pkt = NULL;
3620
                                        continue;
3621
                                }
3622
                                if(!stream->cdone) {
3623
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
3624
                                                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     %s candidates not gathered yet for stream??\n", handle->handle_id, video ? "video" : "audio");
3625
                                                stream->noerrorlog = TRUE;        /* Don't flood with the same error all over again */
3626
                                        }
3627
                                        g_free(pkt->data);
3628
                                        pkt->data = NULL;
3629
                                        g_free(pkt);
3630
                                        pkt = NULL;
3631
                                        continue;
3632
                                }
3633
                                stream->noerrorlog = FALSE;
3634
                                if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_out) {
3635
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
3636
                                                JANUS_LOG(LOG_WARN, "[%"SCNu64"]     %s stream component has no valid SRTP session (yet?)\n", handle->handle_id, video ? "video" : "audio");
3637
                                                component->noerrorlog = TRUE;        /* Don't flood with the same error all over again */
3638
                                        }
3639
                                        g_free(pkt->data);
3640
                                        pkt->data = NULL;
3641
                                        g_free(pkt);
3642
                                        pkt = NULL;
3643
                                        continue;
3644
                                }
3645
                                component->noerrorlog = FALSE;
3646
                                if(pkt->encrypted) {
3647
                                        /* Already RTP (probably a retransmission?) */
3648
                                        rtp_header *header = (rtp_header *)pkt->data;
3649
                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] ... Retransmitting seq.nr %"SCNu16"\n\n", handle->handle_id, ntohs(header->seq_number));
3650
                                        int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, pkt->length, (const gchar *)pkt->data);
3651
                                        if(sent < pkt->length) {
3652
                                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, pkt->length);
3653
                                        }
3654
                                } else {
3655
                                        /* FIXME Copy in a buffer and fix SSRC */
3656
                                        char sbuf[JANUS_BUFSIZE];
3657
                                        memcpy(sbuf, pkt->data, pkt->length);
3658
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
3659
                                                /* Overwrite SSRC */
3660
                                                rtp_header *header = (rtp_header *)sbuf;
3661
                                                header->ssrc = htonl(video ? stream->video_ssrc : stream->audio_ssrc);
3662
                                        }
3663
                                        int protected = pkt->length;
3664
                                        int res = srtp_protect(component->dtls->srtp_out, sbuf, &protected);
3665
                                        if(res != srtp_err_status_ok) {
3666
                                                /* We don't spam the logs for every SRTP error: just take note of this, and print a summary later */
3667
                                                handle->srtp_errors_count++;
3668
                                                handle->last_srtp_error = res;
3669
                                                /* If we're debugging, though, print every occurrence */
3670
                                                rtp_header *header = (rtp_header *)sbuf;
3671
                                                guint32 timestamp = ntohl(header->timestamp);
3672
                                                guint16 seq = ntohs(header->seq_number);
3673
                                                JANUS_LOG(LOG_DBG, "[%"SCNu64"] ... SRTP protect error... %s (len=%d-->%d, ts=%"SCNu32", seq=%"SCNu16")...\n", handle->handle_id, janus_srtp_error_str(res), pkt->length, protected, timestamp, seq);
3674
                                        } else {
3675
                                                /* Shoot! */
3676
                                                int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, protected, sbuf);
3677
                                                if(sent < protected) {
3678
                                                        JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, protected);
3679
                                                }
3680
                                                /* Update stats */
3681
                                                if(sent > 0) {
3682
                                                        /* Update the RTCP context as well */
3683
                                                        rtp_header *header = (rtp_header *)sbuf;
3684
                                                        guint32 timestamp = ntohl(header->timestamp);
3685
                                                        if(pkt->type == JANUS_ICE_PACKET_AUDIO) {
3686
                                                                component->out_stats.audio_packets++;
3687
                                                                component->out_stats.audio_bytes += sent;
3688
                                                                stream->audio_last_ts = timestamp;
3689
                                                                /* Let's check if this was G.711: in case we may need to change the timestamp base */
3690
                                                                rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx : stream->audio_rtcp_ctx;
3691
                                                                int pt = header->type;
3692
                                                                if((pt == 0 || pt == 8) && (rtcp_ctx->tb == 48000))
3693
                                                                        rtcp_ctx->tb = 8000;
3694
                                                        } else if(pkt->type == JANUS_ICE_PACKET_VIDEO) {
3695
                                                                component->out_stats.video_packets++;
3696
                                                                component->out_stats.video_bytes += sent;
3697
                                                                stream->video_last_ts = timestamp;
3698
                                                        }
3699
                                                }
3700
                                                if(max_nack_queue > 0) {
3701
                                                        /* Save the packet for retransmissions that may be needed later */
3702
                                                        janus_rtp_packet *p = (janus_rtp_packet *)g_malloc0(sizeof(janus_rtp_packet));
3703
                                                        p->data = (char *)g_malloc0(protected);
3704
                                                        memcpy(p->data, sbuf, protected);
3705
                                                        p->length = protected;
3706
                                                        p->created = janus_get_monotonic_time();
3707
                                                        p->last_retransmit = 0;
3708
                                                        janus_mutex_lock(&component->mutex);
3709
                                                        component->retransmit_buffer = g_list_append(component->retransmit_buffer, p);
3710
                                                        janus_mutex_unlock(&component->mutex);
3711
                                                }
3712
                                        }
3713
                                }
3714
                        } else {
3715
                                /* Data */
3716
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS)) {
3717
                                        g_free(pkt->data);
3718
                                        pkt->data = NULL;
3719
                                        g_free(pkt);
3720
                                        pkt = NULL;
3721
                                        continue;
3722
                                }
3723
#ifdef HAVE_SCTP
3724
                                janus_ice_stream *stream = handle->data_stream ? handle->data_stream : (handle->audio_stream ? handle->audio_stream : handle->video_stream);
3725
                                if(!stream) {
3726
                                        g_free(pkt->data);
3727
                                        pkt->data = NULL;
3728
                                        g_free(pkt);
3729
                                        pkt = NULL;
3730
                                        continue;
3731
                                }
3732
                                janus_ice_component *component = stream->rtp_component;
3733
                                if(!component) {
3734
                                        g_free(pkt->data);
3735
                                        pkt->data = NULL;
3736
                                        g_free(pkt);
3737
                                        pkt = NULL;
3738
                                        continue;
3739
                                }
3740
                                if(!stream->cdone) {
3741
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
3742
                                                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     SCTP candidates not gathered yet for stream??\n", handle->handle_id);
3743
                                                stream->noerrorlog = TRUE;        /* Don't flood with the same error all over again */
3744
                                        }
3745
                                        g_free(pkt->data);
3746
                                        pkt->data = NULL;
3747
                                        g_free(pkt);
3748
                                        pkt = NULL;
3749
                                        continue;
3750
                                }
3751
                                stream->noerrorlog = FALSE;
3752
                                if(!component->dtls) {
3753
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
3754
                                                JANUS_LOG(LOG_WARN, "[%"SCNu64"]     SCTP stream component has no valid DTLS session (yet?)\n", handle->handle_id);
3755
                                                component->noerrorlog = TRUE;        /* Don't flood with the same error all over again */
3756
                                        }
3757
                                        g_free(pkt->data);
3758
                                        pkt->data = NULL;
3759
                                        g_free(pkt);
3760
                                        pkt = NULL;
3761
                                        continue;
3762
                                }
3763
                                component->noerrorlog = FALSE;
3764
                                janus_dtls_wrap_sctp_data(component->dtls, pkt->data, pkt->length);
3765
#endif
3766
                        }
3767
                        g_free(pkt->data);
3768
                        pkt->data = NULL;
3769
                        g_free(pkt);
3770
                        pkt = NULL;
3771
                        continue;
3772
                }
3773
        }
3774
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE send thread leaving...\n", handle->handle_id);
3775
        g_thread_unref(g_thread_self());
3776
        return NULL;
3777
}
3778

    
3779
void janus_ice_relay_rtp(janus_ice_handle *handle, int video, char *buf, int len) {
3780
        if(!handle || buf == NULL || len < 1)
3781
                return;
3782
        if((!video && !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO))
3783
                        || (video && !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)))
3784
                return;
3785
        /* Queue this packet */
3786
        janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
3787
        pkt->data = g_malloc0(len);
3788
        memcpy(pkt->data, buf, len);
3789
        pkt->length = len;
3790
        pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
3791
        pkt->control = FALSE;
3792
        pkt->encrypted = FALSE;
3793
        if(handle->queued_packets != NULL)
3794
                g_async_queue_push(handle->queued_packets, pkt);
3795
}
3796

    
3797
void janus_ice_relay_rtcp_internal(janus_ice_handle *handle, int video, char *buf, int len, gboolean filter_rtcp) {
3798
        if(!handle || buf == NULL || len < 1)
3799
                return;
3800
        /* We use this internal method to check whether we need to filter RTCP (e.g., to make
3801
         * sure we don't just forward any SR/RR from peers/plugins, but use our own) or it has
3802
         * already been done, and so this is actually a packet added by the ICE send thread */
3803
        char *rtcp_buf = buf;
3804
        int rtcp_len = len;
3805
        if(filter_rtcp) {
3806
                /* FIXME Strip RR/SR/SDES/NACKs/etc. */
3807
                rtcp_buf = janus_rtcp_filter(buf, len, &rtcp_len);
3808
                if(rtcp_buf == NULL)
3809
                        return;
3810
        }
3811
        if(rtcp_len < 1)
3812
                return;
3813
        /* Queue this packet */
3814
        janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
3815
        pkt->data = g_malloc0(len);
3816
        memcpy(pkt->data, rtcp_buf, rtcp_len);
3817
        pkt->length = rtcp_len;
3818
        pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
3819
        pkt->control = TRUE;
3820
        pkt->encrypted = FALSE;
3821
        if(handle->queued_packets != NULL)
3822
                g_async_queue_push(handle->queued_packets, pkt);
3823
        if(rtcp_buf != buf) {
3824
                /* We filtered the original packet, deallocate it */
3825
                g_free(rtcp_buf);
3826
        }
3827
}
3828

    
3829
void janus_ice_relay_rtcp(janus_ice_handle *handle, int video, char *buf, int len) {
3830
        janus_ice_relay_rtcp_internal(handle, video, buf, len, TRUE);
3831
}
3832

    
3833
#ifdef HAVE_SCTP
3834
void janus_ice_relay_data(janus_ice_handle *handle, char *buf, int len) {
3835
        if(!handle || buf == NULL || len < 1)
3836
                return;
3837
        /* Queue this packet */
3838
        janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
3839
        pkt->data = g_malloc0(len);
3840
        memcpy(pkt->data, buf, len);
3841
        pkt->length = len;
3842
        pkt->type = JANUS_ICE_PACKET_DATA;
3843
        pkt->control = FALSE;
3844
        pkt->encrypted = FALSE;
3845
        if(handle->queued_packets != NULL)
3846
                g_async_queue_push(handle->queued_packets, pkt);
3847
}
3848
#endif
3849

    
3850
void janus_ice_dtls_handshake_done(janus_ice_handle *handle, janus_ice_component *component) {
3851
        if(!handle || !component)
3852
                return;
3853
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] The DTLS handshake for the component %d in stream %d has been completed\n",
3854
                handle->handle_id, component->component_id, component->stream_id);
3855
        /* Check if all components are ready */
3856
        janus_mutex_lock(&handle->mutex);
3857
        if(handle->audio_stream && !handle->audio_stream->disabled) {
3858
                if(handle->audio_stream->rtp_component && (!handle->audio_stream->rtp_component->dtls ||
3859
                                !handle->audio_stream->rtp_component->dtls->srtp_valid)) {
3860
                        /* Still waiting for this component to become ready */
3861
                        janus_mutex_unlock(&handle->mutex);
3862
                        return;
3863
                }
3864
                if(handle->audio_stream->rtcp_component && (!handle->audio_stream->rtcp_component->dtls ||
3865
                                !handle->audio_stream->rtcp_component->dtls->srtp_valid)) {
3866
                        /* Still waiting for this component to become ready */
3867
                        janus_mutex_unlock(&handle->mutex);
3868
                        return;
3869
                }
3870
        }
3871
        if(handle->video_stream && !handle->video_stream->disabled) {
3872
                if(handle->video_stream->rtp_component && (!handle->video_stream->rtp_component->dtls ||
3873
                                !handle->video_stream->rtp_component->dtls->srtp_valid)) {
3874
                        /* Still waiting for this component to become ready */
3875
                        janus_mutex_unlock(&handle->mutex);
3876
                        return;
3877
                }
3878
                if(handle->video_stream->rtcp_component && (!handle->video_stream->rtcp_component->dtls ||
3879
                                !handle->video_stream->rtcp_component->dtls->srtp_valid)) {
3880
                        /* Still waiting for this component to become ready */
3881
                        janus_mutex_unlock(&handle->mutex);
3882
                        return;
3883
                }
3884
        }
3885
        if(handle->data_stream && !handle->data_stream->disabled) {
3886
                if(handle->data_stream->rtp_component && (!handle->data_stream->rtp_component->dtls ||
3887
                                !handle->data_stream->rtp_component->dtls->srtp_valid)) {
3888
                        /* Still waiting for this component to become ready */
3889
                        janus_mutex_unlock(&handle->mutex);
3890
                        return;
3891
                }
3892
        }
3893
        if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY)) {
3894
                /* Already notified */
3895
                janus_mutex_unlock(&handle->mutex);
3896
                return;
3897
        }
3898
        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
3899
        janus_mutex_unlock(&handle->mutex);
3900
        JANUS_LOG(LOG_INFO, "[%"SCNu64"] The DTLS handshake has been completed\n", handle->handle_id);
3901
        /* Notify the plugin that the WebRTC PeerConnection is ready to be used */
3902
        janus_plugin *plugin = (janus_plugin *)handle->app;
3903
        if(plugin != NULL) {
3904
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about it (%s)\n", handle->handle_id, plugin->get_name());
3905
                if(plugin && plugin->setup_media && janus_plugin_session_is_alive(handle->app_handle))
3906
                        plugin->setup_media(handle->app_handle);
3907
        }
3908
        /* Also prepare JSON event to notify user/application */
3909
        janus_session *session = (janus_session *)handle->session;
3910
        if(session == NULL)
3911
                return;
3912
        json_t *event = json_object();
3913
        json_object_set_new(event, "janus", json_string("webrtcup"));
3914
        json_object_set_new(event, "session_id", json_integer(session->session_id));
3915
        json_object_set_new(event, "sender", json_integer(handle->handle_id));
3916
        /* Send the event */
3917
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
3918
        janus_session_notify_event(session->session_id, event);
3919
        /* Notify event handlers as well */
3920
        if(janus_events_is_enabled()) {
3921
                json_t *info = json_object();
3922
                json_object_set_new(info, "connection", json_string("webrtcup"));
3923
                janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, session->session_id, handle->handle_id, info);
3924
        }
3925
}