Statistics
| Branch: | Revision:

janus-gateway / ice.c @ 1d31e31f

History | View | Annotate | Download (143 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 <netdb.h>
21
#include <fcntl.h>
22
#include <stun/usages/bind.h>
23
#include <nice/debug.h>
24

    
25
#include "janus.h"
26
#include "debug.h"
27
#include "ice.h"
28
#include "turnrest.h"
29
#include "dtls.h"
30
#include "sdp.h"
31
#include "rtp.h"
32
#include "rtcp.h"
33
#include "apierror.h"
34
#include "events.h"
35

    
36
/* STUN server/port, if any */
37
static char *janus_stun_server = NULL;
38
static uint16_t janus_stun_port = 0;
39

    
40
char *janus_ice_get_stun_server(void) {
41
        return janus_stun_server;
42
}
43
uint16_t janus_ice_get_stun_port(void) {
44
        return janus_stun_port;
45
}
46

    
47

    
48
/* TURN server/port and credentials, if any */
49
static char *janus_turn_server = NULL;
50
static uint16_t janus_turn_port = 0;
51
static char *janus_turn_user = NULL, *janus_turn_pwd = NULL;
52
static NiceRelayType janus_turn_type = NICE_RELAY_TYPE_TURN_UDP;
53

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

    
61

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

    
71

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

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

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

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

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

    
144
        }
145
}
146
gint janus_ice_get_rtcpmux_blackhole_port(void) {
147
        return janus_force_rtcpmux_blackhole_port;
148
}
149
gboolean janus_ice_is_rtcpmux_forced(void) {
150
        return janus_force_rtcpmux;
151
}
152

    
153

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

    
180

    
181
/* NAT 1:1 stuff */
182
static gboolean nat_1_1_enabled = FALSE;
183
void janus_ice_enable_nat_1_1(void) {
184
        nat_1_1_enabled = TRUE;
185
}
186

    
187
/* Interface/IP enforce/ignore lists */
188
GList *janus_ice_enforce_list = NULL, *janus_ice_ignore_list = NULL;
189
janus_mutex ice_list_mutex;
190

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

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

    
244

    
245
/* RTP/RTCP port range */
246
uint16_t rtp_range_min = 0;
247
uint16_t rtp_range_max = 0;
248

    
249

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

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

    
262
gboolean janus_is_rtcp(gchar *buf);
263
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
/* Maximum values for the NACK queue/retransmissions */
285
#define DEFAULT_MAX_NACK_QUEUE        300
286
/* Maximum ignore count after retransmission (100ms) */
287
#define MAX_NACK_IGNORE                        100000
288

    
289
static uint max_nack_queue = DEFAULT_MAX_NACK_QUEUE;
290
void janus_set_max_nack_queue(uint mnq) {
291
        max_nack_queue = mnq;
292
        JANUS_LOG(LOG_VERB, "Setting max NACK queue to %d\n", max_nack_queue);
293
}
294
uint janus_get_max_nack_queue(void) {
295
        return max_nack_queue;
296
}
297

    
298

    
299
#define SEQ_MISSING_WAIT 12000 /*  12ms */
300
#define SEQ_NACKED_WAIT 155000 /* 155ms */
301
/* seq_info_t list functions */
302
static void janus_seq_append(seq_info_t **head, seq_info_t *new_seq) {
303
        if(*head == NULL) {
304
                new_seq->prev = new_seq;
305
                new_seq->next = new_seq;
306
                *head = new_seq;
307
        } else {
308
                seq_info_t *last_seq = (*head)->prev;
309
                new_seq->prev = last_seq;
310
                new_seq->next = *head;
311
                (*head)->prev = new_seq;
312
                last_seq->next = new_seq;
313
        }
314
}
315
static seq_info_t *janus_seq_pop_head(seq_info_t **head) {
316
        seq_info_t *pop_seq = *head;
317
        if(pop_seq) {
318
                seq_info_t *new_head = pop_seq->next;
319
                if (pop_seq == new_head) {
320
                        *head = NULL;
321
                } else {
322
                        *head = new_head;
323
                        new_head->prev = pop_seq->prev;
324
                        new_head->prev->next = new_head;
325
                }
326
        }
327
        return pop_seq;
328
}
329
static void janus_seq_list_free(seq_info_t **head) {
330
        if(!*head) return;
331
        seq_info_t *cur = *head;
332
        do {
333
                seq_info_t *next = cur->next;
334
                g_free(cur);
335
                cur = next;
336
        } while(cur != *head);
337
        *head = NULL;
338
}
339
static int janus_seq_in_range(guint16 seqn, guint16 start, guint16 len) {
340
        /* Supports wrapping sequence (easier with int range) */
341
        int n = seqn;
342
        int nh = (1<<16) + n;
343
        int s = start;
344
        int e = s + len;
345
        return (s <= n && n < e) || (s <= nh && nh < e);
346
}
347

    
348

    
349
/* Map of old plugin sessions that have been closed */
350
static GHashTable *old_plugin_sessions;
351
static janus_mutex old_plugin_sessions_mutex;
352
gboolean janus_plugin_session_is_alive(janus_plugin_session *plugin_session) {
353
        /* Make sure this plugin session is still alive */
354
        janus_mutex_lock(&old_plugin_sessions_mutex);
355
        janus_plugin_session *result = g_hash_table_lookup(old_plugin_sessions, plugin_session);
356
        janus_mutex_unlock(&old_plugin_sessions_mutex);
357
        if(result != NULL) {
358
                JANUS_LOG(LOG_ERR, "Invalid plugin session (%p)\n", plugin_session);
359
        }
360
        return (result == NULL);
361
}
362

    
363
/* Watchdog for removing old handles */
364
static GHashTable *old_handles = NULL;
365
static GMainContext *handles_watchdog_context = NULL;
366
GMainLoop *handles_watchdog_loop = NULL;
367
GThread *handles_watchdog = NULL;
368
static janus_mutex old_handles_mutex;
369

    
370
static gboolean janus_ice_handles_cleanup(gpointer user_data) {
371
        janus_ice_handle *handle = (janus_ice_handle *) user_data;
372

    
373
        JANUS_LOG(LOG_INFO, "Cleaning up handle %"SCNu64"...\n", handle->handle_id);
374
        janus_ice_free(handle);
375

    
376
        return G_SOURCE_REMOVE;
377
}
378

    
379
static gboolean janus_ice_handles_check(gpointer user_data) {
380
        GMainContext *watchdog_context = (GMainContext *) user_data;
381
        janus_mutex_lock(&old_handles_mutex);
382
        if(old_handles && g_hash_table_size(old_handles) > 0) {
383
                GHashTableIter iter;
384
                gpointer value;
385
                g_hash_table_iter_init(&iter, old_handles);
386
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
387
                        janus_ice_handle *handle = (janus_ice_handle *) value;
388
                        if (!handle) {
389
                                continue;
390
                        }
391
                        /* Schedule the ICE handle for deletion */
392
                        g_hash_table_iter_remove(&iter);
393
                        GSource *timeout_source = g_timeout_source_new_seconds(3);
394
                        g_source_set_callback(timeout_source, janus_ice_handles_cleanup, handle, NULL);
395
                        g_source_attach(timeout_source, watchdog_context);
396
                        g_source_unref(timeout_source);
397
                }
398
        }
399
        janus_mutex_unlock(&old_handles_mutex);
400

    
401
        if(janus_force_rtcpmux_blackhole_fd > 0) {
402
                /* Also read the blackhole socket (unneeded RTCP components keepalives) and dump the packets */
403
                char buffer[1500];
404
                struct sockaddr_storage addr;
405
                socklen_t len = sizeof(addr);
406
                ssize_t res = 0;
407
                do {
408
                        /* Read and ignore */
409
                        res = recvfrom(janus_force_rtcpmux_blackhole_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, &len);
410
                } while(res > -1);
411
        }
412

    
413
        return G_SOURCE_CONTINUE;
414
}
415

    
416
static gpointer janus_ice_handles_watchdog(gpointer user_data) {
417
        GMainLoop *loop = (GMainLoop *) user_data;
418
        GMainContext *watchdog_context = g_main_loop_get_context(loop);
419
        GSource *timeout_source;
420

    
421
        timeout_source = g_timeout_source_new_seconds(1);
422
        g_source_set_callback(timeout_source, janus_ice_handles_check, watchdog_context, NULL);
423
        g_source_attach(timeout_source, watchdog_context);
424
        g_source_unref(timeout_source);
425

    
426
        JANUS_LOG(LOG_INFO, "ICE handles watchdog started\n");
427

    
428
        g_main_loop_run(loop);
429

    
430
        return NULL;
431
}
432

    
433

    
434
static void janus_ice_notify_media(janus_ice_handle *handle, gboolean video, gboolean up) {
435
        if(handle == NULL)
436
                return;
437
        /* Prepare JSON event to notify user/application */
438
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Notifying that we %s receiving %s\n",
439
                handle->handle_id, up ? "are" : "are NOT", video ? "video" : "audio");
440
        janus_session *session = (janus_session *)handle->session;
441
        if(session == NULL)
442
                return;
443
        json_t *event = json_object();
444
        json_object_set_new(event, "janus", json_string("media"));
445
        json_object_set_new(event, "session_id", json_integer(session->session_id));
446
        json_object_set_new(event, "sender", json_integer(handle->handle_id));
447
        json_object_set_new(event, "type", json_string(video ? "video" : "audio"));
448
        json_object_set_new(event, "receiving", json_string(up ? "true" : "false"));
449
        /* Send the event */
450
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
451
        janus_session_notify_event(session->session_id, event);
452
        /* Notify event handlers as well */
453
        if(janus_events_is_enabled()) {
454
                json_t *info = json_object();
455
                json_object_set_new(info, "media", json_string(video ? "video" : "audio"));
456
                json_object_set_new(info, "receiving", json_string(up ? "true" : "false"));
457
                janus_events_notify_handlers(JANUS_EVENT_TYPE_MEDIA, session->session_id, handle->handle_id, info);
458
        }
459
}
460

    
461
void janus_ice_notify_hangup(janus_ice_handle *handle, const char *reason) {
462
        if(handle == NULL)
463
                return;
464
        /* Prepare JSON event to notify user/application */
465
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Notifying WebRTC hangup\n", handle->handle_id);
466
        janus_session *session = (janus_session *)handle->session;
467
        if(session == NULL)
468
                return;
469
        json_t *event = json_object();
470
        json_object_set_new(event, "janus", json_string("hangup"));
471
        json_object_set_new(event, "session_id", json_integer(session->session_id));
472
        json_object_set_new(event, "sender", json_integer(handle->handle_id));
473
        if(reason != NULL)
474
                json_object_set_new(event, "reason", json_string(reason));
475
        /* Send the event */
476
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
477
        janus_session_notify_event(session->session_id, event);
478
        /* Notify event handlers as well */
479
        if(janus_events_is_enabled()) {
480
                json_t *info = json_object();
481
                json_object_set_new(info, "connection", json_string("hangup"));
482
                janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, session->session_id, handle->handle_id, info);
483
        }
484
}
485

    
486

    
487
/* Trickle helpers */
488
janus_ice_trickle *janus_ice_trickle_new(janus_ice_handle *handle, const char *transaction, json_t *candidate) {
489
        if(transaction == NULL || candidate == NULL)
490
                return NULL;
491
        janus_ice_trickle *trickle = g_malloc0(sizeof(janus_ice_trickle));
492
        trickle->handle = handle;
493
        trickle->received = janus_get_monotonic_time();
494
        trickle->transaction = g_strdup(transaction);
495
        trickle->candidate = json_deep_copy(candidate);
496
        return trickle;
497
}
498

    
499
gint janus_ice_trickle_parse(janus_ice_handle *handle, json_t *candidate, const char **error) {
500
        const char *ignore_error = NULL;
501
        if (error == NULL) {
502
                error = &ignore_error;
503
        }
504
        if(handle == NULL) {
505
                *error = "Invalid handle";
506
                return JANUS_ERROR_HANDLE_NOT_FOUND;
507
        }
508
        /* Parse trickle candidate */
509
        if(!json_is_object(candidate) || json_object_get(candidate, "completed") != NULL) {
510
                JANUS_LOG(LOG_VERB, "No more remote candidates for handle %"SCNu64"!\n", handle->handle_id);
511
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES);
512
        } else {
513
                /* Handle remote candidate */
514
                json_t *mid = json_object_get(candidate, "sdpMid");
515
                if(!mid) {
516
                        *error = "Trickle error: missing mandatory element (sdpMid)";
517
                        return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
518
                }
519
                if(!json_is_string(mid)) {
520
                        *error = "Trickle error: invalid element type (sdpMid should be a string)";
521
                        return JANUS_ERROR_INVALID_ELEMENT_TYPE;
522
                }
523
                json_t *mline = json_object_get(candidate, "sdpMLineIndex");
524
                if(!mline) {
525
                        *error = "Trickle error: missing mandatory element (sdpMLineIndex)";
526
                        return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
527
                }
528
                if(!json_is_integer(mline) || json_integer_value(mline) < 0) {
529
                        *error = "Trickle error: invalid element type (sdpMLineIndex should be an integer)";
530
                        return JANUS_ERROR_INVALID_ELEMENT_TYPE;
531
                }
532
                json_t *rc = json_object_get(candidate, "candidate");
533
                if(!rc) {
534
                        *error = "Trickle error: missing mandatory element (candidate)";
535
                        return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
536
                }
537
                if(!json_is_string(rc)) {
538
                        *error = "Trickle error: invalid element type (candidate should be a string)";
539
                        return JANUS_ERROR_INVALID_ELEMENT_TYPE;
540
                }
541
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Trickle candidate (%s): %s\n", handle->handle_id, json_string_value(mid), json_string_value(rc));
542
                /* Parse it */
543
                int sdpMLineIndex = json_integer_value(mline);
544
                int video = 0, data = 0;
545
                /* FIXME badly, we should have an array of m-lines in the handle object */
546
                switch(sdpMLineIndex) {
547
                        case 0:
548
                                if(handle->audio_stream == NULL) {
549
                                        video = handle->video_stream ? 1 : 0;
550
                                        data = !video;
551
                                }
552
                                break;
553
                        case 1:
554
                                if(handle->audio_stream == NULL) {
555
                                        data = 1;
556
                                } else {
557
                                        video = handle->video_stream ? 1 : 0;
558
                                        data = !video;
559
                                }
560
                                break;
561
                        case 2:
562
                                data = 1;
563
                                break;
564
                        default:
565
                                /* FIXME We don't support more than 3 m-lines right now */
566
                                *error = "Trickle error: invalid element type (sdpMLineIndex not [0,2])";
567
                                return JANUS_ERROR_INVALID_ELEMENT_TYPE;
568
                }
569
#ifndef HAVE_SCTP
570
                data = 0;
571
#endif
572
                if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)
573
                                && sdpMLineIndex != 0) {
574
                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got a %s candidate but we're bundling, ignoring...\n", handle->handle_id, json_string_value(mid));
575
                } else {
576
                        janus_ice_stream *stream = video ? handle->video_stream : (data ? handle->data_stream : handle->audio_stream);
577
                        if(stream == NULL) {
578
                                *error = "Trickle error: invalid element type (no such stream)";
579
                                return JANUS_ERROR_TRICKE_INVALID_STREAM;
580
                        }
581
                        int res = janus_sdp_parse_candidate(stream, json_string_value(rc), 1);
582
                        if(res != 0) {
583
                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Failed to parse candidate... (%d)\n", handle->handle_id, res);
584
                                /* FIXME Should we return an error? */
585
                        }
586
                }
587
        }
588
        return 0;
589
}
590

    
591
void janus_ice_trickle_destroy(janus_ice_trickle *trickle) {
592
        if(trickle == NULL)
593
                return;
594
        trickle->handle = NULL;
595
        if(trickle->transaction)
596
                g_free(trickle->transaction);
597
        trickle->transaction = NULL;
598
        if(trickle->candidate)
599
                json_decref(trickle->candidate);
600
        trickle->candidate = NULL;
601
        g_free(trickle);
602
}
603

    
604

    
605
/* libnice initialization */
606
void janus_ice_init(gboolean ice_lite, gboolean ice_tcp, gboolean ipv6, uint16_t rtp_min_port, uint16_t rtp_max_port) {
607
        janus_ice_lite_enabled = ice_lite;
608
        janus_ice_tcp_enabled = ice_tcp;
609
        janus_ipv6_enabled = ipv6;
610
        JANUS_LOG(LOG_INFO, "Initializing ICE stuff (%s mode, ICE-TCP candidates %s, IPv6 support %s)\n",
611
                janus_ice_lite_enabled ? "Lite" : "Full",
612
                janus_ice_tcp_enabled ? "enabled" : "disabled",
613
                janus_ipv6_enabled ? "enabled" : "disabled");
614
        if(janus_ice_tcp_enabled) {
615
#ifndef HAVE_LIBNICE_TCP
616
                JANUS_LOG(LOG_WARN, "libnice version < 0.1.8, disabling ICE-TCP support\n");
617
                janus_ice_tcp_enabled = FALSE;
618
#else
619
                if(!janus_ice_lite_enabled) {
620
                        JANUS_LOG(LOG_WARN, "ICE-TCP only works in libnice if you enable ICE Lite too: disabling ICE-TCP support\n");
621
                        janus_ice_tcp_enabled = FALSE;
622
                }
623
#endif
624
        }
625
        /* libnice debugging is disabled unless explicitly stated */
626
        nice_debug_disable(TRUE);
627

    
628
        /*! \note The RTP/RTCP port range configuration may be just a placeholder: for
629
         * instance, libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails
630
         * when linking with an undefined reference to \c nice_agent_set_port_range 
631
         * so this is checked by the install.sh script in advance. */
632
        rtp_range_min = rtp_min_port;
633
        rtp_range_max = rtp_max_port;
634
        if(rtp_range_max < rtp_range_min) {
635
                JANUS_LOG(LOG_WARN, "Invalid ICE port range: %"SCNu16" > %"SCNu16"\n", rtp_range_min, rtp_range_max);
636
        } else if(rtp_range_min > 0 || rtp_range_max > 0) {
637
#ifndef HAVE_PORTRANGE
638
                JANUS_LOG(LOG_WARN, "nice_agent_set_port_range unavailable, port range disabled\n");
639
#else
640
                JANUS_LOG(LOG_INFO, "ICE port range: %"SCNu16"-%"SCNu16"\n", rtp_range_min, rtp_range_max);
641
#endif
642
        }
643

    
644
        /* We keep track of old plugin sessions to avoid problems */
645
        old_plugin_sessions = g_hash_table_new(NULL, NULL);
646
        janus_mutex_init(&old_plugin_sessions_mutex);
647

    
648
        /* Start the handles watchdog */
649
        janus_mutex_init(&old_handles_mutex);
650
        old_handles = g_hash_table_new(NULL, NULL);
651
        handles_watchdog_context = g_main_context_new();
652
        handles_watchdog_loop = g_main_loop_new(handles_watchdog_context, FALSE);
653
        GError *error = NULL;
654
        handles_watchdog = g_thread_try_new("handles watchdog", &janus_ice_handles_watchdog, handles_watchdog_loop, &error);
655
        if(error != NULL) {
656
                JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to start handles watchdog...\n", error->code, error->message ? error->message : "??");
657
                exit(1);
658
        }
659
        
660
#ifdef HAVE_LIBCURL
661
        /* Initialize the TURN REST API client stack, whether we're going to use it or not */
662
        janus_turnrest_init();
663
#endif
664

    
665
}
666

    
667
void janus_ice_deinit(void) {
668
        JANUS_LOG(LOG_INFO, "Ending ICE handles watchdog mainloop...\n");
669
        g_main_loop_quit(handles_watchdog_loop);
670
        g_thread_join(handles_watchdog);
671
        handles_watchdog = NULL;
672
        g_main_loop_unref(handles_watchdog_loop);
673
        g_main_context_unref(handles_watchdog_context);
674
        janus_mutex_lock(&old_handles_mutex);
675
        if(old_handles != NULL)
676
                g_hash_table_destroy(old_handles);
677
        old_handles = NULL;
678
        janus_mutex_unlock(&old_handles_mutex);
679
#ifdef HAVE_LIBCURL
680
        janus_turnrest_deinit();
681
#endif
682
}
683

    
684
int janus_ice_set_stun_server(gchar *stun_server, uint16_t stun_port) {
685
        if(stun_server == NULL)
686
                return 0;        /* No initialization needed */
687
        if(stun_port == 0)
688
                stun_port = 3478;
689
        JANUS_LOG(LOG_INFO, "STUN server to use: %s:%u\n", stun_server, stun_port);
690
        /* Resolve address to get an IP */
691
        struct addrinfo *res = NULL;
692
        if(getaddrinfo(stun_server, NULL, NULL, &res) != 0) {
693
                JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", stun_server);
694
                if(res)
695
                        freeaddrinfo(res);
696
                return -1;
697
        }
698
        janus_stun_server = janus_address_to_ip(res->ai_addr);
699
        freeaddrinfo(res);
700
        if(janus_stun_server == NULL) {
701
                JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", stun_server);
702
                return -1;
703
        }
704
        janus_stun_port = stun_port;
705
        JANUS_LOG(LOG_VERB, "  >> %s:%u\n", janus_stun_server, janus_stun_port);
706
        /* Test the STUN server */
707
        StunAgent stun;
708
        stun_agent_init (&stun, STUN_ALL_KNOWN_ATTRIBUTES, STUN_COMPATIBILITY_RFC5389, 0);
709
        StunMessage msg;
710
        uint8_t buf[1500];
711
        size_t len = stun_usage_bind_create(&stun, &msg, buf, 1500);
712
        JANUS_LOG(LOG_INFO, "Testing STUN server: message is of %zu bytes\n", len);
713
        int fd = socket(AF_INET, SOCK_DGRAM, 0);
714
        struct sockaddr_in address, remote;
715
        address.sin_family = AF_INET;
716
        address.sin_port = 0;
717
        address.sin_addr.s_addr = INADDR_ANY;
718
        remote.sin_family = AF_INET;
719
        remote.sin_port = htons(janus_stun_port);
720
        remote.sin_addr.s_addr = inet_addr(janus_stun_server);
721
        if(bind(fd, (struct sockaddr *)(&address), sizeof(struct sockaddr)) < 0) {
722
                JANUS_LOG(LOG_FATAL, "Bind failed for STUN BINDING test\n");
723
                return -1;
724
        }
725
        int bytes = sendto(fd, buf, len, 0, (struct sockaddr*)&remote, sizeof(remote));
726
        if(bytes < 0) {
727
                JANUS_LOG(LOG_FATAL, "Error sending STUN BINDING test\n");
728
                return -1;
729
        }
730
        JANUS_LOG(LOG_VERB, "  >> Sent %d bytes %s:%u, waiting for reply...\n", bytes, janus_stun_server, janus_stun_port);
731
        struct timeval timeout;
732
        fd_set readfds;
733
        FD_ZERO(&readfds);
734
        FD_SET(fd, &readfds);
735
        timeout.tv_sec = 5;        /* FIXME Don't wait forever */
736
        timeout.tv_usec = 0;
737
        select(fd+1, &readfds, NULL, NULL, &timeout);
738
        if(!FD_ISSET(fd, &readfds)) {
739
                JANUS_LOG(LOG_FATAL, "No response to our STUN BINDING test\n");
740
                return -1;
741
        }
742
        socklen_t addrlen = sizeof(remote);
743
        bytes = recvfrom(fd, buf, 1500, 0, (struct sockaddr*)&remote, &addrlen);
744
        JANUS_LOG(LOG_VERB, "  >> Got %d bytes...\n", bytes);
745
        if(stun_agent_validate (&stun, &msg, buf, bytes, NULL, NULL) != STUN_VALIDATION_SUCCESS) {
746
                JANUS_LOG(LOG_FATAL, "Failed to validate STUN BINDING response\n");
747
                return -1;
748
        }
749
        StunClass class = stun_message_get_class(&msg);
750
        StunMethod method = stun_message_get_method(&msg);
751
        if(class != STUN_RESPONSE || method != STUN_BINDING) {
752
                JANUS_LOG(LOG_FATAL, "Unexpected STUN response: %d/%d\n", class, method);
753
                return -1;
754
        }
755
        StunMessageReturn ret = stun_message_find_xor_addr(&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, (struct sockaddr_storage *)&address, &addrlen);
756
        JANUS_LOG(LOG_VERB, "  >> XOR-MAPPED-ADDRESS: %d\n", ret);
757
        if(ret == STUN_MESSAGE_RETURN_SUCCESS) {
758
                char *public_ip = janus_address_to_ip((struct sockaddr *)&address);
759
                JANUS_LOG(LOG_INFO, "  >> Our public address is %s\n", public_ip);
760
                janus_set_public_ip(public_ip);
761
                g_free(public_ip);
762
                return 0;
763
        }
764
        ret = stun_message_find_addr(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, (struct sockaddr_storage *)&address, &addrlen);
765
        JANUS_LOG(LOG_VERB, "  >> MAPPED-ADDRESS: %d\n", ret);
766
        if(ret == STUN_MESSAGE_RETURN_SUCCESS) {
767
                char *public_ip = janus_address_to_ip((struct sockaddr *)&address);
768
                JANUS_LOG(LOG_INFO, "  >> Our public address is %s\n", public_ip);
769
                janus_set_public_ip(public_ip);
770
                g_free(public_ip);
771
                return 0;
772
        }
773
        return -1;
774
}
775

    
776
int janus_ice_set_turn_server(gchar *turn_server, uint16_t turn_port, gchar *turn_type, gchar *turn_user, gchar *turn_pwd) {
777
        if(turn_server == NULL)
778
                return 0;        /* No initialization needed */
779
        if(turn_type == NULL)
780
                turn_type = (char *)"udp";
781
        if(turn_port == 0)
782
                turn_port = 3478;
783
        JANUS_LOG(LOG_INFO, "TURN server to use: %s:%u (%s)\n", turn_server, turn_port, turn_type);
784
        if(!strcasecmp(turn_type, "udp")) {
785
                janus_turn_type = NICE_RELAY_TYPE_TURN_UDP;
786
        } else if(!strcasecmp(turn_type, "tcp")) {
787
                janus_turn_type = NICE_RELAY_TYPE_TURN_TCP;
788
        } else if(!strcasecmp(turn_type, "tls")) {
789
                janus_turn_type = NICE_RELAY_TYPE_TURN_TLS;
790
        } else {
791
                JANUS_LOG(LOG_ERR, "Unsupported relay type '%s'...\n", turn_type);
792
                return -1;
793
        }
794
        /* Resolve address to get an IP */
795
        struct addrinfo *res = NULL;
796
        if(getaddrinfo(turn_server, NULL, NULL, &res) != 0) {
797
                JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", turn_server);
798
                if(res)
799
                        freeaddrinfo(res);
800
                return -1;
801
        }
802
        if(janus_turn_server != NULL)
803
                g_free(janus_turn_server);
804
        janus_turn_server = janus_address_to_ip(res->ai_addr);
805
        freeaddrinfo(res);
806
        if(janus_turn_server == NULL) {
807
                JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", turn_server);
808
                return -1;
809
        }
810
        janus_turn_port = turn_port;
811
        JANUS_LOG(LOG_VERB, "  >> %s:%u\n", janus_turn_server, janus_turn_port);
812
        if(janus_turn_user != NULL)
813
                g_free(janus_turn_user);
814
        janus_turn_user = NULL;
815
        if(turn_user)
816
                janus_turn_user = g_strdup(turn_user);
817
        if(janus_turn_pwd != NULL)
818
                g_free(janus_turn_pwd);
819
        janus_turn_pwd = NULL;
820
        if(turn_pwd)
821
                janus_turn_pwd = g_strdup(turn_pwd);
822
        return 0;
823
}
824

    
825
int janus_ice_set_turn_rest_api(gchar *api_server, gchar *api_key, gchar *api_method) {
826
#ifndef HAVE_LIBCURL
827
        JANUS_LOG(LOG_ERR, "Janus has been nuilt with no libcurl support, TURN REST API unavailable\n");
828
        return -1; 
829
#else
830
        if(api_server != NULL &&
831
                        (strstr(api_server, "http://") != api_server && strstr(api_server, "https://") != api_server)) {
832
                JANUS_LOG(LOG_ERR, "Invalid TURN REST API backend: not an HTTP address\n");
833
                return -1;
834
        }
835
        janus_turnrest_set_backend(api_server, api_key, api_method);
836
        JANUS_LOG(LOG_INFO, "TURN REST API backend: %s\n", api_server ? api_server : "(disabled)");
837
#endif
838
        return 0;
839
}
840

    
841

    
842
/* ICE stuff */
843
static const gchar *janus_ice_state_name[] = 
844
{
845
        "disconnected",
846
        "gathering",
847
        "connecting",
848
        "connected",
849
        "ready",
850
        "failed"
851
};
852
const gchar *janus_get_ice_state_name(gint state) {
853
        if(state < 0 || state > 5)
854
                return NULL;
855
        return janus_ice_state_name[state];
856
}
857

    
858
/* Stats */
859
void janus_ice_stats_queue_free(gpointer data);
860
void janus_ice_stats_queue_free(gpointer data) {
861
        janus_ice_stats_item *s = (janus_ice_stats_item *)data;
862
        g_free(s);
863
}
864

    
865
void janus_ice_stats_reset(janus_ice_stats *stats) {
866
        if(stats == NULL)
867
                return;
868
        stats->audio_packets = 0;
869
        stats->audio_bytes = 0;
870
        if(stats->audio_bytes_lastsec)
871
                g_list_free_full(stats->audio_bytes_lastsec, &janus_ice_stats_queue_free);
872
        stats->audio_bytes_lastsec = NULL;
873
        stats->audio_notified_lastsec = FALSE;
874
        stats->audio_nacks = 0;
875
        stats->video_packets = 0;
876
        stats->video_bytes = 0;
877
        if(stats->video_bytes_lastsec)
878
                g_list_free_full(stats->video_bytes_lastsec, &janus_ice_stats_queue_free);
879
        stats->video_bytes_lastsec = NULL;
880
        stats->video_notified_lastsec = FALSE;
881
        stats->video_nacks = 0;
882
        stats->data_packets = 0;
883
        stats->data_bytes = 0;
884
}
885

    
886

    
887
/* ICE Handles */
888
janus_ice_handle *janus_ice_handle_create(void *gateway_session) {
889
        if(gateway_session == NULL)
890
                return NULL;
891
        janus_session *session = (janus_session *)gateway_session;
892
        guint64 handle_id = 0;
893
        while(handle_id == 0) {
894
                handle_id = g_random_int();
895
                if(janus_ice_handle_find(gateway_session, handle_id) != NULL) {
896
                        /* Handle ID already taken, try another one */
897
                        handle_id = 0;
898
                }
899
        }
900
        JANUS_LOG(LOG_INFO, "Creating new handle in session %"SCNu64": %"SCNu64"\n", session->session_id, handle_id);
901
        janus_ice_handle *handle = (janus_ice_handle *)g_malloc0(sizeof(janus_ice_handle));
902
        if(handle == NULL) {
903
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
904
                return NULL;
905
        }
906
        handle->session = gateway_session;
907
        handle->created = janus_get_monotonic_time();
908
        handle->handle_id = handle_id;
909
        handle->app = NULL;
910
        handle->app_handle = NULL;
911
        janus_mutex_init(&handle->mutex);
912

    
913
        /* Set up other stuff. */
914
        janus_mutex_lock(&session->mutex);
915
        if(session->ice_handles == NULL)
916
                session->ice_handles = g_hash_table_new(NULL, NULL);
917
        g_hash_table_insert(session->ice_handles, GUINT_TO_POINTER(handle_id), handle);
918
        janus_mutex_unlock(&session->mutex);
919

    
920
        return handle;
921
}
922

    
923
janus_ice_handle *janus_ice_handle_find(void *gateway_session, guint64 handle_id) {
924
        if(gateway_session == NULL)
925
                return NULL;
926
        janus_session *session = (janus_session *)gateway_session;
927
        janus_mutex_lock(&session->mutex);
928
        janus_ice_handle *handle = session->ice_handles ? g_hash_table_lookup(session->ice_handles, GUINT_TO_POINTER(handle_id)) : NULL;
929
        janus_mutex_unlock(&session->mutex);
930
        return handle;
931
}
932

    
933
gint janus_ice_handle_attach_plugin(void *gateway_session, guint64 handle_id, janus_plugin *plugin) {
934
        if(gateway_session == NULL)
935
                return JANUS_ERROR_SESSION_NOT_FOUND;
936
        if(plugin == NULL)
937
                return JANUS_ERROR_PLUGIN_NOT_FOUND;
938
        janus_session *session = (janus_session *)gateway_session;
939
        janus_ice_handle *handle = janus_ice_handle_find(session, handle_id);
940
        if(handle == NULL)
941
                return JANUS_ERROR_HANDLE_NOT_FOUND;
942
        janus_mutex_lock(&session->mutex);
943
        if(handle->app != NULL) {
944
                /* This handle is already attached to a plugin */
945
                janus_mutex_unlock(&session->mutex);
946
                return JANUS_ERROR_PLUGIN_ATTACH;
947
        }
948
        int error = 0;
949
        janus_plugin_session *session_handle = g_malloc0(sizeof(janus_plugin_session));
950
        if(session_handle == NULL) {
951
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
952
                janus_mutex_unlock(&session->mutex);
953
                return JANUS_ERROR_UNKNOWN;        /* FIXME Do we need something like "Internal Server Error"? */
954
        }
955
        session_handle->gateway_handle = handle;
956
        session_handle->plugin_handle = NULL;
957
        session_handle->stopped = 0;
958
        plugin->create_session(session_handle, &error);
959
        if(error) {
960
                /* TODO Make error struct to pass verbose information */
961
                janus_mutex_unlock(&session->mutex);
962
                return error;
963
        }
964
        handle->app = plugin;
965
        handle->app_handle = session_handle;
966
        /* Make sure this plugin session is not in the old sessions list */
967
        janus_mutex_lock(&old_plugin_sessions_mutex);
968
        g_hash_table_remove(old_plugin_sessions, session_handle);
969
        janus_mutex_unlock(&old_plugin_sessions_mutex);
970
        janus_mutex_unlock(&session->mutex);
971
        /* Notify event handlers */
972
        if(janus_events_is_enabled())
973
                janus_events_notify_handlers(JANUS_EVENT_TYPE_HANDLE, session->session_id, handle_id, "attached");
974
        return 0;
975
}
976

    
977
gint janus_ice_handle_destroy(void *gateway_session, guint64 handle_id) {
978
        if(gateway_session == NULL)
979
                return JANUS_ERROR_SESSION_NOT_FOUND;
980
        janus_session *session = (janus_session *)gateway_session;
981
        janus_ice_handle *handle = janus_ice_handle_find(session, handle_id);
982
        if(handle == NULL)
983
                return JANUS_ERROR_HANDLE_NOT_FOUND;
984
        janus_mutex_lock(&session->mutex);
985
        janus_plugin *plugin_t = (janus_plugin *)handle->app;
986
        if(plugin_t == NULL) {
987
                /* There was no plugin attached, probably something went wrong there */
988
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
989
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
990
                if(handle->iceloop)
991
                        g_main_loop_quit(handle->iceloop);
992
                janus_mutex_unlock(&session->mutex);
993
                return 0;
994
        }
995
        JANUS_LOG(LOG_INFO, "Detaching handle from %s\n", plugin_t->get_name());
996
        /* TODO Actually detach handle... */
997
        int error = 0;
998
        janus_mutex_lock(&old_plugin_sessions_mutex);
999
        /* This is to tell the plugin to stop using this session: we'll get rid of it later */
1000
        handle->app_handle->stopped = 1;
1001
        /* And this is to put the plugin session in the old sessions list, to avoid it being used */
1002
        g_hash_table_insert(old_plugin_sessions, handle->app_handle, handle->app_handle);
1003
        janus_mutex_unlock(&old_plugin_sessions_mutex);
1004
        /* Notify the plugin that the session's over */
1005
        plugin_t->destroy_session(handle->app_handle, &error);
1006
        /* Get rid of the handle now */
1007
        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1008
        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
1009
        if(handle->iceloop)
1010
                g_main_loop_quit(handle->iceloop);
1011

    
1012
        /* Prepare JSON event to notify user/application */
1013
        json_t *event = json_object();
1014
        json_object_set_new(event, "janus", json_string("detached"));
1015
        json_object_set_new(event, "session_id", json_integer(session->session_id));
1016
        json_object_set_new(event, "sender", json_integer(handle_id));
1017
        /* Send the event */
1018
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
1019
        janus_session_notify_event(session->session_id, event);
1020
        janus_mutex_unlock(&session->mutex);
1021
        /* We only actually destroy the handle later */
1022
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Handle detached (error=%d), scheduling destruction\n", handle_id, error);
1023
        janus_mutex_lock(&old_handles_mutex);
1024
        g_hash_table_insert(old_handles, GUINT_TO_POINTER(handle_id), handle);
1025
        janus_mutex_unlock(&old_handles_mutex);
1026
        /* Notify event handlers as well */
1027
        if(janus_events_is_enabled())
1028
                janus_events_notify_handlers(JANUS_EVENT_TYPE_HANDLE, session->session_id, handle_id, "detached");
1029
        return error;
1030
}
1031

    
1032
void janus_ice_free(janus_ice_handle *handle) {
1033
        if(handle == NULL)
1034
                return;
1035
        janus_mutex_lock(&handle->mutex);
1036
        handle->session = NULL;
1037
        handle->app = NULL;
1038
        if(handle->app_handle != NULL) {
1039
                janus_mutex_lock(&old_plugin_sessions_mutex);
1040
                handle->app_handle->stopped = 1;
1041
                g_hash_table_insert(old_plugin_sessions, handle->app_handle, handle->app_handle);
1042
                handle->app_handle->gateway_handle = NULL;
1043
                handle->app_handle->plugin_handle = NULL;
1044
                g_free(handle->app_handle);
1045
                handle->app_handle = NULL;
1046
                janus_mutex_unlock(&old_plugin_sessions_mutex);
1047
        }
1048
        janus_mutex_unlock(&handle->mutex);
1049
        janus_ice_webrtc_free(handle);
1050
        JANUS_LOG(LOG_INFO, "[%"SCNu64"] Handle and related resources freed\n", handle->handle_id);
1051
        g_free(handle);
1052
        handle = NULL;
1053
}
1054

    
1055
void janus_ice_webrtc_hangup(janus_ice_handle *handle) {
1056
        if(handle == NULL)
1057
                return;
1058
        if(handle->queued_packets != NULL)
1059
                g_async_queue_push(handle->queued_packets, &janus_ice_dtls_alert);
1060
        if(handle->send_thread == NULL) {
1061
                /* Get rid of the loop */
1062
                if(handle->iceloop) {
1063
                        gint64 waited = 0;
1064
                        while(handle->iceloop && !g_main_loop_is_running(handle->iceloop)) {
1065
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE loop exists but is not running, waiting for it to run\n", handle->handle_id);
1066
                                g_usleep (100000);
1067
                                waited += 100000;
1068
                                if(waited >= G_USEC_PER_SEC) {
1069
                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   -- Waited a second, that's enough!\n", handle->handle_id);
1070
                                        break;
1071
                                }
1072
                        }
1073
                        if(handle->iceloop && g_main_loop_is_running(handle->iceloop)) {
1074
                                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");
1075
                                g_main_loop_quit(handle->iceloop);
1076
                                g_main_context_wakeup(handle->icectx);
1077
                        }
1078
                }
1079
        }
1080
        handle->icethread = NULL;
1081
}
1082

    
1083
void janus_ice_webrtc_free(janus_ice_handle *handle) {
1084
        if(handle == NULL)
1085
                return;
1086
        janus_mutex_lock(&handle->mutex);
1087
        if(handle->iceloop != NULL) {
1088
                g_main_loop_unref (handle->iceloop);
1089
                handle->iceloop = NULL;
1090
        }
1091
        if(handle->icectx != NULL) {
1092
                g_main_context_unref (handle->icectx);
1093
                handle->icectx = NULL;
1094
        }
1095
        handle->icethread = NULL;
1096
        if(handle->streams != NULL) {
1097
                janus_ice_stream_free(handle->streams, handle->audio_stream);
1098
                handle->audio_stream = NULL;
1099
                janus_ice_stream_free(handle->streams, handle->video_stream);
1100
                handle->video_stream = NULL;
1101
                janus_ice_stream_free(handle->streams, handle->data_stream);
1102
                handle->data_stream = NULL;
1103
                g_hash_table_destroy(handle->streams);
1104
                handle->streams = NULL;
1105
        }
1106
        if(handle->agent != NULL) {
1107
                if(G_IS_OBJECT(handle->agent))
1108
                        g_object_unref(handle->agent);
1109
                handle->agent = NULL;
1110
        }
1111
        handle->agent_created = 0;
1112
        if(handle->pending_trickles) {
1113
                while(handle->pending_trickles) {
1114
                        GList *temp = g_list_first(handle->pending_trickles);
1115
                        handle->pending_trickles = g_list_remove_link(handle->pending_trickles, temp);
1116
                        janus_ice_trickle *trickle = (janus_ice_trickle *)temp->data;
1117
                        g_list_free(temp);
1118
                        janus_ice_trickle_destroy(trickle);
1119
                }
1120
        }
1121
        handle->pending_trickles = NULL;
1122
        g_free(handle->rtp_profile);
1123
        handle->rtp_profile = NULL;
1124
        g_free(handle->local_sdp);
1125
        handle->local_sdp = NULL;
1126
        g_free(handle->remote_sdp);
1127
        handle->remote_sdp = NULL;
1128
        if(handle->queued_packets != NULL) {
1129
                janus_ice_queued_packet *pkt = NULL;
1130
                while(g_async_queue_length(handle->queued_packets) > 0) {
1131
                        pkt = g_async_queue_try_pop(handle->queued_packets);
1132
                        if(pkt != NULL && pkt != &janus_ice_dtls_alert) {
1133
                                g_free(pkt->data);
1134
                                pkt->data = NULL;
1135
                                g_free(pkt);
1136
                                pkt = NULL;
1137
                        }
1138
                }
1139
                g_async_queue_unref(handle->queued_packets);
1140
                handle->queued_packets = NULL;
1141
        }
1142
        if(handle->audio_mid != NULL) {
1143
                g_free(handle->audio_mid);
1144
                handle->audio_mid = NULL;
1145
        }
1146
        if(handle->video_mid != NULL) {
1147
                g_free(handle->video_mid);
1148
                handle->video_mid = NULL;
1149
        }
1150
        if(handle->data_mid != NULL) {
1151
                g_free(handle->data_mid);
1152
                handle->data_mid = NULL;
1153
        }
1154
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
1155
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
1156
        g_atomic_int_set(&handle->send_thread_created, 0);
1157
        janus_mutex_unlock(&handle->mutex);
1158
        JANUS_LOG(LOG_INFO, "[%"SCNu64"] WebRTC resources freed\n", handle->handle_id);
1159
}
1160

    
1161
void janus_ice_stream_free(GHashTable *streams, janus_ice_stream *stream) {
1162
        if(stream == NULL)
1163
                return;
1164
        if(streams != NULL)
1165
                g_hash_table_remove(streams, GUINT_TO_POINTER(stream->stream_id));
1166
        if(stream->components != NULL) {
1167
                janus_ice_component_free(stream->components, stream->rtp_component);
1168
                stream->rtp_component = NULL;
1169
                janus_ice_component_free(stream->components, stream->rtcp_component);
1170
                stream->rtcp_component = NULL;
1171
                g_hash_table_destroy(stream->components);
1172
        }
1173
        stream->handle = NULL;
1174
        if(stream->remote_hashing != NULL) {
1175
                g_free(stream->remote_hashing);
1176
                stream->remote_hashing = NULL;
1177
        }
1178
        if(stream->remote_fingerprint != NULL) {
1179
                g_free(stream->remote_fingerprint);
1180
                stream->remote_fingerprint = NULL;
1181
        }
1182
        if(stream->ruser != NULL) {
1183
                g_free(stream->ruser);
1184
                stream->ruser = NULL;
1185
        }
1186
        if(stream->rpass != NULL) {
1187
                g_free(stream->rpass);
1188
                stream->rpass = NULL;
1189
        }
1190
        g_free(stream->audio_rtcp_ctx);
1191
        stream->audio_rtcp_ctx = NULL;
1192
        g_free(stream->video_rtcp_ctx);
1193
        stream->video_rtcp_ctx = NULL;
1194
        stream->audio_last_ts = 0;
1195
        stream->video_last_ts = 0;
1196
        g_free(stream);
1197
        stream = NULL;
1198
}
1199

    
1200
void janus_ice_component_free(GHashTable *components, janus_ice_component *component) {
1201
        if(component == NULL)
1202
                return;
1203
        janus_ice_stream *stream = component->stream;
1204
        if(stream == NULL)
1205
                return;
1206
        janus_ice_handle *handle = stream->handle;
1207
        if(handle == NULL)
1208
                return;
1209
        //~ janus_mutex_lock(&handle->mutex);
1210
        if(components != NULL)
1211
                g_hash_table_remove(components, GUINT_TO_POINTER(component->component_id));
1212
        component->stream = NULL;
1213
        if(component->source != NULL) {
1214
                g_source_destroy(component->source);
1215
                g_source_unref(component->source);
1216
                component->source = NULL;
1217
        }
1218
        if(component->dtls != NULL) {
1219
                janus_dtls_srtp_destroy(component->dtls);
1220
                component->dtls = NULL;
1221
        }
1222
        if(component->retransmit_buffer != NULL) {
1223
                janus_rtp_packet *p = NULL;
1224
                GList *first = g_list_first(component->retransmit_buffer);
1225
                while(first != NULL) {
1226
                        p = (janus_rtp_packet *)first->data;
1227
                        first->data = NULL;
1228
                        component->retransmit_buffer = g_list_delete_link(component->retransmit_buffer, first);
1229
                        g_free(p->data);
1230
                        p->data = NULL;
1231
                        g_free(p);
1232
                        first = g_list_first(component->retransmit_buffer);
1233
                }
1234
        }
1235
        if(component->candidates != NULL) {
1236
                GSList *i = NULL, *candidates = component->candidates;
1237
                for (i = candidates; i; i = i->next) {
1238
                        NiceCandidate *c = (NiceCandidate *) i->data;
1239
                        if(c != NULL) {
1240
                                nice_candidate_free(c);
1241
                                c = NULL;
1242
                        }
1243
                }
1244
                g_slist_free(candidates);
1245
                candidates = NULL;
1246
        }
1247
        component->candidates = NULL;
1248
        if(component->local_candidates != NULL) {
1249
                GSList *i = NULL, *candidates = component->local_candidates;
1250
                for (i = candidates; i; i = i->next) {
1251
                        gchar *c = (gchar *) i->data;
1252
                        if(c != NULL) {
1253
                                g_free(c);
1254
                                c = NULL;
1255
                        }
1256
                }
1257
                g_slist_free(candidates);
1258
                candidates = NULL;
1259
        }
1260
        component->local_candidates = NULL;
1261
        if(component->remote_candidates != NULL) {
1262
                GSList *i = NULL, *candidates = component->remote_candidates;
1263
                for (i = candidates; i; i = i->next) {
1264
                        gchar *c = (gchar *) i->data;
1265
                        if(c != NULL) {
1266
                                g_free(c);
1267
                                c = NULL;
1268
                        }
1269
                }
1270
                g_slist_free(candidates);
1271
                candidates = NULL;
1272
        }
1273
        component->remote_candidates = NULL;
1274
        if(component->selected_pair != NULL)
1275
                g_free(component->selected_pair);
1276
        component->selected_pair = NULL;
1277
        if(component->last_seqs_audio)
1278
                janus_seq_list_free(&component->last_seqs_audio);
1279
        if(component->last_seqs_video)
1280
                janus_seq_list_free(&component->last_seqs_video);
1281
        janus_ice_stats_reset(&component->in_stats);
1282
        janus_ice_stats_reset(&component->out_stats);
1283
        g_free(component);
1284
        //~ janus_mutex_unlock(&handle->mutex);
1285
}
1286

    
1287
/* Call plugin slow_link callback if enough NACKs within a second */
1288
#define SLOW_LINK_NACKS_PER_SEC 8
1289
static void
1290
janus_slow_link_update(janus_ice_component *component, janus_ice_handle *handle,
1291
                       guint nacks, int video, int uplink, gint64 now           ) {
1292
        if(now - component->sl_nack_period_ts > 2 * G_USEC_PER_SEC) {
1293
                /* old nacks too old, don't count them */
1294
                component->sl_nack_period_ts = now;
1295
                component->sl_nack_recent_cnt = 0;
1296
        }
1297
        component->sl_nack_recent_cnt += nacks;
1298
        if(component->sl_nack_recent_cnt >= SLOW_LINK_NACKS_PER_SEC
1299
           && now - component->last_slowlink_time > 1 * G_USEC_PER_SEC) {
1300
                janus_plugin *plugin = (janus_plugin *)handle->app;
1301
                if(plugin && plugin->slow_link && janus_plugin_session_is_alive(handle->app_handle))
1302
                        plugin->slow_link(handle->app_handle, uplink, video);
1303
                component->last_slowlink_time = now;
1304
                component->sl_nack_period_ts = now;
1305
                component->sl_nack_recent_cnt = 0;
1306
        }
1307
}
1308

    
1309

    
1310
/* Callbacks */
1311
void janus_ice_cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer user_data) {
1312
        janus_ice_handle *handle = (janus_ice_handle *)user_data;
1313
        if(!handle)
1314
                return;
1315
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Gathering done for stream %d\n", handle->handle_id, stream_id);
1316
        handle->cdone++;
1317
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
1318
        if(!stream) {
1319
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]  No stream %d??\n", handle->handle_id, stream_id);
1320
                return;
1321
        }
1322
        stream->cdone = 1;
1323
}
1324

    
1325
void janus_ice_cb_component_state_changed(NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer ice) {
1326
        janus_ice_handle *handle = (janus_ice_handle *)ice;
1327
        if(!handle)
1328
                return;
1329
        if(component_id > 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
1330
                /* State changed for a component we don't need anymore (rtcp-mux) */
1331
                return;
1332
        }
1333
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Component state changed for component %d in stream %d: %d (%s)\n",
1334
                handle->handle_id, component_id, stream_id, state, janus_get_ice_state_name(state));
1335
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
1336
        if(!stream) {
1337
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
1338
                return;
1339
        }
1340
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
1341
        if(!component) {
1342
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
1343
                return;
1344
        }
1345
        component->state = state;
1346
        /* Notify event handlers */
1347
        if(janus_events_is_enabled()) {
1348
                janus_session *session = (janus_session *)handle->session;
1349
                json_t *info = json_object();
1350
                json_object_set_new(info, "ice", json_string(janus_get_ice_state_name(state)));
1351
                json_object_set_new(info, "stream_id", json_integer(stream_id));
1352
                json_object_set_new(info, "component_id", json_integer(component_id));
1353
                janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, session->session_id, handle->handle_id, info);
1354
        }
1355
        /* Handle new state */
1356
        if((state == NICE_COMPONENT_STATE_CONNECTED || state == NICE_COMPONENT_STATE_READY)
1357
                        && handle->send_thread == NULL) {
1358
                /* Make sure we're not trying to start the thread more than once */
1359
                if(!g_atomic_int_compare_and_exchange(&handle->send_thread_created, 0, 1)) {
1360
                        return;
1361
                }
1362
                /* Start the outgoing data thread */
1363
                GError *error = NULL;
1364
                handle->send_thread = g_thread_try_new("ice send thread", &janus_ice_send_thread, handle, &error);
1365
                if(error != NULL) {
1366
                        /* FIXME We should clear some resources... */
1367
                        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 : "??");
1368
                        return;
1369
                }
1370
        }
1371
        /* FIXME Even in case the state is 'connected', we wait for the 'new-selected-pair' callback to do anything */
1372
        if(state == NICE_COMPONENT_STATE_FAILED) {
1373
                /* Failed doesn't mean necessarily we need to give up: we may be trickling */
1374
                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));
1375
                gboolean answer_recv = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_GOT_ANSWER);
1376
                gboolean alert_set = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1377
                if(handle && trickle_recv && answer_recv && !alert_set) {
1378
                        /* FIXME Should we really give up for what may be a failure in only one of the media? */
1379
                        if(stream->disabled) {
1380
                                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);
1381
                                return;
1382
                        }
1383
                        JANUS_LOG(LOG_ERR, "[%"SCNu64"] ICE failed for component %d in stream %d...\n", handle->handle_id, component_id, stream_id);
1384
                        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
1385
                        janus_plugin *plugin = (janus_plugin *)handle->app;
1386
                        if(plugin != NULL) {
1387
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about it (%s)\n", handle->handle_id, plugin->get_name());
1388
                                if(plugin && plugin->hangup_media)
1389
                                        plugin->hangup_media(handle->app_handle);
1390
                        }
1391
                        janus_ice_notify_hangup(handle, "ICE failed");
1392
                } else {
1393
                        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",
1394
                                handle->handle_id, component_id, stream_id,
1395
                                trickle_recv ? "received" : "pending",
1396
                                answer_recv ? "received" : "pending",
1397
                                alert_set ? "set" : "not set");
1398
                }
1399
        }
1400
}
1401

    
1402
#ifndef HAVE_LIBNICE_TCP
1403
void janus_ice_cb_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, gchar *local, gchar *remote, gpointer ice) {
1404
#else
1405
void janus_ice_cb_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, NiceCandidate *local, NiceCandidate *remote, gpointer ice) {
1406
#endif
1407
        janus_ice_handle *handle = (janus_ice_handle *)ice;
1408
        if(!handle)
1409
                return;
1410
        if(component_id > 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
1411
                /* New selected pair for a component we don't need anymore (rtcp-mux) */
1412
                return;
1413
        }
1414
#ifndef HAVE_LIBNICE_TCP
1415
        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);
1416
#else
1417
        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);
1418
#endif
1419
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
1420
        if(!stream) {
1421
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
1422
                return;
1423
        }
1424
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
1425
        if(!component) {
1426
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
1427
                return;
1428
        }
1429
        if(component->selected_pair)
1430
                g_free(component->selected_pair);
1431
        char sp[200];
1432
#ifndef HAVE_LIBNICE_TCP
1433
        g_snprintf(sp, 200, "%s <-> %s", local, remote);
1434
#else
1435
        gchar laddress[NICE_ADDRESS_STRING_LEN], raddress[NICE_ADDRESS_STRING_LEN];
1436
        gint lport = 0, rport = 0;
1437
        nice_address_to_string(&(local->addr), (gchar *)&laddress);
1438
        nice_address_to_string(&(remote->addr), (gchar *)&raddress);
1439
        lport = nice_address_get_port(&(local->addr));
1440
        rport = nice_address_get_port(&(remote->addr));
1441
        const char *ltype = NULL, *rtype = NULL; 
1442
        switch(local->type) {
1443
                case NICE_CANDIDATE_TYPE_HOST:
1444
                        ltype = "host";
1445
                        break;
1446
                case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
1447
                        ltype = "srflx";
1448
                        break;
1449
                case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
1450
                        ltype = "prflx";
1451
                        break;
1452
                case NICE_CANDIDATE_TYPE_RELAYED:
1453
                        ltype = "relay";
1454
                        break;
1455
                default:
1456
                        break;
1457
        }
1458
        switch(remote->type) {
1459
                case NICE_CANDIDATE_TYPE_HOST:
1460
                        rtype = "host";
1461
                        break;
1462
                case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
1463
                        rtype = "srflx";
1464
                        break;
1465
                case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
1466
                        rtype = "prflx";
1467
                        break;
1468
                case NICE_CANDIDATE_TYPE_RELAYED:
1469
                        rtype = "relay";
1470
                        break;
1471
                default:
1472
                        break;
1473
        }
1474
        g_snprintf(sp, 200, "%s:%d [%s,%s] <-> %s:%d [%s,%s]",
1475
                laddress, lport, ltype, local->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "udp" : "tcp",
1476
                raddress, rport, rtype, remote->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "udp" : "tcp");
1477
#endif
1478
        component->selected_pair = g_strdup(sp);
1479
        /* Notify event handlers */
1480
        if(janus_events_is_enabled()) {
1481
                janus_session *session = (janus_session *)handle->session;
1482
                json_t *info = json_object();
1483
                json_object_set_new(info, "selected-pair", json_string(sp));
1484
                json_object_set_new(info, "stream_id", json_integer(stream_id));
1485
                json_object_set_new(info, "component_id", json_integer(component_id));
1486
                janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, session->session_id, handle->handle_id, info);
1487
        }
1488
        /* Now we can start the DTLS handshake (FIXME This was on the 'connected' state notification, before) */
1489
        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Component is ready enough, starting DTLS handshake...\n", handle->handle_id);
1490
        /* Have we been here before? (might happen, when trickling) */
1491
        if(component->dtls != NULL)
1492
                return;
1493
        component->component_connected = janus_get_monotonic_time();
1494
        /* Create DTLS-SRTP context, at last */
1495
        component->dtls = janus_dtls_srtp_create(component, stream->dtls_role);
1496
        if(!component->dtls) {
1497
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component DTLS-SRTP session??\n", handle->handle_id);
1498
                return;
1499
        }
1500
        janus_dtls_srtp_handshake(component->dtls);
1501
        /* Create retransmission timer */
1502
        component->source = g_timeout_source_new(100);
1503
        g_source_set_callback(component->source, janus_dtls_retry, component->dtls, NULL);
1504
        guint id = g_source_attach(component->source, handle->icectx);
1505
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Creating retransmission timer with ID %u\n", handle->handle_id, id);
1506
}
1507

    
1508
#ifndef HAVE_LIBNICE_TCP
1509
void janus_ice_cb_new_remote_candidate (NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation, gpointer ice) {
1510
#else
1511
void janus_ice_cb_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate, gpointer ice) {
1512
#endif
1513
        janus_ice_handle *handle = (janus_ice_handle *)ice;
1514
#ifndef HAVE_LIBNICE_TCP
1515
        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);
1516
#else
1517
        const char *ctype = NULL;
1518
        switch(candidate->type) {
1519
                case NICE_CANDIDATE_TYPE_HOST:
1520
                        ctype = "host";
1521
                        break;
1522
                case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
1523
                        ctype = "srflx";
1524
                        break;
1525
                case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
1526
                        ctype = "prflx";
1527
                        break;
1528
                case NICE_CANDIDATE_TYPE_RELAYED:
1529
                        ctype = "relay";
1530
                        break;
1531
                default:
1532
                        break;
1533
        }
1534
        guint stream_id = candidate->stream_id;
1535
        guint component_id = candidate->component_id;
1536
        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);
1537
#endif
1538
        if(!handle)
1539
                return;
1540
        if(component_id > 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
1541
                /* New remote candidate for a component we don't need anymore (rtcp-mux) */
1542
                return;
1543
        }
1544
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
1545
        if(!stream) {
1546
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
1547
                return;
1548
        }
1549
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
1550
        if(!component) {
1551
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
1552
                return;
1553
        }
1554
#ifndef HAVE_LIBNICE_TCP
1555
        /* Get remote candidates and look for the related foundation */
1556
        NiceCandidate *candidate = NULL;
1557
        GSList *candidates = nice_agent_get_remote_candidates(agent, component_id, stream_id), *tmp = candidates;
1558
        while(tmp) {
1559
                NiceCandidate *c = (NiceCandidate *)tmp->data;
1560
                if(candidate == NULL) {
1561
                        /* Check if this is what we're looking for */
1562
                        if(!strcasecmp(c->foundation, foundation)) {
1563
                                /* It is! */
1564
                                candidate = c;
1565
                                tmp = tmp->next;
1566
                                continue;
1567
                        }
1568
                }
1569
                nice_candidate_free(c);
1570
                tmp = tmp->next;
1571
        }
1572
        g_slist_free(candidates);
1573
        if(candidate == NULL) {
1574
                JANUS_LOG(LOG_WARN, "Candidate with foundation %s not found?\n", foundation);
1575
                return;
1576
        }
1577
#endif
1578
        /* Render the candidate and add it to the remote_candidates cache for the admin API */
1579
        if(candidate->type != NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
1580
                /* ... but only if it's 'prflx', the others we add ourselves */
1581
                goto candidatedone;
1582
        }
1583
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream #%d, Component #%d\n", handle->handle_id, candidate->stream_id, candidate->component_id);
1584
        gchar address[NICE_ADDRESS_STRING_LEN], base_address[NICE_ADDRESS_STRING_LEN];
1585
        gint port = 0, base_port = 0;
1586
        nice_address_to_string(&(candidate->addr), (gchar *)&address);
1587
        port = nice_address_get_port(&(candidate->addr));
1588
        nice_address_to_string(&(candidate->base_addr), (gchar *)&base_address);
1589
        base_port = nice_address_get_port(&(candidate->base_addr));
1590
        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Address:    %s:%d\n", handle->handle_id, address, port);
1591
        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Priority:   %d\n", handle->handle_id, candidate->priority);
1592
        JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Foundation: %s\n", handle->handle_id, candidate->foundation);
1593
        char buffer[100];
1594
        if(candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
1595
                g_snprintf(buffer, 100,
1596
                        "%s %d %s %d %s %d typ prflx raddr %s rport %d\r\n", 
1597
                                candidate->foundation,
1598
                                candidate->component_id,
1599
                                "udp",
1600
                                candidate->priority,
1601
                                address,
1602
                                port,
1603
                                base_address,
1604
                                base_port);
1605
        } else {
1606
                if(!janus_ice_tcp_enabled) {
1607
                        /* ICETCP support disabled */
1608
                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping prflx TCP candidate, ICETCP support disabled...\n", handle->handle_id);
1609
                        goto candidatedone;
1610
                }
1611
#ifndef HAVE_LIBNICE_TCP
1612
                /* TCP candidates are only supported since libnice 0.1.8 */
1613
                JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping prflx TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
1614
                        goto candidatedone;
1615
#else
1616
                const char *type = NULL;
1617
                switch(candidate->transport) {
1618
                        case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
1619
                                type = "active";
1620
                                break;
1621
                        case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
1622
                                type = "passive";
1623
                                break;
1624
                        case NICE_CANDIDATE_TRANSPORT_TCP_SO:
1625
                                type = "so";
1626
                                break;
1627
                        default:
1628
                                break;
1629
                }
1630
                if(type == NULL) {
1631
                        /* FIXME Unsupported transport */
1632
                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping nonUDP/TCP prflx candidate...\n", handle->handle_id);
1633
                        goto candidatedone;
1634
                } else {
1635
                        g_snprintf(buffer, 100,
1636
                                "%s %d %s %d %s %d typ prflx raddr %s rport %d tcptype %s\r\n",
1637
                                        candidate->foundation,
1638
                                        candidate->component_id,
1639
                                        "tcp",
1640
                                        candidate->priority,
1641
                                        address,
1642
                                        port,
1643
                                        base_address,
1644
                                        base_port,
1645
                                        type);
1646
                }
1647
#endif
1648
        }
1649

    
1650
        /* Save for the summary, in case we need it */
1651
        component->remote_candidates = g_slist_append(component->remote_candidates, g_strdup(buffer));
1652

    
1653
candidatedone:
1654
#ifndef HAVE_LIBNICE_TCP
1655
        nice_candidate_free(candidate);
1656
#endif
1657
        return;
1658
}
1659

    
1660
void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer ice) {
1661
        janus_ice_component *component = (janus_ice_component *)ice;
1662
        if(!component) {
1663
                JANUS_LOG(LOG_ERR, "No component %d in stream %d??\n", component_id, stream_id);
1664
                return;
1665
        }
1666
        janus_ice_stream *stream = component->stream;
1667
        if(!stream) {
1668
                JANUS_LOG(LOG_ERR, "No stream %d??\n", stream_id);
1669
                return;
1670
        }
1671
        janus_ice_handle *handle = stream->handle;
1672
        if(!handle) {
1673
                JANUS_LOG(LOG_ERR, "No handle for stream %d??\n", stream_id);
1674
                return;
1675
        }
1676
        if(!component->dtls) {        /* Still waiting for the DTLS stack */
1677
                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);
1678
                return;
1679
        }
1680
        /* What is this? */
1681
        if (janus_is_dtls(buf) || (!janus_is_rtp(buf) && !janus_is_rtcp(buf))) {
1682
                /* This is DTLS: either handshake stuff, or data coming from SCTP DataChannels */
1683
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Looks like DTLS!\n", handle->handle_id);
1684
                janus_dtls_srtp_incoming_msg(component->dtls, buf, len);
1685
                /* Update stats (TODO Do the same for the last second window as well) */
1686
                component->in_stats.data_packets++;
1687
                component->in_stats.data_bytes += len;
1688
                return;
1689
        }
1690
        /* Not DTLS... RTP or RTCP? (http://tools.ietf.org/html/rfc5761#section-4) */
1691
        if(len < 12)
1692
                return;        /* Definitely nothing useful */
1693
        if(component_id == 1 && (!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) || janus_is_rtp(buf))) {
1694
                /* FIXME If rtcp-mux is not used, a first component is always RTP; otherwise, we need to check */
1695
                //~ JANUS_LOG(LOG_HUGE, "[%"SCNu64"]  Got an RTP packet (%s stream)!\n", handle->handle_id,
1696
                        //~ janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? "bundled" : (stream->stream_id == handle->audio_id ? "audio" : "video"));
1697
                if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_in) {
1698
                        JANUS_LOG(LOG_WARN, "[%"SCNu64"]     Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
1699
                } else {
1700
                        rtp_header *header = (rtp_header *)buf;
1701
                        /* Is this audio or video? */
1702
                        int video = 0;
1703
                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
1704
                                /* Easy enough */
1705
                                video = (stream->stream_id == handle->video_id ? 1 : 0);
1706
                        } else {
1707
                                /* Bundled streams, check SSRC */
1708
                                guint32 packet_ssrc = ntohl(header->ssrc);
1709
                                video = ((stream->video_ssrc_peer == packet_ssrc || stream->video_ssrc_peer_rtx == packet_ssrc) ? 1 : 0);
1710
                                if(!video && stream->audio_ssrc_peer != packet_ssrc) {
1711
                                        /* FIXME In case it happens, we should check what it is */
1712
                                        JANUS_LOG(LOG_WARN, "Not video and not audio? dropping (SSRC %"SCNu32")...\n", packet_ssrc);
1713
                                        return;
1714
                                }
1715
                                if(stream->video_ssrc_peer_rtx == packet_ssrc) {
1716
                                        /* FIXME This is a video retransmission: set the regular peer SSRC so
1717
                                         * that we avoid outgoing SRTP errors in case we got the packet already */
1718
                                        header->ssrc = htonl(stream->video_ssrc_peer);
1719
                                }
1720
                                //~ JANUS_LOG(LOG_VERB, "[RTP] Bundling: this is %s (video=%"SCNu64", audio=%"SCNu64", got %ld)\n",
1721
                                        //~ video ? "video" : "audio", stream->video_ssrc_peer, stream->audio_ssrc_peer, ntohl(header->ssrc));
1722
                        }
1723

    
1724
                        int buflen = len;
1725
                        err_status_t res = srtp_unprotect(component->dtls->srtp_in, buf, &buflen);
1726
                        if(res != err_status_ok) {
1727
                                if(res != err_status_replay_fail && res != err_status_replay_old) {
1728
                                        /* 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) */
1729
                                        rtp_header *header = (rtp_header *)buf;
1730
                                        guint32 timestamp = ntohl(header->timestamp);
1731
                                        guint16 seq = ntohs(header->seq_number);
1732
                                        JANUS_LOG(LOG_ERR, "[%"SCNu64"]     SRTP unprotect error: %s (len=%d-->%d, ts=%"SCNu32", seq=%"SCNu16")\n", handle->handle_id, janus_get_srtp_error(res), len, buflen, timestamp, seq);
1733
                                }
1734
                        } else {
1735
                                if(video) {
1736
                                        if(stream->video_ssrc_peer == 0) {
1737
                                                stream->video_ssrc_peer = ntohl(header->ssrc);
1738
                                                JANUS_LOG(LOG_VERB, "[%"SCNu64"]     Peer video SSRC: %u\n", handle->handle_id, stream->video_ssrc_peer);
1739
                                        }
1740
                                } else {
1741
                                        if(stream->audio_ssrc_peer == 0) {
1742
                                                stream->audio_ssrc_peer = ntohl(header->ssrc);
1743
                                                JANUS_LOG(LOG_VERB, "[%"SCNu64"]     Peer audio SSRC: %u\n", handle->handle_id, stream->audio_ssrc_peer);
1744
                                        }
1745
                                }
1746
                                /* Pass the data to the responsible plugin */
1747
                                janus_plugin *plugin = (janus_plugin *)handle->app;
1748
                                if(plugin && plugin->incoming_rtp)
1749
                                        plugin->incoming_rtp(handle->app_handle, video, buf, buflen);
1750
                                /* Update stats (TODO Do the same for the last second window as well) */
1751
                                if(buflen > 0) {
1752
                                        /* Update the last sec queue as well */
1753
                                        janus_ice_stats_item *s = g_malloc0(sizeof(janus_ice_stats_item));
1754
                                        s->bytes = buflen;
1755
                                        s->when = janus_get_monotonic_time();
1756
                                        janus_mutex_lock(&component->mutex);
1757
                                        if(!video) {
1758
                                                if(component->in_stats.audio_bytes == 0 || component->in_stats.audio_notified_lastsec) {
1759
                                                        /* We either received our first audio packet, or we started receiving it again after missing more than a second */
1760
                                                        component->in_stats.audio_notified_lastsec = FALSE;
1761
                                                        janus_ice_notify_media(handle, FALSE, TRUE);
1762
                                                }
1763
                                                component->in_stats.audio_packets++;
1764
                                                component->in_stats.audio_bytes += buflen;
1765
                                                component->in_stats.audio_bytes_lastsec = g_list_append(component->in_stats.audio_bytes_lastsec, s);
1766
                                                if(g_list_length(component->in_stats.audio_bytes_lastsec) > 100) {
1767
                                                        GList *first = g_list_first(component->in_stats.audio_bytes_lastsec);
1768
                                                        s = (janus_ice_stats_item *)first->data;
1769
                                                        first->data = NULL;
1770
                                                        component->in_stats.audio_bytes_lastsec = g_list_delete_link(component->in_stats.audio_bytes_lastsec, first);
1771
                                                        g_free(s);
1772
                                                }
1773
                                        } else {
1774
                                                if(component->in_stats.video_bytes == 0 || component->in_stats.video_notified_lastsec) {
1775
                                                        /* We either received our first video packet, or we started receiving it again after missing more than a second */
1776
                                                        component->in_stats.video_notified_lastsec = FALSE;
1777
                                                        janus_ice_notify_media(handle, TRUE, TRUE);
1778
                                                }
1779
                                                component->in_stats.video_packets++;
1780
                                                component->in_stats.video_bytes += buflen;
1781
                                                component->in_stats.video_bytes_lastsec = g_list_append(component->in_stats.video_bytes_lastsec, s);
1782
                                                if(g_list_length(component->in_stats.video_bytes_lastsec) > 100) {
1783
                                                        GList *first = g_list_first(component->in_stats.video_bytes_lastsec);
1784
                                                        s = (janus_ice_stats_item *)first->data;
1785
                                                        first->data = NULL;
1786
                                                        component->in_stats.video_bytes_lastsec = g_list_delete_link(component->in_stats.video_bytes_lastsec, first);
1787
                                                        g_free(s);
1788
                                                }
1789
                                        }
1790
                                        janus_mutex_unlock(&component->mutex);
1791
                                }
1792

    
1793
                                /* Update the RTCP context as well */
1794
                                rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx : stream->audio_rtcp_ctx;
1795
                                if(rtcp_ctx == NULL) {
1796
                                        /* We still need an RTCP context here, create it now */
1797
                                        rtcp_ctx = g_malloc0(sizeof(rtcp_context));
1798
                                        if(video) {
1799
                                                rtcp_ctx->tb = 90000;        /* FIXME */
1800
                                                stream->video_rtcp_ctx = rtcp_ctx;
1801
                                        } else {
1802
                                                rtcp_ctx->tb = 48000;        /* FIXME */
1803
                                                stream->audio_rtcp_ctx = rtcp_ctx;
1804
                                        }
1805
                                }
1806
                                janus_rtcp_process_incoming_rtp(rtcp_ctx, buf, buflen, janus_get_max_nack_queue());
1807

    
1808
                                /* Keep track of RTP sequence numbers, in case we need to NACK them */
1809
                                /*         Note: unsigned int overflow/underflow wraps (defined behavior) */
1810
                                guint16 new_seqn = ntohs(header->seq_number);
1811
                                guint16 cur_seqn;
1812
                                int last_seqs_len = 0;
1813
                                janus_mutex_lock(&component->mutex);
1814
                                seq_info_t **last_seqs = video ? &component->last_seqs_video : &component->last_seqs_audio;
1815
                                seq_info_t *cur_seq = *last_seqs;
1816
                                if(cur_seq) {
1817
                                        cur_seq = cur_seq->prev;
1818
                                        cur_seqn = cur_seq->seq;
1819
                                } else {
1820
                                        /* First seq, set up to add one seq */
1821
                                        cur_seqn = new_seqn - (guint16)1; /* Can wrap */
1822
                                }
1823
                                if(!janus_seq_in_range(new_seqn, cur_seqn, LAST_SEQS_MAX_LEN) &&
1824
                                                !janus_seq_in_range(cur_seqn, new_seqn, 1000)) {
1825
                                        /* Jump too big, start fresh */
1826
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Big sequence number jump %hu -> %hu (%s stream)\n",
1827
                                                handle->handle_id, cur_seqn, new_seqn, video ? "video" : "audio");
1828
                                        janus_seq_list_free(last_seqs);
1829
                                        cur_seq = NULL;
1830
                                        cur_seqn = new_seqn - (guint16)1;
1831
                                }
1832

    
1833
                                GSList *nacks = NULL;
1834
                                gint64 now = janus_get_monotonic_time();
1835

    
1836
                                if(janus_seq_in_range(new_seqn, cur_seqn, LAST_SEQS_MAX_LEN)) {
1837
                                        /* Add new seq objs forward */
1838
                                        while(cur_seqn != new_seqn) {
1839
                                                cur_seqn += (guint16)1; /* can wrap */
1840
                                                seq_info_t *seq_obj = g_malloc0(sizeof(seq_info_t));
1841
                                                seq_obj->seq = cur_seqn;
1842
                                                seq_obj->ts = now;
1843
                                                seq_obj->state = (cur_seqn == new_seqn) ? SEQ_RECVED : SEQ_MISSING;
1844
                                                janus_seq_append(last_seqs, seq_obj);
1845
                                                last_seqs_len++;
1846
                                        }
1847
                                }
1848
                                if(cur_seq) {
1849
                                        /* Scan old seq objs backwards */
1850
                                        for (;;) {
1851
                                                last_seqs_len++;
1852
                                                if(cur_seq->seq == new_seqn) {
1853
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Recieved missed sequence number %"SCNu16"\n", handle->handle_id, cur_seq->seq);
1854
                                                        cur_seq->state = SEQ_RECVED;
1855
                                                } else if(cur_seq->state == SEQ_MISSING && now - cur_seq->ts > SEQ_MISSING_WAIT) {
1856
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Missed sequence number %"SCNu16", sending 1st NACK\n", handle->handle_id, cur_seq->seq);
1857
                                                        nacks = g_slist_append(nacks, GUINT_TO_POINTER(cur_seq->seq));
1858
                                                        cur_seq->state = SEQ_NACKED;
1859
                                                } else if(cur_seq->state == SEQ_NACKED  && now - cur_seq->ts > SEQ_NACKED_WAIT) {
1860
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Missed sequence number %"SCNu16", sending 2nd NACK\n", handle->handle_id, cur_seq->seq);
1861
                                                        nacks = g_slist_append(nacks, GUINT_TO_POINTER(cur_seq->seq));
1862
                                                        cur_seq->state = SEQ_GIVEUP;
1863
                                                }
1864
                                                if(cur_seq == *last_seqs) {
1865
                                                        /* Just processed head */
1866
                                                        break;
1867
                                                }
1868
                                                cur_seq = cur_seq->prev;
1869
                                        }
1870
                                }
1871
                                while(last_seqs_len > LAST_SEQS_MAX_LEN) {
1872
                                        seq_info_t *node = janus_seq_pop_head(last_seqs);
1873
                                        g_free(node);
1874
                                        last_seqs_len--;
1875
                                }
1876

    
1877
                                guint nacks_count = g_slist_length(nacks);
1878
                                if(nacks_count) {
1879
                                        /* Generate a NACK and send it */
1880
                                        JANUS_LOG(LOG_DBG, "[%"SCNu64"] now sending NACK for %u missed packets\n", handle->handle_id, nacks_count);
1881
                                        char nackbuf[120];
1882
                                        int res = janus_rtcp_nacks(nackbuf, sizeof(nackbuf), nacks);
1883
                                        if(res > 0)
1884
                                                janus_ice_relay_rtcp(handle, video, nackbuf, res);
1885
                                        /* Update stats */
1886
                                        component->nack_sent_recent_cnt += nacks_count;
1887
                                        if(video) {
1888
                                                component->out_stats.video_nacks += nacks_count;
1889
                                        } else {
1890
                                                component->out_stats.audio_nacks += nacks_count;
1891
                                        }
1892
                                        /* Inform the plugin about the slow downlink in case it's needed */
1893
                                        janus_slow_link_update(component, handle, nacks_count, video, 0, now);
1894
                                }
1895
                                if (component->nack_sent_recent_cnt &&
1896
                                    now - component->nack_sent_log_ts > 5 * G_USEC_PER_SEC) {
1897
                                        JANUS_LOG(LOG_VERB, "[%10"SCNu64"]  sent NACKs for %u missing packets\n",
1898
                                                              handle->handle_id, component->nack_sent_recent_cnt);
1899
                                        component->nack_sent_recent_cnt = 0;
1900
                                        component->nack_sent_log_ts = now;
1901
                                }
1902
                                janus_mutex_unlock(&component->mutex);
1903
                                g_slist_free(nacks);
1904
                                nacks = NULL;
1905
                        }
1906
                }
1907
                return;
1908
        }
1909
        if(component_id == 2 || (component_id == 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) && janus_is_rtcp(buf))) {
1910
                /* FIXME A second component is always RTCP; in case of rtcp-mux, we need to check */
1911
                JANUS_LOG(LOG_HUGE, "[%"SCNu64"]  Got an RTCP packet (%s stream)!\n", handle->handle_id,
1912
                        janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? "bundled" : (stream->stream_id == handle->audio_id ? "audio" : "video"));
1913
                if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_in) {
1914
                        JANUS_LOG(LOG_WARN, "[%"SCNu64"]     Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
1915
                } else {
1916
                        int buflen = len;
1917
                        err_status_t res = srtp_unprotect_rtcp(component->dtls->srtp_in, buf, &buflen);
1918
                        if(res != err_status_ok) {
1919
                                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     SRTCP unprotect error: %s (len=%d-->%d)\n", handle->handle_id, janus_get_srtp_error(res), len, buflen);
1920
                        } else {
1921
                                /* Is this audio or video? */
1922
                                int video = 0;
1923
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
1924
                                        /* Easy enough */
1925
                                        video = (stream->stream_id == handle->video_id ? 1 : 0);
1926
                                } else {
1927
                                        /* Bundled streams, should we check the SSRCs? */
1928
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO)) {
1929
                                                /* No audio has been negotiated, definitely video */
1930
                                                JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is video (no audio has been negotiated)\n", handle->handle_id);
1931
                                                video = 1;
1932
                                        } else if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)) {
1933
                                                /* No video has been negotiated, definitely audio */
1934
                                                JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is audio (no video has been negotiated)\n", handle->handle_id);
1935
                                                video = 0;
1936
                                        } else {
1937
                                                if(stream->audio_ssrc_peer == 0 || stream->video_ssrc_peer == 0) {
1938
                                                        /* We don't know the remote SSRC: this can happen for recvonly clients
1939
                                                         * (see https://groups.google.com/forum/#!topic/discuss-webrtc/5yuZjV7lkNc)
1940
                                                         * Check the local SSRC, compare it to what we have */
1941
                                                        guint32 rtcp_ssrc = janus_rtcp_get_receiver_ssrc(buf, len);
1942
                                                        if(rtcp_ssrc == stream->audio_ssrc) {
1943
                                                                video = 0;
1944
                                                        } else if(rtcp_ssrc == stream->video_ssrc) {
1945
                                                                video = 1;
1946
                                                        } else {
1947
                                                                /* Mh, no SR or RR? Try checking if there's any FIR, PLI or REMB */
1948
                                                                if(janus_rtcp_has_fir(buf, len) || janus_rtcp_has_pli(buf, len) || janus_rtcp_get_remb(buf, len)) {
1949
                                                                        video = 1;
1950
                                                                }
1951
                                                        }
1952
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (local SSRC: video=%"SCNu32", audio=%"SCNu32", got %"SCNu32")\n",
1953
                                                                handle->handle_id, video ? "video" : "audio", stream->video_ssrc, stream->audio_ssrc, rtcp_ssrc);
1954
                                                } else {
1955
                                                        /* Check the remote SSRC, compare it to what we have */
1956
                                                        guint32 rtcp_ssrc = janus_rtcp_get_sender_ssrc(buf, len);
1957
                                                        video = (stream->video_ssrc_peer == rtcp_ssrc ? 1 : 0);
1958
                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (remote SSRC: video=%"SCNu32", audio=%"SCNu32", got %"SCNu32")\n",
1959
                                                                handle->handle_id, video ? "video" : "audio", stream->video_ssrc_peer, stream->audio_ssrc_peer, rtcp_ssrc);
1960
                                                }
1961
                                        }
1962
                                }
1963
                                /* Let's process this RTCP (compound?) packet, and update the RTCP context for this stream in case */
1964
                                rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx : stream->audio_rtcp_ctx;
1965
                                if(rtcp_ctx == NULL) {
1966
                                        /* We still need an RTCP context here, create it now */
1967
                                        rtcp_ctx = g_malloc0(sizeof(rtcp_context));
1968
                                        if(video) {
1969
                                                rtcp_ctx->tb = 90000;        /* FIXME */
1970
                                                stream->video_rtcp_ctx = rtcp_ctx;
1971
                                        } else {
1972
                                                rtcp_ctx->tb = 48000;        /* FIXME */
1973
                                                stream->audio_rtcp_ctx = rtcp_ctx;
1974
                                        }
1975
                                }
1976
                                janus_rtcp_parse(rtcp_ctx, buf, buflen);
1977

    
1978
                                /* Now let's see if there are any NACKs to handle */
1979
                                gint64 now = janus_get_monotonic_time();
1980
                                GSList *nacks = janus_rtcp_get_nacks(buf, buflen);
1981
                                guint nacks_count = g_slist_length(nacks);
1982
                                if(nacks_count) {
1983
                                        /* Handle NACK */
1984
                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"]     Just got some NACKS (%d) we should handle...\n", handle->handle_id, nacks_count);
1985
                                        GSList *list = nacks;
1986
                                        int retransmits_cnt = 0;
1987
                                        janus_mutex_lock(&component->mutex);
1988
                                        while(list) {
1989
                                                unsigned int seqnr = GPOINTER_TO_UINT(list->data);
1990
                                                JANUS_LOG(LOG_DBG, "[%"SCNu64"]   >> %u\n", handle->handle_id, seqnr);
1991
                                                GList *rp = component->retransmit_buffer;
1992
                                                while(rp) {
1993
                                                        janus_rtp_packet *p = (janus_rtp_packet *)rp->data;
1994
                                                        if(p) {
1995
                                                                rtp_header *rh = (rtp_header *)p->data;
1996
                                                                if(ntohs(rh->seq_number) == seqnr) {
1997
                                                                        /* Should we retransmit this packet? */
1998
                                                                        if((p->last_retransmit > 0) && (now-p->last_retransmit < MAX_NACK_IGNORE)) {
1999
                                                                                JANUS_LOG(LOG_HUGE, "[%"SCNu64"]   >> >> Packet %u was retransmitted just %"SCNi64"ms ago, skipping\n", handle->handle_id, seqnr, now-p->last_retransmit);
2000
                                                                                break;
2001
                                                                        }
2002
                                                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"]   >> >> Scheduling %u for retransmission due to NACK\n", handle->handle_id, seqnr);
2003
                                                                        p->last_retransmit = now;
2004
                                                                        retransmits_cnt++;
2005
                                                                        /* Enqueue it */
2006
                                                                        janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
2007
                                                                        pkt->data = g_malloc0(p->length);
2008
                                                                        memcpy(pkt->data, p->data, p->length);
2009
                                                                        pkt->length = p->length;
2010
                                                                        pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
2011
                                                                        pkt->control = FALSE;
2012
                                                                        pkt->encrypted = TRUE;        /* This was already encrypted before */
2013
                                                                        if(handle->queued_packets != NULL)
2014
                                                                                g_async_queue_push(handle->queued_packets, pkt);
2015
                                                                        break;
2016
                                                                }
2017
                                                        }
2018
                                                        rp = rp->next;
2019
                                                }
2020
                                                list = list->next;
2021
                                        }
2022
                                        component->retransmit_recent_cnt += retransmits_cnt;
2023
                                        /* FIXME Remove the NACK compound packet, we've handled it */
2024
                                        buflen = janus_rtcp_remove_nacks(buf, buflen);
2025
                                        /* Update stats */
2026
                                        if(video) {
2027
                                                component->in_stats.video_nacks += nacks_count;
2028
                                        } else {
2029
                                                component->in_stats.audio_nacks += nacks_count;
2030
                                        }
2031
                                        /* Inform the plugin about the slow uplink in case it's needed */
2032
                                        janus_slow_link_update(component, handle, retransmits_cnt, video, 1, now);
2033
                                        janus_mutex_unlock(&component->mutex);
2034
                                        g_slist_free(nacks);
2035
                                        nacks = NULL;
2036
                                }
2037
                                if (component->retransmit_recent_cnt &&
2038
                                    now - component->retransmit_log_ts > 5 * G_USEC_PER_SEC) {
2039
                                        JANUS_LOG(LOG_VERB, "[%10"SCNu64"]  retransmitted %u packets due to NACK\n",
2040
                                                              handle->handle_id,    component->retransmit_recent_cnt);
2041
                                        component->retransmit_recent_cnt = 0;
2042
                                        component->retransmit_log_ts = now;
2043
                                }
2044

    
2045
                                janus_plugin *plugin = (janus_plugin *)handle->app;
2046
                                if(plugin && plugin->incoming_rtcp)
2047
                                        plugin->incoming_rtcp(handle->app_handle, video, buf, buflen);
2048
                        }
2049
                }
2050
                return;
2051
        }
2052
        if(component_id == 3 || (janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)
2053
                        && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS))) {
2054
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Not RTP and not RTCP... may these be data channels?\n", handle->handle_id);
2055
                janus_dtls_srtp_incoming_msg(component->dtls, buf, len);
2056
                /* Update stats (TODO Do the same for the last second window as well) */
2057
                if(len > 0) {
2058
                        component->in_stats.data_packets++;
2059
                        component->in_stats.data_bytes += len;
2060
                }
2061
                return;
2062
        }
2063
}
2064

    
2065
void janus_ice_incoming_data(janus_ice_handle *handle, char *buffer, int length) {
2066
        if(handle == NULL || buffer == NULL || length <= 0)
2067
                return;
2068
        janus_plugin *plugin = (janus_plugin *)handle->app;
2069
        if(plugin && plugin->incoming_data)
2070
                plugin->incoming_data(handle->app_handle, buffer, length);
2071
}
2072

    
2073

    
2074
/* Thread to create agent */
2075
void *janus_ice_thread(void *data) {
2076
        janus_ice_handle *handle = data;
2077
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE thread started\n", handle->handle_id);
2078
        GMainLoop *loop = handle->iceloop;
2079
        if(loop == NULL) {
2080
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Invalid loop...\n", handle->handle_id);
2081
                g_thread_unref(g_thread_self());
2082
                return NULL;
2083
        }
2084
        g_usleep (100000);
2085
        JANUS_LOG(LOG_DBG, "[%"SCNu64"] Looping (ICE)...\n", handle->handle_id);
2086
        g_main_loop_run (loop);
2087
        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
2088
        if(handle->cdone == 0)
2089
                handle->cdone = -1;
2090
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE thread ended!\n", handle->handle_id);
2091
        /* This handle has been destroyed, wait a bit and then free all the resources */
2092
        g_usleep (1*G_USEC_PER_SEC);
2093
        if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP)) {
2094
                //~ janus_ice_free(handle);
2095
        } else {
2096
                janus_ice_webrtc_free(handle);
2097
        }
2098
        g_thread_unref(g_thread_self());
2099
        return NULL;
2100
}
2101

    
2102
/* Helper: candidates */
2103
void janus_ice_candidates_to_sdp(janus_ice_handle *handle, char *sdp, guint stream_id, guint component_id)
2104
{
2105
        if(!handle || !handle->agent || !sdp)
2106
                return;
2107
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
2108
        if(!stream) {
2109
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No stream %d??\n", handle->handle_id, stream_id);
2110
                return;
2111
        }
2112
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
2113
        if(!component) {
2114
                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
2115
                return;
2116
        }
2117
        NiceAgent* agent = handle->agent;
2118
        /* adding a stream should cause host candidates to be generated */
2119
        char *host_ip = NULL;
2120
        if(nat_1_1_enabled) {
2121
                /* A 1:1 NAT mapping was specified, overwrite all the host addresses with the public IP */
2122
                host_ip = janus_get_public_ip();
2123
                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);
2124
        }
2125
        GSList *candidates, *i;
2126
        candidates = nice_agent_get_local_candidates (agent, stream_id, component_id);
2127
        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);
2128
        gboolean log_candidates = (component->local_candidates == NULL);
2129
        for (i = candidates; i; i = i->next) {
2130
                NiceCandidate *c = (NiceCandidate *) i->data;
2131
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream #%d, Component #%d\n", handle->handle_id, c->stream_id, c->component_id);
2132
                gchar address[NICE_ADDRESS_STRING_LEN], base_address[NICE_ADDRESS_STRING_LEN];
2133
                gint port = 0, base_port = 0;
2134
                nice_address_to_string(&(c->addr), (gchar *)&address);
2135
                port = nice_address_get_port(&(c->addr));
2136
                nice_address_to_string(&(c->base_addr), (gchar *)&base_address);
2137
                base_port = nice_address_get_port(&(c->base_addr));
2138
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Address:    %s:%d\n", handle->handle_id, address, port);
2139
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Priority:   %d\n", handle->handle_id, c->priority);
2140
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Foundation: %s\n", handle->handle_id, c->foundation);
2141
                /* SDP time */
2142
                gchar buffer[100];
2143
                if(c->type == NICE_CANDIDATE_TYPE_HOST) {
2144
                        /* 'host' candidate */
2145
                        if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
2146
                                g_snprintf(buffer, 100,
2147
                                        "a=candidate:%s %d %s %d %s %d typ host\r\n", 
2148
                                                c->foundation,
2149
                                                c->component_id,
2150
                                                "udp",
2151
                                                c->priority,
2152
                                                host_ip ? host_ip : address,
2153
                                                port);
2154
                        } else {
2155
                                if(!janus_ice_tcp_enabled) {
2156
                                        /* ICE-TCP support disabled */
2157
                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping host TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
2158
                                        nice_candidate_free(c);
2159
                                        continue;
2160
                                }
2161
#ifndef HAVE_LIBNICE_TCP
2162
                                /* TCP candidates are only supported since libnice 0.1.8 */
2163
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping host TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
2164
                                nice_candidate_free(c);
2165
                                continue;
2166
#else
2167
                                const char *type = NULL;
2168
                                switch(c->transport) {
2169
                                        case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2170
                                                type = "active";
2171
                                                break;
2172
                                        case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2173
                                                type = "passive";
2174
                                                break;
2175
                                        case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2176
                                                type = "so";
2177
                                                break;
2178
                                        default:
2179
                                                break;
2180
                                }
2181
                                if(type == NULL) {
2182
                                        /* FIXME Unsupported transport */
2183
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP host candidate...\n", handle->handle_id);
2184
                                        nice_candidate_free(c);
2185
                                        continue;
2186
                                } else {
2187
                                        g_snprintf(buffer, 100,
2188
                                                "a=candidate:%s %d %s %d %s %d typ host tcptype %s\r\n", 
2189
                                                        c->foundation,
2190
                                                        c->component_id,
2191
                                                        "tcp",
2192
                                                        c->priority,
2193
                                                        host_ip ? host_ip : address,
2194
                                                        port,
2195
                                                        type);
2196
                                }
2197
#endif
2198
                        }
2199
                } else if(c->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) {
2200
                        /* 'srflx' candidate */
2201
                        if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
2202
                                nice_address_to_string(&(c->base_addr), (gchar *)&base_address);
2203
                                gint base_port = nice_address_get_port(&(c->base_addr));
2204
                                g_snprintf(buffer, 100,
2205
                                        "a=candidate:%s %d %s %d %s %d typ srflx raddr %s rport %d\r\n", 
2206
                                                c->foundation,
2207
                                                c->component_id,
2208
                                                "udp",
2209
                                                c->priority,
2210
                                                address,
2211
                                                port,
2212
                                                base_address,
2213
                                                base_port);
2214
                        } else {
2215
                                if(!janus_ice_tcp_enabled) {
2216
                                        /* ICE-TCP support disabled */
2217
                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping srflx TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
2218
                                        nice_candidate_free(c);
2219
                                        continue;
2220
                                }
2221
#ifndef HAVE_LIBNICE_TCP
2222
                                /* TCP candidates are only supported since libnice 0.1.8 */
2223
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping srflx TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
2224
                                nice_candidate_free(c);
2225
                                continue;
2226
#else
2227
                                const char *type = NULL;
2228
                                switch(c->transport) {
2229
                                        case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2230
                                                type = "active";
2231
                                                break;
2232
                                        case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2233
                                                type = "passive";
2234
                                                break;
2235
                                        case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2236
                                                type = "so";
2237
                                                break;
2238
                                        default:
2239
                                                break;
2240
                                }
2241
                                if(type == NULL) {
2242
                                        /* FIXME Unsupported transport */
2243
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP srflx candidate...\n", handle->handle_id);
2244
                                        nice_candidate_free(c);
2245
                                        continue;
2246
                                } else {
2247
                                        g_snprintf(buffer, 100,
2248
                                                "a=candidate:%s %d %s %d %s %d typ srflx raddr %s rport %d tcptype %s\r\n", 
2249
                                                        c->foundation,
2250
                                                        c->component_id,
2251
                                                        "tcp",
2252
                                                        c->priority,
2253
                                                        address,
2254
                                                        port,
2255
                                                        base_address,
2256
                                                        base_port,
2257
                                                        type);
2258
                                }
2259
#endif
2260
                        }
2261
                } else if(c->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
2262
                        /* 'prflx' candidate: skip it, we don't add them to the SDP */
2263
                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping prflx candidate...\n", handle->handle_id);
2264
                        nice_candidate_free(c);
2265
                        continue;
2266
                } else if(c->type == NICE_CANDIDATE_TYPE_RELAYED) {
2267
                        /* 'relay' candidate */
2268
                        if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
2269
                                g_snprintf(buffer, 100,
2270
                                        "a=candidate:%s %d %s %d %s %d typ relay raddr %s rport %d\r\n", 
2271
                                                c->foundation,
2272
                                                c->component_id,
2273
                                                "udp",
2274
                                                c->priority,
2275
                                                address,
2276
                                                port,
2277
                                                base_address,
2278
                                                base_port);
2279
                        } else {
2280
                                if(!janus_ice_tcp_enabled) {
2281
                                        /* ICE-TCP support disabled */
2282
                                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping relay TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
2283
                                        nice_candidate_free(c);
2284
                                        continue;
2285
                                }
2286
#ifndef HAVE_LIBNICE_TCP
2287
                                /* TCP candidates are only supported since libnice 0.1.8 */
2288
                                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping relay TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
2289
                                nice_candidate_free(c);
2290
                                continue;
2291
#else
2292
                                const char *type = NULL;
2293
                                switch(c->transport) {
2294
                                        case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2295
                                                type = "active";
2296
                                                break;
2297
                                        case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2298
                                                type = "passive";
2299
                                                break;
2300
                                        case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2301
                                                type = "so";
2302
                                                break;
2303
                                        default:
2304
                                                break;
2305
                                }
2306
                                if(type == NULL) {
2307
                                        /* FIXME Unsupported transport */
2308
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP relay candidate...\n", handle->handle_id);
2309
                                        nice_candidate_free(c);
2310
                                        continue;
2311
                                } else {
2312
                                        g_snprintf(buffer, 100,
2313
                                                "a=candidate:%s %d %s %d %s %d typ relay raddr %s rport %d tcptype %s\r\n", 
2314
                                                        c->foundation,
2315
                                                        c->component_id,
2316
                                                        "tcp",
2317
                                                        c->priority,
2318
                                                        address,
2319
                                                        port,
2320
                                                        base_address,
2321
                                                        base_port,
2322
                                                        type);
2323
                                }
2324
#endif
2325
                        }
2326
                }
2327
                g_strlcat(sdp, buffer, JANUS_BUFSIZE);
2328
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]     %s", handle->handle_id, buffer); /* buffer already newline terminated */
2329
                if(log_candidates) {
2330
                        /* Save for the summary, in case we need it */
2331
                        component->local_candidates = g_slist_append(component->local_candidates, g_strdup(buffer+strlen("a=candidate:")));
2332
                }
2333
                nice_candidate_free(c);
2334
        }
2335
        g_slist_free(candidates);
2336
}
2337

    
2338
void janus_ice_setup_remote_candidates(janus_ice_handle *handle, guint stream_id, guint component_id) {
2339
        if(!handle || !handle->agent || !handle->streams)
2340
                return;
2341
        janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
2342
        if(!stream || !stream->components) {
2343
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] No such stream %d: cannot setup remote candidates for component %d\n", handle->handle_id, stream_id, component_id);
2344
                return;
2345
        }
2346
        if(stream->disabled) {
2347
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream %d is disabled, skipping remote candidates for component %d\n", handle->handle_id, stream_id, component_id);
2348
                return;
2349
        }
2350
        janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
2351
        if(!component) {
2352
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] No such component %d in stream %d: cannot setup remote candidates\n", handle->handle_id, component_id, stream_id);
2353
                return;
2354
        }
2355
        if(component->process_started) {
2356
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Component %d in stream %d has already been set up\n", handle->handle_id, component_id, stream_id);
2357
                return;
2358
        }
2359
        if(!component->candidates || !component->candidates->data) {
2360
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE)
2361
                                || janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES)) { 
2362
                        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);
2363
                }
2364
                return;
2365
        }
2366
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ## Setting remote candidates: stream %d, component %d (%u in the list)\n",
2367
                handle->handle_id, stream_id, component_id, g_slist_length(component->candidates));
2368
        /* Add all candidates */
2369
        NiceCandidate *c = NULL;
2370
        GSList *gsc = component->candidates;
2371
        gchar *rufrag = NULL, *rpwd = NULL;
2372
        while(gsc) {
2373
                c = (NiceCandidate *) gsc->data;
2374
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] >> Remote Stream #%d, Component #%d\n", handle->handle_id, c->stream_id, c->component_id);
2375
                if(c->username && !rufrag)
2376
                        rufrag = c->username;
2377
                if(c->password && !rpwd)
2378
                        rpwd = c->password;
2379
                gchar address[NICE_ADDRESS_STRING_LEN];
2380
                nice_address_to_string(&(c->addr), (gchar *)&address);
2381
                gint port = nice_address_get_port(&(c->addr));
2382
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Address:    %s:%d\n", handle->handle_id, address, port);
2383
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Priority:   %d\n", handle->handle_id, c->priority);
2384
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Foundation: %s\n", handle->handle_id, c->foundation);
2385
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Username:   %s\n", handle->handle_id, c->username);
2386
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]   Password:   %s\n", handle->handle_id, c->password);
2387
                gsc = gsc->next;
2388
        }
2389
        if(rufrag && rpwd) {
2390
                JANUS_LOG(LOG_VERB, "[%"SCNu64"]  Setting remote credentials...\n", handle->handle_id);
2391
                if(!nice_agent_set_remote_credentials(handle->agent, stream_id, rufrag, rpwd)) {
2392
                        JANUS_LOG(LOG_ERR, "[%"SCNu64"]  failed to set remote credentials!\n", handle->handle_id);
2393
                }
2394
        }
2395
        guint added = nice_agent_set_remote_candidates(handle->agent, stream_id, component_id, component->candidates);
2396
        if(added < g_slist_length(component->candidates)) {
2397
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Failed to set remote candidates :-( (added %u, expected %u)\n",
2398
                        handle->handle_id, added, g_slist_length(component->candidates));
2399
        } else {
2400
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Remote candidates set!\n", handle->handle_id);
2401
                component->process_started = TRUE;
2402
        }
2403
}
2404

    
2405
int janus_ice_setup_local(janus_ice_handle *handle, int offer, int audio, int video, int data, int bundle, int rtcpmux, int trickle) {
2406
        if(!handle)
2407
                return -1;
2408
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting ICE locally: got %s (%d audios, %d videos)\n", handle->handle_id, offer ? "OFFER" : "ANSWER", audio, video);
2409
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_START);
2410
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
2411
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
2412
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
2413
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
2414
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
2415
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
2416

    
2417
        /* Note: in case this is not an OFFER, we don't know whether any medium are supported on the other side or not yet */
2418
        if(audio) {
2419
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
2420
        } else {
2421
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
2422
        }
2423
        if(video) {
2424
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
2425
        } else {
2426
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
2427
        }
2428
        if(data) {
2429
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS);
2430
        } else {
2431
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS);
2432
        }
2433
        /* Note: in case this is not an OFFER, we don't know whether BUNDLE is supported on the other side or not yet,
2434
         * unless Janus was configured to force BUNDLE in which case we enable it on our side anyway */
2435
        if((offer && bundle) || janus_force_bundle) {
2436
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE);
2437
        } else {
2438
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE);
2439
        }
2440
        /* Note: in case this is not an OFFER, we don't know whether rtcp-mux is supported on the other side or not yet,
2441
         * unless Janus was configured to force rtcp-mux in which case we enable it on our side anyway */
2442
        if((offer && rtcpmux) || janus_force_rtcpmux) {
2443
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX);
2444
        } else {
2445
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX);
2446
        }
2447
        /* Note: in case this is not an OFFER, we don't know whether ICE trickling is supported on the other side or not yet */
2448
        if(offer && trickle) {
2449
                janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE);
2450
        } else {
2451
                janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE);
2452
        }
2453
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES);
2454
        janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE_SYNCED);
2455

    
2456
        handle->icectx = g_main_context_new();
2457
        handle->iceloop = g_main_loop_new(handle->icectx, FALSE);
2458
        GError *error = NULL;
2459
        handle->icethread = g_thread_try_new("ice thread", &janus_ice_thread, handle, &error);
2460
        if(error != NULL) {
2461
                /* FIXME We should clear some resources... */
2462
                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 : "??");
2463
                return -1;
2464
         }
2465
        handle->queued_packets = g_async_queue_new();
2466
        /* We wait for ICE to succeed before creating the related thread */
2467
        handle->send_thread = NULL;
2468
        /* Note: NICE_COMPATIBILITY_RFC5245 is only available in more recent versions of libnice */
2469
        handle->controlling = janus_ice_lite_enabled ? FALSE : !offer;
2470
        JANUS_LOG(LOG_INFO, "[%"SCNu64"] Creating ICE agent (ICE %s mode, %s)\n", handle->handle_id,
2471
                janus_ice_lite_enabled ? "Lite" : "Full", handle->controlling ? "controlling" : "controlled");
2472
        g_atomic_int_set(&handle->send_thread_created, 0);
2473
        handle->agent = g_object_new(NICE_TYPE_AGENT,
2474
                "compatibility", NICE_COMPATIBILITY_DRAFT19,
2475
                "main-context", handle->icectx,
2476
                "reliable", FALSE,
2477
                "full-mode", janus_ice_lite_enabled ? FALSE : TRUE,
2478
#ifdef HAVE_LIBNICE_TCP
2479
                "ice-udp", TRUE,
2480
                "ice-tcp", janus_ice_tcp_enabled ? TRUE : FALSE,
2481
#endif
2482
                NULL);
2483
        handle->agent_created = janus_get_monotonic_time();
2484
        /* Any STUN server to use? */
2485
        if(janus_stun_server != NULL && janus_stun_port > 0) {
2486
                g_object_set(G_OBJECT(handle->agent),
2487
                        "stun-server", janus_stun_server,
2488
                        "stun-server-port", janus_stun_port,
2489
                        NULL);
2490
        }
2491
        /* Any dynamic TURN credentials to retrieve via REST API? */
2492
        gboolean have_turnrest_credentials = FALSE;
2493
#ifdef HAVE_LIBCURL
2494
        janus_turnrest_response *turnrest_credentials = janus_turnrest_request();
2495
        if(turnrest_credentials != NULL) {
2496
                have_turnrest_credentials = TRUE;
2497
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got credentials from the TURN REST API backend!\n", handle->handle_id);
2498
                JANUS_LOG(LOG_HUGE, "  -- Username: %s\n", turnrest_credentials->username);
2499
                JANUS_LOG(LOG_HUGE, "  -- Password: %s\n", turnrest_credentials->password);
2500
                JANUS_LOG(LOG_HUGE, "  -- TTL:      %"SCNu32"\n", turnrest_credentials->ttl);
2501
                JANUS_LOG(LOG_HUGE, "  -- Servers:  %d\n", g_list_length(turnrest_credentials->servers));
2502
                GList *server = turnrest_credentials->servers;
2503
                while(server != NULL) {
2504
                        janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2505
                        JANUS_LOG(LOG_HUGE, "  -- -- URI: %s:%"SCNu16" (%d)\n", instance->server, instance->port, instance->transport);
2506
                        server = server->next;
2507
                }
2508
        }
2509
#endif
2510
        g_object_set(G_OBJECT(handle->agent), "upnp", FALSE, NULL);
2511
        g_object_set(G_OBJECT(handle->agent), "controlling-mode", handle->controlling, NULL);
2512
        g_signal_connect (G_OBJECT (handle->agent), "candidate-gathering-done",
2513
                G_CALLBACK (janus_ice_cb_candidate_gathering_done), handle);
2514
        g_signal_connect (G_OBJECT (handle->agent), "component-state-changed",
2515
                G_CALLBACK (janus_ice_cb_component_state_changed), handle);
2516
#ifndef HAVE_LIBNICE_TCP
2517
        g_signal_connect (G_OBJECT (handle->agent), "new-selected-pair",
2518
#else
2519
        g_signal_connect (G_OBJECT (handle->agent), "new-selected-pair-full",
2520
#endif
2521
                G_CALLBACK (janus_ice_cb_new_selected_pair), handle);
2522
#ifndef HAVE_LIBNICE_TCP
2523
        g_signal_connect (G_OBJECT (handle->agent), "new-remote-candidate",
2524
#else
2525
        g_signal_connect (G_OBJECT (handle->agent), "new-remote-candidate-full",
2526
#endif
2527
                G_CALLBACK (janus_ice_cb_new_remote_candidate), handle);
2528

    
2529
        /* Add all local addresses, except those in the ignore list */
2530
        struct ifaddrs *ifaddr, *ifa;
2531
        int family, s, n;
2532
        char host[NI_MAXHOST];
2533
        if(getifaddrs(&ifaddr) == -1) {
2534
                JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error getting list of interfaces...", handle->handle_id);
2535
        } else {
2536
                for(ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
2537
                        if(ifa->ifa_addr == NULL)
2538
                                continue;
2539
                        /* Skip interfaces which are not up and running */
2540
                        if (!((ifa->ifa_flags & IFF_UP) && (ifa->ifa_flags & IFF_RUNNING)))
2541
                                continue;
2542
                        /* Skip loopback interfaces */
2543
                        if (ifa->ifa_flags & IFF_LOOPBACK)
2544
                                continue;
2545
                        family = ifa->ifa_addr->sa_family;
2546
                        if(family != AF_INET && family != AF_INET6)
2547
                                continue;
2548
                        /* We only add IPv6 addresses if support for them has been explicitly enabled (still WIP, mostly) */
2549
                        if(family == AF_INET6 && !janus_ipv6_enabled)
2550
                                continue;
2551
                        /* Check the interface name first, we can ignore that as well: enforce list would be checked later */
2552
                        if(janus_ice_enforce_list == NULL && ifa->ifa_name != NULL && janus_ice_is_ignored(ifa->ifa_name))
2553
                                continue;
2554
                        s = getnameinfo(ifa->ifa_addr,
2555
                                        (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
2556
                                        host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
2557
                        if(s != 0) {
2558
                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] getnameinfo() failed: %s\n", handle->handle_id, gai_strerror(s));
2559
                                continue;
2560
                        }
2561
                        /* Skip 0.0.0.0, :: and local scoped addresses  */
2562
                        if(!strcmp(host, "0.0.0.0") || !strcmp(host, "::") || !strncmp(host, "fe80:", 5))
2563
                                continue;
2564
                        /* Check if this IP address is in the ignore/enforce list, now: the enforce list has the precedence */
2565
                        if(janus_ice_enforce_list != NULL) {
2566
                                if(ifa->ifa_name != NULL && !janus_ice_is_enforced(ifa->ifa_name) && !janus_ice_is_enforced(host))
2567
                                        continue;
2568
                        } else {
2569
                                if(janus_ice_is_ignored(host))
2570
                                        continue;
2571
                        }
2572
                        /* Ok, add interface to the ICE agent */
2573
                        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Adding %s to the addresses to gather candidates for\n", handle->handle_id, host);
2574
                        NiceAddress addr_local;
2575
                        nice_address_init (&addr_local);
2576
                        if(!nice_address_set_from_string (&addr_local, host)) {
2577
                                JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping invalid address %s\n", handle->handle_id, host);
2578
                                continue;
2579
                        }
2580
                        nice_agent_add_local_address (handle->agent, &addr_local);
2581
                }
2582
                freeifaddrs(ifaddr);
2583
        }
2584

    
2585
        handle->cdone = 0;
2586
        handle->streams_num = 0;
2587
        handle->streams = g_hash_table_new(NULL, NULL);
2588
        if(audio) {
2589
                /* Add an audio stream */
2590
                handle->streams_num++;
2591
                handle->audio_id = nice_agent_add_stream (handle->agent, janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) ? 1 : 2);
2592
                janus_ice_stream *audio_stream = (janus_ice_stream *)g_malloc0(sizeof(janus_ice_stream));
2593
                if(audio_stream == NULL) {
2594
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2595
                        return -1;
2596
                }
2597
                handle->audio_mid = NULL;
2598
                audio_stream->stream_id = handle->audio_id;
2599
                audio_stream->handle = handle;
2600
                audio_stream->cdone = 0;
2601
                audio_stream->payload_type = -1;
2602
                audio_stream->disabled = FALSE;
2603
                /* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
2604
                audio_stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
2605
                audio_stream->audio_ssrc = g_random_int();        /* FIXME Should we look for conflicts? */
2606
                audio_stream->audio_ssrc_peer = 0;        /* FIXME Right now we don't know what this will be */
2607
                audio_stream->video_ssrc = 0;
2608
                if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
2609
                        /* If we're bundling, this stream is going to be used for video as well */
2610
                        audio_stream->video_ssrc = g_random_int();        /* FIXME Should we look for conflicts? */
2611
                }
2612
                audio_stream->video_ssrc_peer = 0;        /* FIXME Right now we don't know what this will be */
2613
                audio_stream->video_ssrc_peer_rtx = 0;        /* FIXME Right now we don't know what this will be */
2614
                janus_mutex_init(&audio_stream->mutex);
2615
                audio_stream->components = g_hash_table_new(NULL, NULL);
2616
                g_hash_table_insert(handle->streams, GUINT_TO_POINTER(handle->audio_id), audio_stream);
2617
                if(!have_turnrest_credentials) {
2618
                        /* No TURN REST API server and credentials, any static ones? */
2619
                        if(janus_turn_server != NULL) {
2620
                                /* We need relay candidates as well */
2621
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 1,
2622
                                        janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
2623
                                if(!ok) {
2624
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2625
                                                janus_turn_server, janus_turn_port);
2626
                                }
2627
                        }
2628
#ifdef HAVE_LIBCURL
2629
                } else {
2630
                        /* We need relay candidates as well: add all those we got */
2631
                        GList *server = turnrest_credentials->servers;
2632
                        while(server != NULL) {
2633
                                janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2634
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 1,
2635
                                        instance->server, instance->port,
2636
                                        turnrest_credentials->username, turnrest_credentials->password,
2637
                                        instance->transport);
2638
                                if(!ok) {
2639
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2640
                                                instance->server, instance->port);
2641
                                }
2642
                                server = server->next;
2643
                        }
2644
#endif
2645
                }
2646
                handle->audio_stream = audio_stream;
2647
                janus_ice_component *audio_rtp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
2648
                if(audio_rtp == NULL) {
2649
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2650
                        return -1;
2651
                }
2652
                audio_rtp->stream = audio_stream;
2653
                audio_rtp->stream_id = audio_stream->stream_id;
2654
                audio_rtp->component_id = 1;
2655
                audio_rtp->candidates = NULL;
2656
                audio_rtp->local_candidates = NULL;
2657
                audio_rtp->remote_candidates = NULL;
2658
                audio_rtp->selected_pair = NULL;
2659
                audio_rtp->process_started = FALSE;
2660
                audio_rtp->source = NULL;
2661
                audio_rtp->dtls = NULL;
2662
                audio_rtp->retransmit_buffer = NULL;
2663
                audio_rtp->retransmit_log_ts = 0;
2664
                audio_rtp->retransmit_recent_cnt = 0;
2665
                audio_rtp->nack_sent_log_ts = 0;
2666
                audio_rtp->nack_sent_recent_cnt = 0;
2667
                audio_rtp->last_seqs_audio = NULL;
2668
                audio_rtp->last_seqs_video = NULL;
2669
                audio_rtp->last_slowlink_time = 0;
2670
                audio_rtp->sl_nack_period_ts = 0;
2671
                audio_rtp->sl_nack_recent_cnt = 0;
2672
                janus_ice_stats_reset(&audio_rtp->in_stats);
2673
                janus_ice_stats_reset(&audio_rtp->out_stats);
2674
                janus_mutex_init(&audio_rtp->mutex);
2675
                g_hash_table_insert(audio_stream->components, GUINT_TO_POINTER(1), audio_rtp);
2676
                audio_stream->rtp_component = audio_rtp;
2677
#ifdef HAVE_PORTRANGE
2678
                /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
2679
                nice_agent_set_port_range(handle->agent, handle->audio_id, 1, rtp_range_min, rtp_range_max);
2680
#endif
2681
                janus_ice_component *audio_rtcp = NULL;
2682
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
2683
                        audio_rtcp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
2684
                        if(audio_rtcp == NULL) {
2685
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
2686
                                return -1;
2687
                        }
2688
                        if(!have_turnrest_credentials) {
2689
                                /* No TURN REST API server and credentials, any static ones? */
2690
                                if(janus_turn_server != NULL) {
2691
                                        /* We need relay candidates as well */
2692
                                        gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 2,
2693
                                                janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
2694
                                        if(!ok) {
2695
                                                JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2696
                                                        janus_turn_server, janus_turn_port);
2697
                                        }
2698
                                }
2699
#ifdef HAVE_LIBCURL
2700
                        } else {
2701
                                /* We need relay candidates as well: add all those we got */
2702
                                GList *server = turnrest_credentials->servers;
2703
                                while(server != NULL) {
2704
                                        janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2705
                                        gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 2,
2706
                                                instance->server, instance->port,
2707
                                                turnrest_credentials->username, turnrest_credentials->password,
2708
                                                instance->transport);
2709
                                        if(!ok) {
2710
                                                JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2711
                                                        instance->server, instance->port);
2712
                                        }
2713
                                        server = server->next;
2714
                                }
2715
#endif
2716
                        }
2717
                        audio_rtcp->stream = audio_stream;
2718
                        audio_rtcp->stream_id = audio_stream->stream_id;
2719
                        audio_rtcp->component_id = 2;
2720
                        audio_rtcp->candidates = NULL;
2721
                        audio_rtcp->local_candidates = NULL;
2722
                        audio_rtcp->remote_candidates = NULL;
2723
                        audio_rtcp->selected_pair = NULL;
2724
                        audio_rtcp->process_started = FALSE;
2725
                        audio_rtcp->source = NULL;
2726
                        audio_rtcp->dtls = NULL;
2727
                        audio_rtcp->retransmit_buffer = NULL;
2728
                        audio_rtcp->retransmit_log_ts = 0;
2729
                        audio_rtcp->retransmit_recent_cnt = 0;
2730
                        audio_rtcp->last_slowlink_time = 0;
2731
                        audio_rtcp->sl_nack_period_ts = 0;
2732
                        audio_rtcp->sl_nack_recent_cnt = 0;
2733
                        janus_ice_stats_reset(&audio_rtcp->in_stats);
2734
                        janus_ice_stats_reset(&audio_rtcp->out_stats);
2735
                        janus_mutex_init(&audio_rtcp->mutex);
2736
                        g_hash_table_insert(audio_stream->components, GUINT_TO_POINTER(2), audio_rtcp);
2737
                        audio_stream->rtcp_component = audio_rtcp;
2738
#ifdef HAVE_PORTRANGE
2739
                /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
2740
                        nice_agent_set_port_range(handle->agent, handle->audio_id, 2, rtp_range_min, rtp_range_max);
2741
#endif
2742
                }
2743
                nice_agent_gather_candidates(handle->agent, handle->audio_id);
2744
                nice_agent_attach_recv(handle->agent, handle->audio_id, 1, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, audio_rtp);
2745
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) && audio_rtcp != NULL)
2746
                        nice_agent_attach_recv(handle->agent, handle->audio_id, 2, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, audio_rtcp);
2747
        }
2748
        if(video && (!audio || !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE))) {
2749
                /* Add a video stream */
2750
                handle->streams_num++;
2751
                handle->video_id = nice_agent_add_stream (handle->agent, janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) ? 1 : 2);
2752
                janus_ice_stream *video_stream = (janus_ice_stream *)g_malloc0(sizeof(janus_ice_stream));
2753
                if(video_stream == NULL) {
2754
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2755
                        return -1;
2756
                }
2757
                handle->video_mid = NULL;
2758
                video_stream->handle = handle;
2759
                video_stream->stream_id = handle->video_id;
2760
                video_stream->cdone = 0;
2761
                video_stream->payload_type = -1;
2762
                video_stream->disabled = FALSE;
2763
                /* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
2764
                video_stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
2765
                video_stream->video_ssrc = g_random_int();        /* FIXME Should we look for conflicts? */
2766
                video_stream->video_ssrc_peer = 0;        /* FIXME Right now we don't know what this will be */
2767
                video_stream->video_ssrc_peer_rtx = 0;        /* FIXME Right now we don't know what this will be */
2768
                video_stream->audio_ssrc = 0;
2769
                video_stream->audio_ssrc_peer = 0;
2770
                video_stream->components = g_hash_table_new(NULL, NULL);
2771
                janus_mutex_init(&video_stream->mutex);
2772
                g_hash_table_insert(handle->streams, GUINT_TO_POINTER(handle->video_id), video_stream);
2773
                if(!have_turnrest_credentials) {
2774
                        /* No TURN REST API server and credentials, any static ones? */
2775
                        if(janus_turn_server != NULL) {
2776
                                /* We need relay candidates as well */
2777
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 1,
2778
                                        janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
2779
                                if(!ok) {
2780
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2781
                                                janus_turn_server, janus_turn_port);
2782
                                }
2783
                        }
2784
#ifdef HAVE_LIBCURL
2785
                } else {
2786
                        /* We need relay candidates as well: add all those we got */
2787
                        GList *server = turnrest_credentials->servers;
2788
                        while(server != NULL) {
2789
                                janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2790
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 1,
2791
                                        instance->server, instance->port,
2792
                                        turnrest_credentials->username, turnrest_credentials->password,
2793
                                        instance->transport);
2794
                                if(!ok) {
2795
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2796
                                                instance->server, instance->port);
2797
                                }
2798
                                server = server->next;
2799
                        }
2800
#endif
2801
                }
2802
                handle->video_stream = video_stream;
2803
                janus_ice_component *video_rtp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
2804
                if(video_rtp == NULL) {
2805
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2806
                        return -1;
2807
                }
2808
                video_rtp->stream = video_stream;
2809
                video_rtp->stream_id = video_stream->stream_id;
2810
                video_rtp->component_id = 1;
2811
                video_rtp->candidates = NULL;
2812
                video_rtp->local_candidates = NULL;
2813
                video_rtp->remote_candidates = NULL;
2814
                video_rtp->selected_pair = NULL;
2815
                video_rtp->process_started = FALSE;
2816
                video_rtp->source = NULL;
2817
                video_rtp->dtls = NULL;
2818
                video_rtp->retransmit_buffer = NULL;
2819
                video_rtp->retransmit_log_ts = 0;
2820
                video_rtp->retransmit_recent_cnt = 0;
2821
                video_rtp->nack_sent_log_ts = 0;
2822
                video_rtp->nack_sent_recent_cnt = 0;
2823
                video_rtp->last_seqs_audio = NULL;
2824
                video_rtp->last_seqs_video = NULL;
2825
                video_rtp->last_slowlink_time = 0;
2826
                video_rtp->sl_nack_period_ts = 0;
2827
                video_rtp->sl_nack_recent_cnt = 0;
2828
                janus_ice_stats_reset(&video_rtp->in_stats);
2829
                janus_ice_stats_reset(&video_rtp->out_stats);
2830
                janus_mutex_init(&video_rtp->mutex);
2831
                g_hash_table_insert(video_stream->components, GUINT_TO_POINTER(1), video_rtp);
2832
                video_stream->rtp_component = video_rtp;
2833
#ifdef HAVE_PORTRANGE
2834
                /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
2835
                nice_agent_set_port_range(handle->agent, handle->video_id, 1, rtp_range_min, rtp_range_max);
2836
#endif
2837
                janus_ice_component *video_rtcp = NULL;
2838
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
2839
                        video_rtcp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
2840
                        if(video_rtcp == NULL) {
2841
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
2842
                                return -1;
2843
                        }
2844
                        if(!have_turnrest_credentials) {
2845
                                /* No TURN REST API server and credentials, any static ones? */
2846
                                if(janus_turn_server != NULL) {
2847
                                        /* We need relay candidates as well */
2848
                                        gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 2,
2849
                                                janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
2850
                                        if(!ok) {
2851
                                                JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2852
                                                        janus_turn_server, janus_turn_port);
2853
                                        }
2854
                                }
2855
#ifdef HAVE_LIBCURL
2856
                        } else {
2857
                                /* We need relay candidates as well: add all those we got */
2858
                                GList *server = turnrest_credentials->servers;
2859
                                while(server != NULL) {
2860
                                        janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2861
                                        gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 2,
2862
                                                instance->server, instance->port,
2863
                                                turnrest_credentials->username, turnrest_credentials->password,
2864
                                                instance->transport);
2865
                                        if(!ok) {
2866
                                                JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2867
                                                        instance->server, instance->port);
2868
                                        }
2869
                                        server = server->next;
2870
                                }
2871
#endif
2872
                        }
2873
                        video_rtcp->stream = video_stream;
2874
                        video_rtcp->stream_id = video_stream->stream_id;
2875
                        video_rtcp->component_id = 2;
2876
                        video_rtcp->candidates = NULL;
2877
                        video_rtcp->local_candidates = NULL;
2878
                        video_rtcp->remote_candidates = NULL;
2879
                        video_rtcp->selected_pair = NULL;
2880
                        video_rtcp->process_started = FALSE;
2881
                        video_rtcp->source = NULL;
2882
                        video_rtcp->dtls = NULL;
2883
                        video_rtcp->retransmit_buffer = NULL;
2884
                        video_rtcp->retransmit_log_ts = 0;
2885
                        video_rtcp->retransmit_recent_cnt = 0;
2886
                        video_rtcp->last_slowlink_time = 0;
2887
                        video_rtcp->sl_nack_period_ts = 0;
2888
                        video_rtcp->sl_nack_recent_cnt = 0;
2889
                        janus_ice_stats_reset(&video_rtcp->in_stats);
2890
                        janus_ice_stats_reset(&video_rtcp->out_stats);
2891
                        janus_mutex_init(&video_rtcp->mutex);
2892
                        g_hash_table_insert(video_stream->components, GUINT_TO_POINTER(2), video_rtcp);
2893
                        video_stream->rtcp_component = video_rtcp;
2894
#ifdef HAVE_PORTRANGE
2895
                        /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
2896
                        nice_agent_set_port_range(handle->agent, handle->video_id, 2, rtp_range_min, rtp_range_max);
2897
#endif
2898
                }
2899
                nice_agent_gather_candidates(handle->agent, handle->video_id);
2900
                nice_agent_attach_recv(handle->agent, handle->video_id, 1, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, video_rtp);
2901
                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) && video_rtcp != NULL)
2902
                        nice_agent_attach_recv(handle->agent, handle->video_id, 2, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, video_rtcp);
2903
        }
2904
#ifndef HAVE_SCTP
2905
        handle->data_id = 0;
2906
        handle->data_stream = NULL;
2907
#else
2908
        if(data && ((!audio && !video) || !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE))) {
2909
                /* Add a SCTP/DataChannel stream */
2910
                handle->streams_num++;
2911
                handle->data_id = nice_agent_add_stream (handle->agent, 1);
2912
                janus_ice_stream *data_stream = (janus_ice_stream *)g_malloc0(sizeof(janus_ice_stream));
2913
                if(data_stream == NULL) {
2914
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2915
                        return -1;
2916
                }
2917
                handle->data_mid = NULL;
2918
                if(!have_turnrest_credentials) {
2919
                        /* No TURN REST API server and credentials, any static ones? */
2920
                        if(janus_turn_server != NULL) {
2921
                                /* We need relay candidates as well */
2922
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->data_id, 1,
2923
                                        janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
2924
                                if(!ok) {
2925
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2926
                                                janus_turn_server, janus_turn_port);
2927
                                }
2928
                        }
2929
#ifdef HAVE_LIBCURL
2930
                } else {
2931
                        /* We need relay candidates as well: add all those we got */
2932
                        GList *server = turnrest_credentials->servers;
2933
                        while(server != NULL) {
2934
                                janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
2935
                                gboolean ok = nice_agent_set_relay_info(handle->agent, handle->data_id, 1,
2936
                                        instance->server, instance->port,
2937
                                        turnrest_credentials->username, turnrest_credentials->password,
2938
                                        instance->transport);
2939
                                if(!ok) {
2940
                                        JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
2941
                                                instance->server, instance->port);
2942
                                }
2943
                                server = server->next;
2944
                        }
2945
#endif
2946
                }
2947
                data_stream->handle = handle;
2948
                data_stream->stream_id = handle->data_id;
2949
                data_stream->cdone = 0;
2950
                data_stream->payload_type = -1;
2951
                data_stream->disabled = FALSE;
2952
                /* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
2953
                data_stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
2954
                data_stream->components = g_hash_table_new(NULL, NULL);
2955
                janus_mutex_init(&data_stream->mutex);
2956
                g_hash_table_insert(handle->streams, GUINT_TO_POINTER(handle->data_id), data_stream);
2957
                handle->data_stream = data_stream;
2958
                janus_ice_component *data_component = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
2959
                if(data_component == NULL) {
2960
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2961
                        return -1;
2962
                }
2963
                data_component->stream = data_stream;
2964
                data_component->stream_id = data_component->stream_id;
2965
                data_component->component_id = 1;
2966
                data_component->candidates = NULL;
2967
                data_component->local_candidates = NULL;
2968
                data_component->remote_candidates = NULL;
2969
                data_component->selected_pair = NULL;
2970
                data_component->process_started = FALSE;
2971
                data_component->source = NULL;
2972
                data_component->dtls = NULL;
2973
                data_component->retransmit_buffer = NULL;
2974
                data_component->retransmit_log_ts = 0;
2975
                data_component->retransmit_recent_cnt = 0;
2976
                data_component->last_slowlink_time = 0;
2977
                data_component->sl_nack_period_ts = 0;
2978
                data_component->sl_nack_recent_cnt = 0;
2979
                janus_ice_stats_reset(&data_component->in_stats);
2980
                janus_ice_stats_reset(&data_component->out_stats);
2981
                janus_mutex_init(&data_component->mutex);
2982
                g_hash_table_insert(data_stream->components, GUINT_TO_POINTER(1), data_component);
2983
                data_stream->rtp_component = data_component;        /* We use the component called 'RTP' for data */
2984
#ifdef HAVE_PORTRANGE
2985
                /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
2986
                nice_agent_set_port_range(handle->agent, handle->data_id, 1, rtp_range_min, rtp_range_max);
2987
#endif
2988
                nice_agent_gather_candidates(handle->agent, handle->data_id);
2989
                nice_agent_attach_recv(handle->agent, handle->data_id, 1, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, data_component);
2990
        }
2991
#endif
2992
#ifdef HAVE_LIBCURL
2993
        if(turnrest_credentials != NULL) {
2994
                janus_turnrest_response_destroy(turnrest_credentials);
2995
                turnrest_credentials = NULL;
2996
        }
2997
#endif
2998
        return 0;
2999
}
3000

    
3001
void *janus_ice_send_thread(void *data) {
3002
        janus_ice_handle *handle = (janus_ice_handle *)data;
3003
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE send thread started...\n", handle->handle_id);
3004
        janus_ice_queued_packet *pkt = NULL;
3005
        gint64 before = janus_get_monotonic_time(),
3006
                audio_rtcp_last_rr = before, audio_rtcp_last_sr = before,
3007
                video_rtcp_last_rr = before, video_rtcp_last_sr = before;
3008
        while(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) {
3009
                if(handle->queued_packets != NULL) {
3010
                        pkt = g_async_queue_timeout_pop(handle->queued_packets, 500000);
3011
                } else {
3012
                        g_usleep(100000);
3013
                }
3014
                /* First of all, let's see if everything's fine on the recv side */
3015
                gint64 now = janus_get_monotonic_time();
3016
                if(now-before >= G_USEC_PER_SEC) {
3017
                        if(handle->audio_stream && handle->audio_stream->rtp_component) {
3018
                                janus_ice_component *component = handle->audio_stream->rtp_component;
3019
                                GList *lastitem = g_list_last(component->in_stats.audio_bytes_lastsec);
3020
                                janus_ice_stats_item *last = lastitem ? ((janus_ice_stats_item *)lastitem->data) : NULL;
3021
                                if(!component->in_stats.audio_notified_lastsec && last && now-last->when >= G_USEC_PER_SEC) {
3022
                                        /* Notify that we missed more than a second of audio! */
3023
                                        component->in_stats.audio_notified_lastsec = TRUE;
3024
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive audio for more than a second...\n", handle->handle_id);
3025
                                        janus_ice_notify_media(handle, FALSE, FALSE);
3026
                                }
3027
                                if(!component->in_stats.video_notified_lastsec && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
3028
                                        lastitem = g_list_last(component->in_stats.video_bytes_lastsec);
3029
                                        last = lastitem ? ((janus_ice_stats_item *)lastitem->data) : NULL;
3030
                                        if(last && now-last->when >= G_USEC_PER_SEC) {
3031
                                                /* Notify that we missed more than a second of video! */
3032
                                                component->in_stats.video_notified_lastsec = TRUE;
3033
                                                JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive video for more than a second...\n", handle->handle_id);
3034
                                                janus_ice_notify_media(handle, TRUE, FALSE);
3035
                                        }
3036
                                }
3037
                        }
3038
                        if(handle->video_stream && handle->video_stream->rtp_component) {
3039
                                janus_ice_component *component = handle->video_stream->rtp_component;
3040
                                GList *lastitem = g_list_last(component->in_stats.video_bytes_lastsec);
3041
                                janus_ice_stats_item *last = lastitem ? ((janus_ice_stats_item *)lastitem->data) : NULL;
3042
                                if(!component->in_stats.video_notified_lastsec && last && now-last->when >= G_USEC_PER_SEC) {
3043
                                        /* Notify that we missed more than a second of video! */
3044
                                        component->in_stats.video_notified_lastsec = TRUE;
3045
                                        JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive video for more than a second...\n", handle->handle_id);
3046
                                        janus_ice_notify_media(handle, TRUE, FALSE);
3047
                                }
3048
                        }
3049
                        before = now;
3050
                }
3051
                /* Let's check if it's time to send a RTCP RR as well */
3052
                if(now-audio_rtcp_last_rr >= 5*G_USEC_PER_SEC) {
3053
                        janus_ice_stream *stream = handle->audio_stream;
3054
                        if(handle->audio_stream && stream->audio_rtcp_ctx && stream->audio_rtcp_ctx->enabled) {
3055
                                /* Create a RR */
3056
                                int rrlen = 32;
3057
                                char rtcpbuf[32];
3058
                                rtcp_rr *rr = (rtcp_rr *)&rtcpbuf;
3059
                                rr->header.version = 2;
3060
                                rr->header.type = RTCP_RR;
3061
                                rr->header.rc = 1;
3062
                                rr->header.length = htons((rrlen/4)-1);
3063
                                janus_rtcp_report_block(stream->audio_rtcp_ctx, &rr->rb[0]);
3064
                                /* Enqueue it, we'll send it later */
3065
                                janus_ice_relay_rtcp(handle, 0, rtcpbuf, 32);
3066
                        }
3067
                        audio_rtcp_last_rr = now;
3068
                }
3069
                if(now-video_rtcp_last_rr >= 5*G_USEC_PER_SEC) {
3070
                        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);
3071
                        if(stream) {
3072
                                if(stream->video_rtcp_ctx && stream->video_rtcp_ctx->enabled) {
3073
                                        /* Create a RR */
3074
                                        int rrlen = 32;
3075
                                        char rtcpbuf[32];
3076
                                        rtcp_rr *rr = (rtcp_rr *)&rtcpbuf;
3077
                                        rr->header.version = 2;
3078
                                        rr->header.type = RTCP_RR;
3079
                                        rr->header.rc = 1;
3080
                                        rr->header.length = htons((rrlen/4)-1);
3081
                                        janus_rtcp_report_block(stream->video_rtcp_ctx, &rr->rb[0]);
3082
                                        /* Enqueue it, we'll send it later */
3083
                                        janus_ice_relay_rtcp(handle, 1, rtcpbuf, 32);
3084
                                }
3085
                        }
3086
                        video_rtcp_last_rr = now;
3087
                }
3088
                /* Do the same with SR/SDES */
3089
                if(now-audio_rtcp_last_sr >= 500000) {
3090
                        janus_ice_stream *stream = handle->audio_stream;
3091
                        if(stream && stream->rtp_component && stream->rtp_component->out_stats.audio_packets > 0) {
3092
                                /* Create a SR/SDES compound */
3093
                                int srlen = 28;
3094
                                int sdeslen = 20;
3095
                                char rtcpbuf[srlen+sdeslen];
3096
                                rtcp_sr *sr = (rtcp_sr *)&rtcpbuf;
3097
                                sr->header.version = 2;
3098
                                sr->header.type = RTCP_SR;
3099
                                sr->header.rc = 0;
3100
                                sr->header.length = htons((srlen/4)-1);
3101
                                struct timeval tv;
3102
                                gettimeofday(&tv, NULL);
3103
                                uint32_t s = tv.tv_sec + 2208988800u;
3104
                                uint32_t u = tv.tv_usec;
3105
                                uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6);
3106
                                sr->si.ntp_ts_msw = htonl(s);
3107
                                sr->si.ntp_ts_lsw = htonl(f);
3108
                                sr->si.rtp_ts = htonl(stream->audio_last_ts);
3109
                                sr->si.s_packets = htonl(stream->rtp_component->out_stats.audio_packets);
3110
                                sr->si.s_octets = htonl(stream->rtp_component->out_stats.audio_bytes);
3111
                                rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[28];
3112
                                janus_rtcp_sdes((char *)sdes, sdeslen, "janusaudio", 10);
3113
                                /* Enqueue it, we'll send it later */
3114
                                janus_ice_relay_rtcp(handle, 0, rtcpbuf, srlen+sdeslen);
3115
                        }
3116
                        audio_rtcp_last_sr = now;
3117
                }
3118
                if(now-video_rtcp_last_sr >= 500000) {
3119
                        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);
3120
                        if(stream && stream->rtp_component && stream->rtp_component->out_stats.video_packets > 0) {
3121
                                /* Create a SR/SDES compound */
3122
                                int srlen = 28;
3123
                                int sdeslen = 20;
3124
                                char rtcpbuf[srlen+sdeslen];
3125
                                rtcp_sr *sr = (rtcp_sr *)&rtcpbuf;
3126
                                sr->header.version = 2;
3127
                                sr->header.type = RTCP_SR;
3128
                                sr->header.rc = 0;
3129
                                sr->header.length = htons((srlen/4)-1);
3130
                                struct timeval tv;
3131
                                gettimeofday(&tv, NULL);
3132
                                uint32_t s = tv.tv_sec + 2208988800u;
3133
                                uint32_t u = tv.tv_usec;
3134
                                uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6);
3135
                                sr->si.ntp_ts_msw = htonl(s);
3136
                                sr->si.ntp_ts_lsw = htonl(f);
3137
                                sr->si.rtp_ts = htonl(stream->video_last_ts);
3138
                                sr->si.s_packets = htonl(stream->rtp_component->out_stats.video_packets);
3139
                                sr->si.s_octets = htonl(stream->rtp_component->out_stats.video_bytes);
3140
                                rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[28];
3141
                                janus_rtcp_sdes((char *)sdes, sdeslen, "janusvideo", 10);
3142
                                /* Enqueue it, we'll send it later */
3143
                                janus_ice_relay_rtcp(handle, 1, rtcpbuf, srlen+sdeslen);
3144
                        }
3145
                        video_rtcp_last_sr = now;
3146
                }
3147

    
3148
                /* Now let's get on with the packets */
3149
                if(pkt == NULL) {
3150
                        continue;
3151
                }
3152
                if(pkt == &janus_ice_dtls_alert) {
3153
                        /* The session is over, send an alert on all streams and components */
3154
                        if(handle->streams != NULL) {
3155
                                if(handle->audio_stream) {
3156
                                        janus_ice_stream *stream = handle->audio_stream;
3157
                                        if(stream->rtp_component)
3158
                                                janus_dtls_srtp_send_alert(stream->rtp_component->dtls);
3159
                                        if(stream->rtcp_component)
3160
                                                janus_dtls_srtp_send_alert(stream->rtcp_component->dtls);
3161
                                }
3162
                                if(handle->video_stream) {
3163
                                        janus_ice_stream *stream = handle->video_stream;
3164
                                        if(stream->rtp_component)
3165
                                                janus_dtls_srtp_send_alert(stream->rtp_component->dtls);
3166
                                        if(stream->rtcp_component)
3167
                                                janus_dtls_srtp_send_alert(stream->rtcp_component->dtls);
3168
                                }
3169
                                if(handle->data_stream) {
3170
                                        janus_ice_stream *stream = handle->data_stream;
3171
                                        if(stream->rtp_component)
3172
                                                janus_dtls_srtp_send_alert(stream->rtp_component->dtls);
3173
                                        if(stream->rtcp_component)
3174
                                                janus_dtls_srtp_send_alert(stream->rtcp_component->dtls);
3175
                                }
3176
                        }
3177
                        continue;
3178
                }
3179
                if(pkt->data == NULL) {
3180
                        g_free(pkt);
3181
                        pkt = NULL;
3182
                        continue;
3183
                }
3184
                if(pkt->control) {
3185
                        /* RTCP */
3186
                        int video = (pkt->type == JANUS_ICE_PACKET_VIDEO);
3187
                        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);
3188
                        if(!stream) {
3189
                                g_free(pkt->data);
3190
                                pkt->data = NULL;
3191
                                g_free(pkt);
3192
                                pkt = NULL;
3193
                                continue;
3194
                        }
3195
                        janus_ice_component *component = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) ? stream->rtp_component : stream->rtcp_component;
3196
                        if(!component) {
3197
                                g_free(pkt->data);
3198
                                pkt->data = NULL;
3199
                                g_free(pkt);
3200
                                pkt = NULL;
3201
                                continue;
3202
                        }
3203
                        if(!stream->cdone) {
3204
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
3205
                                        JANUS_LOG(LOG_ERR, "[%"SCNu64"]     %s candidates not gathered yet for stream??\n", handle->handle_id, video ? "video" : "audio");
3206
                                        stream->noerrorlog = 1;        /* Don't flood with the same error all over again */
3207
                                }
3208
                                g_free(pkt->data);
3209
                                pkt->data = NULL;
3210
                                g_free(pkt);
3211
                                pkt = NULL;
3212
                                continue;
3213
                        }
3214
                        stream->noerrorlog = 0;
3215
                        if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_out) {
3216
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
3217
                                        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);
3218
                                        component->noerrorlog = 1;        /* Don't flood with the same error all over again */
3219
                                }
3220
                                g_free(pkt->data);
3221
                                pkt->data = NULL;
3222
                                g_free(pkt);
3223
                                pkt = NULL;
3224
                                continue;
3225
                        }
3226
                        component->noerrorlog = 0;
3227
                        if(pkt->encrypted) {
3228
                                /* Already SRTCP */
3229
                                int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, pkt->length, (const gchar *)pkt->data);
3230
                                if(sent < pkt->length) {
3231
                                        JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, pkt->length);
3232
                                }
3233
                        } else {
3234
                                /* Check if there's anything we need to do before sending */
3235
                                uint64_t bitrate = janus_rtcp_get_remb(pkt->data, pkt->length);
3236
                                if(bitrate > 0) {
3237
                                        /* There's a REMB, prepend a RR as it won't work otherwise */
3238
                                        int rrlen = 32;
3239
                                        char *rtcpbuf = g_malloc0(rrlen+pkt->length);
3240
                                        rtcp_rr *rr = (rtcp_rr *)rtcpbuf;
3241
                                        rr->header.version = 2;
3242
                                        rr->header.type = RTCP_RR;
3243
                                        rr->header.rc = 1;
3244
                                        rr->header.length = htons((rrlen/4)-1);
3245
                                        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);
3246
                                        if(stream && stream->video_rtcp_ctx && stream->video_rtcp_ctx->enabled)
3247
                                                janus_rtcp_report_block(stream->video_rtcp_ctx, &rr->rb[0]);
3248
                                        /* Append REMB */
3249
                                        memcpy(rtcpbuf+rrlen, pkt->data, pkt->length);
3250
                                        /* Free old packet and update */
3251
                                        g_free(pkt->data);
3252
                                        pkt->data = rtcpbuf;
3253
                                        pkt->length = rrlen+pkt->length;
3254
                                }
3255
                                /* FIXME Copy in a buffer and fix SSRC */
3256
                                char sbuf[JANUS_BUFSIZE];
3257
                                memcpy(sbuf, pkt->data, pkt->length);
3258
                                /* Fix all SSRCs! */
3259
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
3260
                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Fixing SSRCs (local %u, peer %u)\n", handle->handle_id,
3261
                                                video ? stream->video_ssrc : stream->audio_ssrc,
3262
                                                video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
3263
                                        janus_rtcp_fix_ssrc(NULL, sbuf, pkt->length, 1,
3264
                                                video ? stream->video_ssrc : stream->audio_ssrc,
3265
                                                video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
3266
                                } else {
3267
                                        /* Plan B involved, we trust the plugin to set the right 'local' SSRC and we don't mess with it */
3268
                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Fixing peer SSRC (Plan B, peer %u)\n", handle->handle_id,
3269
                                                video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
3270
                                        janus_rtcp_fix_ssrc(NULL, sbuf, pkt->length, 1, 0,
3271
                                                video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
3272
                                }
3273

    
3274
                                int protected = pkt->length;
3275
                                int res = 0;
3276
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
3277
                                        res = srtp_protect_rtcp(component->dtls->srtp_out, sbuf, &protected);
3278
                                } else {
3279
                                        /* We need to make sure different sources don't use the SRTP context at the same time */
3280
                                        janus_mutex_lock(&component->dtls->srtp_mutex);
3281
                                        res = srtp_protect_rtcp(component->dtls->srtp_out, sbuf, &protected);
3282
                                        janus_mutex_unlock(&component->dtls->srtp_mutex);
3283
                                }
3284
                                //~ JANUS_LOG(LOG_VERB, "[%"SCNu64"] ... SRTCP protect %s (len=%d-->%d)...\n", handle->handle_id, janus_get_srtp_error(res), pkt->length, protected);
3285
                                if(res != err_status_ok) {
3286
                                        JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... SRTCP protect error... %s (len=%d-->%d)...\n", handle->handle_id, janus_get_srtp_error(res), pkt->length, protected);
3287
                                } else {
3288
                                        /* Shoot! */
3289
                                        //~ JANUS_LOG(LOG_VERB, "[%"SCNu64"] ... Sending SRTCP packet (pt=%u, seq=%u, ts=%u)...\n", handle->handle_id,
3290
                                                //~ header->paytype, ntohs(header->seq_number), ntohl(header->timestamp));
3291
                                        int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, protected, sbuf);
3292
                                        if(sent < protected) {
3293
                                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, protected);
3294
                                        }
3295
                                }
3296
                        }
3297
                        g_free(pkt->data);
3298
                        g_free(pkt);
3299
                        continue;
3300
                } else {
3301
                        /* RTP or data */
3302
                        if(pkt->type == JANUS_ICE_PACKET_AUDIO || pkt->type == JANUS_ICE_PACKET_VIDEO) {
3303
                                /* RTP */
3304
                                int video = (pkt->type == JANUS_ICE_PACKET_VIDEO);
3305
                                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);
3306
                                if(!stream) {
3307
                                        g_free(pkt->data);
3308
                                        pkt->data = NULL;
3309
                                        g_free(pkt);
3310
                                        pkt = NULL;
3311
                                        continue;
3312
                                }
3313
                                janus_ice_component *component = stream->rtp_component;
3314
                                if(!component) {
3315
                                        g_free(pkt->data);
3316
                                        pkt->data = NULL;
3317
                                        g_free(pkt);
3318
                                        pkt = NULL;
3319
                                        continue;
3320
                                }
3321
                                if(!stream->cdone) {
3322
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
3323
                                                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     %s candidates not gathered yet for stream??\n", handle->handle_id, video ? "video" : "audio");
3324
                                                stream->noerrorlog = 1;        /* Don't flood with the same error all over again */
3325
                                        }
3326
                                        g_free(pkt->data);
3327
                                        pkt->data = NULL;
3328
                                        g_free(pkt);
3329
                                        pkt = NULL;
3330
                                        continue;
3331
                                }
3332
                                stream->noerrorlog = 0;
3333
                                if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_out) {
3334
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
3335
                                                JANUS_LOG(LOG_WARN, "[%"SCNu64"]     %s stream component has no valid SRTP session (yet?)\n", handle->handle_id, video ? "video" : "audio");
3336
                                                component->noerrorlog = 1;        /* Don't flood with the same error all over again */
3337
                                        }
3338
                                        g_free(pkt->data);
3339
                                        pkt->data = NULL;
3340
                                        g_free(pkt);
3341
                                        pkt = NULL;
3342
                                        continue;
3343
                                }
3344
                                component->noerrorlog = 0;
3345
                                if(pkt->encrypted) {
3346
                                        /* Already RTP (probably a retransmission?) */
3347
                                        rtp_header *header = (rtp_header *)pkt->data;
3348
                                        JANUS_LOG(LOG_HUGE, "[%"SCNu64"] ... Retransmitting seq.nr %"SCNu16"\n\n", handle->handle_id, ntohs(header->seq_number));
3349
                                        int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, pkt->length, (const gchar *)pkt->data);
3350
                                        if(sent < pkt->length) {
3351
                                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, pkt->length);
3352
                                        }
3353
                                } else {
3354
                                        /* FIXME Copy in a buffer and fix SSRC */
3355
                                        char sbuf[JANUS_BUFSIZE];
3356
                                        memcpy(sbuf, pkt->data, pkt->length);
3357
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
3358
                                                /* Overwrite SSRC */
3359
                                                rtp_header *header = (rtp_header *)sbuf;
3360
                                                header->ssrc = htonl(video ? stream->video_ssrc : stream->audio_ssrc);
3361
                                        }
3362
                                        int protected = pkt->length;
3363
                                        int res = srtp_protect(component->dtls->srtp_out, sbuf, &protected);
3364
                                        //~ JANUS_LOG(LOG_VERB, "[%"SCNu64"] ... SRTP protect %s (len=%d-->%d)...\n", handle->handle_id, janus_get_srtp_error(res), pkt->length, protected);
3365
                                        if(res != err_status_ok) {
3366
                                                rtp_header *header = (rtp_header *)sbuf;
3367
                                                guint32 timestamp = ntohl(header->timestamp);
3368
                                                guint16 seq = ntohs(header->seq_number);
3369
                                                JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... SRTP protect error... %s (len=%d-->%d, ts=%"SCNu32", seq=%"SCNu16")...\n", handle->handle_id, janus_get_srtp_error(res), pkt->length, protected, timestamp, seq);
3370
                                        } else {
3371
                                                /* Shoot! */
3372
                                                //~ JANUS_LOG(LOG_VERB, "[%"SCNu64"] ... Sending SRTP packet (pt=%u, ssrc=%u, seq=%u, ts=%u)...\n", handle->handle_id,
3373
                                                        //~ header->type, ntohl(header->ssrc), ntohs(header->seq_number), ntohl(header->timestamp));
3374
                                                int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, protected, sbuf);
3375
                                                if(sent < protected) {
3376
                                                        JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, protected);
3377
                                                }
3378
                                                /* Update stats */
3379
                                                if(sent > 0) {
3380
                                                        rtp_header *header = (rtp_header *)sbuf;
3381
                                                        guint32 timestamp = ntohl(header->timestamp);
3382
                                                        if(pkt->type == JANUS_ICE_PACKET_AUDIO) {
3383
                                                                component->out_stats.audio_packets++;
3384
                                                                component->out_stats.audio_bytes += sent;
3385
                                                                stream->audio_last_ts = timestamp;
3386
                                                        } else if(pkt->type == JANUS_ICE_PACKET_VIDEO) {
3387
                                                                component->out_stats.video_packets++;
3388
                                                                component->out_stats.video_bytes += sent;
3389
                                                                stream->video_last_ts = timestamp;
3390
                                                        }
3391
                                                }
3392
                                                /* Save the packet for retransmissions that may be needed later */
3393
                                                janus_rtp_packet *p = (janus_rtp_packet *)g_malloc0(sizeof(janus_rtp_packet));
3394
                                                p->data = (char *)g_malloc0(protected);
3395
                                                memcpy(p->data, sbuf, protected);
3396
                                                p->length = protected;
3397
                                                p->last_retransmit = 0;
3398
                                                janus_mutex_lock(&component->mutex);
3399
                                                component->retransmit_buffer = g_list_append(component->retransmit_buffer, p);
3400
                                                if(g_list_length(component->retransmit_buffer) > max_nack_queue) {
3401
                                                        /* We only keep a limited window of packets, get rid of the oldest one */
3402
                                                        GList *first = g_list_first(component->retransmit_buffer);
3403
                                                        p = (janus_rtp_packet *)first->data;
3404
                                                        first->data = NULL;
3405
                                                        component->retransmit_buffer = g_list_delete_link(component->retransmit_buffer, first);
3406
                                                        g_free(p->data);
3407
                                                        p->data = NULL;
3408
                                                        g_free(p);
3409
                                                }
3410
                                                janus_mutex_unlock(&component->mutex);
3411
                                        }
3412
                                }
3413
                        } else {
3414
                                /* Data */
3415
                                if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS)) {
3416
                                        g_free(pkt->data);
3417
                                        pkt->data = NULL;
3418
                                        g_free(pkt);
3419
                                        pkt = NULL;
3420
                                        continue;
3421
                                }
3422
#ifdef HAVE_SCTP
3423
                                janus_ice_stream *stream = handle->data_stream ? handle->data_stream : (handle->audio_stream ? handle->audio_stream : handle->video_stream);
3424
                                if(!stream) {
3425
                                        g_free(pkt->data);
3426
                                        pkt->data = NULL;
3427
                                        g_free(pkt);
3428
                                        pkt = NULL;
3429
                                        continue;
3430
                                }
3431
                                janus_ice_component *component = stream->rtp_component;
3432
                                if(!component) {
3433
                                        g_free(pkt->data);
3434
                                        pkt->data = NULL;
3435
                                        g_free(pkt);
3436
                                        pkt = NULL;
3437
                                        continue;
3438
                                }
3439
                                if(!stream->cdone) {
3440
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
3441
                                                JANUS_LOG(LOG_ERR, "[%"SCNu64"]     SCTP candidates not gathered yet for stream??\n", handle->handle_id);
3442
                                                stream->noerrorlog = 1;        /* Don't flood with the same error all over again */
3443
                                        }
3444
                                        g_free(pkt->data);
3445
                                        pkt->data = NULL;
3446
                                        g_free(pkt);
3447
                                        pkt = NULL;
3448
                                        continue;
3449
                                }
3450
                                stream->noerrorlog = 0;
3451
                                if(!component->dtls) {
3452
                                        if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
3453
                                                JANUS_LOG(LOG_WARN, "[%"SCNu64"]     SCTP stream component has no valid DTLS session (yet?)\n", handle->handle_id);
3454
                                                component->noerrorlog = 1;        /* Don't flood with the same error all over again */
3455
                                        }
3456
                                        g_free(pkt->data);
3457
                                        pkt->data = NULL;
3458
                                        g_free(pkt);
3459
                                        pkt = NULL;
3460
                                        continue;
3461
                                }
3462
                                component->noerrorlog = 0;
3463
                                janus_dtls_wrap_sctp_data(component->dtls, pkt->data, pkt->length);
3464
#endif
3465
                        }
3466
                        g_free(pkt->data);
3467
                        pkt->data = NULL;
3468
                        g_free(pkt);
3469
                        pkt = NULL;
3470
                        continue;
3471
                }
3472
        }
3473
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE send thread leaving...\n", handle->handle_id);
3474
        g_thread_unref(g_thread_self());
3475
        return NULL;
3476
}
3477

    
3478
void janus_ice_relay_rtp(janus_ice_handle *handle, int video, char *buf, int len) {
3479
        if(!handle || buf == NULL || len < 1)
3480
                return;
3481
        if((!video && !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO))
3482
                        || (video && !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)))
3483
                return;
3484
        /* Queue this packet */
3485
        janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
3486
        pkt->data = g_malloc0(len);
3487
        memcpy(pkt->data, buf, len);
3488
        pkt->length = len;
3489
        pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
3490
        pkt->control = FALSE;
3491
        pkt->encrypted = FALSE;
3492
        if(handle->queued_packets != NULL)
3493
                g_async_queue_push(handle->queued_packets, pkt);
3494
}
3495

    
3496
static void janus_ice_relay_rtcp_internal(janus_ice_handle *handle, int video, char *buf, int len, gboolean filter_rtcp) {
3497
        if(!handle || buf == NULL || len < 1)
3498
                return;
3499
        /* We use this internal method to check whether we need to filter RTCP (e.g., to make
3500
         * sure we don't just forward any SR/RR from peers/plugins, but use our own) or it has
3501
         * already been done, and so this is actually a packet added by the ICE send thread */
3502
        char *rtcp_buf = buf;
3503
        int rtcp_len = len;
3504
        if(filter_rtcp) {
3505
                /* FIXME Strip RR/SR/SDES/NACKs/etc. */
3506
                rtcp_buf = janus_rtcp_filter(buf, len, &rtcp_len);
3507
                if(rtcp_buf == NULL)
3508
                        return;
3509
        }
3510
        if(rtcp_len < 1)
3511
                return;
3512
        /* Queue this packet */
3513
        janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
3514
        pkt->data = g_malloc0(len);
3515
        memcpy(pkt->data, rtcp_buf, rtcp_len);
3516
        pkt->length = rtcp_len;
3517
        pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
3518
        pkt->control = TRUE;
3519
        pkt->encrypted = FALSE;
3520
        if(handle->queued_packets != NULL)
3521
                g_async_queue_push(handle->queued_packets, pkt);
3522
        if(rtcp_buf != buf) {
3523
                /* We filtered the original packet, deallocate it */
3524
                g_free(rtcp_buf);
3525
        }
3526
}
3527

    
3528
void janus_ice_relay_rtcp(janus_ice_handle *handle, int video, char *buf, int len) {
3529
        janus_ice_relay_rtcp_internal(handle, video, buf, len, TRUE);
3530
}
3531

    
3532
#ifdef HAVE_SCTP
3533
void janus_ice_relay_data(janus_ice_handle *handle, char *buf, int len) {
3534
        if(!handle || buf == NULL || len < 1)
3535
                return;
3536
        /* Queue this packet */
3537
        janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
3538
        pkt->data = g_malloc0(len);
3539
        memcpy(pkt->data, buf, len);
3540
        pkt->length = len;
3541
        pkt->type = JANUS_ICE_PACKET_DATA;
3542
        pkt->control = FALSE;
3543
        pkt->encrypted = FALSE;
3544
        if(handle->queued_packets != NULL)
3545
                g_async_queue_push(handle->queued_packets, pkt);
3546
}
3547
#endif
3548

    
3549
void janus_ice_dtls_handshake_done(janus_ice_handle *handle, janus_ice_component *component) {
3550
        if(!handle || !component)
3551
                return;
3552
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] The DTLS handshake for the component %d in stream %d has been completed\n",
3553
                handle->handle_id, component->component_id, component->stream_id);
3554
        /* Check if all components are ready */
3555
        janus_mutex_lock(&handle->mutex);
3556
        if(handle->audio_stream && !handle->audio_stream->disabled) {
3557
                if(handle->audio_stream->rtp_component && (!handle->audio_stream->rtp_component->dtls ||
3558
                                !handle->audio_stream->rtp_component->dtls->srtp_valid)) {
3559
                        /* Still waiting for this component to become ready */
3560
                        janus_mutex_unlock(&handle->mutex);
3561
                        return;
3562
                }
3563
                if(handle->audio_stream->rtcp_component && (!handle->audio_stream->rtcp_component->dtls ||
3564
                                !handle->audio_stream->rtcp_component->dtls->srtp_valid)) {
3565
                        /* Still waiting for this component to become ready */
3566
                        janus_mutex_unlock(&handle->mutex);
3567
                        return;
3568
                }
3569
        }
3570
        if(handle->video_stream && !handle->video_stream->disabled) {
3571
                if(handle->video_stream->rtp_component && (!handle->video_stream->rtp_component->dtls ||
3572
                                !handle->video_stream->rtp_component->dtls->srtp_valid)) {
3573
                        /* Still waiting for this component to become ready */
3574
                        janus_mutex_unlock(&handle->mutex);
3575
                        return;
3576
                }
3577
                if(handle->video_stream->rtcp_component && (!handle->video_stream->rtcp_component->dtls ||
3578
                                !handle->video_stream->rtcp_component->dtls->srtp_valid)) {
3579
                        /* Still waiting for this component to become ready */
3580
                        janus_mutex_unlock(&handle->mutex);
3581
                        return;
3582
                }
3583
        }
3584
        if(handle->data_stream && !handle->data_stream->disabled) {
3585
                if(handle->data_stream->rtp_component && (!handle->data_stream->rtp_component->dtls ||
3586
                                !handle->data_stream->rtp_component->dtls->srtp_valid)) {
3587
                        /* Still waiting for this component to become ready */
3588
                        janus_mutex_unlock(&handle->mutex);
3589
                        return;
3590
                }
3591
        }
3592
        if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY)) {
3593
                /* Already notified */
3594
                janus_mutex_unlock(&handle->mutex);
3595
                return;
3596
        }
3597
        janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
3598
        janus_mutex_unlock(&handle->mutex);
3599
        JANUS_LOG(LOG_INFO, "[%"SCNu64"] The DTLS handshake has been completed\n", handle->handle_id);
3600
        /* Notify the plugin that the WebRTC PeerConnection is ready to be used */
3601
        janus_plugin *plugin = (janus_plugin *)handle->app;
3602
        if(plugin != NULL) {
3603
                JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about it (%s)\n", handle->handle_id, plugin->get_name());
3604
                if(plugin && plugin->setup_media && janus_plugin_session_is_alive(handle->app_handle))
3605
                        plugin->setup_media(handle->app_handle);
3606
        }
3607
        /* Also prepare JSON event to notify user/application */
3608
        janus_session *session = (janus_session *)handle->session;
3609
        if(session == NULL)
3610
                return;
3611
        json_t *event = json_object();
3612
        json_object_set_new(event, "janus", json_string("webrtcup"));
3613
        json_object_set_new(event, "session_id", json_integer(session->session_id));
3614
        json_object_set_new(event, "sender", json_integer(handle->handle_id));
3615
        /* Send the event */
3616
        JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
3617
        janus_session_notify_event(session->session_id, event);
3618
        /* Notify event handlers as well */
3619
        if(janus_events_is_enabled()) {
3620
                json_t *info = json_object();
3621
                json_object_set_new(info, "connection", json_string("webrtcup"));
3622
                janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, session->session_id, handle->handle_id, info);
3623
        }
3624
}